S: 4850 Moresnet
S: Belgium
+N: Cort Dougan
+E: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~cort/
+D: PowerPC PReP port
+S: Computer Science Department
+S: New Mexico Tech
+S: Socorro NM 87801
+S: USA
+
N: Thomas Dunbar
E: tdunbar@vtaix.cc.vt.edu
D: TeX & METAFONT hacking/maintenance
D: SLS distribution
D: Initial implementation of VC's, pty's and select()
+N: Paul Mackerras
+E: paulus@cs.anu.edu.au
+D: Linux port for PCI Power Macintosh
+S: Dept. of Computer Science
+S: Australian National University
+S: Canberra ACT 0200
+S: AUSTRALIA
+
N: James B. MacLean
E: macleajb@ednet.ns.ca
W: http://www.ednet.ns.ca/~macleajb/dosemu.html
have a use for such a device (such as periodic data sampling), then
say Y here, and go read the file Documentation/rtc.txt for details.
+/dev/nvram support
+CONFIG_NVRAM
+ If you say Y here and create a character special file /dev/nvram
+ with major number 10 and minor number 144 using mknod ("man mknod"),
+ you get access to the non-volatile memory in the real time clock
+ (RTC). This is conventionally called "CMOS RAM" on PCs and "NVRAM"
+ on Ataris. /dev/nvram may be used to view settings there, or to
+ change them (with some utility). It could also be used to frequently
+ save a few bits of very important data, that may not be lost over
+ power-off and for which writing to disk is too insecure. On Atari
+ machines, /dev/nvram is always configured and needs not be selected.
+
ARC console time
CONFIG_RTC_ARC
If you boot your Alpha using the ARC firmware, say Y here. This option
W: http://www.cage.curtin.edu.au/~campbell/parbus/
S: Maintained
+LINUX FOR POWERPC (PREP)
+P: Cort Dougan
+M: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~linuxppc/
+S: Maintained
+
+LINUX FOR POWER MACINTOSH
+P: Paul Mackerras
+M: paulus@cs.anu.edu.au
+L: linux-pmac@samba.anu.edu.au
+S: Maintained
+
FPU EMULATOR
P: Bill Metzenthen
M: billm@suburbia.net
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
#
volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
volatile int smp_process_available=0;
+const char lk_lockmsg[] = "lock from interrupt context at %p\n";
+
+
/*#define SMP_DEBUG*/
#ifdef SMP_DEBUG
SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
endif
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
lilo: vmlinux
if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
archclean:
rm -f vmlinux.gz
- @$(MAKEBOOT) clean
archdep:
- $(MAKEBOOT) dep
static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
- unsigned char scancode, break_flag;
+ unsigned char scancode, break_flag, keycode;
static int reset_warning = 0;
/* save frame for register dump */
/* switch SP pin to output for handshake */
ciaa.cra |= 0x40;
+#if 0 // No longer used
/*
* On receipt of the second RESET_WARNING, we must not pull KDAT high
* again to delay the hard reset as long as possible.
} else
/* Probably a mistake, cancel the alert */
reset_warning = 0;
+#endif
/* wait until 85 us have expired */
udelay(85);
* Check make/break first
*/
break_flag = scancode & BREAK_MASK;
- scancode &= (unsigned char )~BREAK_MASK;
+ keycode = scancode & (unsigned char)~BREAK_MASK;
- if (scancode == AMIKEY_CAPS) {
+ if (keycode == AMIKEY_CAPS) {
/* if the key is CAPS, fake a press/release. */
handle_scancode(AMIKEY_CAPS);
handle_scancode(BREAK_MASK | AMIKEY_CAPS);
- } else if (scancode < 0x78) {
+ } else if (keycode < 0x78) {
/* handle repeat */
if (break_flag) {
del_timer(&amikeyb_rep_timer);
rep_scancode = 0;
} else {
del_timer(&amikeyb_rep_timer);
- rep_scancode = scancode;
+ rep_scancode = keycode;
amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
}
- handle_scancode(break_flag | scancode);
+ handle_scancode(scancode);
} else
- switch (scancode) {
+ switch (keycode) {
case 0x78:
reset_warning = 1;
break;
#endif
default:
printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
- break_flag | scancode);
+ scancode);
break;
}
}
{
int key;
struct ConfigDev *cd;
-
+
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
return(0);
+++ /dev/null
-#
-# linux/arch/m68k/boot/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-
-ifdef CONFIG_AMIGA
-AMIGA_BOOTSTRAP = amiga_bootstrap
-AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
-AMIGA_HOSTCC = m68k-cbm-amigados-gcc
-AMIGA_HOSTINC = -I$(TOPDIR)/include
-AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
-endif
-
-ifdef CONFIG_ATARI
-ATARI_BOOTSTRAP = atari_bootstrap
-ATARI_BOOTOBJS := atari/bootstrap.o
-ATARI_HOSTCC = m68k-mint-gcc
-ATARI_HOSTINC = -I$(TOPDIR)/include
-ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
-
-# BOOTP/TFTP support in bootstrap?
-# USE_BOOTP = y
-
-ifdef USE_BOOTP
-ATARI_BOOTOBJS += atari/bootp.o
-ATARI_HOSTFLAGS += -DUSE_BOOTP
-
-# low-level Ethernet drivers:
-
-# Lance (RieblCard, PAM-VME)
-ATARI_BOOTOBJS += atari/ethlance.o
-ATARI_HOSTFLAGS += -DETHLL_LANCE
-
-endif
-endif
-
-ifdef CONFIG_ATARI
-atari_bootstrap: $(ATARI_BOOTOBJS)
- $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
- rm -f ../../../bootstrap
- ln $@ ../../../bootstrap
-endif
-
-ifdef CONFIG_AMIGA
-amiga_bootstrap: $(AMIGA_BOOTOBJS)
- $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
- rm -f ../../../bootstrap
- ln $@ ../../../bootstrap
-endif
-
-$(AMIGA_BOOTOBJS): %.o: %.c
- $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -c $< -o $@
-
-$(ATARI_BOOTOBJS): %.o: %.c
- $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -c $< -o $@
-
-bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
-
-clean:
- rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap \
- ../../../bootstrap
-
-dep:
+++ /dev/null
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
-** kernel into an Amiga and launches
-** it.
-**
-** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
-**
-** Modified 11-May-94 by Geert Uytterhoeven
-** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-** - A3640 MapROM check
-** Modified 31-May-94 by Geert Uytterhoeven
-** - Memory thrash problem solved
-** Modified 07-March-95 by Geert Uytterhoeven
-** - Memory block sizes are rounded to a multiple of 256K instead of 1M
-** This _requires_ >0.9pl5 to work!
-** (unless all block sizes are multiples of 1M :-)
-** Modified 11-July-95 by Andreas Schwab
-** - Support for ELF kernel (untested!)
-** Modified 10-Jan-96 by Geert Uytterhoeven
-** - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-** - Rewritten option parsing
-** - New parameter passing to linuxboot() (linuxboot_args)
-** Modified 6-Oct-96 by Geert Uytterhoeven
-** - Updated for the new boot information structure
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/file.h>
-#include <unistd.h>
-
-/* required Linux/m68k include files */
-#define __KERNEL_STRICT_NAMES /* This is ugly, I know */
-#define _LINUX_POSIX_TYPES_H
-#include <asm/posix_types.h>
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-/* Amiga bootstrap include files */
-#include "linuxboot.h"
-#include "bootstrap.h"
-
-
-/* Library Bases */
-long __oslibversion = 36;
-extern const struct ExecBase *SysBase;
-
-static const char *memfile_name = NULL;
-
-static int model = AMI_UNKNOWN;
-
-static const char *ProgramName;
-
-struct linuxboot_args args;
-
-
- /*
- * Function Prototypes
- */
-
-static void Usage(void) __attribute__ ((noreturn));
-int main(int argc, char *argv[]);
-static void Puts(const char *str);
-static long GetChar(void);
-static void PutChar(char c);
-static void Printf(const char *fmt, ...);
-static int Open(const char *path);
-static int Seek(int fd, int offset);
-static int Read(int fd, char *buf, int count);
-static void Close(int fd);
-static int FileSize(const char *path);
-static void Sleep(u_long micros);
-
-
-static void Usage(void)
-{
- fprintf(stderr,
- "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
- "Usage: %s [options] [kernel command line]\n\n"
- "Basic options:\n"
- " -h, --help Display this usage information\n"
- " -k, --kernel file Use kernel image `file' (default is `vmlinux')\n"
- " -r, --ramdisk file Use ramdisk image `file'\n"
- "Advanced options:\n"
- " -d, --debug Enable debug mode\n"
- " -b, --baud speed Set the serial port speed (default is 9600)\n"
- " -m, --memfile file Use memory file `file'\n"
- " -v, --keep-video Don't reset the video mode\n"
- " -t, --model id Set the Amiga model to `id'\n"
- " -p, --processor cfm Set the processor type to `cfm\n\n",
- ProgramName);
- exit(EXIT_FAILURE);
-}
-
-
-int main(int argc, char *argv[])
-{
- int i;
- int processor = 0, debugflag = 0, keep_video = 0;
- u_int baud = 0;
- const char *kernel_name = NULL;
- const char *ramdisk_name = NULL;
- char commandline[CL_SIZE] = "";
-
- ProgramName = argv[0];
- while (--argc) {
- argv++;
- if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
- Usage();
- else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
- if (--argc && !kernel_name) {
- kernel_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
- if (--argc && !ramdisk_name) {
- ramdisk_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
- debugflag = 1;
- else if (!strcmp(argv[0], "-b") || !strcmp(argv[0], "--baud"))
- if (--argc && !baud) {
- baud = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
- if (--argc && !memfile_name) {
- memfile_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
- keep_video = 1;
- else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
- if (--argc && !model) {
- model = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--processor"))
- if (--argc && !processor) {
- processor = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else
- break;
- }
- if (!kernel_name)
- kernel_name = "vmlinux";
-
- SysBase = *(struct ExecBase **)4;
-
- /*
- * Join command line options
- */
- i = 0;
- while (argc--) {
- if ((i+strlen(*argv)+1) < CL_SIZE) {
- i += strlen(*argv) + 1;
- if (commandline[0])
- strcat(commandline, " ");
- strcat(commandline, *argv++);
- }
- }
-
- memset(&args.bi, 0, sizeof(args.bi));
- if (processor) {
- int cpu = processor/100%10;
- int fpu = processor/10%10;
- int mmu = processor%10;
- if (cpu)
- args.bi.cputype = 1<<(cpu-1);
- if (fpu)
- args.bi.fputype = 1<<(fpu-1);
- if (mmu)
- args.bi.mmutype = 1<<(mmu-1);
- }
- /*
- * If we have a memory file, read the memory information from it
- */
- if (memfile_name) {
- FILE *fp;
- int i;
-
- if ((fp = fopen(memfile_name, "r")) == NULL) {
- perror("open memory file");
- fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
- return(FALSE);
- }
-
- if (fscanf(fp, "%lu", &args.bi.chip_size) != 1) {
- fprintf(stderr, "memory file does not contain chip memory size\n");
- fclose(fp);
- return(FALSE);
- }
-
- for (i = 0; i < NUM_MEMINFO; i++)
- if (fscanf(fp, "%lx %lu", &args.bi.memory[i].addr,
- &args.bi.memory[i].size) != 2)
- break;
-
- fclose(fp);
- args.bi.num_memory = i;
- }
- strncpy(args.bi.command_line, commandline, CL_SIZE);
- args.bi.command_line[CL_SIZE-1] = '\0';
- if (model != AMI_UNKNOWN)
- args.bi.model = model;
-
- args.kernelname = kernel_name;
- args.ramdiskname = ramdisk_name;
- args.debugflag = debugflag;
- args.keep_video = keep_video;
- args.reset_boards = 1;
- args.baud = baud;
- args.puts = Puts;
- args.getchar = GetChar;
- args.putchar = PutChar;
- args.printf = Printf;
- args.open = Open;
- args.seek = Seek;
- args.read = Read;
- args.close = Close;
- args.filesize = FileSize;
- args.sleep = Sleep;
-
- /* Do The Right Stuff */
- linuxboot(&args);
-
- /* if we ever get here, something went wrong */
- exit(EXIT_FAILURE);
-}
-
-
- /*
- * Routines needed by linuxboot
- */
-
-static void Puts(const char *str)
-{
- fputs(str, stderr);
- fflush(stderr);
-}
-
-static long GetChar(void)
-{
- return(getchar());
-}
-
-static void PutChar(char c)
-{
- fputc(c, stderr);
- fflush(stderr);
-}
-
-static void Printf(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- fflush(stderr);
-}
-
-static int Open(const char *path)
-{
- return(open(path, O_RDONLY));
-}
-
-static int Seek(int fd, int offset)
-{
- return(lseek(fd, offset, SEEK_SET));
-}
-
-
-static int Read(int fd, char *buf, int count)
-{
- return(read(fd, buf, count));
-}
-
-static void Close(int fd)
-{
- close(fd);
-}
-
-static int FileSize(const char *path)
-{
- int fd, size = -1;
-
- if ((fd = open(path, O_RDONLY)) != -1) {
- size = lseek(fd, 0, SEEK_END);
- close(fd);
- }
- return(size);
-}
-
-static void Sleep(u_long micros)
-{
- struct MsgPort *TimerPort;
- struct timerequest *TimerRequest;
-
- if ((TimerPort = CreateMsgPort())) {
- if ((TimerRequest = CreateIORequest(TimerPort,
- sizeof(struct timerequest)))) {
- if (!OpenDevice("timer.device", UNIT_VBLANK,
- (struct IORequest *)TimerRequest, 0)) {
- TimerRequest->io_Command = TR_ADDREQUEST;
- TimerRequest->io_Flags = IOF_QUICK;
- TimerRequest->tv_secs = micros/1000000;
- TimerRequest->tv_micro = micros%1000000;
- DoIO((struct IORequest *)TimerRequest);
- CloseDevice((struct IORequest *)TimerRequest);
- }
- DeleteIORequest(TimerRequest);
- }
- DeleteMsgPort(TimerPort);
- }
-}
+++ /dev/null
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
-** bootloader.
-**
-** Copyright 1993, 1994 by Hamish Macdonald
-**
-** Some minor additions by Michael Rausch 1-11-94
-** Modified 11-May-94 by Geert Uytterhoeven
-** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-** - inline Supervisor() call
-** Modified 10-Jan-96 by Geert Uytterhoeven
-** - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-** - const library bases
-** - fixed register naming for m68k-cbm-amigados-gcc
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-
-struct MsgPort {
- u_char fill1[15];
- u_char mp_SigBit;
- u_char fill2[18];
-};
-
-struct IOStdReq {
- u_char fill1[20];
- struct Device *io_Device;
- u_char fill2[4];
- u_short io_Command;
- u_char io_Flags;
- char io_Error;
- u_long io_Actual;
- u_long io_Length;
- void *io_Data;
- u_char fill4[4];
-};
-
-#define IOF_QUICK (1<<0)
-
-struct timerequest {
- u_char fill1[28];
- u_short io_Command;
- u_char io_Flags;
- u_char fill2[1];
- u_long tv_secs;
- u_long tv_micro;
-};
-
-#define UNIT_VBLANK 1
-#define TR_ADDREQUEST 9
-
-
-struct Library;
-struct IORequest;
-
-
-static __inline char OpenDevice(u_char *devName, u_long unit,
- struct IORequest *ioRequest, u_long flags)
-{
- register char _res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register u_char *a0 __asm("a0") = devName;
- register u_long d0 __asm("d0") = unit;
- register struct IORequest *a1 __asm("a1") = ioRequest;
- register u_long d1 __asm("d1") = flags;
-
- __asm __volatile ("jsr a6@(-0x1bc)"
- : "=r" (_res)
- : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void CloseDevice(struct IORequest *ioRequest)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct IORequest *a1 __asm("a1") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x1c2)"
- : /* no output */
- : "r" (a6), "r" (a1)
- : "a0","a1","d0","d1", "memory");
-}
-
-static __inline char DoIO(struct IORequest *ioRequest)
-{
- register char _res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct IORequest *a1 __asm("a1") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x1c8)"
- : "=r" (_res)
- : "r" (a6), "r" (a1)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
-{
- register struct Library *_res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct MsgPort *a0 __asm("a0") = port;
- register u_long d0 __asm("d0") = size;
-
- __asm __volatile ("jsr a6@(-0x28e)"
- : "=r" (_res)
- : "r" (a6), "r" (a0), "r" (d0)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void DeleteIORequest(void *ioRequest)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register void *a0 __asm("a0") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x294)"
- : /* no output */
- : "r" (a6), "r" (a0)
- : "a0","a1","d0","d1", "memory");
-}
-
-static __inline struct MsgPort *CreateMsgPort(void)
-{
- register struct MsgPort *_res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x29a)"
- : "=r" (_res)
- : "r" (a6)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void DeleteMsgPort(struct MsgPort *port)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct MsgPort *a0 __asm("a0") = port;
-
- __asm __volatile ("jsr a6@(-0x2a0)"
- : /* no output */
- : "r" (a6), "r" (a0)
- : "a0","a1","d0","d1", "memory");
-}
+++ /dev/null
-/*
- * linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
- * on Amiga, used by both Amiboot and
- * Amiga-Lilo.
- *
- * Created 1996 by Geert Uytterhoeven
- *
- *
- * This file is based on the original bootstrap code (bootstrap.c):
- *
- * Copyright (C) 1993, 1994 Hamish Macdonald
- * Greg Harp
- *
- * with work by Michael Rausch
- * Geert Uytterhoeven
- * Frank Neumann
- * Andreas Schwab
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * History:
- * 11 Jun 1997 Fix for unpadded gzipped ramdisks with bootinfo interface
- * version 1.0
- * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
- * interface version 1.0 (Geert)
- * 3 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
- * code for ataboot)
- * 30 Dec 1996 Reverted the CPU detection to the old scheme
- * New boot parameter override scheme (Geert)
- * 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
- * 9 Sep 1996 Rewritten option parsing
- * New parameter passing to linuxboot() (linuxboot_args)
- * (Geert)
- * 18 Aug 1996 Updated for the new boot information structure (Geert)
- * 10 Jan 1996 The real Linux/m68k boot code moved to linuxboot.[ch]
- * (Geert)
- * 11 Jul 1995 Support for ELF kernel (untested!) (Andreas)
- * 7 Mar 1995 Memory block sizes are rounded to a multiple of 256K
- * instead of 1M (Geert)
- * 31 May 1994 Memory thrash problem solved (Geert)
- * 11 May 1994 A3640 MapROM check (Geert)
- */
-
-
-#ifndef __GNUC__
-#error GNU CC is required to compile this program
-#endif /* __GNUC__ */
-
-
-#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <linux/linkage.h>
-#include <asm/bootinfo.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-#include "linuxboot.h"
-
-
-#undef custom
-#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
-
-/* a.out linkage conventions */
-#undef SYMBOL_NAME_STR
-#define SYMBOL_NAME_STR(X) "_"#X
-
-/* temporary stack size */
-#define TEMP_STACKSIZE (256)
-
-#define DEFAULT_BAUD (9600)
-
-extern char copyall, copyallend;
-
-static struct exec kexec;
-static Elf32_Ehdr kexec_elf;
-static const struct linuxboot_args *linuxboot_args;
-
-/* Bootinfo */
-struct amiga_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE (4096)
-static u_long bi_size;
-static union {
- struct bi_record record;
- u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-#define kernelname linuxboot_args->kernelname
-#define ramdiskname linuxboot_args->ramdiskname
-#define debugflag linuxboot_args->debugflag
-#define keep_video linuxboot_args->keep_video
-#define reset_boards linuxboot_args->reset_boards
-#define baud linuxboot_args->baud
-
-#define Puts linuxboot_args->puts
-#define GetChar linuxboot_args->getchar
-#define PutChar linuxboot_args->putchar
-#define Printf linuxboot_args->printf
-#define Open linuxboot_args->open
-#define Seek linuxboot_args->seek
-#define Read linuxboot_args->read
-#define Close linuxboot_args->close
-#define FileSize linuxboot_args->filesize
-#define Sleep linuxboot_args->sleep
-
- /*
- * Function Prototypes
- */
-
-static u_long get_chipset(void);
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu);
-static u_long get_model(u_long chipset);
-static int probe_resident(const char *name);
-static int probe_resource(const char *name);
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-static int check_bootinfo_version(const char *memptr);
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
- u_long start_mem, u_long kernel_size, u_long rd_dest,
- u_long rd_size) __attribute__ ((noreturn));
-asmlinkage u_long maprommed(void);
-#ifdef ZKERNEL
-static int load_zkernel(int fd);
-static int KRead(int fd, void *buf, int cnt);
-static int KSeek(int fd, int offset);
-static int KClose(int fd);
-#else
-#define KRead Read
-#define KSeek Seek
-#define KClose Close
-#endif
-
-
- /*
- * Reset functions for nasty Zorro boards
- */
-
-static void reset_rb3(const struct ConfigDev *cd);
-static void reset_piccolo(const struct ConfigDev *cd);
-static void reset_sd64(const struct ConfigDev *cd);
-static void reset_ariadne(const struct ConfigDev *cd);
-static void reset_hydra(const struct ConfigDev *cd);
-#if 0
-static void reset_a2060(const struct ConfigDev *cd);
-#endif
-
-struct boardreset {
- u_short manuf;
- u_short prod;
- const char *name;
- void (*reset)(const struct ConfigDev *cd);
-};
-
-static struct boardreset boardresetdb[] = {
- { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
- { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
- { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
- { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
- { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
-#if 0
- { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
-#endif
-};
-#define NUM_BOARDRESET sizeof(boardresetdb)/sizeof(*boardresetdb)
-
-static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd);
-
-
-const char *amiga_models[] = {
- "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
- "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
- "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
-};
-const u_long first_amiga_model = AMI_500;
-const u_long last_amiga_model = AMI_DRACO;
-
-
-#define MASK(model) (1<<AMI_##model)
-
-#define CLASS_A3000 (MASK(3000) | MASK(3000T))
-#define CLASS_A4000 (MASK(4000) | MASK(4000T))
-#define CLASS_ZKICK (MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
-
-
- /*
- * Boot the Linux/m68k Operating System
- */
-
-u_long linuxboot(const struct linuxboot_args *args)
-{
- int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip;
- int i, j;
- const struct MemHeader *mnp;
- struct ConfigDev *cdp = NULL;
- char *memptr = NULL;
- u_long *stack = NULL;
- u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
- u_long kernel_size;
- u_int realbaud;
- u_long memreq = 0, text_offset = 0;
- Elf32_Phdr *kernel_phdrs = NULL;
- void (*startfunc)(void);
- u_short manuf;
- u_char prod;
- void *bi_ptr;
-
- linuxboot_args = args;
-
- /* print the greet message */
- Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
- Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
-
- /* Note: Initial values in bi override detected values */
- bi = args->bi;
-
- /* machine is Amiga */
- bi.machtype = MACH_AMIGA;
-
- /* determine chipset */
- if (!bi.chipset)
- bi.chipset = get_chipset();
-
- /* determine CPU, FPU and MMU type */
- if (!bi.cputype)
- get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);
-
- /* determine Amiga model */
- if (!bi.model)
- bi.model = get_model(bi.chipset);
- model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0;
-
- /* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
- /* find all of the autoconfig boards in the system */
- if (!bi.num_autocon)
- for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++)
- if (bi.num_autocon < ZORRO_NUM_AUTO)
- /* copy the contents of each structure into our boot info and
- count this device */
- memcpy(&bi.autocon[bi.num_autocon++], cdp,
- sizeof(struct ConfigDev));
- else
- Printf("Warning: too many AutoConfig devices. Ignoring device at "
- "0x%08lx\n", cdp->cd_BoardAddr);
-
- do_fast = bi.num_memory ? 0 : 1;
- do_chip = bi.chip_size ? 0 : 1;
- /* find out the memory in the system */
- for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
- mnp->mh_Node.ln_Succ;
- mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
- struct MemHeader mh;
-
- /* copy the information */
- mh = *mnp;
-
- /* skip virtual memory */
- if (!(mh.mh_Attributes & MEMF_PUBLIC))
- continue;
-
- /* if we suspect that Kickstart is shadowed in an A3000,
- modify the entry to show 512K more at the top of RAM
- Check first for a MapROMmed A3640 board: overwriting the
- Kickstart image causes an infinite lock-up on reboot! */
- if ((mh.mh_Upper == (void *)0x07f80000) &&
- (model_mask & (CLASS_A3000 | CLASS_A4000)))
- if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
- Puts("A3640 MapROM detected.\n");
- else if (model_mask & CLASS_A3000) {
- mh.mh_Upper = (void *)0x08000000;
- Puts("A3000 shadowed Kickstart detected.\n");
- }
-
- /* if we suspect that Kickstart is zkicked,
- modify the entry to show 512K more at the botton of RAM */
- if ((mh.mh_Lower == (void *)0x00280020) &&
- (model_mask & CLASS_ZKICK)) {
- mh.mh_Lower = (void *)0x00200000;
- Puts("ZKick detected.\n");
- }
-
- /* mask the memory limit values */
- mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
- mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
- /* if fast memory */
- if (do_fast && mh.mh_Attributes & MEMF_FAST) {
- /* set the size value to the size of this block and mask off to a
- 256K increment */
- u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
- if (size > 0)
- if (bi.num_memory < NUM_MEMINFO) {
- /* record the start and size */
- bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
- bi.memory[bi.num_memory].size = size;
- /* count this block */
- bi.num_memory++;
- } else
- Printf("Warning: too many memory blocks. Ignoring block "
- "of %ldK at 0x%08x\n", size>>10,
- (u_long)mh.mh_Lower);
- } else if (do_chip && mh.mh_Attributes & MEMF_CHIP)
- /* if CHIP memory, record the size */
- bi.chip_size = (u_long)mh.mh_Upper;
- }
-
- /* get info from ExecBase */
- if (!bi.vblank)
- bi.vblank = SysBase->VBlankFrequency;
- if (!bi.psfreq)
- bi.psfreq = SysBase->PowerSupplyFrequency;
- if (!bi.eclock)
- bi.eclock = SysBase->ex_EClockFrequency;
-
- /* serial port */
- if (!bi.serper) {
- realbaud = baud ? baud : DEFAULT_BAUD;
- bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
- }
-
- /* display Amiga model */
- if (bi.model >= first_amiga_model && bi.model <= last_amiga_model)
- Printf("%s ", amiga_models[bi.model-first_amiga_model]);
- else
- Puts("Amiga ");
-
- /* display the CPU type */
- Puts("CPU: ");
- switch (bi.cputype) {
- case CPU_68020:
- Puts("68020 (Do you have an MMU?)");
- break;
- case CPU_68030:
- Puts("68030");
- break;
- case CPU_68040:
- Puts("68040");
- break;
- case CPU_68060:
- Puts("68060");
- break;
- default:
- Puts("Insufficient for Linux. Aborting...\n");
- Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
- goto Fail;
- }
- switch (bi.fputype) {
- case FPU_68881:
- Puts(" with 68881 FPU");
- break;
- case FPU_68882:
- Puts(" with 68882 FPU");
- break;
- case FPU_68040:
- case FPU_68060:
- Puts(" with internal FPU");
- break;
- default:
- Puts(" without FPU");
- break;
- }
-
- /* display the chipset */
- switch (bi.chipset) {
- case CS_STONEAGE:
- Puts(", old or unknown chipset");
- break;
- case CS_OCS:
- Puts(", OCS");
- break;
- case CS_ECS:
- Puts(", ECS");
- break;
- case CS_AGA:
- Puts(", AGA chipset");
- break;
- }
-
- Puts("\n\n");
-
- /* display the command line */
- Printf("Command line is '%s'\n", bi.command_line);
-
- /* display the clock statistics */
- Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank);
- Printf("Power Supply Frequency: %ldHz\n", bi.psfreq);
- Printf("EClock Frequency: %ldHz\n\n", bi.eclock);
-
- /* display autoconfig devices */
- if (bi.num_autocon) {
- Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon,
- bi.num_autocon > 1 ? "s" : "");
- for (i = 0; i < bi.num_autocon; i++) {
- Printf("Device %ld: addr = 0x%08lx", i,
- (u_long)bi.autocon[i].cd_BoardAddr);
- boardresetfuncs[i] = NULL;
- if (reset_boards) {
- manuf = bi.autocon[i].cd_Rom.er_Manufacturer;
- prod = bi.autocon[i].cd_Rom.er_Product;
- for (j = 0; j < NUM_BOARDRESET; j++)
- if ((manuf == boardresetdb[j].manuf) &&
- (prod == boardresetdb[j].prod)) {
- Printf(" [%s - will be reset at kernel boot time]",
- boardresetdb[j].name);
- boardresetfuncs[i] = boardresetdb[j].reset;
- break;
- }
- }
- PutChar('\n');
- }
- } else
- Puts("No AutoConfig Devices Found\n");
-
- /* display memory */
- if (bi.num_memory) {
- Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
- bi.num_memory > 1 ? "s " : " ");
- for (i = 0; i < bi.num_memory; i++)
- Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
- bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
- bi.memory[i].size>>10);
- } else {
- Puts("No memory found?! Aborting...\n");
- goto Fail;
- }
-
- /* display chip memory size */
- Printf("%ldK of CHIP memory\n", bi.chip_size>>10);
-
- start_mem = bi.memory[0].addr;
- mem_size = bi.memory[0].size;
-
- /* tell us where the kernel will go */
- Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
- /* verify that there is enough Chip RAM */
- if (bi.chip_size < 512*1024) {
- Puts("Not enough Chip RAM in this system. Aborting...\n");
- goto Fail;
- }
-
- /* verify that there is enough Fast RAM */
- for (fast_total = 0, i = 0; i < bi.num_memory; i++)
- fast_total += bi.memory[i].size;
- if (fast_total < 2*1024*1024) {
- Puts("Not enough Fast RAM in this system. Aborting...\n");
- goto Fail;
- }
-
- /* support for ramdisk */
- if (ramdiskname) {
- int size;
-
- if ((size = FileSize(ramdiskname)) == -1) {
- Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
- goto Fail;
- }
- /* record ramdisk size */
- bi.ramdisk.size = size;
- } else
- bi.ramdisk.size = 0;
- rd_size = bi.ramdisk.size;
- bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size;
-
- /* create the bootinfo structure */
- if (!create_bootinfo())
- goto Fail;
-
- /* open kernel executable and read exec header */
- if ((kfd = Open(kernelname)) == -1) {
- Printf("Unable to open kernel file `%s'\n", kernelname);
- goto Fail;
- }
- if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
- Puts("Unable to read exec header from kernel file\n");
- goto Fail;
- }
-
-#ifdef ZKERNEL
- if (((unsigned char *)&kexec)[0] == 037 &&
- (((unsigned char *)&kexec)[1] == 0213 ||
- ((unsigned char *)&kexec)[1] == 0236)) {
- /* That's a compressed kernel */
- Puts("Kernel is compressed\n");
- if (load_zkernel(kfd)) {
- Puts("Decompression error -- aborting\n");
- goto Fail;
- }
- }
-#endif
-
- switch (N_MAGIC(kexec)) {
- case ZMAGIC:
- if (debugflag)
- Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
- text_offset = N_TXTOFF(kexec);
- break;
-
- case QMAGIC:
- if (debugflag)
- Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
- text_offset = sizeof(kexec);
- /* the text size includes the exec header; remove this */
- kexec.a_text -= sizeof(kexec);
- break;
-
- default:
- /* Try to parse it as an ELF header */
- KSeek(kfd, 0);
- if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
- sizeof(kexec_elf)) &&
- (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
- elf_kernel = 1;
- if (debugflag)
- Puts("\nLoading ELF Linux/m68k kernel...\n");
- /* A few plausibility checks */
- if ((kexec_elf.e_type != ET_EXEC) ||
- (kexec_elf.e_machine != EM_68K) ||
- (kexec_elf.e_version != EV_CURRENT)) {
- Puts("Invalid ELF header contents in kernel\n");
- goto Fail;
- }
- /* Load the program headers */
- if (!(kernel_phdrs =
- (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
- MEMF_FAST | MEMF_PUBLIC |
- MEMF_CLEAR))) {
- Puts("Unable to allocate memory for program headers\n");
- goto Fail;
- }
- KSeek(kfd, kexec_elf.e_phoff);
- if (KRead(kfd, (void *)kernel_phdrs,
- kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
- kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
- Puts("Unable to read program headers from kernel file\n");
- goto Fail;
- }
- break;
- }
- Printf("Wrong magic number 0x%08lx in kernel header\n",
- N_MAGIC(kexec));
- goto Fail;
- }
-
- /* Load the kernel at one page after start of mem */
- start_mem += PAGE_SIZE;
- mem_size -= PAGE_SIZE;
- /* Align bss size to multiple of four */
- if (!elf_kernel)
- kexec.a_bss = (kexec.a_bss+3) & ~3;
-
- /* calculate the total required amount of memory */
- if (elf_kernel) {
- u_long min_addr = 0xffffffff, max_addr = 0;
- for (i = 0; i < kexec_elf.e_phnum; i++) {
- if (min_addr > kernel_phdrs[i].p_vaddr)
- min_addr = kernel_phdrs[i].p_vaddr;
- if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
- max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
- }
- /* This is needed for newer linkers that include the header in
- the first segment. */
- if (min_addr == 0) {
- min_addr = PAGE_SIZE;
- kernel_phdrs[0].p_vaddr += PAGE_SIZE;
- kernel_phdrs[0].p_offset += PAGE_SIZE;
- kernel_phdrs[0].p_filesz -= PAGE_SIZE;
- kernel_phdrs[0].p_memsz -= PAGE_SIZE;
- }
- kernel_size = max_addr-min_addr;
- } else
- kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
- memreq = kernel_size+bi_size+rd_size;
-#ifdef BOOTINFO_COMPAT_1_0
- if (sizeof(compat_bootinfo) > bi_size)
- memreq = kernel_size+sizeof(compat_bootinfo)+rd_size;
-#endif /* BOOTINFO_COMPAT_1_0 */
- if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
- MEMF_CLEAR))) {
- Puts("Unable to allocate memory\n");
- goto Fail;
- }
-
- /* read the text and data segments from the kernel image */
- if (elf_kernel)
- for (i = 0; i < kexec_elf.e_phnum; i++) {
- if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) {
- Printf("Failed to seek to segment %ld\n", i);
- goto Fail;
- }
- if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
- kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
- Printf("Failed to read segment %ld\n", i);
- goto Fail;
- }
- }
- else {
- if (KSeek(kfd, text_offset) == -1) {
- Puts("Failed to seek to text\n");
- goto Fail;
- }
- if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) {
- Puts("Failed to read text\n");
- goto Fail;
- }
- /* data follows immediately after text */
- if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
- Puts("Failed to read data\n");
- goto Fail;
- }
- }
- KClose(kfd);
- kfd = -1;
-
- /* Check kernel's bootinfo version */
- switch (check_bootinfo_version(memptr)) {
- case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
- bi_ptr = &bi_union.record;
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
- if (!create_compat_bootinfo())
- goto Fail;
- bi_ptr = &compat_bootinfo;
- bi_size = sizeof(compat_bootinfo);
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- goto Fail;
- }
-
- /* copy the bootinfo to the end of the kernel image */
- memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size);
-
- if (ramdiskname) {
- if ((rfd = Open(ramdiskname)) == -1) {
- Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
- goto Fail;
- }
- if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) {
- Puts("Failed to read ramdisk file\n");
- goto Fail;
- }
- Close(rfd);
- rfd = -1;
- }
-
- /* allocate temporary chip ram stack */
- if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
- Puts("Unable to allocate memory for stack\n");
- goto Fail;
- }
-
- /* allocate chip ram for copy of startup code */
- startcodesize = ©allend-©all;
- if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
- MEMF_CHIP | MEMF_CLEAR))) {
- Puts("Unable to allocate memory for startcode\n");
- goto Fail;
- }
-
- /* copy startup code to CHIP RAM */
- memcpy(startfunc, ©all, startcodesize);
-
- if (debugflag) {
- if (bi.ramdisk.size)
- Printf("RAM disk at 0x%08lx, size is %ldK\n",
- (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);
-
- if (elf_kernel) {
- PutChar('\n');
- for (i = 0; i < kexec_elf.e_phnum; i++)
- Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
- start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
- kernel_phdrs[i].p_memsz);
- Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
- } else {
- Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
- kexec.a_text);
- Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
- start_mem+kexec.a_text, kexec.a_data);
- Printf("Kernel bss at 0x%08lx, bss size 0x%08lx\n",
- start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
- Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
- }
- Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
- kexec.a_entry);
-
- Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
- Printf("ramdisk lower limit is 0x%08lx\n",
- (u_long)memptr+kernel_size+bi_size);
- Printf("ramdisk src top is 0x%08lx\n",
- (u_long)memptr+kernel_size+bi_size+rd_size);
-
- Puts("\nType a key to continue the Linux/m68k boot...");
- GetChar();
- PutChar('\n');
- }
-
- /* wait for things to settle down */
- Sleep(1000000);
-
- if (!keep_video)
- /* set graphics mode to a nice normal one */
- LoadView(NULL);
-
- Disable();
-
- /* reset nasty Zorro boards */
- if (reset_boards)
- for (i = 0; i < bi.num_autocon; i++)
- if (boardresetfuncs[i])
- boardresetfuncs[i](&bi.autocon[i]);
-
- /* Turn off all DMA */
- custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
- /* turn off caches */
- CacheControl(0, ~0);
-
- /* Go into supervisor state */
- SuperState();
-
- /* turn off any mmu translation */
- disable_mmu();
-
- /* execute the copy-and-go code (from CHIP RAM) */
- start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
- kernel_size, bi.ramdisk.addr, rd_size);
-
- /* Clean up and exit in case of a failure */
-Fail:
- if (kfd != -1)
- KClose(kfd);
- if (rfd != -1)
- Close(rfd);
- if (memptr)
- FreeMem((void *)memptr, memreq);
- if (stack)
- FreeMem((void *)stack, TEMP_STACKSIZE);
- if (kernel_phdrs)
- FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
- return(FALSE);
-}
-
-
- /*
- * Determine the Chipset
- */
-
-static u_long get_chipset(void)
-{
- u_char cs;
- u_long chipset;
-
- if (GfxBase->Version >= 39)
- cs = SetChipRev(SETCHIPREV_BEST);
- else
- cs = GfxBase->ChipRevBits0;
- if ((cs & GFXG_AGA) == GFXG_AGA)
- chipset = CS_AGA;
- else if ((cs & GFXG_ECS) == GFXG_ECS)
- chipset = CS_ECS;
- else if ((cs & GFXG_OCS) == GFXG_OCS)
- chipset = CS_OCS;
- else
- chipset = CS_STONEAGE;
- return(chipset);
-}
-
-
- /*
- * Determine the CPU Type
- */
-
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
-{
- *cpu = *fpu = 0;
-
- if (SysBase->AttnFlags & AFF_68060)
- *cpu = CPU_68060;
- else if (SysBase->AttnFlags & AFF_68040)
- *cpu = CPU_68040;
- else if (SysBase->AttnFlags & AFF_68030)
- *cpu = CPU_68030;
- else if (SysBase->AttnFlags & AFF_68020)
- *cpu = CPU_68020;
-
- if (*cpu == CPU_68040 || *cpu == CPU_68060) {
- if (SysBase->AttnFlags & AFF_FPU40)
- *fpu = *cpu;
- } else if (SysBase->AttnFlags & AFF_68882)
- *fpu = FPU_68882;
- else if (SysBase->AttnFlags & AFF_68881)
- *fpu = FPU_68881;
-
- *mmu = *cpu;
-}
-
- /*
- * Determine the Amiga Model
- */
-
-static u_long get_model(u_long chipset)
-{
- u_long model = AMI_UNKNOWN;
-
- if (debugflag)
- Puts("Amiga model identification:\n");
- if (probe_resource("draco.resource"))
- model = AMI_DRACO;
- else {
- if (debugflag)
- Puts(" Chipset: ");
- switch (chipset) {
- case CS_STONEAGE:
- if (debugflag)
- Puts("Old or unknown\n");
- goto OCS;
- break;
-
- case CS_OCS:
- if (debugflag)
- Puts("OCS\n");
-OCS: if (probe_resident("cd.device"))
- model = AMI_CDTV;
- else
- /* let's call it an A2000 (may be A500, A1000, A2500) */
- model = AMI_2000;
- break;
-
- case CS_ECS:
- if (debugflag)
- Puts("ECS\n");
- if (probe_resident("Magic 36.7") ||
- probe_resident("kickad 36.57") ||
- probe_resident("A3000 Bonus") ||
- probe_resident("A3000 bonus"))
- /* let's call it an A3000 (may be A3000T) */
- model = AMI_3000;
- else if (probe_resource("card.resource"))
- model = AMI_600;
- else
- /* let's call it an A2000 (may be A500[+], A1000, A2500) */
- model = AMI_2000;
- break;
-
- case CS_AGA:
- if (debugflag)
- Puts("AGA\n");
- if (probe_resident("A1000 Bonus") ||
- probe_resident("A4000 bonus"))
- model = probe_resident("NCR scsi.device") ? AMI_4000T :
- AMI_4000;
- else if (probe_resource("card.resource"))
- model = AMI_1200;
- else if (probe_resident("cd.device"))
- model = AMI_CD32;
- else
- model = AMI_3000PLUS;
- break;
- }
- }
- if (debugflag) {
- Puts("\nType a key to continue...");
- GetChar();
- Puts("\n\n");
- }
- return(model);
-}
-
-
- /*
- * Probe for a Resident Modules
- */
-
-static int probe_resident(const char *name)
-{
- const struct Resident *res;
-
- if (debugflag)
- Printf(" Module `%s': ", name);
- res = FindResident(name);
- if (debugflag)
- if (res)
- Printf("0x%08lx\n", res);
- else
- Puts("not present\n");
- return(res ? TRUE : FALSE);
-}
-
-
- /*
- * Probe for an available Resource
- */
-
-static int probe_resource(const char *name)
-{
- const void *res;
-
- if (debugflag)
- Printf(" Resource `%s': ", name);
- res = OpenResource(name);
- if (debugflag)
- if (res)
- Printf("0x%08lx\n", res);
- else
- Puts("not present\n");
- return(res ? TRUE : FALSE);
-}
-
-
- /*
- * Create the Bootinfo structure
- */
-
-static int create_bootinfo(void)
-{
- int i;
- struct bi_record *record;
-
- /* Initialization */
- bi_size = 0;
-
- /* Generic tags */
- if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
- return(0);
- if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
- return(0);
- if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
- return(0);
- if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
- return(0);
- for (i = 0; i < bi.num_memory; i++)
- if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
- return(0);
- if (bi.ramdisk.size)
- if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
- return(0);
- if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
- return(0);
-
- /* Amiga tags */
- if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model))
- return(0);
- for (i = 0; i < bi.num_autocon; i++)
- if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]),
- &bi.autocon[i]))
- return(0);
- if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size))
- return(0);
- if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank))
- return(0);
- if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq))
- return(0);
- if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock))
- return(0);
- if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset))
- return(0);
- if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper))
- return(0);
-
- /* Trailer */
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = BI_LAST;
- bi_size += sizeof(bi_union.record.tag);
-
- return(1);
-}
-
-
- /*
- * Add a Record to the Bootinfo Structure
- */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
- struct bi_record *record;
- u_int size2;
-
- size2 = (sizeof(struct bi_record)+size+3)&-4;
- if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
- Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n");
- return(0);
- }
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = tag;
- record->size = size2;
- memcpy(record->data, data, size);
- bi_size += size2;
- return(1);
-}
-
-
- /*
- * Add a String Record to the Bootinfo Structure
- */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
- return(add_bi_record(tag, strlen(s)+1, (void *)s));
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
- /*
- * Create the Bootinfo structure for backwards compatibility mode
- */
-
-static int create_compat_bootinfo(void)
-{
- u_int i;
-
- compat_bootinfo.machtype = bi.machtype;
- if (bi.cputype & CPU_68020)
- compat_bootinfo.cputype = COMPAT_CPU_68020;
- else if (bi.cputype & CPU_68030)
- compat_bootinfo.cputype = COMPAT_CPU_68030;
- else if (bi.cputype & CPU_68040)
- compat_bootinfo.cputype = COMPAT_CPU_68040;
- else if (bi.cputype & CPU_68060)
- compat_bootinfo.cputype = COMPAT_CPU_68060;
- else {
- Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
- return(0);
- }
- if (bi.fputype & FPU_68881)
- compat_bootinfo.cputype |= COMPAT_FPU_68881;
- else if (bi.fputype & FPU_68882)
- compat_bootinfo.cputype |= COMPAT_FPU_68882;
- else if (bi.fputype & FPU_68040)
- compat_bootinfo.cputype |= COMPAT_FPU_68040;
- else if (bi.fputype & FPU_68060)
- compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else if (bi.fputype) {
- Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
- return(0);
- }
- compat_bootinfo.num_memory = bi.num_memory;
- if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
- Printf("Warning: using only %ld blocks of memory\n",
- COMPAT_NUM_MEMINFO);
- compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
- }
- for (i = 0; i < compat_bootinfo.num_memory; i++) {
- compat_bootinfo.memory[i].addr = bi.memory[i].addr;
- compat_bootinfo.memory[i].size = bi.memory[i].size;
- }
- if (bi.ramdisk.size) {
- bi.ramdisk.addr &= 0xfffffc00;
- compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
- compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
- } else {
- compat_bootinfo.ramdisk_size = 0;
- compat_bootinfo.ramdisk_addr = 0;
- }
- strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
- compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
- compat_bootinfo.bi_amiga.model = bi.model;
- compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon;
- if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) {
- Printf("Warning: using only %ld AutoConfig devices\n",
- COMPAT_NUM_AUTO);
- compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO;
- }
- for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++)
- compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i];
- compat_bootinfo.bi_amiga.chip_size = bi.chip_size;
- compat_bootinfo.bi_amiga.vblank = bi.vblank;
- compat_bootinfo.bi_amiga.psfreq = bi.psfreq;
- compat_bootinfo.bi_amiga.eclock = bi.eclock;
- compat_bootinfo.bi_amiga.chipset = bi.chipset;
- compat_bootinfo.bi_amiga.hw_present = 0;
- return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
- /*
- * Compare the Bootstrap and Kernel Versions
- */
-
-static int check_bootinfo_version(const char *memptr)
-{
- const struct bootversion *bv = (struct bootversion *)memptr;
- unsigned long version = 0;
- int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
- if (bv->magic == BOOTINFOV_MAGIC)
- for (i = 0; bv->machversions[i].machtype != 0; ++i)
- if (bv->machversions[i].machtype == MACH_AMIGA) {
- version = bv->machversions[i].version;
- break;
- }
- if (!version)
- Puts("Kernel has no bootinfo version info, assuming 0.0\n");
-
- kernel_major = BI_VERSION_MAJOR(version);
- kernel_minor = BI_VERSION_MINOR(version);
- boots_major = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
- boots_minor = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
- Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
- boots_minor);
- Printf("Kernel's bootinfo version : %ld.%ld\n", kernel_major,
- kernel_minor);
-
- switch (kernel_major) {
- case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
- if (kernel_minor > boots_minor) {
- Puts("Warning: Bootinfo version of bootstrap and kernel "
- "differ!\n");
- Puts(" Certain features may not work.\n");
- }
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
- Puts("(using backwards compatibility mode)\n");
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- Printf("\nThis bootstrap is too %s for this kernel!\n",
- boots_major < kernel_major ? "old" : "new");
- return(0);
- }
- return(kernel_major);
-}
-
-
- /*
- * Call the copy-and-go-code
- */
-
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
- u_long start_mem, u_long kernel_size, u_long rd_dest,
- u_long rd_size)
-{
- register void (*a0)() __asm("a0") = startfunc;
- register char *a2 __asm("a2") = stackp;
- register char *a3 __asm("a3") = memptr;
- register u_long a4 __asm("a4") = start_mem;
- register u_long d0 __asm("d0") = rd_dest;
- register u_long d1 __asm("d1") = rd_size;
- register u_long d2 __asm("d2") = kernel_size;
- register u_long d3 __asm("d3") = bi_size;
-
- __asm __volatile ("movel a2,sp;"
- "jmp a0@"
- : /* no outputs */
- : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
- "r" (d1), "r" (d2), "r" (d3)
- /* no return */);
- /* fake a noreturn */
- for (;;);
-}
-
-
- /*
- * This assembler code is copied to chip ram, and then executed.
- * It copies the kernel to it's final resting place.
- *
- * It is called with:
- *
- * a3 = memptr
- * a4 = start_mem
- * d0 = rd_dest
- * d1 = rd_size
- * d2 = kernel_size
- * d3 = bi_size
- */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(copyall) ":
- | /* copy kernel text and data */
- movel a3,a0 | src = (u_long *)memptr;
- movel a0,a2 | limit = (u_long *)(memptr+kernel_size);
- addl d2,a2
- movel a4,a1 | dest = (u_long *)start_mem;
-1: cmpl a0,a2
- jeq 2f | while (src < limit)
- moveb a0@+,a1@+ | *dest++ = *src++;
- jra 1b
-2:
- | /* copy bootinfo to end of bss */
- movel a3,a0 | src = (u_long *)(memptr+kernel_size);
- addl d2,a0 | dest = end of bss (already in a1)
- movel d3,d7 | count = bi_size
- subql #1,d7
-1: moveb a0@+,a1@+ | while (--count > -1)
- dbra d7,1b | *dest++ = *src++
-
- | /* copy the ramdisk to the top of memory */
- movel a3,a0 | src = (u_long *)(memptr+kernel_size+bi_size);
- addl d2,a0
- addl d3,a0
- movel d0,a1 | dest = (u_long *)rd_dest;
- movel a0,a2 | limit = (u_long *)(memptr+kernel_size+
- addl d1,a2 | bi_size+rd_size);
-1: cmpl a0,a2
- jeq 2f | while (src > limit)
- moveb a0@+,a1@+ | *dest++ = *src++;
- jra 1b
-2:
- | /* jump to start of kernel */
- movel a4,a0 | jump_to (start_mem);
- jmp a0@
-"
-SYMBOL_NAME_STR(copyallend) ":
-");
-
-
- /*
- * Test for a MapROMmed A3640 Board
- */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(maprommed) ":
- oriw #0x0700,sr
- moveml #0x3f20,sp@-
- | /* Save cache settings */
- .long 0x4e7a1002 | movec cacr,d1 */
- | /* Save MMU settings */
- .long 0x4e7a2003 | movec tc,d2
- .long 0x4e7a3004 | movec itt0,d3
- .long 0x4e7a4005 | movec itt1,d4
- .long 0x4e7a5006 | movec dtt0,d5
- .long 0x4e7a6007 | movec dtt1,d6
- moveq #0,d0
- movel d0,a2
- | /* Disable caches */
- .long 0x4e7b0002 | movec d0,cacr
- | /* Disable MMU */
- .long 0x4e7b0003 | movec d0,tc
- .long 0x4e7b0004 | movec d0,itt0
- .long 0x4e7b0005 | movec d0,itt1
- .long 0x4e7b0006 | movec d0,dtt0
- .long 0x4e7b0007 | movec d0,dtt1
- lea 0x07f80000,a0
- lea 0x00f80000,a1
- movel a0@,d7
- cmpl a1@,d7
- jne 1f
- movel d7,d0
- notl d0
- movel d0,a0@
- nop | /* Thanks to Jörg Mayer! */
- cmpl a1@,d0
- jne 1f
- moveq #-1,d0 | /* MapROMmed A3640 present */
- movel d0,a2
-1: movel d7,a0@
- | /* Restore MMU settings */
- .long 0x4e7b2003 | movec d2,tc
- .long 0x4e7b3004 | movec d3,itt0
- .long 0x4e7b4005 | movec d4,itt1
- .long 0x4e7b5006 | movec d5,dtt0
- .long 0x4e7b6007 | movec d6,dtt1
- | /* Restore cache settings */
- .long 0x4e7b1002 | movec d1,cacr
- movel a2,d0
- moveml sp@+,#0x04fc
- rte
-");
-
-
- /*
- * Reset functions for nasty Zorro boards
- */
-
-static void reset_rb3(const struct ConfigDev *cd)
-{
- volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
-
- /* FN: If a Rainbow III board is present, reset it to disable */
- /* its (possibly activated) vertical blank interrupts as the */
- /* kernel is not yet prepared to handle them (level 6). */
-
- /* set RESET bit in special function register */
- *rb3_reg = 0x01;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit */
- *rb3_reg = 0x00;
-}
-
-static void reset_piccolo(const struct ConfigDev *cd)
-{
- volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
- /* FN: the same stuff as above, for the Piccolo board. */
- /* this also has the side effect of resetting the board's */
- /* output selection logic to use the Amiga's display in single */
- /* monitor systems - which is currently what we want. */
-
- /* set RESET bit in special function register */
- *piccolo_reg = 0x01;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit */
- *piccolo_reg = 0x51;
-}
-
-static void reset_sd64(const struct ConfigDev *cd)
-{
- volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
- /* FN: the same stuff as above, for the SD64 board. */
- /* just as on the Piccolo, this also resets the monitor switch */
-
- /* set RESET bit in special function register */
- *sd64_reg = 0x1f;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit AND switch monitor bit (0x20) */
- *sd64_reg = 0x4f;
-}
-
-static void reset_ariadne(const struct ConfigDev *cd)
-{
- volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
- volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
- volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
-
- volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
- volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
- volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
- volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
- volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
-
- u_short in;
-
- Disable();
-
- /*
- * Reset the Ethernet part (Am79C960 PCnet-ISA)
- */
-
- in = *lance_reset; /* Reset Chip on Read Access */
- *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
- *lance_rdp = 0x0400; /* STOP */
-
- /*
- * Reset the Parallel part (MC68230 PI/T)
- */
-
- *pit_pacr &= 0xfd; /* Port A Control Register */
- *pit_pbcr &= 0xfd; /* Port B Control Register */
- *pit_psr = 0x05; /* Port Status Register */
- *pit_paddr = 0x00; /* Port A Data Direction Register */
- *pit_pbddr = 0x00; /* Port B Data Direction Register */
-
- Enable();
-}
-
-static void reset_hydra(const struct ConfigDev *cd)
-{
- volatile u_char *nic_cr = (u_char *)(cd->cd_BoardAddr+0xffe1);
- volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
- int n = 5000;
-
- Disable();
-
- *nic_cr = 0x21; /* nic command register: software reset etc. */
- while (((*nic_isr & 0x80) == 0) && --n) /* wait for reset to complete */
- ;
-
- Enable();
-}
-
-#if 0
-static void reset_a2060(const struct ConfigDev *cd)
-{
-#error reset_a2060: not yet implemented
-}
-#endif
-
-
-#ifdef ZKERNEL
-
-#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS)
-#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1)
-#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0; /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000 /* window size--must be a power of two, and */
- /* at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#define malloc(x) AllocVec(x, MEMF_FAST | MEMF_PUBLIC)
-#define free(x) FreeVec(x)
-
-#ifdef LILO
-#include "inflate.c"
-#else
-#include "../../../../lib/inflate.c"
-#endif
-
-static void gzip_mark(void **ptr)
-{
-}
-
-static void gzip_release(void **ptr)
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
- if (exit_code)
- return -1;
-
- insize = Read(Zinfd, inbuf, INBUFSIZ);
- if (insize <= 0)
- return -1;
-
- inptr = 1;
- return(inbuf[0]);
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
- int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
- if (exit_code)
- return;
-
- if (chunk >= ZFILE_N_CHUNKS) {
- error("Compressed image too large! Aborting.\n");
- return;
- }
- if (!ZFile[chunk]) {
- if (!(ZFile[chunk] = (char *)AllocMem(ZFILE_CHUNK_SIZE,
- MEMF_FAST | MEMF_PUBLIC))) {
- error("Out of memory for decompresing kernel image\n");
- return;
- }
- }
- memcpy(ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt);
- Zwpos += outcnt;
-
-#define DISPLAY_BITS 10
- if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0)
- PutChar('.');
-
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void error(char *x)
-{
- Printf("\n%s", x);
- exit_code = 1;
-}
-
-static inline int call_sub(int (*func)(void), void *stackp)
-{
- register int _res __asm("d0");
- register int (*a0)(void) __asm("a0") = func;
- register int (*a1)(void) __asm("a1") = stackp;
-
- __asm __volatile ("movel sp,a2;"
- "movel a1,sp;"
- "jsr a0@;"
- "movel a2,sp"
- : "=r" (_res)
- : "r" (a0), "r" (a1)
- : "a0", "a1", "a2", "d0", "d1", "memory");
- return(_res);
-}
-
-static int load_zkernel(int fd)
-{
- int i, err = -1;
-#define ZSTACKSIZE (16384)
- u_long *zstack;
-
- for (i = 0; i < ZFILE_N_CHUNKS; ++i)
- ZFile[i] = NULL;
- Zinfd = fd;
- Seek(fd, 0);
-
- if (!(inbuf = (uch *)AllocMem(INBUFSIZ, MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip buffer\n");
- else {
- if (!(window = (uch *)AllocMem(WSIZE, MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip window\n");
- else {
- if (!(zstack = (u_long *)AllocMem(ZSTACKSIZE,
- MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip stack\n");
- else {
- Puts("Uncompressing kernel image ");
- makecrc();
- if (!(err = call_sub(gunzip, (char *)zstack+ZSTACKSIZE)))
- Puts("done\n");
- ZFileSize = Zwpos;
- FreeMem(zstack, ZSTACKSIZE);
- }
- FreeMem(window, WSIZE);
- window = NULL;
- }
- FreeMem(inbuf, INBUFSIZ);
- inbuf = NULL;
- }
- Close(Zinfd); /* input file not needed anymore */
- return(err);
-}
-
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. (Roman)
- */
-
-static int KRead(int fd, void *buf, int cnt)
-{
- unsigned done = 0;
-
- if (!ZFileSize)
- return(Read(fd, buf, cnt));
-
- if (ZFpos + cnt > ZFileSize)
- cnt = ZFileSize - ZFpos;
-
- while (cnt > 0) {
- unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (ZFpos + n > endchunk)
- n = endchunk - ZFpos;
- memcpy(buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n);
- cnt -= n;
- buf += n;
- done += n;
- ZFpos += n;
-
- if (ZFpos == endchunk) {
- FreeMem(ZFile[chunk], ZFILE_CHUNK_SIZE);
- ZFile[chunk] = NULL;
- }
- }
-
- return(done);
-}
-
-
-static int KSeek(int fd, int offset)
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!ZFileSize)
- return(Seek(fd, offset));
-
- oldpos = ZFpos;
- ZFpos = offset;
- if (ZFpos < 0) {
- ZFpos = 0;
- return(-1);
- } else if (ZFpos > ZFileSize) {
- ZFpos = ZFileSize;
- return(-1);
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> ZFILE_CHUNK_BITS;
- newchunk = ZFpos >> ZFILE_CHUNK_BITS;
- while(oldchunk < newchunk) {
- if (ZFile[oldchunk]) {
- FreeMem(ZFile[oldchunk], ZFILE_CHUNK_SIZE);
- ZFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
- return(ZFpos);
-}
-
-
-static void free_zfile(void)
-{
- int i;
-
- for (i = 0; i < ZFILE_N_CHUNKS; ++i)
- if (ZFile[i]) {
- FreeMem(ZFile[i], ZFILE_CHUNK_SIZE);
- ZFile[i] = NULL;
- }
-}
-
-static int KClose(int fd)
-{
- if (ZFileSize) {
- free_zfile();
- ZFileSize = 0;
- } else
- Close(fd);
- return(0);
-}
-#endif /* ZKERNEL */
+++ /dev/null
-/*
- * linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
- * on Amiga, used by both Amiboot and
- * Amiga-Lilo.
- *
- * Created 1996 by Geert Uytterhoeven
- *
- *
- * This file is based on the original bootstrap code (bootstrap.c):
- *
- * Copyright (C) 1993, 1994 Hamish Macdonald
- * Greg Harp
- *
- * with work by Michael Rausch
- * Geert Uytterhoeven
- * Frank Neumann
- * Andreas Schwab
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <asm/setup.h>
-#include <linux/zorro.h>
-
-
- /*
- * Amiboot Version
- */
-
-#define AMIBOOT_VERSION "5.5"
-
-
- /*
- * Amiga Bootinfo Definitions
- *
- * All limits herein are `soft' limits, i.e. they don't put constraints
- * on the actual parameters in the kernel.
- */
-
-struct amiga_bootinfo {
- u_long machtype; /* machine type = MACH_AMIGA */
- u_long cputype; /* system CPU */
- u_long fputype; /* system FPU */
- u_long mmutype; /* system MMU */
- int num_memory; /* # of memory blocks found */
- struct mem_info memory[NUM_MEMINFO];/* memory description */
- struct mem_info ramdisk; /* ramdisk description */
- char command_line[CL_SIZE]; /* kernel command line parameters */
- u_long model; /* Amiga Model */
- int num_autocon; /* # of autoconfig devices found */
- struct ConfigDev autocon[ZORRO_NUM_AUTO]; /* autoconfig devices */
- u_long chip_size; /* size of chip memory (bytes) */
- u_char vblank; /* VBLANK frequency */
- u_char psfreq; /* power supply frequency */
- u_long eclock; /* EClock frequency */
- u_long chipset; /* native chipset present */
- u_short serper; /* serial port period */
-};
-
-
- /*
- * Parameters passed to linuxboot()
- */
-
-struct linuxboot_args {
- struct amiga_bootinfo bi; /* Initial values override detected values */
- const char *kernelname;
- const char *ramdiskname;
- int debugflag;
- int keep_video;
- int reset_boards;
- u_int baud;
- void (*puts)(const char *str);
- long (*getchar)(void);
- void (*putchar)(char c);
- void (*printf)(const char *fmt, ...);
- int (*open)(const char *path);
- int (*seek)(int fd, int offset);
- int (*read)(int fd, char *buf, int count);
- void (*close)(int fd);
- int (*filesize)(const char *path);
- void (*sleep)(u_long micros);
-};
-
-
- /*
- * Boot the Linux/m68k Operating System
- */
-
-extern u_long linuxboot(const struct linuxboot_args *args);
-
-
- /*
- * Amiga Models
- */
-
-extern const char *amiga_models[];
-extern const u_long first_amiga_model;
-extern const u_long last_amiga_model;
-
-
- /*
- * Exec Library Definitions
- */
-
-#define TRUE (1)
-#define FALSE (0)
-
-
-struct List {
- struct Node *lh_Head;
- struct Node *lh_Tail;
- struct Node *lh_TailPred;
- u_char lh_Type;
- u_char l_pad;
-};
-
-struct MemChunk {
- struct MemChunk *mc_Next; /* pointer to next chunk */
- u_long mc_Bytes; /* chunk byte size */
-};
-
-#define MEMF_PUBLIC (1<<0)
-#define MEMF_CHIP (1<<1)
-#define MEMF_FAST (1<<2)
-#define MEMF_LOCAL (1<<8)
-#define MEMF_CLEAR (1<<16)
-
-struct MemHeader {
- struct Node mh_Node;
- u_short mh_Attributes; /* characteristics of this region */
- struct MemChunk *mh_First; /* first free region */
- void *mh_Lower; /* lower memory bound */
- void *mh_Upper; /* upper memory bound+1 */
- u_long mh_Free; /* total number of free bytes */
-};
-
-struct ExecBase {
- u_char fill1[20];
- u_short Version;
- u_char fill2[274];
- u_short AttnFlags;
- u_char fill3[24];
- struct List MemList;
- u_char fill4[194];
- u_char VBlankFrequency;
- u_char PowerSupplyFrequency;
- u_char fill5[36];
- u_long ex_EClockFrequency;
- u_char fill6[60];
-};
-
-#define AFB_68020 (1)
-#define AFF_68020 (1<<AFB_68020)
-#define AFB_68030 (2)
-#define AFF_68030 (1<<AFB_68030)
-#define AFB_68040 (3)
-#define AFF_68040 (1<<AFB_68040)
-#define AFB_68881 (4)
-#define AFF_68881 (1<<AFB_68881)
-#define AFB_68882 (5)
-#define AFF_68882 (1<<AFB_68882)
-#define AFB_FPU40 (6) /* ONLY valid if AFB_68040 or AFB_68060 */
-#define AFF_FPU40 (1<<AFB_FPU40) /* is set; also set for 68060 FPU */
-#define AFB_68060 (7)
-#define AFF_68060 (1<<AFB_68060)
-
-struct Resident;
-
-
- /*
- * Graphics Library Definitions
- */
-
-struct GfxBase {
- u_char fill1[20];
- u_short Version;
- u_char fill2[194];
- u_short NormalDisplayRows;
- u_short NormalDisplayColumns;
- u_char fill3[16];
- u_char ChipRevBits0;
- u_char fill4[307];
-};
-
-#define GFXB_HR_AGNUS (0)
-#define GFXF_HR_AGNUS (1<<GFXB_HR_AGNUS)
-#define GFXB_HR_DENISE (1)
-#define GFXF_HR_DENISE (1<<GFXB_HR_DENISE)
-#define GFXB_AA_ALICE (2)
-#define GFXF_AA_ALICE (1<<GFXB_AA_ALICE)
-#define GFXB_AA_LISA (3)
-#define GFXF_AA_LISA (1<<GFXB_AA_LISA)
-
- /*
- * HiRes(=Big) Agnus present; i.e.
- * 1MB chipmem, big blits (none of interest so far) and programmable sync
- */
-#define GFXG_OCS (GFXF_HR_AGNUS)
- /*
- * HiRes Agnus/Denise present; we are running on ECS
- */
-#define GFXG_ECS (GFXF_HR_AGNUS|GFXF_HR_DENISE)
- /*
- * Alice and Lisa present; we are running on AGA
- */
-#define GFXG_AGA (GFXF_AA_ALICE|GFXF_AA_LISA)
-
-#define SETCHIPREV_BEST (0xffffffff)
-#define HIRES (0x8000)
-
-struct View;
-
-
- /*
- * Amiga Shared Library/Device Functions
- */
-
-extern const struct ExecBase *SysBase;
-
-#define LVOAllocMem (-0xc6)
-#define LVOAllocVec (-0x2ac)
-#define LVOCacheControl (-0x288)
-#define LVODisable (-0x78)
-#define LVOEnable (-0x7e)
-#define LVOFindResident (-0x60)
-#define LVOFreeMem (-0xd2)
-#define LVOFreeVec (-0x2b2)
-#define LVOOpenresource (-0x1f2)
-#define LVOSuperState (-0x96)
-#define LVOSupervisor (-0x1e)
-
-static __inline void *AllocMem(u_long byteSize, u_long requirements)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = byteSize;
- register u_long d1 __asm("d1") = requirements;
-
- __asm __volatile ("jsr a6@(-0xc6)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline void *AllocVec(u_long byteSize, u_long requirements)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = byteSize;
- register u_long d1 __asm("d1") = requirements;
-
- __asm __volatile ("jsr a6@(-0x2ac)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
-{
- register u_long _res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = cacheBits;
- register u_long d1 __asm("d1") = cacheMask;
-
- __asm __volatile ("jsr a6@(-0x288)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline void Disable(void)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x78)"
- : /* no output */
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void Enable(void)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x7e)"
- : /* no output */
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline struct Resident *FindResident(const u_char *name)
-{
- register struct Resident *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register const u_char *a1 __asm("a1") = name;
-
- __asm __volatile ("jsr a6@(-0x60)"
- : "=r" (_res)
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
- return _res;
-}
-
-static __inline void FreeMem(void *memoryBlock, u_long byteSize)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register void *a1 __asm("a1") = memoryBlock;
- register u_long d0 __asm("d0") = byteSize;
-
- __asm __volatile ("jsr a6@(-0xd2)"
- : /* no output */
- : "r" (_base), "r" (a1), "r" (d0)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void FreeVec(void *memoryBlock)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register void *a1 __asm("a1") = memoryBlock;
-
- __asm __volatile ("jsr a6@(-0x2b2)"
- : /* no output */
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void *OpenResource(const u_char *resName)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register const u_char *a1 __asm("a1") = resName;
-
- __asm __volatile ("jsr a6@(-0x1f2)"
- : "=r" (_res)
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
- return _res;
-}
-
-static __inline void *SuperState(void)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x96)"
- : "=r" (_res)
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline u_long Supervisor(u_long (*userfunc)(void))
-{
- register u_long _res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long (*d7)() __asm("d7") = userfunc;
-
- __asm __volatile ("exg d7,a5;"
- "jsr a6@(-0x1e);"
- "exg d7,a5"
- : "=r" (_res)
- : "r" (_base), "r" (d7)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
-extern const struct ExpansionBase *ExpansionBase;
-
-#define LVOFindConfigDev (-0x48)
-
-static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
- long manufacturer, long product)
-{
- register struct ConfigDev *_res __asm("d0");
- register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
- register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
- register long d0 __asm("d0") = manufacturer;
- register long d1 __asm("d1") = product;
-
- __asm __volatile ("jsr a6@(-0x48)"
- : "=r" (_res)
- : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
-extern const struct GfxBase *GfxBase;
-
-#define LVOLoadView (-0xde)
-#define LVOSetChipRev (-0x378)
-
-static __inline void LoadView(struct View *view)
-{
- register const struct GfxBase *_base __asm("a6") = GfxBase;
- register struct View *a1 __asm("a1") = view;
-
- __asm __volatile ("jsr a6@(-0xde)"
- : /* no output */
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline u_long SetChipRev(u_long want)
-{
- register u_long _res __asm("d0");
- register const struct GfxBase *_base __asm("a6") = GfxBase;
- register u_long d0 __asm("d0") = want;
-
- __asm __volatile ("jsr a6@(-0x378)"
- : "=r" (_res)
- : "r" (_base), "r" (d0)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
- /*
- * Bootstrap Support Functions
- */
-
-static __inline void disable_mmu(void)
-{
- if (SysBase->AttnFlags & AFF_68040)
- __asm __volatile ("moveq #0,d0;"
- ".long 0x4e7b0003;" /* movec d0,tc */
- ".long 0x4e7b0004;" /* movec d0,itt0 */
- ".long 0x4e7b0005;" /* movec d0,itt1 */
- ".long 0x4e7b0006;" /* movec d0,dtt0 */
- ".long 0x4e7b0007" /* movec d0,dtt1 */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- else {
- __asm __volatile ("subl #4,sp;"
- "pmove tc,sp@;"
- "bclr #7,sp@;"
- "pmove sp@,tc;"
- "addl #4,sp");
- if (SysBase->AttnFlags & AFF_68030)
- __asm __volatile ("clrl sp@-;"
- ".long 0xf0170800;" /* pmove sp@,tt0 */
- ".long 0xf0170c00;" /* pmove sp@,tt1 */
- "addql #4,sp");
- }
-}
+++ /dev/null
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bootp.h"
-
-
-/* --------------------------------------------------------------------- */
-/* Protocol Header Structures */
-
-struct etherhdr {
- HWADDR dst_addr;
- HWADDR src_addr;
- unsigned short type;
-};
-
-struct arphdr {
- unsigned short hrd; /* format of hardware address */
- unsigned short pro; /* format of protocol address */
- unsigned char hln; /* length of hardware address */
- unsigned char pln; /* length of protocol address */
- unsigned short op; /* ARP opcode (command) */
- unsigned char addr[0]; /* addresses (var len) */
-};
-
-struct iphdr {
- unsigned char version : 4;
- unsigned char ihl : 4;
- unsigned char tos;
- unsigned short tot_len;
- unsigned short id;
- unsigned short frag_off;
- unsigned char ttl;
- unsigned char protocol;
- unsigned short chksum;
- IPADDR src_addr;
- IPADDR dst_addr;
-};
-
-struct udphdr {
- unsigned short src_port;
- unsigned short dst_port;
- unsigned short len;
- unsigned short chksum;
-};
-
-struct bootp {
- unsigned char op; /* packet opcode type */
- unsigned char htype; /* hardware addr type */
- unsigned char hlen; /* hardware addr length */
- unsigned char hops; /* gateway hops */
- unsigned long xid; /* transaction ID */
- unsigned short secs; /* seconds since boot began */
- unsigned short unused;
- IPADDR ciaddr; /* client IP address */
- IPADDR yiaddr; /* 'your' IP address */
- IPADDR siaddr; /* server IP address */
- IPADDR giaddr; /* gateway IP address */
- unsigned char chaddr[16]; /* client hardware address */
- unsigned char sname[64]; /* server host name */
- unsigned char file[128]; /* boot file name */
- unsigned char vend[64]; /* vendor-specific area */
-};
-
-struct tftp_req {
- unsigned short opcode;
- char name[512];
-};
-
-struct tftp_data {
- unsigned short opcode;
- unsigned short nr;
- unsigned char data[512];
-};
-
-struct tftp_ack {
- unsigned short opcode;
- unsigned short nr;
-};
-
-struct tftp_error {
- unsigned short opcode;
- unsigned short errcode;
- char str[512];
-};
-
-
-typedef struct {
- struct etherhdr ether;
- struct arphdr arp;
-} ARP;
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
-} UDP;
-
-#define UDP_BOOTPS 67
-#define UDP_BOOTPC 68
-#define UDP_TFTP 69
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
- struct bootp bootp;
-} BOOTP;
-
-#define BOOTREQUEST 1
-#define BOOTREPLY 2
-#define BOOTP_RETRYS 5
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
- union tftp {
- unsigned short opcode;
- struct tftp_req req;
- struct tftp_data data;
- struct tftp_ack ack;
- struct tftp_error error;
- } tftp;
-} TFTP;
-
-#define TFTP_RRQ 1
-#define TFTP_WRQ 2
-#define TFTP_DATA 3
-#define TFTP_ACK 4
-#define TFTP_ERROR 5
-
-
-/* --------------------------------------------------------------------- */
-/* Addresses */
-
-static HWADDR MyHwaddr;
-static HWADDR ServerHwaddr;
-static IPADDR MyIPaddr;
-static IPADDR ServerIPaddr;
-
-static IPADDR IP_Unknown_Addr = 0x00000000;
-static IPADDR IP_Broadcast_Addr = 0xffffffff;
-static HWADDR Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-
-#define HZ 200
-#define _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-/* --------------------------------------------------------------------- */
-/* Error Strings */
-
-static char *ErrStr[] = {
- "timeout",
- "general Ethernet transmit error",
- "general Ethernet receive error",
- "Ethernet framing error",
- "Ethernet overflow error",
- "Ethernet CRC error"
-};
-
-
-/* --------------------------------------------------------------------- */
-/* Kfile Emulation Definitions */
-
-#define KFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define KFILE_CHUNK_SIZE (1 << KFILE_CHUNK_BITS)
-#define KFILE_CHUNK_MASK (KFILE_CHUNK_SIZE-1)
-#define KFILE_N_CHUNKS (2*1024*1024/KFILE_CHUNK_SIZE)
-
-char *KFile[KFILE_N_CHUNKS];
-int KFileSize = 0;
-int KFpos = 0;
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static void free_kfile( void );
-static int bootp( char *image_name );
-static int tftp( char *image_name );
-static int udp_send( UDP *pkt, int len, int fromport, int toport );
-static unsigned short ip_checksum( struct iphdr *buf );
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
-static void print_ip( IPADDR addr );
-static void print_hw( HWADDR addr );
-static int check_ethif( void );
-static int eth_send( Packet *pkt, int len );
-static int eth_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-
-/* --------------------------------------------------------------------- */
-/* Interface to bootstrap.c */
-
-/* get_remote_kernel():
- * Perform all necessary steps to get the kernel image
- * from the boot server. If successfull (retval == 0), subsequent calls to
- * kread() can access the data. Fatal errors (i.e., retrying is useless)
- * return -2, others -1.
- */
-
-int get_remote_kernel( const char *kname /* optional */ )
-
-{ char image_name[256];
- int rv;
-
- /* Check if a Ethernet interface is present and determine the Ethernet
- * address */
- if (check_ethif() < 0) {
- printf( "No Ethernet interface found -- no remote boot possible.\n" );
- return( -2 );
- }
-
- /* Do a BOOTP request to find out our IP address and the kernel image's
- * name; we also learn the IP and Ethernet address of our server */
- if (kname)
- strcpy( image_name, kname );
- else
- *image_name = 0;
- if ((rv = bootp( image_name )) < 0)
- return( rv );
-
- /* Now start a TFTP connection to receive the kernel image */
- if ((rv = tftp( image_name )) < 0)
- return( rv );
-
- return( 0 );
-}
-
-
-/* ll_read(), ll_lseek(), ll_close():
- * Functions for accessing the received kernel image like with read(),
- * lseek(), close().
- */
-
-int ll_read( int fd, void *buf, unsigned cnt )
-
-{ unsigned done = 0;
-
- if (!KFileSize)
- return( read( fd, buf, cnt ) );
-
- if (KFpos + cnt > KFileSize)
- cnt = KFileSize - KFpos;
-
- while( cnt > 0 ) {
- unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (KFpos + n > endchunk)
- n = endchunk - KFpos;
- memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
- cnt -= n;
- buf += n;
- done += n;
- KFpos += n;
-
- if (KFpos == endchunk) {
- free( KFile[chunk] );
- KFile[chunk] = NULL;
- }
- }
-
- return( done );
-}
-
-
-int ll_lseek( int fd, int where, int whence )
-
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!KFileSize)
- return( lseek( fd, where, whence ) );
-
- oldpos = KFpos;
- switch( whence ) {
- case SEEK_SET:
- KFpos = where;
- break;
- case SEEK_CUR:
- KFpos += where;
- break;
- case SEEK_END:
- KFpos = KFileSize + where;
- break;
- default:
- return( -1 );
- }
- if (KFpos < 0) {
- KFpos = 0;
- return( -1 );
- }
- else if (KFpos > KFileSize) {
- KFpos = KFileSize;
- return( -1 );
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> KFILE_CHUNK_BITS;
- newchunk = KFpos >> KFILE_CHUNK_BITS;
- while( oldchunk < newchunk ) {
- if (KFile[oldchunk]) {
- free( KFile[oldchunk] );
- KFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
-
- return( KFpos );
-}
-
-
-int ll_close( int fd )
-
-{
- if (!KFileSize)
- return( close( fd ) );
-
- free_kfile();
- return( 0 );
-}
-
-
-static void free_kfile( void )
-
-{ int i;
-
- for( i = 0; i < KFILE_N_CHUNKS; ++i )
- if (KFile[i]) free( KFile[i] );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/* BOOTP Procedure */
-
-
-static int bootp( char *image_name )
-
-{ BOOTP req;
- Packet _reply;
- BOOTP *reply = (BOOTP *)_reply;
- static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
- unsigned long starttime, rancopy;
- int err, len, retry;
-
- memset( (char *)&req, 0, sizeof(req) );
- /* Now fill in the packet... */
- req.bootp.op = BOOTREQUEST;
- req.bootp.htype = 1; /* 10Mb/s Ethernet */
- req.bootp.hlen = 6;
- memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
-
- /* Put in the minimal RFC1497 Magic cookie */
- memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
- /* Put the user precified bootfile name in place */
- memcpy( req.bootp.file, image_name, strlen(image_name)+1);
-
- starttime = _hz_200;
- for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
-
- /* Initialize server addresses and own IP to defaults */
- ServerIPaddr = IP_Broadcast_Addr; /* 255.255.255.255 */
- MyIPaddr = IP_Unknown_Addr; /* 0.0.0.0 */
- memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
-
- if (retry)
- sleep( 3 );
-
- req.bootp.xid = rancopy = _hz_200;
- req.bootp.secs = (_hz_200 - starttime) / HZ;
-
- if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
- UDP_BOOTPC, UDP_BOOTPS )) < 0) {
- printf( "bootp send: %s\n", ErrStr[-err-1] );
- continue;
- }
-
- if ((err = udp_rcv( (UDP *)reply, &len,
- UDP_BOOTPS, UDP_BOOTPC )) < 0) {
- printf( "bootp rcv: %s\n", ErrStr[-err-1] );
- continue;
- }
- if (len < sizeof(struct bootp)) {
- printf( "received short BOOTP packet (%d bytes)\n", len );
- continue;
- }
-
- if (reply->bootp.xid == rancopy)
- /* Ok, got the answer */
- break;
- printf( "bootp: xid mismatch\n" );
- }
- if (retry >= BOOTP_RETRYS) {
- printf( "No response from a bootp server\n" );
- return( -2 );
- }
-
- ServerIPaddr = reply->bootp.siaddr;
- memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
- printf( "\nBoot server is " );
- if (strlen(reply->bootp.sname) > 0)
- printf( "%s, IP ", reply->bootp.sname );
- print_ip( ServerIPaddr );
- printf( ", HW address " );
- print_hw( ServerHwaddr );
- printf( "\n" );
-
- MyIPaddr = reply->bootp.yiaddr;
- printf( "My IP address is " );
- print_ip( MyIPaddr );
- printf( "\n" );
-
- strcpy( image_name, reply->bootp.file );
- return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* TFTP Procedure */
-
-
-static int tftp( char *image_name )
-
-{ TFTP spkt;
- Packet _rpkt;
- TFTP *rpkt = (TFTP *)&_rpkt;
- unsigned short mytid, rtid = 0;
- int blk, retries, i, wpos, err, len, datalen;
- static char rotchar[4] = { '|', '/', '-', '\\' };
-
- retries = 5;
- /* Construct and send a read request */
- repeat_req:
- spkt.tftp.req.opcode = TFTP_RRQ;
- strcpy( spkt.tftp.req.name, image_name );
- strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
- mytid = _hz_200 & 0xffff;
-
- if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
- strlen(image_name) + 1 +
- strlen( "octect" ) +1,
- mytid, UDP_TFTP )) < 0) {
- printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_req;
- return( err == ETIMEO ? -2 : -1 );
- }
-
- retries = 5;
- for( i = 0; i < KFILE_N_CHUNKS; ++i )
- KFile[i] = NULL;
- wpos = 0;
- printf( "Receiving kernel image %s:\n", image_name );
-
- for( blk = 1; ; ++blk ) {
-
- repeat_data:
- if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
- printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_data;
- goto err;
- }
- if (rtid == 0)
- /* Store the remote port at the first packet received */
- rtid = rpkt->udp.src_port;
-
- if (rpkt->tftp.opcode == TFTP_ERROR) {
- if (strlen(rpkt->tftp.error.str) > 0)
- printf( "TFTP error: %s\n", rpkt->tftp.error.str );
- else
- printf( "TFTP error #%d (no description)\n",
- rpkt->tftp.error.errcode );
- goto err;
- }
- else if (rpkt->tftp.opcode != TFTP_DATA) {
- printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
- if (--retries > 0)
- goto repeat_data;
- goto err;
- }
-
- if (rpkt->tftp.data.nr != blk) {
- /* doubled data packet; ignore it */
- goto repeat_data;
- }
- datalen = len - sizeof(rpkt->tftp.data.opcode) -
- sizeof(rpkt->tftp.data.nr);
-
- /* store data */
- if (datalen > 0) {
- int chunk = wpos >> KFILE_CHUNK_BITS;
- if (chunk >= KFILE_N_CHUNKS) {
- printf( "TFTP: file too large! Aborting.\n" );
- out_of_mem:
- spkt.tftp.error.opcode = TFTP_ERROR;
- spkt.tftp.error.errcode = 3;
- strcpy( spkt.tftp.error.str, "Out of memory" );
- udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
- goto err;
- }
- if (!KFile[chunk]) {
- if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
- printf( "TFTP: Out of memory for kernel image\n" );
- goto out_of_mem;
- }
- }
- memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
- rpkt->tftp.data.data, datalen );
- wpos += datalen;
-
-#define DISPLAY_BITS 13
- if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
- printf( "\r %c %7d Bytes ",
- rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
- fflush( stdout );
- }
- }
-
- /* Send ACK packet */
- repeat_ack:
- spkt.tftp.ack.opcode = TFTP_ACK;
- spkt.tftp.ack.nr = blk;
- if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
- mytid, rtid )) < 0) {
- printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_ack;
- goto err;
- }
-
- if (datalen < 512) {
- /* This was the last packet */
- printf( "\r %7d Bytes done\n\n", wpos );
- break;
- }
-
- retries = 5;
- }
-
- KFileSize = wpos;
- return( 0 );
-
- err:
- free_kfile();
- return( -1 );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/* UDP/IP Protocol Quick Hack Implementation */
-
-
-static int udp_send( UDP *pkt, int len, int fromport, int toport )
-
-{
- /* UDP layer */
- pkt->udp.src_port = fromport;
- pkt->udp.dst_port = toport;
- pkt->udp.len = (len += sizeof(struct udphdr));
- pkt->udp.chksum = 0; /* Too lazy to calculate :-) */
-
- /* IP layer */
- pkt->ip.version = 4;
- pkt->ip.ihl = 5;
- pkt->ip.tos = 0;
- pkt->ip.tot_len = (len += sizeof(struct iphdr));
- pkt->ip.id = 0;
- pkt->ip.frag_off = 0;
- pkt->ip.ttl = 255;
- pkt->ip.protocol = 17; /* UDP */
- pkt->ip.src_addr = MyIPaddr;
- pkt->ip.dst_addr = ServerIPaddr;
- pkt->ip.chksum = 0;
- pkt->ip.chksum = ip_checksum( &pkt->ip );
-
- /* Ethernet layer */
- memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
- memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
- pkt->ether.type = 0x0800;
- len += sizeof(struct etherhdr);
-
- return( eth_send( (Packet *)pkt, len ) );
-}
-
-
-static unsigned short ip_checksum( struct iphdr *buf )
-
-{ unsigned long sum = 0, wlen = 5;
-
- __asm__ ("subqw #1,%2\n"
- "1:\t"
- "movel %1@+,%/d0\n\t"
- "addxl %/d0,%0\n\t"
- "dbra %2,1b\n\t"
- "movel %0,%/d0\n\t"
- "swap %/d0\n\t"
- "addxw %/d0,%0\n\t"
- "clrw %/d0\n\t"
- "addxw %/d0,%0"
- : "=d" (sum), "=a" (buf), "=d" (wlen)
- : "0" (sum), "1" (buf), "2" (wlen)
- : "d0");
- return( (~sum) & 0xffff );
-}
-
-
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
-
-{ int err;
-
- repeat:
- if ((err = eth_rcv( (Packet *)pkt, len )))
- return( err );
-
- /* Ethernet layer */
- if (pkt->ether.type == 0x0806) {
- /* ARP */
- ARP *pk = (ARP *)pkt;
- unsigned char *shw, *sip, *thw, *tip;
-
- if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
- pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
- /* Wrong hardware type or protocol; or reply -> ignore */
- goto repeat;
- shw = pk->arp.addr;
- sip = shw + pk->arp.hln;
- thw = sip + pk->arp.pln;
- tip = thw + pk->arp.hln;
-
- if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
- memcpy( thw, shw, pk->arp.hln );
- memcpy( tip, sip, pk->arp.pln );
- memcpy( shw, &MyHwaddr, pk->arp.hln );
- memcpy( sip, &MyIPaddr, pk->arp.pln );
-
- memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
- memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
- eth_send( (Packet *)pk, *len );
- }
- goto repeat;
- }
- else if (pkt->ether.type != 0x0800) {
- printf( "Unknown Ethernet packet type %04x received\n",
- pkt->ether.type );
- goto repeat;
- }
-
- /* IP layer */
- if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
- printf( "Received packet for wrong IP address\n" );
- goto repeat;
- }
- if (ServerIPaddr != IP_Unknown_Addr &&
- ServerIPaddr != IP_Broadcast_Addr &&
- pkt->ip.src_addr != ServerIPaddr) {
- printf( "Received packet from wrong server\n" );
- goto repeat;
- }
- /* If IP header is longer than 5 longs, delete the options */
- if (pkt->ip.ihl > 5) {
- char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
- memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
- }
-
- /* UDP layer */
- if (fromport != 0 && pkt->udp.src_port != fromport) {
- printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
- goto repeat;
- }
- if (pkt->udp.dst_port != atport) {
- printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
- goto repeat;
- }
-
- *len = pkt->udp.len - sizeof(struct udphdr);
- return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Address Printing */
-
-
-static void print_ip( IPADDR addr )
-
-{
- printf( "%ld.%ld.%ld.%ld",
- (addr >> 24) & 0xff,
- (addr >> 16) & 0xff,
- (addr >> 8) & 0xff,
- addr & 0xff );
-}
-
-
-static void print_hw( HWADDR addr )
-
-{
- printf( "%02x:%02x:%02x:%02x:%02x:%02x",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Ethernet Interface Abstraction Layer */
-
-
-#ifdef ETHLL_LANCE
-#include "ethlance.h"
-#endif
-
-static ETHIF_SWITCH *PossibleInterfaces[] = {
-#ifdef ETHLL_LANCE
- &LanceSwitch,
-#endif
-};
-
-#define N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
-
-/* Detected interface */
-static ETHIF_SWITCH *Ethif = NULL;
-
-
-static int check_ethif( void )
-
-{ int i;
-
- /* Check for configured interfaces */
- Ethif = NULL;
- for( i = 0; i < N_PossibleInterfaces; ++i ) {
- if (PossibleInterfaces[i]->probe() >= 0) {
- Ethif = PossibleInterfaces[i];
- break;
- }
- }
- if (!Ethif)
- return( -1 );
-
- if (Ethif->init() < 0) {
- printf( "Ethernet interface initialization failed\n" );
- return( -1 );
- }
- Ethif->get_hwaddr( &MyHwaddr );
- return( 0 );
-}
-
-
-static int eth_send( Packet *pkt, int len )
-
-{
- return( Ethif->snd( pkt, len ));
-}
-
-
-static int eth_rcv( Packet *pkt, int *len )
-
-{
- return( Ethif->rcv( pkt, len ));
-}
-
-
-#if 0
-static void dump_packet( UDP *pkt )
-
-{ int i, l;
- unsigned char *p;
-
- printf( "Packet dump:\n" );
-
- printf( "Ethernet header:\n" );
- printf( " dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
- printf( " src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
- printf( " type: %04x\n", pkt->ether.type );
-
- printf( "IP header:\n" );
- printf( " version: %d\n", pkt->ip.version );
- printf( " hdr len: %d\n", pkt->ip.ihl );
- printf( " tos: %d\n", pkt->ip.tos );
- printf( " tot_len: %d\n", pkt->ip.tot_len );
- printf( " id: %d\n", pkt->ip.id );
- printf( " frag_off: %d\n", pkt->ip.frag_off );
- printf( " ttl: %d\n", pkt->ip.ttl );
- printf( " prot: %d\n", pkt->ip.protocol );
- printf( " src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
- printf( " dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
-
- printf( "UDP header:\n" );
- printf( " src port: %d\n", pkt->udp.src_port );
- printf( " dst port: %d\n", pkt->udp.dst_port );
- printf( " len: %d\n", pkt->udp.len );
-
- printf( "Data:" );
- l = pkt->udp.len - sizeof(pkt->udp);
- p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
- for( i = 0; i < l; ++i ) {
- if ((i % 32) == 0)
- printf( "\n %04x ", i );
- printf( "%02x ", *p );
- }
- printf( "\n" );
-}
-#endif
+++ /dev/null
-#ifndef _bootp_h
-#define _bootp_h
-
-/* --------------------------------------------------------------------- */
-/* Ethernet Definitions */
-
-#define PKTLEN 1544
-typedef unsigned char Packet[PKTLEN];
-
-#define ETHADDRLEN 6
-typedef unsigned char HWADDR[ETHADDRLEN];
-
-typedef struct {
- int (*probe)( void );
- int (*init)( void );
- void (*get_hwaddr)( HWADDR *addr );
- int (*snd)( Packet *pkt, int len );
- int (*rcv)( Packet *pkt, int *len );
-} ETHIF_SWITCH;
-
-
-/* error codes */
-#define ETIMEO -1 /* Timeout */
-#define ESEND -2 /* General send error (carrier, abort, ...) */
-#define ERCV -3 /* General receive error */
-#define EFRAM -4 /* Framing error */
-#define EOVERFL -5 /* Overflow (too long packet) */
-#define ECRC -6 /* CRC error */
-
-
-typedef unsigned long IPADDR;
-
-
-/***************************** Prototypes *****************************/
-
-int get_remote_kernel( const char *kname );
-int ll_read( int fd, void *buf, unsigned cnt );
-int ll_lseek( int fd, int where, int whence );
-int ll_close( int fd );
-
-/************************* End of Prototypes **************************/
-
-#endif /* _bootp_h */
-
+++ /dev/null
-/*
-** bootstrap.c -- Load and launch the Atari Linux kernel
-**
-** Copyright 1993 by Arjan Knor
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-** History:
-** 01 Feb 1997 Implemented kernel decompression (Roman)
-** 28 Nov 1996 Fixed and tested previous change (James)
-** 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
-** 12 Nov 1996 Fixed and tested previous change (Andreas)
-** 18 Aug 1996 Updated for the new boot information structure (untested!)
-** (Geert)
-** 10 Dec 1995 BOOTP/TFTP support (Roman)
-** 03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
-** 11 Jul 1995 Add support for ELF format kernel (Andreas)
-** 16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
-** (Andreas)
-** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
-** start address is KSTART_ADDR + PAGE_SIZE, this
-** does not need the ugly kludge with
-** -fwritable-strings (++andreas)
-** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
-** mentions all ST-Ram and the mover is located somewhere
-** in the middle of memory (roman)
-** Added the default arguments file known from the other
-** bootstrap version
-** 19 Feb 1994 Changed everything so that it works? (rdv)
-** 14 Mar 1994 New mini-copy routine used (rdv)
-*/
-
-
-#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-#include "sysvars.h"
-#include <osbind.h>
-#include <sys/types.h>
-#include <sys/file.h>
-
-/* linux specific include files */
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/page.h>
-
-#define _LINUX_TYPES_H /* Hack to prevent including <linux/types.h> */
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-
-/* Atari bootstrap include file */
-#include "bootstrap.h"
-
-#define MIN_RAMSIZE (3) /* 3 MB */
-#define TEMP_STACKSIZE 256
-
-extern char *optarg;
-extern int optind;
-static void get_default_args( int *argc, char ***argv );
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-/* This is missing in <unistd.h> */
-extern int sync (void);
-
-/* Bootinfo */
-static struct atari_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE (4096)
-static u_long bi_size;
-static union {
-struct bi_record record;
- u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-u_long *cookiejar;
-u_long userstk;
-
-/* getcookie -- function to get the value of the given cookie. */
-static int getcookie(char *cookie, u_long *value)
-{
- int i = 0;
-
- while(cookiejar[i] != 0L) {
- if(cookiejar[i] == *(u_long *)cookie) {
- *value = cookiejar[i + 1];
- return 1;
- }
- i += 2;
- }
- return -1;
-}
-
-static void usage(void)
-{
- fprintf(stderr, "Usage:\n"
- "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
- " [option...]\n");
- exit(EXIT_FAILURE);
-}
-
-/*
- * Copy the kernel and the ramdisk to their final resting places.
- *
- * I assume that the kernel data and the ramdisk reside somewhere
- * in the middle of the memory.
- *
- * This program itself should be somewhere in the first 4096 bytes of memory
- * where the kernel never will be. In this way it can never be overwritten
- * by itself.
- *
- * At this point the registers have:
- * a0: the start of the final kernel
- * a1: the start of the current kernel
- * a2: the end of the final ramdisk
- * a3: the end of the current ramdisk
- * d0: the kernel size
- * d1: the ramdisk size
- */
-asm ("
-.text
-.globl _copyall, _copyallend
-_copyall:
-
- movel a0,a4 /* save the start of the kernel for booting */
-
-1: movel a1@+,a0@+ /* copy the kernel starting at the beginning */
- subql #4,d0
- jcc 1b
-
- tstl d1
- beq 3f
-
-2: movel a3@-,a2@- /* copy the ramdisk starting at the end */
- subql #4,d1
- jcc 2b
-
-3: jmp a4@ /* jump to the start of the kernel */
-_copyallend:
-");
-
-extern char copyall, copyallend;
-
-
-/* Test for a Medusa: This is the only machine on which address 0 is
- * writeable!
- * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
- * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
- * in the range where the Medusa always asserts DTACK.
- * On the Hades address 0 is writeable as well and it asserts DTACK on
- * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000
- * is tested. On the Medusa this gives a bus error.
- */
-
-int test_medusa( void )
-
-{ int rv = 0;
-
- __asm__ __volatile__
- ( "movel 0x8,a0\n\t"
- "movel sp,a1\n\t"
- "moveb 0x0,d1\n\t"
- "movel #Lberr,0x8\n\t"
- "moveq #0,%0\n\t"
- "clrb 0x0\n\t"
- "nop \n\t"
- "moveb d1,0x0\n\t"
- "nop \n\t"
- "tstb 0x00ff82fe\n\t"
- "nop \n\t"
- "moveq #1,%0\n\t"
- "tstb 0xb0000000\n\t"
- "nop \n\t"
- "moveq #0,%0\n"
- "Lberr:\t"
- "movel a1,sp\n\t"
- "movel a0,0x8"
- : "=d" (rv)
- : /* no inputs */
- : "d1", "a0", "a1", "memory" );
-
- return( rv );
-}
-
-
-/* Test if FPU instructions are executed in hardware, or if they're
- emulated in software. For this, the F-line vector is temporarily
- replaced. */
-
-int test_software_fpu(void)
-{
- int rv = 0;
-
- __asm__ __volatile__
- ( "movel 0x2c,a0\n\t"
- "movel sp,a1\n\t"
- "movel #Lfline,0x2c\n\t"
- "moveq #1,%0\n\t"
- "fnop \n\t"
- "nop \n\t"
- "moveq #0,%0\n"
- "Lfline:\t"
- "movel a1,sp\n\t"
- "movel a0,0x2c"
- : "=d" (rv)
- : /* no inputs */
- : "a0", "a1" );
-
- return rv;
-}
-
-
-void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
-
-{ static u_long save_addr;
- u_long test_base, saved_contents[16];
-#define TESTADDR(i) (*((u_long *)((char *)test_base + i*8*MB)))
-#define TESTPAT 0x12345678
- unsigned short oldflags;
- int i;
-
- /* This ensures at least that none of the test addresses conflicts
- * with the test code itself */
- test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
- *bank1 = *bank2 = 0;
-
- /* Interrupts must be disabled because arbitrary addresses may be
- * temporarily overwritten, even code of an interrupt handler */
- __asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
- disable_cache();
-
- /* save contents of the test addresses */
- for( i = 0; i < 16; ++i )
- saved_contents[i] = TESTADDR(i);
-
- /* write 0s into all test addresses */
- for( i = 0; i < 16; ++i )
- TESTADDR(i) = 0;
-
- /* test for bank 1 */
-#if 0
- /* This is Freddi's original test, but it didn't work. */
- TESTADDR(0) = TESTADDR(1) = TESTPAT;
- if (TESTADDR(1) == TESTPAT) {
- if (TESTADDR(2) == TESTPAT)
- *bank1 = 8*MB;
- else if (TESTADDR(3) == TESTPAT)
- *bank1 = 16*MB;
- else
- *bank1 = 32*MB;
- }
- else {
- if (TESTADDR(2) == TESTPAT)
- *bank1 = 0;
- else
- *bank1 = 16*MB;
- }
-#else
- TESTADDR(0) = TESTPAT;
- if (TESTADDR(1) == TESTPAT)
- *bank1 = 8*MB;
- else if (TESTADDR(2) == TESTPAT)
- *bank1 = 16*MB;
- else if (TESTADDR(4) == TESTPAT)
- *bank1 = 32*MB;
- else
- *bank1 = 64*MB;
-#endif
-
- /* test for bank2 */
- if (TESTADDR(8) != 0)
- *bank2 = 0;
- else {
- TESTADDR(8) = TESTPAT;
- if (TESTADDR(9) != 0) {
- if (TESTADDR(10) == TESTPAT)
- *bank2 = 8*MB;
- else
- *bank2 = 32*MB;
- }
- else {
- TESTADDR(9) = TESTPAT;
- if (TESTADDR(10) == TESTPAT)
- *bank2 = 16*MB;
- else
- *bank2 = 64*MB;
- }
- }
-
- /* restore contents of the test addresses and restore interrupt mask */
- for( i = 0; i < 16; ++i )
- TESTADDR(i) = saved_contents[i];
- __asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
-}
-
-#undef TESTADDR
-#undef TESTPAT
-
-
-static int check_bootinfo_version(char *memptr)
-{
- struct bootversion *bv = (struct bootversion *)memptr;
- unsigned long version = 0;
- int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
- printf( "\n" );
- if (bv->magic == BOOTINFOV_MAGIC) {
- for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
- if (bv->machversions[i].machtype == MACH_ATARI) {
- version = bv->machversions[i].version;
- break;
- }
- }
- }
- if (!version)
- printf("Kernel has no bootinfo version info, assuming 0.0\n");
-
- kernel_major = BI_VERSION_MAJOR(version);
- kernel_minor = BI_VERSION_MINOR(version);
- boots_major = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
- boots_minor = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
- printf("Bootstrap's bootinfo version: %d.%d\n",
- boots_major, boots_minor);
- printf("Kernel's bootinfo version : %d.%d\n",
- kernel_major, kernel_minor);
-
- switch (kernel_major) {
- case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
- if (kernel_minor > boots_minor) {
- printf("Warning: Bootinfo version of bootstrap and kernel "
- "differ!\n");
- printf(" Certain features may not work.\n");
- }
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
- printf("(using backwards compatibility mode)\n");
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- printf("\nThis bootstrap is too %s for this kernel!\n",
- boots_major < kernel_major ? "old" : "new");
- return 0;
- }
- return kernel_major;
-}
-
-
-#ifdef USE_BOOTP
-# include "bootp.h"
-#else
-# define ll_read read
-# define ll_lseek lseek
-# define ll_close close
-#endif
-
-#ifdef ZKERNEL
-static int load_zkernel( int fd );
-static int kread( int fd, void *buf, unsigned cnt );
-static int klseek( int fd, int where, int whence );
-static int kclose( int fd );
-#else
-# define kread read
-# define klseek lseek
-# define kclose close
-#endif
-
-/* ++andreas: this must be inline due to Super */
-static inline void boot_exit (int) __attribute__ ((noreturn));
-static inline void boot_exit(int status)
-{
- /* first go back to user mode */
- (void)Super(userstk);
- getchar();
- exit(status);
-}
-
-int main(int argc, char *argv[])
-{
- int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
- int load_to_stram = 0;
- char *ramdisk_name, *kernel_name, *memptr;
- u_long ST_ramsize, TT_ramsize, memreq;
- u_long cpu_type, fpu_type, mch_type, mint;
- struct exec kexec;
- int elf_kernel = 0;
- Elf32_Ehdr kexec_elf;
- Elf32_Phdr *kernel_phdrs = NULL;
- u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
- int prefer_bootp = 1, kname_set = 0, n_knames;
-#ifdef USE_BOOTP
- int err;
-#endif
- char kname_list[5][64];
- void *bi_ptr;
-
- ramdisk_name = NULL;
- kernel_name = "vmlinux";
-
- /* print the startup message */
- puts("\fLinux/68k Atari Bootstrap version 2.2"
-#ifdef USE_BOOTP
- " (with BOOTP)"
-#endif
- );
- puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
-
- /* ++roman: If no arguments on the command line, read them from
- * file */
- if (argc == 1)
- get_default_args( &argc, &argv );
-
- /* machine is Atari */
- bi.machtype = MACH_ATARI;
-
- /* check arguments */
- while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
- switch (ch) {
- case 'd':
- debugflag = 1;
- break;
- case 't':
- ignore_ttram = 1;
- break;
- case 's':
- load_to_stram = 1;
- break;
- case 'k':
- kernel_name = optarg;
- kname_set = 1;
- break;
- case 'r':
- ramdisk_name = optarg;
- break;
- case 'b':
- prefer_bootp = 0;
- break;
- case '?':
- default:
- usage();
- }
-
- argc -= optind;
- argv += optind;
-
- /* We have to access some system variables to get
- * the information we need, so we must switch to
- * supervisor mode first.
- */
- userstk = Super(0L);
-
- /* get the info we need from the cookie-jar */
- cookiejar = *_p_cookies;
- if(cookiejar == 0L) {
- /* if we find no cookies, it's probably an ST */
- fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
- boot_exit(EXIT_FAILURE);
- }
-
- /* Exit if MiNT/MultiTOS is running. */
- if(getcookie("MiNT", &mint) != -1)
- {
- puts("Warning: MiNT is running\n");
-#if 0
- puts("Linux cannot be started when MiNT is running. Aborting...\n");
- boot_exit(EXIT_FAILURE);
-#endif
- }
-
- /* get _CPU, _FPU and _MCH */
- getcookie("_CPU", &cpu_type);
- getcookie("_FPU", &fpu_type);
- getcookie("_MCH", &mch_type);
-
- /* check if we are on a 68030/40 with FPU */
- if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
- {
- puts("Machine type currently not supported. Aborting...");
- boot_exit(EXIT_FAILURE);
- }
-
- switch(cpu_type) {
- case 0:
- case 10: break;
- case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break;
- case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break;
- case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break;
- case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break;
- default:
- fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
- boot_exit(EXIT_FAILURE);
- break;
- }
-
- printf("CPU: %ld; ", cpu_type + 68000);
- printf("FPU: ");
-
- /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
- * some software may set it to wrong values (68882 or the like) */
- if (cpu_type == 40) {
- bi.fputype = FPU_68040;
- puts( "68040\n" );
- }
- else if (cpu_type == 60) {
- bi.fputype = FPU_68060;
- puts( "68060\n" );
- }
- else {
- switch ((fpu_type >> 16) & 7) {
- case 0:
- puts("not present\n");
- break;
- case 1:
- puts("SFP004 not supported. Assuming no FPU.");
- break;
- case 2:
- /* try to determine real type */
- if (fpu_idle_frame_size () != 0x18)
- goto m68882;
- /* fall through */
- case 4:
- bi.fputype = FPU_68881;
- puts("68881\n");
- break;
- case 6:
- m68882:
- bi.fputype = FPU_68882;
- puts("68882\n");
- break;
- default:
- puts("Unknown FPU type. Assuming no FPU.");
- break;
- }
- }
- /* ++roman: If an FPU was announced in the cookie, test
- whether it is a real hardware FPU or a software emulator! */
- if (bi.fputype) {
- if (test_software_fpu()) {
- bi.fputype = 0;
- puts("FPU: software emulated. Assuming no FPU.");
- }
- }
-
- /* Get the amounts of ST- and TT-RAM. */
- /* The size must be a multiple of 1MB. */
- i = 0;
-
- if (!test_medusa()) {
- struct {
- unsigned short version; /* version - currently 1 */
- unsigned long fr_start; /* start addr FastRAM */
- unsigned long fr_len; /* length FastRAM */
- } *magn_cookie;
- struct {
- unsigned long version;
- unsigned long fr_start; /* start addr */
- unsigned long fr_len; /* length */
- } *fx_cookie;
-
- TT_ramsize = 0;
- if (!ignore_ttram) {
- /* "Original" or properly emulated TT-Ram */
- if (*ramtop) {
- /* the 'ramtop' variable at 0x05a4 is not
- * officially documented. We use it anyway
- * because it is the only way to get the TTram size.
- * (It is zero if there is no TTram.)
- */
- bi.memory[i].addr = TT_RAM_BASE;
- bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
- TT_ramsize = bi.memory[i].size / MB;
- i++;
- printf("TT-RAM: %ld Mb; ", TT_ramsize);
- }
-
- /* test for MAGNUM alternate RAM
- * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
- */
- if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
- bi.memory[i].addr = magn_cookie->fr_start;
- bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
- TT_ramsize += bi.memory[i].size / MB;
- printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
- i++;
- }
-
- /* BlowUps FX */
- if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
- /* if fx is set (cookie call above),
- * we assume that BlowUps FX-card
- * is installed. (Nat!)
- */
- bi.memory[i].addr = fx_cookie->fr_start;
- bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
- printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
- i++;
- }
- }
-
- bi.memory[i].addr = 0;
- bi.memory[i].size = *phystop & ~(MB - 1);
- ST_ramsize = bi.memory[i].size / MB;
- i++;
- printf("ST-RAM: %ld Mb\n", ST_ramsize );
-
- bi.num_memory = i;
-
- if (load_to_stram && i > 1) {
- /* Put ST-RAM first in the list of mem blocks */
- struct mem_info temp = bi.memory[i - 1];
- bi.memory[i - 1] = bi.memory[0];
- bi.memory[0] = temp;
- }
- }
- else {
- u_long bank1, bank2, medusa_st_ram;
-
- get_medusa_bank_sizes( &bank1, &bank2 );
- medusa_st_ram = *phystop & ~(MB - 1);
- bank1 -= medusa_st_ram;
- TT_ramsize = 0;
-
- bi.memory[i].addr = 0;
- bi.memory[i].size = medusa_st_ram;
- ST_ramsize = bi.memory[i].size / MB;
- i++;
- printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
-
- if (!ignore_ttram && bank1 > 0) {
- bi.memory[i].addr = 0x20000000 + medusa_st_ram;
- bi.memory[i].size = bank1;
- TT_ramsize += bank1;
- i++;
- printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
- }
-
- if (!ignore_ttram && bank2 > 0) {
- bi.memory[i].addr = 0x24000000;
- bi.memory[i].size = bank2;
- TT_ramsize += bank2;
- i++;
- printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
- }
-
- bi.num_memory = i;
- printf("\n");
- }
-
- /* verify that there is enough RAM; ST- and TT-RAM combined */
- if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
- puts("Not enough RAM. Aborting...");
- boot_exit(10);
- }
-
-#if 0
- /* Get language/keyboard info */
- /* TODO: do we need this ? */
- /* Could be used to auto-select keyboard map later on. (rdv) */
- if (getcookie("_AKP",&language) == -1)
- {
- /* Get the language info from the OS-header */
- os_header = *_sysbase;
- os_header = os_header->os_beg;
- lang = (os_header->os_conf) >> 1;
- printf("Language: ");
- switch(lang) {
- case HOL: puts("Dutch"); break; /* Own country first :-) */
- case USA: puts("American"); break;
- case SWG: puts("Switzerland (German)"); break;
- case FRG: puts("German"); break;
- case FRA: puts("French"); break;
- case SWF: puts("Switzerland (French)"); break;
- case UK: puts("English"); break;
- case SPA: puts("Spanish"); break;
- case ITA: puts("Italian"); break;
- case SWE: puts("Swedish"); break;
- case TUR: puts("Turkey"); break;
- case FIN: puts("Finnish"); break;
- case NOR: puts("Norwegian"); break;
- case DEN: puts("Danish"); break;
- case SAU: puts("Saudi-Arabian"); break;
- default: puts("Unknown"); break;
- }
- }
- else
- {
- printf("Language: ");
- switch(language & 0x0F)
- {
- case 1: printf("German "); break;
- case 2: printf("French "); break;
- case 4: printf("Spanish "); break;
- case 5: printf("Italian "); break;
- case 7: printf("Swiss French "); break;
- case 8: printf("Swiss German "); break;
- default: printf("English ");
- }
- printf("Keyboard type :");
- switch(language >> 8)
- {
- case 1: printf("German "); break;
- case 2: printf("French "); break;
- case 4: printf("Spanish "); break;
- case 5: printf("Italian "); break;
- case 7: printf("Swiss French "); break;
- case 8: printf("Swiss German "); break;
- default: printf("English ");
- }
- printf("\n");
- }
-#endif
-
- /* Pass contents of the _MCH cookie to the kernel */
- bi.mch_cookie = mch_type;
-
- /*
- * Copy command line options into the kernel command line.
- */
- i = 0;
- while (argc--) {
- if ((i+strlen(*argv)+1) < CL_SIZE) {
- i += strlen(*argv) + 1;
- if (bi.command_line[0])
- strcat (bi.command_line, " ");
- strcat (bi.command_line, *argv++);
- }
- }
- printf ("Command line is '%s'\n", bi.command_line);
-
- start_mem = bi.memory[0].addr;
- mem_size = bi.memory[0].size;
-
- /* tell us where the kernel will go */
- printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-#ifdef TEST
- /*
- ** Temporary exit point for testing
- */
- boot_exit(-1);
-#endif /* TEST */
-
- i = 0;
-#ifdef USE_BOOTP
- if (!kname_set)
- kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
-#endif
-#ifdef ZKERNEL
- strcpy( kname_list[i], kernel_name );
- strcat( kname_list[i], ".gz" );
- ++i;
-#endif
- strcpy( kname_list[i++], kernel_name );
-#ifdef ZKERNEL
- if (!kname_set)
- strcpy( kname_list[i++], "vmlinuz" );
-#endif
- n_knames = i;
-
- kfd = -1;
-#ifdef USE_BOOTP
- if (prefer_bootp) {
- for( i = 0; i < n_knames; ++i ) {
- if ((err = get_remote_kernel( kname_list[i] )) >= 0)
- goto kernel_open;
- if (err < -1) /* fatal error; retries don't help... */
- break;
- }
- printf( "\nremote boot failed; trying local kernel\n" );
- }
-#endif
- for( i = 0; i < n_knames; ++i ) {
- if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
- goto kernel_open;
- }
-#ifdef USE_BOOTP
- if (!prefer_bootp) {
- printf( "\nlocal kernel failed; trying remote boot\n" );
- for( i = 0; i < n_knames; ++i ) {
- if ((err = get_remote_kernel( kname_list[i] )) >= 0)
- goto kernel_open;
- if (err < -1) /* fatal error; retries don't help... */
- break;
- }
- }
-#endif
- fprintf( stderr, "Unable to open any kernel file\n(Tried " );
- for( i = 0; i < n_knames; ++i ) {
- fprintf( stderr, "%s%s", kname_list[i],
- i < n_knames-2 ? ", " :
- i == n_knames-2 ? ", and " :
- ")\n" );
- }
- boot_exit( EXIT_FAILURE );
-
- kernel_open:
-
- if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
- {
- fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
- boot_exit (EXIT_FAILURE);
- }
-
-#ifdef ZKERNEL
- if (((unsigned char *)&kexec)[0] == 037 &&
- (((unsigned char *)&kexec)[1] == 0213 ||
- ((unsigned char *)&kexec)[1] == 0236)) {
- /* That's a compressed kernel */
- printf( "Kernel is compressed\n" );
- if (load_zkernel( kfd )) {
- printf( "Decompression error -- aborting\n" );
- boot_exit( EXIT_FAILURE );
- }
- }
-#endif
-
- switch (N_MAGIC(kexec)) {
- case ZMAGIC:
- text_offset = N_TXTOFF(kexec);
- break;
- case QMAGIC:
- text_offset = sizeof(kexec);
- /* the text size includes the exec header; remove this */
- kexec.a_text -= sizeof(kexec);
- break;
- default:
- /* Try to parse it as an ELF header */
- klseek (kfd, 0, SEEK_SET);
- if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
- && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
- {
- elf_kernel = 1;
- /* A few plausibility checks */
- if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
- || kexec_elf.e_version != EV_CURRENT)
- {
- fprintf (stderr, "Invalid ELF header contents in kernel\n");
- boot_exit (EXIT_FAILURE);
- }
- /* Load the program headers */
- kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
- if (kernel_phdrs == NULL)
- {
- fprintf (stderr, "Unable to allocate memory for program headers\n");
- boot_exit (EXIT_FAILURE);
- }
- klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
- if (kread (kfd, (void *) kernel_phdrs,
- kexec_elf.e_phnum * sizeof (*kernel_phdrs))
- != kexec_elf.e_phnum * sizeof (*kernel_phdrs))
- {
- fprintf (stderr, "Unable to read program headers from %s\n",
- kernel_name);
- boot_exit (EXIT_FAILURE);
- }
- break;
- }
- fprintf (stderr, "Wrong magic number %lo in kernel header\n",
- N_MAGIC(kexec));
- boot_exit (EXIT_FAILURE);
- }
-
- /* Load the kernel one page after start of mem */
- start_mem += PAGE_SIZE;
- mem_size -= PAGE_SIZE;
- /* Align bss size to multiple of four */
- if (!elf_kernel)
- kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
- /* init ramdisk */
- if(ramdisk_name) {
- if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
- fprintf(stderr, "Unable to open ramdisk file %s\n",
- ramdisk_name);
- boot_exit(EXIT_FAILURE);
- }
- bi.ramdisk.size = lseek(rfd, 0, SEEK_END);
- }
- else
- bi.ramdisk.size = 0;
-
- /* calculate the total required amount of memory */
- if (elf_kernel)
- {
- u_long min_addr = 0xffffffff, max_addr = 0;
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- if (min_addr > kernel_phdrs[i].p_vaddr)
- min_addr = kernel_phdrs[i].p_vaddr;
- if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
- max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
- }
- /* This is needed for newer linkers that include the header in
- the first segment. */
- if (min_addr == 0)
- {
- min_addr = PAGE_SIZE;
- kernel_phdrs[0].p_vaddr += PAGE_SIZE;
- kernel_phdrs[0].p_offset += PAGE_SIZE;
- kernel_phdrs[0].p_filesz -= PAGE_SIZE;
- kernel_phdrs[0].p_memsz -= PAGE_SIZE;
- }
- kernel_size = max_addr - min_addr;
- }
- else
- kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
-
- rd_size = bi.ramdisk.size;
- if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
- /* If running low on ST ram load ramdisk into alternate ram. */
- bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
- else
- /* Else hopefully there is enough ST ram. */
- bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
-
- /* create the bootinfo structure */
- if (!create_bootinfo())
- boot_exit (EXIT_FAILURE);
-
- memreq = kernel_size + bi_size;
-#ifdef BOOTINFO_COMPAT_1_0
- if (sizeof(compat_bootinfo) > bi_size)
- memreq = kernel_size+sizeof(compat_bootinfo);
-#endif /* BOOTINFO_COMPAT_1_0 */
- /* align load address of ramdisk image, read() is sloooow on odd addr. */
- memreq = ((memreq + 3) & ~3) + rd_size;
-
- /* allocate RAM for the kernel */
- if (!(memptr = (char *)Malloc (memreq)))
- {
- fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
- boot_exit (EXIT_FAILURE);
- }
- else
- fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
-
- (void)memset(memptr, 0, memreq);
-
- /* read the text and data segments from the kernel image */
- if (elf_kernel)
- {
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to segment %d\n", i);
- boot_exit (EXIT_FAILURE);
- }
- if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
- kernel_phdrs[i].p_filesz)
- != kernel_phdrs[i].p_filesz)
- {
- fprintf (stderr, "Failed to read segment %d\n", i);
- boot_exit (EXIT_FAILURE);
- }
- }
- }
- else
- {
- if (klseek (kfd, text_offset, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to text\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
- {
- fprintf (stderr, "Failed to read text\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- /* data follows immediately after text */
- if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
- {
- fprintf (stderr, "Failed to read data\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- }
- kclose (kfd);
-
- /* Check kernel's bootinfo version */
- switch (check_bootinfo_version(memptr)) {
- case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
- bi_ptr = &bi_union.record;
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
- if (!create_compat_bootinfo()) {
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- bi_ptr = &compat_bootinfo;
- bi_size = sizeof(compat_bootinfo);
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- /* copy the boot_info struct to the end of the kernel image */
- memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size);
-
- /* read the ramdisk image */
- if (rfd != -1)
- {
- if (lseek (rfd, 0, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- if (read (rfd, memptr + memreq - rd_size,
- rd_size) != rd_size)
- {
- fprintf (stderr, "Failed to read ramdisk file\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- close (rfd);
- }
-
- /* for those who want to debug */
- if (debugflag)
- {
- if (bi.ramdisk.size)
- printf ("RAM disk at %#lx, size is %ld\n",
- (u_long)(memptr + memreq - rd_size),
- bi.ramdisk.size);
-
- if (elf_kernel)
- {
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- printf ("Kernel segment %d at %#lx, size %ld\n", i,
- start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
- kernel_phdrs[i].p_memsz);
- }
- }
- else
- {
- printf ("\nKernel text at %#lx, code size %d\n",
- start_mem, kexec.a_text);
- printf ("Kernel data at %#lx, data size %d\n",
- start_mem + kexec.a_text, kexec.a_data );
- printf ("Kernel bss at %#lx, bss size %d\n",
- start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
- }
- printf ("\nboot_info is at %#lx\n",
- start_mem + kernel_size);
- printf ("\nKernel entry is %#lx\n",
- elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
- printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size);
- printf ("ramdisk lower limit is %#lx\n",
- (u_long)(memptr + memreq - rd_size));
- printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
-
- printf ("Type a key to continue the Linux boot...");
- fflush (stdout);
- getchar();
- }
-
- printf("Booting Linux...\n");
-
- sync ();
-
- /* turn off interrupts... */
- disable_interrupts();
-
- /* turn off caches... */
- disable_cache();
-
- /* ..and any MMU translation */
- disable_mmu();
-
- /* ++guenther: allow reset if launched with MiNT */
- *(long*)0x426 = 0;
-
- /* copy mover code to a safe place if needed */
- memcpy ((void *) 0x400, ©all, ©allend - ©all);
-
- /* setup stack */
- change_stack ((void *) PAGE_SIZE);
-
- /*
- * On the Atari you can have two situations:
- * 1. One piece of contiguous RAM (Falcon)
- * 2. Two pieces of contiguous RAM (TT)
- * In case 2 you can load your program into ST-ram and load your data in
- * any old RAM you have left.
- * In case 1 you could overwrite your own program when copying the
- * kernel and ramdisk to their final positions.
- * To solve this the mover code is copied to a safe place first.
- * Then this program jumps to the mover code. After the mover code
- * has finished it jumps to the start of the kernel in its new position.
- * I thought the memory just after the interrupt vector table was a safe
- * place because it is used by TOS to store some system variables.
- * This range goes from 0x400 to approx. 0x5B0.
- * This is more than enough for the miniscule mover routine (16 bytes).
- */
-
- jump_to_mover((char *) start_mem, memptr,
- (char *) bi.ramdisk.addr + rd_size, memptr + memreq,
- kernel_size + bi_size, rd_size,
- (void *) 0x400);
-
- for (;;);
- /* NOTREACHED */
-}
-
-
-
-#define MAXARGS 30
-
-static void get_default_args( int *argc, char ***argv )
-
-{ FILE *f;
- static char *nargv[MAXARGS];
- char arg[256], *p;
- int c, quote, state;
-
- if (!(f = fopen( "bootargs", "r" )))
- return;
-
- *argc = 1;
- if (***argv)
- nargv[0] = **argv;
- else
- nargv[0] = "bootstrap";
- *argv = nargv;
-
- quote = state = 0;
- p = arg;
- while( (c = fgetc(f)) != EOF ) {
-
- if (state == 0) {
- /* outside args, skip whitespace */
- if (!isspace(c)) {
- state = 1;
- p = arg;
- }
- }
-
- if (state) {
- /* inside an arg: copy it into 'arg', obeying quoting */
- if (!quote && (c == '\'' || c == '"'))
- quote = c;
- else if (quote && c == quote)
- quote = 0;
- else if (!quote && isspace(c)) {
- /* end of this arg */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- state = 0;
- }
- else
- *p++ = c;
- }
- }
- if (state) {
- /* last arg finished by EOF! */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- }
- fclose( f );
-
- nargv[*argc] = 0;
-}
-
-
- /*
- * Create the Bootinfo Structure
- */
-
-static int create_bootinfo(void)
-{
- int i;
- struct bi_record *record;
-
- /* Initialization */
- bi_size = 0;
-
- /* Generic tags */
- if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
- return(0);
- if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
- return(0);
- if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
- return(0);
- if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
- return(0);
- for (i = 0; i < bi.num_memory; i++)
- if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
- return(0);
- if (bi.ramdisk.size)
- if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
- return(0);
- if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
- return(0);
-
- /* Atari tags */
- if (!add_bi_record(BI_ATARI_MCH_COOKIE, sizeof(bi.mch_cookie),
- &bi.mch_cookie))
- return(0);
-
- /* Trailer */
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = BI_LAST;
- bi_size += sizeof(bi_union.record.tag);
-
- return(1);
-}
-
-
- /*
- * Add a Record to the Bootinfo Structure
- */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
- struct bi_record *record;
- u_short size2;
-
- size2 = (sizeof(struct bi_record)+size+3)&-4;
- if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
- fprintf (stderr, "Can't add bootinfo record. Ask a wizard to enlarge me.\n");
- return(0);
- }
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = tag;
- record->size = size2;
- memcpy(record->data, data, size);
- bi_size += size2;
- return(1);
-}
-
-
- /*
- * Add a String Record to the Bootinfo Structure
- */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
- return add_bi_record(tag, strlen(s)+1, (void *)s);
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
- /*
- * Create the Bootinfo structure for backwards compatibility mode
- */
-
-static int create_compat_bootinfo(void)
-{
- u_int i;
-
- compat_bootinfo.machtype = bi.machtype;
- if (bi.cputype & CPU_68020)
- compat_bootinfo.cputype = COMPAT_CPU_68020;
- else if (bi.cputype & CPU_68030)
- compat_bootinfo.cputype = COMPAT_CPU_68030;
- else if (bi.cputype & CPU_68040)
- compat_bootinfo.cputype = COMPAT_CPU_68040;
- else if (bi.cputype & CPU_68060)
- compat_bootinfo.cputype = COMPAT_CPU_68060;
- else {
- printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
- return(0);
- }
- if (bi.fputype & FPU_68881)
- compat_bootinfo.cputype |= COMPAT_FPU_68881;
- else if (bi.fputype & FPU_68882)
- compat_bootinfo.cputype |= COMPAT_FPU_68882;
- else if (bi.fputype & FPU_68040)
- compat_bootinfo.cputype |= COMPAT_FPU_68040;
- else if (bi.fputype & FPU_68060)
- compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else {
- printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
- return(0);
- }
- compat_bootinfo.num_memory = bi.num_memory;
- if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
- printf("Warning: using only %d blocks of memory\n",
- COMPAT_NUM_MEMINFO);
- compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
- }
- for (i = 0; i < compat_bootinfo.num_memory; i++) {
- compat_bootinfo.memory[i].addr = bi.memory[i].addr;
- compat_bootinfo.memory[i].size = bi.memory[i].size;
- }
- if (bi.ramdisk.size) {
- compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
- compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
- } else {
- compat_bootinfo.ramdisk_size = 0;
- compat_bootinfo.ramdisk_addr = 0;
- }
- strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
- compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
- compat_bootinfo.bi_atari.hw_present = 0;
- compat_bootinfo.bi_atari.mch_cookie = bi.mch_cookie;
- return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-#ifdef ZKERNEL
-
-#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS)
-#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1)
-#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0; /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000 /* window size--must be a power of two, and */
- /* at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../../../../lib/inflate.c"
-
-static void gzip_mark( void **ptr )
-{
-}
-
-static void gzip_release( void **ptr )
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf( void )
-{
- if (exit_code)
- return -1;
-
- insize = ll_read( Zinfd, inbuf, INBUFSIZ );
- if (insize <= 0)
- return -1;
-
- inptr = 1;
- return( inbuf[0] );
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window( void )
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
- int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
- if (chunk >= ZFILE_N_CHUNKS) {
- fprintf( stderr, "compressed image too large! Aborting.\n" );
- boot_exit( EXIT_FAILURE );
- }
- if (!ZFile[chunk]) {
- if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) {
- fprintf( stderr, "Out of memory for decompresing kernel image\n" );
- boot_exit( EXIT_FAILURE );
- }
- }
- memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt );
- Zwpos += outcnt;
-
-#define DISPLAY_BITS 13
- if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) {
- printf( "." );
- fflush( stdout );
- }
-
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void error( char *x )
-{
- fprintf( stderr, "\n%s", x);
- exit_code = 1;
-}
-
-static int load_zkernel( int fd )
-{
- int i, err;
-
- for( i = 0; i < ZFILE_N_CHUNKS; ++i )
- ZFile[i] = NULL;
- Zinfd = fd;
- ll_lseek( fd, 0, SEEK_SET );
-
- if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) {
- fprintf( stderr, "Couldn't allocate gunzip buffer\n" );
- boot_exit( EXIT_FAILURE );
- }
- if (!(window = (uch *)Malloc( WSIZE ))) {
- fprintf( stderr, "Couldn't allocate gunzip window\n" );
- boot_exit( EXIT_FAILURE );
- }
-
- printf( "Uncompressing kernel image " );
- fflush( stdout );
- makecrc();
- if (!(err = gunzip()))
- printf( "done\n" );
- ZFileSize = Zwpos;
- ll_close( Zinfd ); /* input file not needed anymore */
-
- Mfree( inbuf );
- Mfree( window );
- return( err );
-}
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman)
- */
-
-static int kread( int fd, void *buf, unsigned cnt )
-{
- unsigned done = 0;
-
- if (!ZFileSize)
- return( ll_read( fd, buf, cnt ) );
-
- if (ZFpos + cnt > ZFileSize)
- cnt = ZFileSize - ZFpos;
-
- while( cnt > 0 ) {
- unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (ZFpos + n > endchunk)
- n = endchunk - ZFpos;
- memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n );
- cnt -= n;
- buf += n;
- done += n;
- ZFpos += n;
-
- if (ZFpos == endchunk) {
- Mfree( ZFile[chunk] );
- ZFile[chunk] = NULL;
- }
- }
-
- return( done );
-}
-
-
-static int klseek( int fd, int where, int whence )
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!ZFileSize)
- return( ll_lseek( fd, where, whence ) );
-
- oldpos = ZFpos;
- switch( whence ) {
- case SEEK_SET:
- ZFpos = where;
- break;
- case SEEK_CUR:
- ZFpos += where;
- break;
- case SEEK_END:
- ZFpos = ZFileSize + where;
- break;
- default:
- return( -1 );
- }
- if (ZFpos < 0) {
- ZFpos = 0;
- return( -1 );
- }
- else if (ZFpos > ZFileSize) {
- ZFpos = ZFileSize;
- return( -1 );
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> ZFILE_CHUNK_BITS;
- newchunk = ZFpos >> ZFILE_CHUNK_BITS;
- while( oldchunk < newchunk ) {
- if (ZFile[oldchunk]) {
- Mfree( ZFile[oldchunk] );
- ZFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
-
- return( ZFpos );
-}
-
-
-static void free_zfile( void )
-{
- int i;
-
- for( i = 0; i < ZFILE_N_CHUNKS; ++i )
- if (ZFile[i]) Mfree( ZFile[i] );
-}
-
-static int kclose( int fd )
-{
- if (ZFileSize) {
- free_zfile();
- return( 0 );
- }
- else
- return( ll_close( fd ) );
-}
-
-
-
-#endif /* ZKERNEL */
+++ /dev/null
-/*
-** bootstrap.h -- This file is a part of the Atari bootloader.
-**
-** Copyright 1993 by Arjan Knor
-**
-** Modified by Andreas Schwab
-** - clear transparent translation registers
-** Modified 18-Aug-96 by Geert Uytterhoeven
-** - Updated for the new boot information structure (untested!)
-** Modified 1996-11-12 by Andreas Schwab
-** - Fixed and tested previous change
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#ifndef BOOTSTRAP_H
-#define BOOTSTRAP_H
-
- /*
- * Atari Bootinfo Definitions
- *
- * All limits herein are `soft' limits, i.e. they don't put constraints
- * on the actual parameters in the kernel.
- */
-
-struct atari_bootinfo {
- unsigned long machtype; /* machine type */
- unsigned long cputype; /* system CPU */
- unsigned long fputype; /* system FPU */
- unsigned long mmutype; /* system MMU */
- int num_memory; /* # of memory blocks found */
- struct mem_info memory[NUM_MEMINFO]; /* memory description */
- struct mem_info ramdisk; /* ramdisk description */
- char command_line[CL_SIZE]; /* kernel command line parameters */
- unsigned long mch_cookie; /* _MCH cookie from TOS */
-};
-
-
-/* _MCH cookie values */
-#define MACH_ST 0
-#define MACH_STE 1
-#define MACH_TT 2
-#define MACH_FALCON 3
-
-/* some constants for memory handling */
-#define ST_RAM 0
-#define TT_RAM 1
-#define TT_RAM_BASE (u_long)(0x01000000)
-#define MB (1024 * 1024)
-#define START_MEM (bi.memory[0].addr)
-#define MEM_SIZE (bi.memory[0].size)
-
-/* the various CPU- and FPU-types */
-#define AFF_68000 (1)
-#define AFF_68020 (2)
-#define AFF_68030 (4)
-#define AFF_68040 (8)
-#define AFF_68881 (16)
-#define AFF_68882 (32)
-
-/* the possible OS-languages */
-#define USA 0
-#define FRG 1
-#define FRA 2
-#define UK 3
-#define SPA 4
-#define ITA 5
-#define SWE 6
-#define SWF 7
-#define SWG 8
-#define TUR 9
-#define FIN 10
-#define NOR 11
-#define DEN 12
-#define SAU 13
-#define HOL 14
-
-/* some inline functions */
-
-static __inline int fpu_idle_frame_size (void)
-{
- char fpu_frame[216];
- __asm__ __volatile__ ("fnop"::);
- __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
- return fpu_frame[1];
-}
-
-static __inline void change_stack (u_long *stackp)
-{
- __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
-}
-
-static __inline void disable_interrupts (void)
-{
- __asm__ volatile ("orw #0x700,sr":);
-}
-
-extern struct atari_bootinfo bi;
-static __inline void disable_cache (void)
-{
- __asm__ volatile ("movec %0,cacr" :: "d" (0));
- if (bi.cputype & CPU_68060) {
- /* '060: clear branch cache after disabling it;
- * disable superscalar operation (and enable FPU) */
- __asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
- __asm__ volatile ("moveq #0,d0;"
- ".long 0x4e7b0808" /* movec d0,pcr */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- }
-}
-
-static __inline void disable_mmu (void)
-{
- if (bi.cputype & (CPU_68040|CPU_68060)) {
- __asm__ volatile ("moveq #0,d0;"
- ".long 0x4e7b0003;" /* movec d0,tc */
- ".long 0x4e7b0004;" /* movec d0,itt0 */
- ".long 0x4e7b0005;" /* movec d0,itt1 */
- ".long 0x4e7b0006;" /* movec d0,dtt0 */
- ".long 0x4e7b0007" /* movec d0,dtt1 */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- }
- else {
- __asm__ volatile ("subl #4,sp\n\t"
- "pmove tc,sp@\n\t"
- "bclr #7,sp@\n\t"
- "pmove sp@,tc\n\t"
- "addl #4,sp");
- if (bi.cputype & CPU_68030) {
- __asm__ volatile ("clrl sp@-\n\t"
- ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
- ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
- "addl #4,sp\n");
- }
- }
-}
-
-static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
- void *) __attribute__ ((noreturn));
-static __inline void jump_to_mover (void *kernel_start, void *mem_start,
- void *ramdisk_end, void *mem_end,
- int kernel_size, int ramdisk_size,
- void *mover_addr)
-{
- asm volatile ("movel %0,a0\n\t"
- "movel %1,a1\n\t"
- "movel %2,a2\n\t"
- "movel %3,a3\n\t"
- "movel %4,d0\n\t"
- "movel %5,d1\n\t"
- "jmp %6@\n"
- : /* no outputs */
- : "g" (kernel_start), "g" (mem_start),
- "g" (ramdisk_end), "g" (mem_end),
- "g" (kernel_size), "g" (ramdisk_size),
- "a" (mover_addr)
- : "a0", "a1", "a2", "a3", "d0", "d1");
-
- /* Avoid warning that function may return */
- for (;;) ;
-}
-
-#endif /* BOOTSTRAP_H */
-
+++ /dev/null
-
-#include <stdio.h>
-#include <string.h>
-
-#include "bootp.h"
-#include "ethlance.h"
-
-
-struct {
- volatile unsigned short *memaddr;
- volatile unsigned short *ioaddr;
-} lance_addr_list[] = {
- { (void *)0xfe010000, (void *)0xfe00fff0 }, /* RieblCard VME in TT */
- { (void *)0xfec10000, (void *)0xfec0fff0 }, /* RieblCard VME in MegaSTE
- (highest byte stripped) */
- { (void *)0xfee00000, (void *)0xfeff7000 }, /* RieblCard in ST
- (highest byte stripped) */
- { (void *)0xfecf0000, (void *)0xfecffff0 }, /* PAMCard VME in TT and MSTE
- (highest byte stripped) */
-};
-
-#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
-
-#define TX_RING_SIZE 1
-#define TX_RING_LEN_BITS 0
-
-#define RX_RING_SIZE 16
-#define RX_RING_LEN_BITS (4 << 5)
-
-#define offsetof(type,elt) ((unsigned long)(&(((type *)0)->elt)))
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
- unsigned short base; /* Low word of base addr */
- volatile unsigned char flag;
- unsigned char base_hi; /* High word of base addr (unused) */
- short buf_length; /* This length is 2s complement! */
- short msg_length; /* This length is "normal". */
-};
-
-struct lance_tx_head {
- unsigned short base; /* Low word of base addr */
- volatile unsigned char flag;
- unsigned char base_hi; /* High word of base addr (unused) */
- short length; /* Length is 2s complement! */
- volatile short misc;
-};
-
-struct ringdesc {
- unsigned short adr_lo; /* Low 16 bits of address */
- unsigned char len; /* Length bits */
- unsigned char adr_hi; /* High 8 bits of address (unused) */
-};
-
-struct lance_packet {
- volatile unsigned char data[PKTLEN];
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
- unsigned short mode; /* Pre-set mode */
- unsigned char hwaddr[6]; /* Physical ethernet address */
- unsigned filter[2]; /* Multicast filter (unused). */
- /* Receive and transmit ring base, along with length bits. */
- struct ringdesc rx_ring;
- struct ringdesc tx_ring;
-};
-
-/* The whole layout of the Lance shared memory */
-struct lance_memory {
- struct lance_init_block init;
- struct lance_tx_head tx_head[TX_RING_SIZE];
- struct lance_rx_head rx_head[RX_RING_SIZE];
- struct lance_packet tx_packet[TX_RING_SIZE];
- struct lance_packet rx_packet[TX_RING_SIZE];
-};
-
-#define RIEBL_MAGIC 0x09051990
-#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a))
-#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e))
-#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe))
-
-struct lance_ioreg {
-/* base+0x0 */ volatile unsigned short data;
-/* base+0x2 */ volatile unsigned short addr;
- unsigned char _dummy1[3];
-/* base+0x7 */ volatile unsigned char ivec;
- unsigned char _dummy2[5];
-/* base+0xd */ volatile unsigned char eeprom;
- unsigned char _dummy3;
-/* base+0xf */ volatile unsigned char mem;
-};
-
-enum lance_type {
- OLD_RIEBL, /* old Riebl card without battery */
- NEW_RIEBL, /* new Riebl card with battery */
- PAM_CARD /* PAM card with EEPROM */
-} CardType;
-
-HWADDR dev_addr;
-
-/* This is a default address for the old RieblCards without a battery
- * that have no ethernet address at boot time. 00:00:36:04 is the
- * prefix for Riebl cards, the 00:00 at the end is arbitrary.
- */
-
-HWADDR OldRieblDefHwaddr = {
- 0x00, 0x00, 0x36, 0x04, 0x00, 0x00
-};
-
-struct lance_ioreg *IO;
-struct lance_memory *MEM;
-
-#define DREG IO->data
-#define AREG IO->addr
-#define REGA(a) ( AREG = (a), DREG )
-
-int CurRx;
-
-
-/* Definitions for the Lance */
-
-/* tx_head flags */
-#define TMD1_ENP 0x01
-#define TMD1_STP 0x02
-#define TMD1_DEF 0x04
-#define TMD1_ONE 0x08
-#define TMD1_MORE 0x10
-#define TMD1_ERR 0x40
-#define TMD1_OWN 0x80
-
-#define TMD1_OWN_CHIP TMD1_OWN
-#define TMD1_OWN_HOST 0
-
-/* tx_head misc field */
-#define TMD3_TDR 0x03FF
-#define TMD3_RTRY 0x0400
-#define TMD3_LCAR 0x0800
-#define TMD3_LCOL 0x1000
-#define TMD3_UFLO 0x4000
-#define TMD3_BUFF3 0x8000
-
-/* rx_head flags */
-#define RMD1_ENP 0x01
-#define RMD1_STP 0x02
-#define RMD1_BUFF 0x04
-#define RMD1_CRC 0x08
-#define RMD1_OFLO 0x10
-#define RMD1_FRAM 0x20
-#define RMD1_ERR 0x40
-#define RMD1_OWN 0x80
-
-#define RMD1_OWN_CHIP RMD1_OWN
-#define RMD1_OWN_HOST 0
-
-/* register names */
-#define CSR0 0
-#define CSR1 1
-#define CSR2 2
-#define CSR3 3
-
-/* CSR0 */
-#define CSR0_INIT 0x0001 /* initialize */
-#define CSR0_STRT 0x0002 /* start */
-#define CSR0_STOP 0x0004 /* stop */
-#define CSR0_TDMD 0x0008 /* transmit demand */
-#define CSR0_TXON 0x0010 /* transmitter on */
-#define CSR0_RXON 0x0020 /* receiver on */
-#define CSR0_INEA 0x0040 /* interrupt enable */
-#define CSR0_INTR 0x0080 /* interrupt active */
-#define CSR0_IDON 0x0100 /* initialization done */
-#define CSR0_TINT 0x0200 /* transmitter interrupt */
-#define CSR0_RINT 0x0400 /* receiver interrupt */
-#define CSR0_MERR 0x0800 /* memory error */
-#define CSR0_MISS 0x1000 /* missed frame */
-#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) */
-#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits */
-#define CSR0_ERR 0x8000 /* error */
-
-/* CSR3 */
-#define CSR3_BCON 0x0001
-#define CSR3_ACON 0x0002
-#define CSR3_BSWP 0x0004
-
-
-#define HZ 200
-#define _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static int lance_probe( void );
-static int addr_readable( volatile void *regp, int wordflag );
-static int lance_init( void );
-static void lance_get_hwaddr( HWADDR *addr );
-static int lance_snd( Packet *pkt, int len );
-static int lance_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-ETHIF_SWITCH LanceSwitch = {
- lance_probe, lance_init, lance_get_hwaddr,
- lance_snd, lance_rcv
-};
-
-
-static int lance_probe( void )
-
-{ int i;
-
- for( i = 0; i < N_LANCE_ADDR; ++i ) {
- if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
- (lance_addr_list[i].memaddr[0] = 1,
- lance_addr_list[i].memaddr[0] == 1) &&
- (lance_addr_list[i].memaddr[0] = 0,
- lance_addr_list[i].memaddr[0] == 0) &&
- addr_readable( lance_addr_list[i].ioaddr, 1 )) {
- break;
- }
- }
- if (i == N_LANCE_ADDR) return( -1 );
-
- IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
- MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
- REGA( CSR0 ) = CSR0_STOP;
-
- return( 0 );
-}
-
-
-static int addr_readable( volatile void *regp, int wordflag )
-
-{ int ret;
- long *vbr, save_berr;
-
- __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : );
- save_berr = vbr[2];
-
- __asm__ __volatile__
- ( "movel %/sp,%/d1\n\t"
- "movel #Lberr,%2@\n\t"
- "moveq #0,%0\n\t"
- "tstl %3\n\t"
- "bne 1f\n\t"
- "tstb %1@\n\t"
- "bra 2f\n"
-"1: tstw %1@\n"
-"2: moveq #1,%0\n"
-"Lberr: movel %/d1,%/sp"
- : "=&d" (ret)
- : "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
- : "d1", "memory"
- );
-
- vbr[2] = save_berr;
-
- return( ret );
-}
-
-
-static int lance_init( void )
-
-{ int i;
-
- /* Now test for type: If the eeprom I/O port is readable, it is a
- * PAM card */
- if (addr_readable( &(IO->eeprom), 0 )) {
- /* Switch back to Ram */
- i = IO->mem;
- CardType = PAM_CARD;
- }
- else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
- CardType = NEW_RIEBL;
- }
- else
- CardType = OLD_RIEBL;
-
- /* Get the ethernet address */
- switch( CardType ) {
- case OLD_RIEBL:
- /* No ethernet address! (Set some default address) */
- memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
- break;
- case NEW_RIEBL:
- memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
- break;
- case PAM_CARD:
- i = IO->eeprom;
- for( i = 0; i < ETHADDRLEN; ++i )
- dev_addr[i] =
- ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
- ((((unsigned short *)MEM)[i*2+1] & 0x0f));
- i = IO->mem;
- break;
- }
-
- MEM->init.mode = 0x0000; /* Disable Rx and Tx. */
- for( i = 0; i < ETHADDRLEN; i++ )
- MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
- MEM->init.filter[0] = 0x00000000;
- MEM->init.filter[1] = 0x00000000;
- MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
- MEM->init.rx_ring.adr_hi = 0;
- MEM->init.rx_ring.len = RX_RING_LEN_BITS;
- MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
- MEM->init.tx_ring.adr_hi = 0;
- MEM->init.tx_ring.len = TX_RING_LEN_BITS;
-
- REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0);
- REGA( CSR2 ) = 0;
- REGA( CSR1 ) = 0;
- REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
-
- i = 1000000;
- while( i-- > 0 )
- if (DREG & CSR0_IDON)
- break;
- if (i < 0 || (DREG & CSR0_ERR)) {
- DREG = CSR0_STOP;
- return( -1 );
- }
- DREG = CSR0_IDON;
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
- MEM->tx_head[i].flag = TMD1_OWN_HOST;
- MEM->tx_head[i].base_hi = 0;
- MEM->tx_head[i].length = 0;
- MEM->tx_head[i].misc = 0;
- }
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
- MEM->rx_head[i].flag = TMD1_OWN_CHIP;
- MEM->rx_head[i].base_hi = 0;
- MEM->rx_head[i].buf_length = -PKTLEN;
- MEM->rx_head[i].msg_length = 0;
- }
- CurRx = 0;
-
- return( 0 );
-}
-
-
-static void lance_get_hwaddr( HWADDR *addr )
-
-{
- memcpy( addr, dev_addr, ETHADDRLEN );
-}
-
-
-static int lance_snd( Packet *pkt, int len )
-
-{ unsigned long timeout;
-
- /* The old LANCE chips doesn't automatically pad buffers to min. size. */
- len = (len < 60) ? 60 : len;
- /* PAM-Card has a bug: Can only send packets with even number of bytes! */
- if (CardType == PAM_CARD && (len & 1))
- ++len;
-
- MEM->tx_head[0].length = -len;
- MEM->tx_head[0].misc = 0;
- memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
- MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
- MEM->tx_head[0].base_hi = 0;
- MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-
- /* Trigger an immediate send poll. */
- REGA( CSR0 ) = CSR0_TDMD;
-
- /* Wait for packet being sent */
- timeout = _hz_200 + 3*HZ;
- while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
- !MEM->tx_head[0].misc &&
- _hz_200 < timeout )
- ;
-
- if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
- !(MEM->tx_head[0].misc & TMD1_ERR))
- /* sent ok */
- return( 0 );
-
- /* failure */
- if (_hz_200 >= timeout)
- return( ETIMEO );
- if (MEM->tx_head[0].misc & TMD3_UFLO) {
- /* On FIFO errors, must re-turn on TX! */
- DREG = CSR0_STRT;
- }
-
- return( ESEND );
-}
-
-
-static int lance_rcv( Packet *pkt, int *len )
-
-{ unsigned long timeout;
- int stat;
-
- /* Wait for a packet */
- timeout = _hz_200 + 4*HZ;
- while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
- _hz_200 < timeout )
- ;
- /* Not ours -> was a timeout */
- if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
- return( ETIMEO );
-
- /* Check for errors */
- if (stat != (RMD1_ENP|RMD1_STP)) {
- MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
- if (stat & RMD1_FRAM) return( EFRAM );
- if (stat & RMD1_OFLO) return( EOVERFL );
- if (stat & RMD1_CRC) return( ECRC );
- return( ERCV );
- }
-
- /* Get the packet */
- *len = MEM->rx_head[CurRx].msg_length & 0xfff;
- memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
-
- /* Give the buffer back to the chip */
- MEM->rx_head[CurRx].buf_length = -PKTLEN;
- MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
- CurRx = (CurRx + 1) % RX_RING_SIZE;
-
- return( 0 );
-}
-
-
+++ /dev/null
-
-#ifndef _ethlance_h
-#define _ethlance_h
-
-extern ETHIF_SWITCH LanceSwitch;
-
-#endif /* _ethlance_h */
+++ /dev/null
-typedef struct _osheader
-{
- unsigned short os_entry;
- unsigned short os_version;
- void *reseth;
- struct _osheader *os_beg;
- void *os_end;
- long os_rsv1;
- void *os_magic;
- long os_date;
- unsigned short os_conf;
- unsigned short os_dosdate;
- char **p_root;
- unsigned char **pkbshift;
- void **p_run;
- char *p_rsv2;
-} OSHEADER;
-
-#define phystop ((unsigned long *)0x42e)
-#define _sysbase ((OSHEADER **)0x4f2)
-#define _p_cookies ((unsigned long **)0x5a0)
-#define ramtop ((unsigned long *)0x5a4)
define_bool CONFIG_VT_CONSOLE y
define_bool CONFIG_FB_CONSOLE y
+if [ "$CONFIG_ATARI" = "y" ]; then
+ define_bool CONFIG_NVRAM y
+fi
+
tristate 'Parallel printer support' CONFIG_PRINTER
if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+ bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
fi
if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
"$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=y
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=y
#include <linux/linkage.h>
#include <asm/entry.h>
+
|################################
| (1) EXAMPLE CALL-OUTS #
| #
set_scrmem(fg_console, 0);
set_origin(fg_console);
#endif /* XXX */
- update_screen(fg_console);
+ /* don't update in graphics mode */
+ if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
+
set_cursor(fg_console);
return 0;
console_table[currcons]->winsize = ws;
}
- if (currcons == fg_console)
- update_screen(fg_console);
+ /* don't update in graphics mode */
+ if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
}
void vc_disallocate(unsigned int currcons)
andw #ALLOWINT,%sr
/* check if we need to do software interrupts */
-
+
movel SYMBOL_NAME(bh_active),%d0
andl SYMBOL_NAME(bh_mask),%d0
jeq SYMBOL_NAME(ret_from_exception)
movel %d2,%a0@
lea %pc@(SYMBOL_NAME(is_medusa)),%a0
movel %d3,%a0@
+ lea %pc@(Liobase),%a0
+ movel %d2,%a0@ /* On a Hades the iobase must be set
+ before opening the serial port. */
Lnotypetest:
#endif
struct pt_regs *regs = (struct pt_regs *) &name;
lock_kernel();
- error = getname(name, &filename);
- if (error)
+ filename = getname(name);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
return -ENOSYS;
}
-/* Convert virtual address VADDR to physical address PADDR, recording
- in VALID whether the virtual address is actually mapped. */
-#define virt_to_phys_040(vaddr, paddr, valid) \
-{ \
- unsigned long _mmusr; \
+/* Convert virtual address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr) \
+({ \
+ unsigned long _mmusr, _paddr; \
\
__asm__ __volatile__ (".chip 68040\n\t" \
"ptestr (%1)\n\t" \
".chip 68k" \
: "=r" (_mmusr) \
: "a" (vaddr)); \
- if (!(_mmusr & MMU_R_040)) \
- (valid) = 0; \
- else \
- { \
- (valid) = 1; \
- (paddr) = _mmusr & PAGE_MASK; \
- } \
-}
+ _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \
+ _paddr; \
+})
static inline int
cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
{
- unsigned long paddr;
- int valid;
+ unsigned long paddr, i;
switch (scope)
{
break;
case FLUSH_SCOPE_LINE:
- len >>= 4;
/* Find the physical address of the first mapped page in the
address range. */
- for (;;)
- {
- virt_to_phys_040 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ if ((paddr = virt_to_phys_040(addr))) {
+ paddr += addr & ~(PAGE_MASK | 15);
+ len = (len + (addr & 15) + 15) >> 4;
+ } else {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ len = (len + 15) >> 4;
+ }
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
while (len--)
{
switch (cache)
: : "a" (paddr));
break;
}
- addr += 16;
- if (len)
+ if (!--i && len)
{
- if ((addr & (PAGE_SIZE-1)) < 16)
+ addr += PAGE_SIZE;
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
{
- /* Recompute physical address when crossing a page
- boundary. */
- for (;;)
- {
- virt_to_phys_040 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
}
- else
- paddr += 16;
}
+ else
+ paddr += 16;
}
break;
default:
case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
{
- virt_to_phys_040 (addr, paddr, valid);
- if (!valid)
+ if (!(paddr = virt_to_phys_040(addr)))
continue;
switch (cache)
{
return 0;
}
-#define virt_to_phys_060(vaddr, paddr, valid) \
-{ \
+#define virt_to_phys_060(vaddr) \
+({ \
+ unsigned long paddr; \
__asm__ __volatile__ (".chip 68060\n\t" \
"plpar (%0)\n\t" \
".chip 68k" \
: "=a" (paddr) \
: "0" (vaddr)); \
- (valid) = 1; /* XXX */ \
-}
+ (paddr); /* XXX */ \
+})
static inline int
cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
{
- unsigned long paddr;
- int valid;
+ unsigned long paddr, i;
switch (scope)
{
break;
case FLUSH_SCOPE_LINE:
- len >>= 4;
/* Find the physical address of the first mapped page in the
address range. */
- for (;;)
- {
- virt_to_phys_060 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ len += addr & 15;
+ addr &= -16;
+ if (!(paddr = virt_to_phys_060(addr))) {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ }
+ len = (len + 15) >> 4;
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
while (len--)
{
switch (cache)
: : "a" (paddr));
break;
}
- addr += 16;
- if (len)
+ if (!--i && len)
{
- if ((addr & (PAGE_SIZE-1)) < 16)
- {
- /* Recompute the physical address when crossing a
- page boundary. */
- for (;;)
- {
- virt_to_phys_060 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
- }
- else
- paddr += 16;
+ addr += PAGE_SIZE;
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
+ }
}
+ else
+ paddr += 16;
}
break;
default:
case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+ addr &= PAGE_MASK; /* Workaround for bug in some
+ revisions of the 68060 */
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
{
- virt_to_phys_060 (addr, paddr, valid);
- if (!valid)
+ if (!(paddr = virt_to_phys_060(addr)))
continue;
switch (cache)
{
bool 'Sysctl support' CONFIG_SYSCTL
if [ "$CONFIG_SGI" != "y" ]; then
- tristate 'Parallel port support' CONFIG_PARPORT
+ tristate 'Parallel port support' CONFIG_PNP_PARPORT
fi
endmenu
# CONFIG_IP_ACCT is not set
# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
#
# (it is safe to leave these untouched)
b loc_call
li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot
-loc_scsi: PANIC("Unimplemented loc_scsi handler")
+loc_scsi: li s1,~JAZZ_IE_SCSI
+ li a0,12 # JAZZ_SCSI_IRQ */
+ b loc_call
+ li t3,PTRSIZE*12 # JAZZ_ETHERNET_IRQ # delay slot
/*
* Keyboard interrupt handler
* Clear all interrupt flags
*/
r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR);
/*
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/jazz.h>
#include <asm/ptrace.h>
extern void jazz_machine_halt(void);
extern void jazz_machine_power_off(void);
+void (*board_time_init)(struct irqaction *irq);
+
+__initfunc(static void jazz_time_init(struct irqaction *irq))
+{
+ /* set the clock to 100 Hz */
+ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+ setup_x86_irq(0, irq);
+}
+
__initfunc(static void jazz_irq_setup(void))
{
set_except_vector(0, jazz_handle_int);
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
JAZZ_IE_ETHERNET |
+ JAZZ_IE_SCSI |
JAZZ_IE_SERIAL1 |
JAZZ_IE_SERIAL2 |
JAZZ_IE_PARALLEL |
__initfunc(void jazz_setup(void))
{
+ tag *atag;
+
+ /*
+ * we just check if a tag_screen_info can be gathered
+ * in setup_arch(), if yes we don't proceed futher...
+ */
+ atag = bi_TagFind(tag_screen_info);
+ if (!atag) {
+ /*
+ * If no, we try to find the tag_arc_displayinfo which is
+ * always created by Milo for an ARC box (for now Milo only
+ * works on ARC boxes :) -Stoned.
+ */
+ atag = bi_TagFind(tag_arcdisplayinfo);
+ if (atag) {
+ screen_info.orig_x =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x;
+ screen_info.orig_y =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y;
+ screen_info.orig_video_cols =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns;
+ screen_info.orig_video_lines =
+ ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines;
+ }
+ }
+
irq_setup = jazz_irq_setup;
fd_cacheflush = jazz_fd_cacheflush;
feature = &jazz_feature; // Will go away
+ port_base = JAZZ_PORT_BASE;
isa_slot_offset = 0xe3000000;
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
request_region(0x80,0x10,"dma page reg");
request_region(0xc0,0x20,"dma2");
+ board_time_init = jazz_time_init;
/* The RTC is outside the port address space */
_machine_restart = jazz_machine_restart;
* an ELF header.
*/
static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode,
+ struct dentry * interpreter_dentry,
unsigned int *interp_load_addr)
{
struct file * file;
if((interp_elf_ex->e_type != ET_EXEC &&
interp_elf_ex->e_type != ET_DYN) ||
!elf_check_arch(interp_elf_ex->e_machine) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
+ (!interpreter_dentry->d_inode->i_op ||
+ !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)) {
printk("IRIX interp has bad e_type %d\n", interp_elf_ex->e_type);
return 0xffffffff;
}
return 0xffffffff;
}
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff,
+ retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff,
(char *) elf_phdata,
sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1);
dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
#endif
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
+ elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY);
if (elf_exec_fileno < 0) {
printk("Could not open IRIX interp inode.\n");
kfree(elf_phdata);
/* First of all, some simple consistency checks */
if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
!elf_check_arch(ehp->e_machine) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)) {
+ (!bprm->dentry->d_inode->i_op ||
+ !bprm->dentry->d_inode->i_op->default_file_ops ||
+ !bprm->dentry->d_inode->i_op->default_file_ops->mmap)) {
return -ENOEXEC;
}
/* Look for an IRIX ELF interpreter. */
static inline int look_for_irix_interpreter(char **name,
- struct inode **interpreter_inode,
+ struct dentry **interpreter_dentry,
struct elfhdr *interp_elf_ex,
struct elf_phdr *epp,
struct linux_binprm *bprm, int pnum)
{
int i, old_fs;
int retval = -EINVAL;
+ struct dentry *dentry = NULL;
*name = NULL;
for(i = 0; i < pnum; i++, epp++) {
/* It is illegal to have two interpreters for one executable. */
if(*name != NULL)
- goto losing;
+ goto out;
*name = (char *) kmalloc((epp->p_filesz +
strlen(IRIX_INTERP_PREFIX)),
return -ENOMEM;
strcpy(*name, IRIX_INTERP_PREFIX);
- retval = read_exec(bprm->inode, epp->p_offset, (*name + 16),
+ retval = read_exec(bprm->dentry, epp->p_offset, (*name + 16),
epp->p_filesz, 1);
if(retval < 0)
- goto losing;
+ goto out;
old_fs = get_fs(); set_fs(get_ds());
- retval = namei(NAM_FOLLOW_LINK, *name, interpreter_inode);
+ dentry = namei(*name);
set_fs(old_fs);
- if(retval < 0)
- goto losing;
+ if(IS_ERR(dentry)) {
+ retval = PTR_ERR(dentry);
+ goto out;
+ }
- retval = read_exec(*interpreter_inode, 0, bprm->buf, 128, 1);
- if(retval < 0)
- goto losing;
+ retval = read_exec(dentry, 0, bprm->buf, 128, 1);
+ if(retval)
+ goto dput_and_out;
*interp_elf_ex = *((struct elfhdr *) bprm->buf);
}
+ *interpreter_dentry = dentry;
return 0;
-losing:
+dput_and_out:
+ dput(dentry);
+out:
kfree(*name);
return retval;
}
}
static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
- struct inode *iino, unsigned int *iladdr,
+ struct dentry *identry, unsigned int *iladdr,
int pnum, int old_fs,
unsigned int *eentry)
{
return -1;
set_fs(old_fs);
- *eentry = load_irix_interp(ihp, iino, iladdr);
+ *eentry = load_irix_interp(ihp, identry, iladdr);
old_fs = get_fs();
set_fs(get_ds());
- iput(iino);
+ dput(identry);
if(*eentry == 0xffffffff)
return -1;
struct pt_regs * regs)
{
struct elfhdr elf_ex, interp_elf_ex;
- struct inode *interpreter_inode;
+ struct dentry *interpreter_dentry;
struct elf_phdr *elf_phdata, *elf_ihdr, *elf_ephdr;
unsigned int load_addr, elf_bss, elf_brk;
unsigned int elf_entry, interp_load_addr = 0;
if (elf_phdata == NULL)
return -ENOMEM;
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
+ retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata,
elf_ex.e_phentsize * elf_ex.e_phnum, 1);
if (retval < 0) {
kfree (elf_phdata);
elf_bss = 0;
elf_brk = 0;
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
+ elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY);
if (elf_exec_fileno < 0) {
kfree (elf_phdata);
end_code = 0;
end_data = 0;
- retval = look_for_irix_interpreter(&elf_interpreter, &interpreter_inode,
+ retval = look_for_irix_interpreter(&elf_interpreter,
+ &interpreter_dentry,
&interp_elf_ex, elf_phdata, bprm,
elf_ex.e_phnum);
if(retval) {
if(elf_interpreter) {
retval = map_interpreter(elf_phdata, &interp_elf_ex,
- interpreter_inode, &interp_load_addr,
+ interpreter_dentry, &interp_load_addr,
elf_ex.e_phnum, old_fs, &elf_entry);
kfree(elf_interpreter);
if(retval) {
struct file * file;
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
unsigned int len;
int elf_bss;
int retval;
len = 0;
file = current->files->fd[fd];
- inode = file->f_inode;
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
elf_bss = 0;
if (!file || !file->f_op)
/* First of all, some simple consistency checks. */
if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
!elf_check_arch(elf_ex.e_machine) ||
- (!inode->i_op || !inode->i_op->default_file_ops->mmap))
+ (!dentry->d_inode->i_op ||
+ !dentry->d_inode->i_op->default_file_ops->mmap))
return -ENOEXEC;
/* Now read in all of the header information. */
if (elf_phdata == NULL)
return -ENOMEM;
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
+ retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata,
sizeof(struct elf_phdr) * elf_ex.e_phnum, 1);
j = 0;
*/
static int dump_write(struct file *file, const void *addr, int nr)
{
- file->f_inode->i_status |= ST_MODIFIED;
- return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+ return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr;
}
static int dump_seek(struct file *file, off_t off)
{
if (file->f_op->llseek) {
- if (file->f_op->llseek(file->f_inode, file, off, 0) != off)
+ if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off)
return 0;
} else
file->f_pos = off;
{
int has_dumped = 0;
struct file file;
+ struct dentry *dentry;
struct inode *inode;
unsigned short fs;
char corefile[6+sizeof(current->comm)];
fs = get_fs();
set_fs(KERNEL_DS);
- memcpy(corefile,"core.",5);
+ memcpy(corefile,"core.", 5);
#if 0
memcpy(corefile+5,current->comm,sizeof(current->comm));
#else
corefile[4] = '\0';
#endif
- if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+ dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600);
+ if (IS_ERR(dentry)) {
inode = NULL;
goto end_coredump;
}
+ inode = dentry->d_inode;
if (!S_ISREG(inode->i_mode))
goto end_coredump;
if (!inode->i_op || !inode->i_op->default_file_ops)
goto end_coredump;
- file.f_mode = 3;
- file.f_flags = 0;
- file.f_count = 1;
- file.f_inode = inode;
- file.f_pos = 0;
- file.f_reada = 0;
- file.f_op = inode->i_op->default_file_ops;
- if (file.f_op->open)
- if (file.f_op->open(inode,&file))
- goto end_coredump;
+ if (init_private_file(&file, dentry, 3))
+ goto end_coredump;
if (!file.f_op->write)
goto close_coredump;
has_dumped = 1;
close_coredump:
if (file.f_op->release)
- file.f_op->release(inode,&file);
+ file.f_op->release(inode, &file);
end_coredump:
set_fs(fs);
- iput(inode);
+ dput(dentry);
#ifndef CONFIG_BINFMT_ELF
MOD_DEC_USE_COUNT;
#endif
*/
asmlinkage int sys_execve(struct pt_regs *regs)
{
- int res;
+ int error;
char * filename;
lock_kernel();
- res = getname((char *) (long)regs->regs[4], &filename);
- if (res)
+ filename = getname((char *) (long)regs->regs[4]);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
goto out;
- res = do_execve(filename, (char **) (long)regs->regs[5],
- (char **) (long)regs->regs[6], regs);
+ error = do_execve(filename, (char **) (long)regs->regs[5],
+ (char **) (long)regs->regs[6], regs);
putname(filename);
out:
unlock_kernel();
- return res;
+ return error;
}
/*
*
* Copyright (C) 1995, 1996 by Ralf Baechle
*
- * $Id: syscalls.h,v 1.5 1997/06/25 17:08:35 ralf Exp $
+ * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
*/
/*
SYS(sys_query_module, 5)
SYS(sys_poll, 3)
SYS(sys_nfsservctl, 3)
+SYS(sys_setresgid, 3) /* 4190 */
+SYS(sys_getresgid, 3)
-/* $Id: sysirix.c,v 1.2 1997/06/17 15:24:26 ralf Exp $
+/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
* sysirix.c: IRIX system call emulation.
*
* Copyright (C) 1996 David S. Miller
asmlinkage int irix_statfs(const char *path, struct irix_statfs *buf,
int len, int fs_type)
{
+ struct dentry *dentry;
struct inode *inode;
struct statfs kbuf;
int error, old_fs, i;
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
if (error)
goto out;
- error = namei(NAM_FOLLOW_LINK, path, &inode);
- if (error)
- goto out;
- if (!inode->i_sb->s_op->statfs) {
- iput(inode);
- error = -ENOSYS;
+ dentry = namei(path);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
goto out;
- }
+ inode = dentry->d_inode;
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto dput_and_out;
- iput(inode);
__put_user(kbuf.f_type, &buf->f_type);
__put_user(kbuf.f_bsize, &buf->f_bsize);
__put_user(kbuf.f_frsize, &buf->f_frsize);
}
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
{
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
struct statfs kbuf;
struct file *file;
int error, old_fs, i;
error = -EBADF;
goto out;
}
- if (!(inode = file->f_inode)) {
+ if (!(dentry = file->f_dentry)) {
+ error = -ENOENT;
+ goto out;
+ }
+ if (!(inode = dentry->d_inode)) {
error = -ENOENT;
goto out;
}
+ if (!inode->i_sb) {
+ error = -ENODEV;
+ goto out;
+ }
if (!inode->i_sb->s_op->statfs) {
error = -ENOSYS;
goto out;
}
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto out;
__put_user(kbuf.f_type, &buf->f_type);
__put_user(kbuf.f_bsize, &buf->f_bsize);
asmlinkage int irix_exec(struct pt_regs *regs)
{
int error, base = 0;
- char * filename;
+ char *filename;
lock_kernel();
if(regs->regs[2] == 1000)
base = 1;
- error = getname((char *) (long)regs->regs[base + 4], &filename);
- if (error)
+ filename = getname((char *) (long)regs->regs[base + 4]);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) (long)regs->regs[base + 5],
(char **) 0, regs);
asmlinkage int irix_exece(struct pt_regs *regs)
{
int error, base = 0;
- char * filename;
+ char *filename;
lock_kernel();
if(regs->regs[2] == 1000)
base = 1;
- error = getname((char *) (long)regs->regs[base + 4], &filename);
- if (error)
+ filename = getname((char *) (long)regs->regs[base + 4]);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) (long)regs->regs[base + 5],
(char **) (long)regs->regs[base + 6], regs);
asmlinkage int irix_statvfs(char *fname, struct irix_statvfs *buf)
{
+ struct dentry *dentry;
struct inode *inode;
struct statfs kbuf;
int error, old_fs, i;
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
if(error)
goto out;
- error = namei(NAM_FOLLOW_LINK, fname, &inode);
- if(error)
- goto out;
- if(!inode->i_sb->s_op->statfs) {
- iput(inode);
- error = -ENOSYS;
+ dentry = namei(fname);
+ error = PTR_ERR(dentry);
+ if(!IS_ERR(dentry))
goto out;
- }
+ inode = dentry->d_inode;
+
+ error = -ENOSYS;
+ if(!inode->i_sb->s_op->statfs)
+ goto dput_and_out;
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto dput_and_out;
- iput(inode);
__put_user(kbuf.f_bsize, &buf->f_bsize);
__put_user(kbuf.f_frsize, &buf->f_frsize);
__put_user(kbuf.f_blocks, &buf->f_blocks);
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
{
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
struct statfs kbuf;
struct file *file;
int error, old_fs, i;
error = -EBADF;
goto out;
}
- if (!(inode = file->f_inode)) {
+ if (!(dentry = file->f_dentry)) {
+ error = -ENOENT;
+ goto out;
+ }
+ if (!(inode = dentry->d_inode)) {
error = -ENOENT;
goto out;
}
}
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto out;
__put_user(kbuf.f_bsize, &buf->f_bsize);
__put_user(kbuf.f_frsize, &buf->f_frsize);
return error;
}
-#define NOFOLLOW_LINKS NAM_FOLLOW_TRAILSLASH
-#define FOLLOW_LINKS NAM_FOLLOW_LINK
+#define NOFOLLOW_LINKS 0
+#define FOLLOW_LINKS 1
-static inline int chown_common(char *filename, uid_t user, gid_t group, int follow)
+static inline int chown_common(uid_t user, gid_t group, struct dentry *dentry)
{
struct inode * inode;
int error;
struct iattr newattrs;
- error = namei(follow, filename,&inode);
- if (error)
- return error;
- if (IS_RDONLY(inode)) {
- iput(inode);
- return -EROFS;
- }
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {
- iput(inode);
- return -EPERM;
- }
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out;
+ inode = dentry->d_inode;
+
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto dput_and_out;
+
if (user == (uid_t) -1)
user = inode->i_uid;
if (group == (gid_t) -1)
newattrs.ia_mode &= ~S_ISGID;
newattrs.ia_valid |= ATTR_MODE;
}
- inode->i_dirt = 1;
if (inode->i_sb->dq_op) {
inode->i_sb->dq_op->initialize(inode, -1);
+ error = -EDQUOT;
if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
- return -EDQUOT;
+ goto dput_and_out;
error = notify_change(inode, &newattrs);
if (error)
inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
} else
error = notify_change(inode, &newattrs);
- iput(inode);
- return(error);
+
+dput_and_out:
+ dput(dentry);
+out:
+ return error;
}
-asmlinkage int irix_chown(char *fname, int uid, int gid)
+asmlinkage int irix_chown(const char *filename, int uid, int gid)
{
int retval;
+ struct dentry *dentry;
lock_kernel();
/* Do follow any and all links... */
- retval = chown_common(fname, uid, gid, FOLLOW_LINKS);
+ dentry = namei(filename);
+ retval = chown_common(uid, gid, dentry);
unlock_kernel();
return retval;
}
-asmlinkage int irix_lchown(char *fname, int uid, int gid)
+asmlinkage int irix_lchown(const char *filename, int uid, int gid)
{
int retval;
+ struct dentry *dentry;
lock_kernel();
/* Do _not_ follow any links... */
- retval = chown_common(fname, uid, gid, NOFOLLOW_LINKS);
+ dentry = lnamei(filename);
+ retval = chown_common(uid, gid, dentry);
unlock_kernel();
return retval;
}
asmlinkage int irix_statvfs64(char *fname, struct irix_statvfs64 *buf)
{
+ struct dentry *dentry;
struct inode *inode;
struct statfs kbuf;
int error, old_fs, i;
error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
if(error)
goto out;
- error = namei(NAM_FOLLOW_LINK, fname, &inode);
- if(error)
- goto out;
- if(!inode->i_sb->s_op->statfs) {
- iput(inode);
- error = -ENOSYS;
+ dentry = namei(fname);
+ error = PTR_ERR(dentry);
+ if(IS_ERR(dentry))
goto out;
- }
+ error = -ENOSYS;
+ inode = dentry->d_inode;
+ if(!inode->i_sb->s_op->statfs)
+ goto dput_and_out;
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto dput_and_out;
- iput(inode);
__put_user(kbuf.f_bsize, &buf->f_bsize);
__put_user(kbuf.f_frsize, &buf->f_frsize);
__put_user(kbuf.f_blocks, &buf->f_blocks);
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
{
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
struct statfs kbuf;
struct file *file;
int error, old_fs, i;
error = -EBADF;
goto out;
}
- if (!(inode = file->f_inode)) {
+ if (!(dentry = file->f_dentry)) {
+ error = -ENOENT;
+ goto out;
+ }
+ if (!(inode = dentry->d_inode)) {
error = -ENOENT;
goto out;
}
}
old_fs = get_fs(); set_fs(get_ds());
- inode->i_sb->s_op->statfs(inode->i_sb, &kbuf, sizeof(struct statfs));
+ error = inode->i_sb->s_op->statfs(inode->i_sb, &kbuf,
+ sizeof(struct statfs));
set_fs(old_fs);
+ if (error)
+ goto out;
__put_user(kbuf.f_bsize, &buf->f_bsize);
__put_user(kbuf.f_frsize, &buf->f_frsize);
asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
{
struct file *file;
+ struct dentry *dentry;
+ struct inode *inode;
struct irix_dirent32 *lastdirent;
struct irix_dirent32_callback buf;
int error;
printk("[%s:%d] ngetdents(%d, %p, %d, %p) ", current->comm,
current->pid, fd, dirent, count, eob);
#endif
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
- error = -EBADF;
+ error = -EBADF;
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
- }
- if (!file->f_op || !file->f_op->readdir) {
- error = -ENOTDIR;
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
- }
- if(verify_area(VERIFY_WRITE, dirent, count) ||
- verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
- error = -EFAULT;
+
+ inode = dentry->d_inode;
+ if (!inode)
goto out;
- }
+
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+
+ error = -EFAULT;
+ if(!access_ok(VERIFY_WRITE, dirent, count) ||
+ !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+ goto out;
+
__put_user(0, eob);
buf.current_dir = (struct irix_dirent32 *) dirent;
buf.previous = NULL;
buf.count = count;
buf.error = 0;
- error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir32);
+
+ error = file->f_op->readdir(inode, file, &buf, irix_filldir32);
if (error < 0)
goto out;
lastdirent = buf.previous;
asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
{
struct file *file;
+ struct dentry *dentry;
+ struct inode *inode;
struct irix_dirent64 *lastdirent;
struct irix_dirent64_callback buf;
int error;
printk("[%s:%d] getdents64(%d, %p, %d) ", current->comm,
current->pid, fd, dirent, cnt);
#endif
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
- error = -EBADF;
+ error = -EBADF;
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
- }
- if (!file->f_op || !file->f_op->readdir) {
- error = -ENOTDIR;
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
- }
- if(verify_area(VERIFY_WRITE, dirent, cnt)) {
- error = -EFAULT;
+
+ inode = dentry->d_inode;
+ if (!inode)
goto out;
- }
- if(cnt < (sizeof(struct irix_dirent64) + 255)) {
- error = -EINVAL;
+
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+
+ error = -EFAULT;
+ if(!access_ok(VERIFY_WRITE, dirent, cnt))
+ goto out;
+
+ error = -EINVAL;
+ if(cnt < (sizeof(struct irix_dirent64) + 255))
goto out;
- }
buf.curr = (struct irix_dirent64 *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+ error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
if (error < 0)
goto out;
lastdirent = buf.previous;
asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
{
struct file *file;
+ struct dentry *dentry;
+ struct inode *inode;
struct irix_dirent64 *lastdirent;
struct irix_dirent64_callback buf;
int error;
printk("[%s:%d] ngetdents64(%d, %p, %d) ", current->comm,
current->pid, fd, dirent, cnt);
#endif
- if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
- error = -EBADF;
+ error = -EBADF;
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
goto out;
- }
- if (!file->f_op || !file->f_op->readdir) {
- error = -ENOTDIR;
+
+ dentry = file->f_dentry;
+ if (!dentry)
goto out;
- }
- if(verify_area(VERIFY_WRITE, dirent, cnt) ||
- verify_area(VERIFY_WRITE, eob, sizeof(*eob))) {
- error = -EFAULT;
+
+ inode = dentry->d_inode;
+ if (!inode)
goto out;
- }
- if(cnt < (sizeof(struct irix_dirent64) + 255)) {
- error = -EINVAL;
+
+ error = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+
+ error = -EFAULT;
+ if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
+ !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
+ goto out;
+
+ error = -EINVAL;
+ if(cnt < (sizeof(struct irix_dirent64) + 255))
goto out;
- }
*eob = 0;
buf.curr = (struct irix_dirent64 *) dirent;
buf.previous = NULL;
buf.count = cnt;
buf.error = 0;
- error = file->f_op->readdir(file->f_inode, file, &buf, irix_filldir64);
+ error = file->f_op->readdir(inode, file, &buf, irix_filldir64);
if (error < 0)
goto out;
lastdirent = buf.previous;
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: sysmips.c,v 1.4 1997/06/30 15:52:37 ralf Exp $
+ * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
*/
#include <linux/errno.h>
#include <linux/linkage.h>
switch(cmd)
{
case SETNAME:
- if (!suser()) {
- retval = -EPERM;
+ retval = -EPERM;
+ if (!suser())
goto out;
- }
+
name = (char *) arg1;
len = strlen_user(name);
+
+ retval = len;
if (len < 0)
- retval = len;
goto out;
+
+ retval = -EINVAL;
if (len == 0 || len > __NEW_UTS_LEN)
- retval = -EINVAL;
goto out;
+
copy_from_user(system_utsname.nodename, name, len);
system_utsname.nodename[len] = '\0';
retval = 0;
*/
bad_area:
up(&mm->mmap_sem);
- /* Did we have an exception handler installed? */
-
- fixup = search_exception_table(regs->cp0_epc);
- if (fixup) {
- long new_epc;
- new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
- printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n",
- regs->cp0_epc, new_epc);
- regs->cp0_epc = new_epc;
- goto out;
- }
if (user_mode(regs)) {
tsk->tss.cp0_badvaddr = address;
force_sig(SIGSEGV, tsk);
goto out;
}
+
+ /* Did we have an exception handler installed? */
+ fixup = search_exception_table(regs->cp0_epc);
+ if (fixup) {
+ long new_epc;
+ new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n",
+ tsk->comm, regs->cp0_epc, new_epc);
+ regs->cp0_epc = new_epc;
+ goto out;
+ }
+
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
zeropage(unsigned long page)
{
flush_page_to_ram(page);
- sync_mem();
__zeropage(page);
}
CC = gcc$(SUFFIX)
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
CFLAGS = $(CFLAGSINC) \
- -Wstrict-prototypes \
- -fomit-frame-pointer \
+ -Wstrict-prototypes -fomit-frame-pointer \
-fno-builtin \
- -finhibit-size-directive -fno-strength-reduce\
- -O2 -fsigned-char -pipe -mstring -mmultiple
+ -finhibit-size-directive \
+ -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
+# -fverbose-asm
CPP = $(CC) -E $(CFLAGS)
AR = ar$(SUFFIX)
RANLIB = ranlib$(SUFFIX)
STRIP = strip$(SUFFIX)
NM = nm$(SUFFIX)
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
+ifdef CONFIG_601
+CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
endif
-ifdef CONFIG_603e
-CFLAGS := $(CFLAGS) -mcpu=603e -DCPU=603e
+ifdef CONFIG_603
+CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
endif
ifdef CONFIG_604
CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
endif
-#
-# NFS_ROOT_NAME specifies the default name of the directory to mount
-# as root via NFS, if the kernel does not get the "root=" option from
-# the boot loader. The "%s" will be replaced by the IP-number of the
-# local system.
-#
-NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root\""
-
HEAD := arch/ppc/kernel/head.o
ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
-
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-netboot: vmlinux
+checks:
+ @$(MAKE) -C arch/$(ARCH)/kernel checks
+
+netboot: checks vmlinux
@$(MAKEBOOT) netboot
-znetboot: vmlinux
+znetboot: checks vmlinux
@$(MAKEBOOT) znetboot
-zImage: vmlinux
+#rcpboot: checks vmlinux
+# @$(MAKEBOOT) rcpboot
+
+zImage: checks vmlinux
@$(MAKEBOOT) zImage
-floppy: vmlinux
+floppy: checks vmlinux
@$(MAKEBOOT) floppy
-install: vmlinux
+install: checks vmlinux
@$(MAKEBOOT) install
+vmlinux.coff : checks vmlinux
+ $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
+
arch/ppc/kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
arch/ppc/lib: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
+diffs:
+ arch/ppc/mkdiff
+
+tar:
+ arch/ppc/mktar
archclean:
- rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h TAGS
+ rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
+ rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+ rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
@$(MAKEBOOT) clean
archdep:
+ $(MAKE) -C arch/ppc/boot fastdep
+ $(MAKE) -C arch/ppc/kernel fastdep
+ $(MAKE) -C arch/ppc/mm fastdep
+ $(MAKE) -C arch/ppc/lib fastdep
+
+tags :
+ etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c
-corttags :
- etags arch/ppc/*/*.c include/asm/* */*.c drivers/*/*.c net/*.c
#
# Copyright (C) 1994 by Linus Torvalds
# Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
#
.c.s:
ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
-GZIP_FLAGS = -9
+GZIP_FLAGS = -v9
SYSTEM = $(TOPDIR)/vmlinux
all: $(TOPDIR)/zImage
-mkboot : cortstrip.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mkboot cortstrip.c
+mkprep : mkprep.c
+ $(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+
+find_name : find_name.c
+ $(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
mk_type41: mk_type41.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mk_type41 mk_type41.c
+ $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
+
+piggyback: piggyback.c
+ $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-floppy: zImage $(TOPDIR)/vmlinux
+floppy: $(TOPDIR)/vmlinux zImage
dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
-netboot : $(TOPDIR)/vmlinux mkboot
- mkboot $(TOPDIR)/vmlinux $(TOPDIR)/netboot
-# rcp $(TOPDIR)/netboot charon:/usr/tftpboot/vmlinux
+netboot : $(TOPDIR)/vmlinux mkprep
+ mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+
+znetboot : zvmlinux mkprep
+ mkprep zvmlinux $(TOPDIR)/znetboot
+ cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
-znetboot : mkboot zvmlinux
- mkboot zvmlinux $(TOPDIR)/znetboot
+rcpboot : znetboot
rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
-zImage: mk_type41 zvmlinux
-# make znetboot ourselves since using the normal dep
-# will rcp it -- Cort
- mkboot zvmlinux $(TOPDIR)/znetboot
- mk_type41 $(TOPDIR)/znetboot $(TOPDIR)/zImage
+zImage: zvmlinux mkprep
+ mkprep -pbp zvmlinux $(TOPDIR)/zImage
install: zImage
dd if=$(TOPDIR)/zImage of=/dev/sda4
ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
cp $(TOPDIR)/System.map $(INSTALL_PATH)/
-zvmlinux: $(OBJECTS) $(SYSTEM) piggyback netboot $(TOPDIR)/vmlinux
- gzip ${GZIP_FLAGS} <$(TOPDIR)/netboot | ./piggyback | $(AS) -o piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name
+ mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
$(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
- rm -f piggy.o xx_boot
-
-head.o: head.s
-
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional head.S -o head.s
-
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+ rm -f piggy.o
clean:
- rm -f piggyback zvmlinux mk_type41 mkprep mkboot
+ rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
dep:
+ $(CPP) -M *.S *.c > .depend
+
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* amount to skip */
-#define PLACE 65536
-
-/* size of read buffer */
-#define SIZE 0x100000
-
-/* crude program to strip the elf header to make a bootable
- image via tftp
- */
-
-
-int main(int argc, char **argv )
-{
- int fd, fdo;
- unsigned char data[SIZE];
- int i, n, skip;
-
-#if 0
- if ( argc != 3 )
- {
- fprintf(stderr,"%s infile outfile\n", argv[0]);
- exit(-1);
- }
-#endif
-
-
- fd = open(argv[1], O_RDONLY);
- if ( fd == -1 )
- {
- fprintf(stderr,"Couldn't open %s\n", argv[1]);
- perror("open()");
- exit(-1);
- }
-
- fdo = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,0755);
- if ( fdo == -1 )
- {
- fprintf(stderr,"Couldn't open %s\n", argv[2]);
- perror("open()");
- exit(-1);
- }
-
-#if 0
- skip = atoi(argv[3]);
-#else
- skip = PLACE;
-#endif
- i = lseek(fd, skip, SEEK_SET);
- /*printf("lseek'd %d bytes\n", i);*/
- if ( i == -1 )
- {
- perror("lseek()");
- }
-
- while ( (n = read(fd, data, SIZE)) > 0 )
- {
- /*printf("Read %d bytes\n", n);*/
- i = write(fdo, data, n);
- /*printf("Wrote %d bytes\n", i); */
- }
-
-
- close(fdo);
- close(fd);
- return(0);
-}
-
-
--- /dev/null
+#include <stdio.h>
+#include <asm/page.h>
+#include <sys/mman.h>
+/*
+ * Finds a given address in the System.map and prints it out
+ * with its neighbors. -- Cort
+ */
+
+void main(int argc, char **argv)
+{
+ unsigned long addr, cmp, i;
+ FILE *f;
+ char *ptr;
+ char s[256], last[256];
+
+ if ( argc < 2 )
+ {
+ fprintf(stderr, "Usage: %s <address>\n", argv[0]);
+ exit(-1);
+ }
+
+ for ( i = 1 ; argv[i] ; i++ )
+ {
+ sscanf( argv[i], "%0x", &addr );
+ /* adjust if addr is relative to kernelbase */
+ if ( addr < PAGE_OFFSET )
+ addr += PAGE_OFFSET;
+
+ if ( (f = fopen( "System.map", "r" )) == NULL )
+ {
+ perror("fopen()\n");
+ exit(-1);
+ }
+
+ while ( !feof(f) )
+ {
+ fgets(s, 255 , f);
+ sscanf( s, "%0x", &cmp );
+ if ( addr < cmp )
+ break;
+ strcpy( last, s);
+ }
+
+ printf( "%s", last);
+ }
+ fclose(f);
+}
extern void flush_outbuf OF((void));
extern void flush_window OF((void));
extern char *strlwr OF((char *s));
-extern char *basename OF((char *fname));
+/*extern char *basename OF((char *fname));*/
extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
extern void error OF((char *m));
extern void warn OF((char *a, char *b));
#include "../kernel/ppc_defs.h"
#include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
.text
*/
#ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+static char rcsid[] = "$Id: inflate.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
#endif
#include "gzip.h"
_put_MSR(_get_MSR() & ~0x0030);
vga_init(0xC0000000);
- clear_screen();
+ /*clear_screen();*/
output_ptr = 0;
#endif
}
-#if 0
-verify_ram()
-{
- unsigned long loc;
- puts("Clearing memory:");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0x0;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0x0)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("0");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0xFFFFFFFF;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0xFFFFFFFF)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("1");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = loc;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != loc)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("?");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0xDEADB00B;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0xDEADB00B)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts(">");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0x0;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0x0)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("\n");
-}
-
do_cksum(unsigned long loc)
{
unsigned int ptr, cksum;
}
return (errors == 0);
}
-#endif
void puthex(unsigned long val)
{
+++ /dev/null
-/*
- * This program will make a type 0x41 load image from an
- * executable file. Note: assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
- */
-
-#include <stdio.h>
-#include <errno.h>
-#ifdef linux
-#include <asm/stat.h>
-#else
-#include <sys/stat.h>
-#endif
-
-_LE(long val, unsigned char *le)
-{
- le[0] = val;
- le[1] = val >> 8;
- le[2] = val >> 16;
- le[3] = val >> 24;
-}
-
-main(int argc, char *argv[])
-{
- int in_fd, out_fd, len, size;
- struct stat info;
- char buf[8192];
- struct hdr
- {
- unsigned long entry_point;
- unsigned long image_length;
- } hdr;
- if (argc != 3)
- {
- fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
- exit(1);
- }
- if ((in_fd = open(argv[1], 0)) < 0)
- {
- fprintf(stderr, "Can't open input file: '%s': %s\n", argv[1], strerror(errno));
- exit(2);
- }
- if ((out_fd = creat(argv[2], 0666)) < 0)
- {
- fprintf(stderr, "Can't create output file: '%s': %s\n", argv[2], strerror(errno));
- exit(2);
- }
- if (fstat(in_fd, &info) < 0)
- {
- fprintf(stderr, "Can't get info on input file: %s\n", strerror(errno));
- exit(4);
- }
- write_prep_boot_partition(out_fd);
- _LE(0x400, &hdr.entry_point);
- _LE(info.st_size+0x400, &hdr.image_length);
- lseek(out_fd, 0x200, 0);
- if (write(out_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
- {
- fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
- exit(5);
- }
- lseek(out_fd, 0x400, 0);
- while ((len = read(in_fd, buf, sizeof(buf))) > 0)
- {
- if (write(out_fd, buf, len) != len)
- {
- fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
- exit(5);
- }
- }
- if (len < 0)
- {
- fprintf(stderr, "Can't read input file: %s\n", strerror(errno));
- exit(6);
- }
- close(in_fd);
- close(out_fd);
-}
-
-/* Adapted from IBM Naked Application Package (NAP) */
-
-#define Align(value,boundary) \
- (((value) + (boundary) - 1) & ~((boundary) - 1))
-
-#define HiByte(word) ((word_t)(word) >> 8)
-#define LoByte(word) ((word_t)(word) & 0xFF)
-
-#define HiWord(dword) ((dword_t)(dword) >> 16)
-#define LoWord(dword) ((dword_t)(dword) & 0xFFFF)
-
-/*
- * Little-endian stuff
- */
-#define LeWord(word) \
- (((word_t)(word) >> 8) | ((word_t)(word) << 8))
-
-#define LeDword(dword) \
- (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-#define PcDword(dword) \
- (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-
-typedef unsigned long dword_t;
-typedef unsigned short word_t;
-typedef unsigned char byte_t;
-typedef byte_t block_t[512];
-typedef byte_t page_t[4096];
-
-/*
- * Partition table entry
- * - from the PReP spec
- */
-typedef struct partition_entry {
- byte_t boot_indicator;
- byte_t starting_head;
- byte_t starting_sector;
- byte_t starting_cylinder;
-
- byte_t system_indicator;
- byte_t ending_head;
- byte_t ending_sector;
- byte_t ending_cylinder;
-
- dword_t beginning_sector;
- dword_t number_of_sectors;
-} partition_entry_t;
-
-#define BootActive 0x80
-#define SystemPrep 0x41
-
-
-/*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block. It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition. The "PReP" partition contains the "load image" starting
- * at offset zero within the partition. The first block of the load image is
- * a dummy PC boot block. The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image. The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-void
-write_prep_boot_partition(int out_fd)
-{
- block_t block;
- partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
- dword_t *entry = (dword_t *)&block[0];
- dword_t *length = (dword_t *)&block[4];
-
- bzero( &block, sizeof block );
-
- /*
- * Magic marker
- */
- block[510] = 0x55;
- block[511] = 0xAA;
-
- /*
- * Build a "PReP" partition table entry in the boot record
- * - "PReP" may only look at the system_indicator
- */
- pe->boot_indicator = BootActive;
- pe->system_indicator = SystemPrep;
-
- /*
- * The first block of the diskette is used by this "boot record" which
- * actually contains the partition table. (The first block of the
- * partition contains the boot image, but I digress...) We'll set up
- * one partition on the diskette and it shall contain the rest of the
- * diskette.
- */
- pe->starting_head = 0; /* zero-based */
- pe->starting_sector = 2; /* one-based */
- pe->starting_cylinder = 0; /* zero-based */
-
- pe->ending_head = 1; /* assumes two heads */
- pe->ending_sector = 18; /* assumes 18 sectors/track */
- pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
-
- /*
- * The "PReP" software ignores the above fields and just looks at
- * the next two.
- * - size of the diskette is (assumed to be)
- * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
- * - unlike the above sector numbers, the beginning sector is zero-based!
- */
-#if 0
- pe->beginning_sector = LeDword(1);
-#else
- /* This has to be 0 on the PowerStack? */
- pe->beginning_sector = LeDword(0);
-#endif
- pe->number_of_sectors = LeDword(2*18*80-1);
-
- /*
- * Write the partition table
- */
- lseek( out_fd, 0, 0 );
- write( out_fd, block, sizeof block );
-}
-
/*
- * This program will make a type 0x41 load image from an
- * executable file. Note: assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
+ * Makes a prep bootable image which can be dd'd onto
+ * a disk device to make a bootdisk. Will take
+ * as input a elf executable, strip off the header
+ * and write out a boot image as:
+ * 1) default - strips elf header
+ * suitable as a network boot image
+ * 2) -pbp - strips elf header and writes out prep boot partition image
+ * cat or dd onto disk for booting
+ * 3) -asm - strips elf header and writes out as asm data
+ * useful for generating data for a compressed image
+ * -- Cort
*/
-#include <stdio.h>
-#include <errno.h>
#ifdef linux
+#include <linux/types.h>
#include <asm/stat.h>
+/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
#else
+#include <unistd.h>
#include <sys/stat.h>
#endif
-#include <asm/byteorder.h> /* use same as kernel -- Cort */
+
+#include <stdio.h>
+#include <errno.h>
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+ return (((x & 0x000000ffU) << 24) |
+ ((x & 0x0000ff00U) << 8) |
+ ((x & 0x00ff0000U) >> 8) |
+ ((x & 0xff000000U) >> 24));
+}
+
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+ return (((x & 0x00ff) << 8) |
+ ((x & 0xff00) >> 8));
+}
+
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+
+/* size of read buffer */
+#define SIZE 0x1000
+
typedef unsigned long dword_t;
typedef unsigned short word_t;
typedef byte_t block_t[512];
typedef byte_t page_t[4096];
-_LE(long val, unsigned char *le)
-{
- le[0] = val;
- le[1] = val >> 8;
- le[2] = val >> 16;
- le[3] = val >> 24;
-}
/*
* Partition table entry
* - from the PReP spec
*/
typedef struct partition_entry {
- byte_t boot_indicator;
- byte_t starting_head;
- byte_t starting_sector;
- byte_t starting_cylinder;
-
- byte_t system_indicator;
- byte_t ending_head;
- byte_t ending_sector;
- byte_t ending_cylinder;
-
- dword_t beginning_sector;
- dword_t number_of_sectors;
+ byte_t boot_indicator;
+ byte_t starting_head;
+ byte_t starting_sector;
+ byte_t starting_cylinder;
+
+ byte_t system_indicator;
+ byte_t ending_head;
+ byte_t ending_sector;
+ byte_t ending_cylinder;
+
+ dword_t beginning_sector;
+ dword_t number_of_sectors;
} partition_entry_t;
#define BootActive 0x80
#define SystemPrep 0x41
+void copy_image(int , int);
+void write_prep_partition(int , int );
+void write_asm_data( int in, int out );
+
+unsigned int elfhdr_size = 65536;
int main(int argc, char *argv[])
{
- struct stat info;
- char buf[8192];
- int in_fd, out_fd,len;
+ int in_fd, out_fd;
+ int argptr = 1;
+ unsigned int prep = 0;
+ unsigned int asmoutput = 0;
+
+ if ( (argc < 3) || (argc > 4) )
+ {
+ fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
+ exit(-1);
+ }
+
+ /* needs to handle args more elegantly -- but this is a small/simple program */
+
+ /* check for -pbp */
+ if ( !strcmp( argv[argptr], "-pbp" ) )
+ {
+ prep = 1;
+ argptr++;
+ }
+
+ /* check for -asm */
+ if ( !strcmp( argv[argptr], "-asm" ) )
+ {
+ asmoutput = 1;
+ argptr++;
+ }
+
+ /* input file */
+ if ( !strcmp( argv[argptr], "-" ) )
+ in_fd = 0; /* stdin */
+ else
+ if ((in_fd = open( argv[argptr] , 0)) < 0)
+ exit(-1);
+ argptr++;
+
+ /* output file */
+ if ( !strcmp( argv[argptr], "-" ) )
+ out_fd = 1; /* stdout */
+ else
+ if ((out_fd = creat( argv[argptr] , 0755)) < 0)
+ exit(-1);
+ argptr++;
+
+ /* skip elf header in input file */
+ lseek(in_fd, elfhdr_size, SEEK_SET);
+
+ /* write prep partition if necessary */
+ if ( prep )
+ write_prep_partition( in_fd, out_fd );
+
+ /* write input image to bootimage */
+ if ( asmoutput )
+ write_asm_data( in_fd, out_fd );
+ else
+ copy_image(in_fd, out_fd);
+
+ return 0;
+}
+
+void write_prep_partition(int in, int out)
+{
unsigned char block[512];
partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
- dword_t *entry = (dword_t *)&block[0x50];
- dword_t *length = (dword_t *)&block[0x51];
+ dword_t *entry = (dword_t *)&block[0];
+ dword_t *length = (dword_t *)&block[sizeof(long)];
+ struct stat info;
- if (argc != 3)
- {
- fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
- exit(1);
- }
- if ((in_fd = open(argv[1], 0)) < 0)
- {
- exit(2);
- }
- if ((out_fd = creat(argv[2], 0755)) < 0)
- {
- exit(2);
- }
+ if (fstat(in, &info) < 0)
+ {
+ fprintf(stderr,"info failed\n");
+ exit(-1);
+ }
+
+ bzero( block, sizeof block );
- bzero( &block, sizeof block );
-
+
+ /* set entry point and boot image size */
+ *entry = cpu_to_le32(0x400);
+ /* need use size - elfheader? */
+ *length = cpu_to_le32(info.st_size+0x400);
/*
- * Magic marker
+ * Writes the "boot record", which contains the partition table, to the
+ * diskette, followed by the dummy PC boot block and load image descriptor
+ * block. It returns the number of bytes it has written to the load
+ * image.
+ *
+ * The boot record is the first block of the diskette and identifies the
+ * "PReP" partition. The "PReP" partition contains the "load image" starting
+ * at offset zero within the partition. The first block of the load image is
+ * a dummy PC boot block. The second block is the "load image descriptor"
+ * which contains the size of the load image and the entry point into the
+ * image. The actual boot image starts at offset 1024 bytes (third sector)
+ * in the partition.
*/
+
+ /* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
+ /*
+ * Build a "PReP" partition table entry in the boot record
+ * - "PReP" may only look at the system_indicator
+ */
pe->boot_indicator = BootActive;
pe->system_indicator = SystemPrep;
- pe->starting_head = 0; /* zero-based */
- pe->starting_sector = 2; /* one-based */
- pe->starting_cylinder = 0; /* zero-based */
-
- pe->ending_head = 1; /* assumes two heads */
- pe->ending_sector = 18; /* assumes 18 sectors/track */
- pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+ /*
+ * The first block of the diskette is used by this "boot record" which
+ * actually contains the partition table. (The first block of the
+ * partition contains the boot image, but I digress...) We'll set up
+ * one partition on the diskette and it shall contain the rest of the
+ * diskette.
+ */
+ pe->starting_head = 0; /* zero-based */
+ pe->starting_sector = 2; /* one-based */
+ pe->starting_cylinder = 0; /* zero-based */
+ pe->ending_head = 1; /* assumes two heads */
+ pe->ending_sector = 18; /* assumes 18 sectors/track */
+ pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+ /*
+ * The "PReP" software ignores the above fields and just looks at
+ * the next two.
+ * - size of the diskette is (assumed to be)
+ * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+ * - unlike the above sector numbers, the beginning sector is zero-based!
+ */
#if 0
-#if 0
- pe->beginning_sector = LeDword(1);
+ pe->beginning_sector = cpu_to_le32(1);
#else
- /* This has to be 0 on the PowerStack? */
- pe->beginning_sector = LeDword(0);
-#endif
- pe->number_of_sectors = LeDword(2*18*80-1);
-#endif
+ /* This has to be 0 on the PowerStack? */
+ pe->beginning_sector = cpu_to_le32(0);
+#endif
+/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+
+ write( out, block, sizeof(block) );
+ write( out, entry, sizeof(*entry) );
+ write( out, length, sizeof(*length) );
+ /* set file position to 2nd sector where image will be written */
+ lseek( out, 0x400, SEEK_SET );
+}
+
+
+
+void
+copy_image(int in, int out)
+{
+ char buf[SIZE];
+ int n;
+
+ while ( (n = read(in, buf, SIZE)) > 0 )
+ write(out, buf, n);
+}
+
+
+void
+write_asm_data( int in, int out )
+{
+ int i, cnt, pos, len;
+ unsigned int cksum, val;
+ unsigned char *lp;
+ unsigned char buf[SIZE];
+ unsigned char str[256];
- if (fstat(in_fd, &info) < 0)
+ write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
+ strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
+ pos = 0;
+ cksum = 0;
+ while ((len = read(in, buf, sizeof(buf))) > 0)
+ {
+ cnt = 0;
+ lp = (unsigned char *)buf;
+ len = (len + 3) & ~3; /* Round up to longwords */
+ for (i = 0; i < len; i += 4)
{
- exit(4);
+ if (cnt == 0)
+ {
+ write( out, "\t.long\t", strlen( "\t.long\t" ) );
+ }
+ sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+ write( out, str, strlen(str) );
+ val = *(unsigned long *)lp;
+ cksum ^= val;
+ lp += 4;
+ if (++cnt == 4)
+ {
+ cnt = 0;
+ sprintf( str, " # %x \n", pos+i-12);
+ write( out, str, strlen(str) );
+ } else
+ {
+ write( out, ",", 1 );
+ }
}
- /* begin execution at 0x400 */
- _LE(0x400,(unsigned char *)entry);
- _LE(info.st_size+0x400,length);
-
- lseek( out_fd, 0, 0 );
- /* write out 1st block */
- write( out_fd, block, sizeof block );
-
- /* copy image */
-#if 1
- lseek(out_fd, 0x400, 0);
- while ((len = read(in_fd, buf, sizeof(buf))) > 0)
- {
- if (write(out_fd, buf, len) != len)
- {
- exit(5);
- }
- }
- if (len < 0)
- {
- exit(6);
- }
- close(in_fd);
- close(out_fd);
-#endif
- return 0;
-}
+ if (cnt)
+ {
+ write( out, "0\n", 2 );
+ }
+ pos += len;
+ }
+ sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+ write( out, str, strlen(str) );
+ fprintf(stderr, "cksum = %x\n", cksum);
+}
+++ /dev/null
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[8192];
- if (argc != 1)
- {
- fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
- exit(1);
- }
- fprintf(stdout, "#\n");
- fprintf(stdout, "# Miscellaneous data structures:\n");
- fprintf(stdout, "# WARNING - this file is automatically generated!\n");
- fprintf(stdout, "#\n");
- fprintf(stdout, "\n");
- fprintf(stdout, "\t.data\n");
- fprintf(stdout, "\t.globl input_data\n");
- fprintf(stdout, "input_data:\n");
- pos = 0;
- cksum = 0;
- while ((len = read(0, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- fprintf(stdout, "\t.long\t");
- }
- fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- fprintf(stdout, " # %x \n", pos+i-12);
- fflush(stdout);
- } else
- {
- fprintf(stdout, ",");
- }
- }
- if (cnt)
- {
- fprintf(stdout, "0\n");
- }
- pos += len;
- }
- fprintf(stdout, "\t.globl input_len\n");
- fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
- fflush(stdout);
- fclose(stdout);
- fprintf(stderr, "cksum = %x\n", cksum);
- exit(0);
-}
-
*/
#ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+static char rcsid[] = "$Id: unzip.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
#endif
#include "gzip.h"
* Steve Sellgren
* San Francisco Indigo Company
* sfindigo!sellgren@uunet.uu.net
+ *
+ * Original concept by:
+ * Gary Thomas <gdt@linuxppc.org>
+ * Adapted for Moto boxes by:
+ * Pat Kane & Mark Scott, 1996
+ * Adapted for IBM portables by:
+ * Takeshi Ishimoto
+ * Multi-console support:
+ * Terje Malmedal <terje.malmedal@usit.uio.no>
+ */
+
+#include "iso_font.h"
+#include <linux/delay.h>
+
+extern char *vidmem;
+extern int lines, cols;
+/* estimate for delay */
+unsigned long loops_per_sec = 50000000;;
+/*
+ * VGA Register
+ */
+struct VgaRegs
+{
+ unsigned short io_port;
+ unsigned char io_index;
+ unsigned char io_value;
+};
+
+/*
+ * Default console text mode registers used to reset
+ * graphics adapter.
+ */
+#define NREGS 54
+#define ENDMK 0xFFFF /* End marker */
+
+#define S3Vendor 0x5333
+#define CirrusVendor 0x1013
+#define DiamondVendor 0x100E
+#define MatroxVendor 0x102B
+#define ParadiseVendor 0x101C
+
+struct VgaRegs GenVgaTextRegs[NREGS+1] = {
+/* port index value */
+ /* SR Regs */
+ 0x3c4, 0x1, 0x0,
+ 0x3c4, 0x2, 0x3,
+ 0x3c4, 0x3, 0x0,
+ 0x3c4, 0x4, 0x2,
+ /* CR Regs */
+ 0x3d4, 0x0, 0x5f,
+ 0x3d4, 0x1, 0x4f,
+ 0x3d4, 0x2, 0x50,
+ 0x3d4, 0x3, 0x82,
+ 0x3d4, 0x4, 0x55,
+ 0x3d4, 0x5, 0x81,
+ 0x3d4, 0x6, 0xbf,
+ 0x3d4, 0x7, 0x1f,
+ 0x3d4, 0x8, 0x00,
+ 0x3d4, 0x9, 0x4f,
+ 0x3d4, 0xa, 0x0d,
+ 0x3d4, 0xb, 0x0e,
+ 0x3d4, 0xc, 0x00,
+ 0x3d4, 0xd, 0x00,
+ 0x3d4, 0xe, 0x00,
+ 0x3d4, 0xf, 0x00,
+ 0x3d4, 0x10, 0x9c,
+ 0x3d4, 0x11, 0x8e,
+ 0x3d4, 0x12, 0x8f,
+ 0x3d4, 0x13, 0x28,
+ 0x3d4, 0x14, 0x1f,
+ 0x3d4, 0x15, 0x96,
+ 0x3d4, 0x16, 0xb9,
+ 0x3d4, 0x17, 0xa3,
+ /* GR Regs */
+ 0x3ce, 0x0, 0x0,
+ 0x3ce, 0x1, 0x0,
+ 0x3ce, 0x2, 0x0,
+ 0x3ce, 0x3, 0x0,
+ 0x3ce, 0x4, 0x0,
+ 0x3ce, 0x5, 0x10,
+ 0x3ce, 0x6, 0xe,
+ 0x3ce, 0x7, 0x0,
+ 0x3ce, 0x8, 0xff,
+ ENDMK
+};
+
+struct VgaRegs S3TextRegs[NREGS+1] = {
+/* port index value */
+ /* SR Regs */
+ 0x3c4, 0x1, 0x0,
+ 0x3c4, 0x2, 0x3,
+ 0x3c4, 0x3, 0x0,
+ 0x3c4, 0x4, 0x2,
+ /* CR Regs */
+ 0x3d4, 0x0, 0x5f,
+ 0x3d4, 0x1, 0x4f,
+ 0x3d4, 0x2, 0x50,
+ 0x3d4, 0x3, 0x82,
+ 0x3d4, 0x4, 0x55,
+ 0x3d4, 0x5, 0x81,
+ 0x3d4, 0x6, 0xbf,
+ 0x3d4, 0x7, 0x1f,
+ 0x3d4, 0x8, 0x00,
+ 0x3d4, 0x9, 0x4f,
+ 0x3d4, 0xa, 0x0d,
+ 0x3d4, 0xb, 0x0e,
+ 0x3d4, 0xc, 0x00,
+ 0x3d4, 0xd, 0x00,
+ 0x3d4, 0xe, 0x00,
+ 0x3d4, 0xf, 0x00,
+ 0x3d4, 0x10, 0x9c,
+ 0x3d4, 0x11, 0x8e,
+ 0x3d4, 0x12, 0x8f,
+ 0x3d4, 0x13, 0x28,
+ 0x3d4, 0x14, 0x1f,
+ 0x3d4, 0x15, 0x96,
+ 0x3d4, 0x16, 0xb9,
+ 0x3d4, 0x17, 0xa3,
+ /* GR Regs */
+ 0x3ce, 0x0, 0x0,
+ 0x3ce, 0x1, 0x0,
+ 0x3ce, 0x2, 0x0,
+ 0x3ce, 0x3, 0x0,
+ 0x3ce, 0x4, 0x0,
+ 0x3ce, 0x5, 0x10,
+ 0x3ce, 0x6, 0xe,
+ 0x3ce, 0x7, 0x0,
+ 0x3ce, 0x8, 0xff,
+ ENDMK
+};
+
+struct RGBColors
+{
+ unsigned char r, g, b;
+};
+
+/*
+ * Default console text mode color table.
+ * These values were obtained by booting Linux with
+ * text mode firmware & then dumping the registers.
+ */
+struct RGBColors TextCLUT[256] =
+{
+ /* red green blue */
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x2a,
+ 0x0, 0x2a, 0x0,
+ 0x0, 0x2a, 0x2a,
+ 0x2a, 0x0, 0x0,
+ 0x2a, 0x0, 0x2a,
+ 0x2a, 0x2a, 0x0,
+ 0x2a, 0x2a, 0x2a,
+ 0x0, 0x0, 0x15,
+ 0x0, 0x0, 0x3f,
+ 0x0, 0x2a, 0x15,
+ 0x0, 0x2a, 0x3f,
+ 0x2a, 0x0, 0x15,
+ 0x2a, 0x0, 0x3f,
+ 0x2a, 0x2a, 0x15,
+ 0x2a, 0x2a, 0x3f,
+ 0x0, 0x15, 0x0,
+ 0x0, 0x15, 0x2a,
+ 0x0, 0x3f, 0x0,
+ 0x0, 0x3f, 0x2a,
+ 0x2a, 0x15, 0x0,
+ 0x2a, 0x15, 0x2a,
+ 0x2a, 0x3f, 0x0,
+ 0x2a, 0x3f, 0x2a,
+ 0x0, 0x15, 0x15,
+ 0x0, 0x15, 0x3f,
+ 0x0, 0x3f, 0x15,
+ 0x0, 0x3f, 0x3f,
+ 0x2a, 0x15, 0x15,
+ 0x2a, 0x15, 0x3f,
+ 0x2a, 0x3f, 0x15,
+ 0x2a, 0x3f, 0x3f,
+ 0x15, 0x0, 0x0,
+ 0x15, 0x0, 0x2a,
+ 0x15, 0x2a, 0x0,
+ 0x15, 0x2a, 0x2a,
+ 0x3f, 0x0, 0x0,
+ 0x3f, 0x0, 0x2a,
+ 0x3f, 0x2a, 0x0,
+ 0x3f, 0x2a, 0x2a,
+ 0x15, 0x0, 0x15,
+ 0x15, 0x0, 0x3f,
+ 0x15, 0x2a, 0x15,
+ 0x15, 0x2a, 0x3f,
+ 0x3f, 0x0, 0x15,
+ 0x3f, 0x0, 0x3f,
+ 0x3f, 0x2a, 0x15,
+ 0x3f, 0x2a, 0x3f,
+ 0x15, 0x15, 0x0,
+ 0x15, 0x15, 0x2a,
+ 0x15, 0x3f, 0x0,
+ 0x15, 0x3f, 0x2a,
+ 0x3f, 0x15, 0x0,
+ 0x3f, 0x15, 0x2a,
+ 0x3f, 0x3f, 0x0,
+ 0x3f, 0x3f, 0x2a,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3f,
+ 0x15, 0x3f, 0x15,
+ 0x15, 0x3f, 0x3f,
+ 0x3f, 0x15, 0x15,
+ 0x3f, 0x15, 0x3f,
+ 0x3f, 0x3f, 0x15,
+ 0x3f, 0x3f, 0x3f,
+ 0x39, 0xc, 0x5,
+ 0x15, 0x2c, 0xf,
+ 0x26, 0x10, 0x3d,
+ 0x29, 0x29, 0x38,
+ 0x4, 0x1a, 0xe,
+ 0x2, 0x1e, 0x3a,
+ 0x3c, 0x25, 0x33,
+ 0x3c, 0xc, 0x2c,
+ 0x3f, 0x3, 0x2b,
+ 0x1c, 0x9, 0x13,
+ 0x25, 0x2a, 0x35,
+ 0x1e, 0xa, 0x38,
+ 0x24, 0x8, 0x3,
+ 0x3, 0xe, 0x36,
+ 0xc, 0x6, 0x2a,
+ 0x26, 0x3, 0x32,
+ 0x5, 0x2f, 0x33,
+ 0x3c, 0x35, 0x2f,
+ 0x2d, 0x26, 0x3e,
+ 0xd, 0xa, 0x10,
+ 0x25, 0x3c, 0x11,
+ 0xd, 0x4, 0x2e,
+ 0x5, 0x19, 0x3e,
+ 0xc, 0x13, 0x34,
+ 0x2b, 0x6, 0x24,
+ 0x4, 0x3, 0xd,
+ 0x2f, 0x3c, 0xc,
+ 0x2a, 0x37, 0x1f,
+ 0xf, 0x12, 0x38,
+ 0x38, 0xe, 0x2a,
+ 0x12, 0x2f, 0x19,
+ 0x29, 0x2e, 0x31,
+ 0x25, 0x13, 0x3e,
+ 0x33, 0x3e, 0x33,
+ 0x1d, 0x2c, 0x25,
+ 0x15, 0x15, 0x5,
+ 0x32, 0x25, 0x39,
+ 0x1a, 0x7, 0x1f,
+ 0x13, 0xe, 0x1d,
+ 0x36, 0x17, 0x34,
+ 0xf, 0x15, 0x23,
+ 0x2, 0x35, 0xd,
+ 0x15, 0x3f, 0xc,
+ 0x14, 0x2f, 0xf,
+ 0x19, 0x21, 0x3e,
+ 0x27, 0x11, 0x2f,
+ 0x38, 0x3f, 0x3c,
+ 0x36, 0x2d, 0x15,
+ 0x16, 0x17, 0x2,
+ 0x1, 0xa, 0x3d,
+ 0x1b, 0x11, 0x3f,
+ 0x21, 0x3c, 0xd,
+ 0x1a, 0x39, 0x3d,
+ 0x8, 0xe, 0xe,
+ 0x22, 0x21, 0x23,
+ 0x1e, 0x30, 0x5,
+ 0x1f, 0x22, 0x3d,
+ 0x1e, 0x2f, 0xa,
+ 0x0, 0x1c, 0xe,
+ 0x0, 0x1c, 0x15,
+ 0x0, 0x1c, 0x1c,
+ 0x0, 0x15, 0x1c,
+ 0x0, 0xe, 0x1c,
+ 0x0, 0x7, 0x1c,
+ 0xe, 0xe, 0x1c,
+ 0x11, 0xe, 0x1c,
+ 0x15, 0xe, 0x1c,
+ 0x18, 0xe, 0x1c,
+ 0x1c, 0xe, 0x1c,
+ 0x1c, 0xe, 0x18,
+ 0x1c, 0xe, 0x15,
+ 0x1c, 0xe, 0x11,
+ 0x1c, 0xe, 0xe,
+ 0x1c, 0x11, 0xe,
+ 0x1c, 0x15, 0xe,
+ 0x1c, 0x18, 0xe,
+ 0x1c, 0x1c, 0xe,
+ 0x18, 0x1c, 0xe,
+ 0x15, 0x1c, 0xe,
+ 0x11, 0x1c, 0xe,
+ 0xe, 0x1c, 0xe,
+ 0xe, 0x1c, 0x11,
+ 0xe, 0x1c, 0x15,
+ 0xe, 0x1c, 0x18,
+ 0xe, 0x1c, 0x1c,
+ 0xe, 0x18, 0x1c,
+ 0xe, 0x15, 0x1c,
+ 0xe, 0x11, 0x1c,
+ 0x14, 0x14, 0x1c,
+ 0x16, 0x14, 0x1c,
+ 0x18, 0x14, 0x1c,
+ 0x1a, 0x14, 0x1c,
+ 0x1c, 0x14, 0x1c,
+ 0x1c, 0x14, 0x1a,
+ 0x1c, 0x14, 0x18,
+ 0x1c, 0x14, 0x16,
+ 0x1c, 0x14, 0x14,
+ 0x1c, 0x16, 0x14,
+ 0x1c, 0x18, 0x14,
+ 0x1c, 0x1a, 0x14,
+ 0x1c, 0x1c, 0x14,
+ 0x1a, 0x1c, 0x14,
+ 0x18, 0x1c, 0x14,
+ 0x16, 0x1c, 0x14,
+ 0x14, 0x1c, 0x14,
+ 0x14, 0x1c, 0x16,
+ 0x14, 0x1c, 0x18,
+ 0x14, 0x1c, 0x1a,
+ 0x14, 0x1c, 0x1c,
+ 0x14, 0x1a, 0x1c,
+ 0x14, 0x18, 0x1c,
+ 0x14, 0x16, 0x1c,
+ 0x0, 0x0, 0x10,
+ 0x4, 0x0, 0x10,
+ 0x8, 0x0, 0x10,
+ 0xc, 0x0, 0x10,
+ 0x10, 0x0, 0x10,
+ 0x10, 0x0, 0xc,
+ 0x10, 0x0, 0x8,
+ 0x10, 0x0, 0x4,
+ 0x10, 0x0, 0x0,
+ 0x10, 0x4, 0x0,
+ 0x10, 0x8, 0x0,
+ 0x10, 0xc, 0x0,
+ 0x10, 0x10, 0x0,
+ 0xc, 0x10, 0x0,
+ 0x8, 0x10, 0x0,
+ 0x4, 0x10, 0x0,
+ 0x0, 0x10, 0x0,
+ 0x0, 0x10, 0x4,
+ 0x0, 0x10, 0x8,
+ 0x0, 0x10, 0xc,
+ 0x0, 0x10, 0x10,
+ 0x0, 0xc, 0x10,
+ 0x0, 0x8, 0x10,
+ 0x0, 0x4, 0x10,
+ 0x8, 0x8, 0x10,
+ 0xa, 0x8, 0x10,
+ 0xc, 0x8, 0x10,
+ 0xe, 0x8, 0x10,
+ 0x10, 0x8, 0x10,
+ 0x10, 0x8, 0xe,
+ 0x10, 0x8, 0xc,
+ 0x10, 0x8, 0xa,
+ 0x10, 0x8, 0x8,
+ 0x10, 0xa, 0x8,
+ 0x10, 0xc, 0x8,
+ 0x10, 0xe, 0x8,
+ 0x10, 0x10, 0x8,
+ 0xe, 0x10, 0x8,
+ 0xc, 0x10, 0x8,
+ 0xa, 0x10, 0x8,
+ 0x8, 0x10, 0x8,
+ 0x8, 0x10, 0xa,
+ 0x8, 0x10, 0xc,
+ 0x8, 0x10, 0xe,
+ 0x8, 0x10, 0x10,
+ 0x8, 0xe, 0x10,
+ 0x8, 0xc, 0x10,
+ 0x8, 0xa, 0x10,
+ 0xb, 0xb, 0x10,
+ 0xc, 0xb, 0x10,
+ 0xd, 0xb, 0x10,
+ 0xf, 0xb, 0x10,
+ 0x10, 0xb, 0x10,
+ 0x10, 0xb, 0xf,
+ 0x10, 0xb, 0xd,
+ 0x10, 0xb, 0xc,
+ 0x10, 0xb, 0xb,
+ 0x10, 0xc, 0xb,
+ 0x10, 0xd, 0xb,
+ 0x10, 0xf, 0xb,
+ 0x10, 0x10, 0xb,
+ 0xf, 0x10, 0xb,
+ 0xd, 0x10, 0xb,
+ 0xc, 0x10, 0xb,
+ 0xb, 0x10, 0xb,
+ 0xb, 0x10, 0xc,
+ 0xb, 0x10, 0xd,
+ 0xb, 0x10, 0xf,
+ 0xb, 0x10, 0x10,
+ 0xb, 0xf, 0x10,
+ 0xb, 0xd, 0x10,
+ 0xb, 0xc, 0x10,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0
+};
+
+unsigned char AC[21] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+static int scanPCI(int start_slt);
+static int PCIVendor(int);
+static void printslots(void);
+int delayLoop(int);
+extern void puthex(unsigned long);
+extern void puts(const char *);
+static void unlockS3(void);
+
+static inline
+outw(int port, unsigned short val)
+{
+ outb(port, val >> 8);
+ outb(port+1, val);
+}
+
+#define PPC_601 1
+
+vga_init(unsigned char *ISA_mem)
+{
+ int slot;
+ struct VgaRegs *VgaTextRegs;
+
+ if ((_get_PVR()>>16) == PPC_601) {
+ return(old_vga_init(ISA_mem));
+ }
+
+#if 1
+ /* See if VGA already in TEXT mode - exit if so! */
+ outb(0x3CE, 0x06);
+ if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;}
+#endif
+
+ /* If no VGA responding in text mode, then we have some work to do...
+ */
+ slot = -1;
+ while((slot = scanPCI(slot)) > -1) { /* find video card in use */
+ unlockVideo(slot); /* enable I/O to card */
+ VgaTextRegs = GenVgaTextRegs;
+
+ switch (PCIVendor(slot)) {
+ default:
+ break;
+ case(S3Vendor):
+ unlockS3();
+ VgaTextRegs = S3TextRegs;
+ break;
+
+ case(CirrusVendor):
+ outw(0x3C4, 0x0612); /* unlock ext regs */
+ outw(0x3C4, 0x0700); /* reset ext sequence mode */
+ break;
+
+ case(ParadiseVendor): /* IBM Portable 850 */
+ outw(0x3ce, 0x0f05); /* unlock pardise registers */
+ outw(0x3c4, 0x0648);
+ outw(0x3d4, 0x2985);
+ outw(0x3d4, 0x34a6);
+ outb(0x3ce, 0x0b); /* disable linear addressing */
+ outb(0x3cf, inb(0x3cf) & ~0x30);
+ outw(0x3c4, 0x1400);
+ outb(0x3ce, 0x0e); /* disable 256 color mode */
+ outb(0x3cf, inb(0x3cf) & ~0x01);
+ outb(0xd00, 0xff); /* enable auto-centering */
+ if (!(inb(0xd01) & 0x03)) {
+ outb(0x3d4, 0x33);
+ outb(0x3d5, inb(0x3d5) & ~0x90);
+ outb(0x3d4, 0x32);
+ outb(0x3d5, inb(0x3d5) | 0x04);
+ outw(0x3d4, 0x0250);
+ outw(0x3d4, 0x07ba);
+ outw(0x3d4, 0x0900);
+ outw(0x3d4, 0x15e7);
+ outw(0x3d4, 0x2a95);
+ }
+ outw(0x3d4, 0x34a0);
+ break;
+
+ #if 0 /* Untested - probably doesn't work */
+ case(MatroxVendor):
+ case(DiamondVendor):
+ puts("VGA Chip Vendor ID: ");
+ puthex(PCIVendor(slot));
+ puts("\n");
+ delayLoop(1);
+ #endif
+ };
+
+ outw(0x3C4, 0x0120); /* disable video */
+ setTextRegs(VgaTextRegs); /* initial register setup */
+ setTextCLUT(0); /* load color lookup table */
+ loadFont(ISA_mem); /* load font */
+ setTextRegs(VgaTextRegs); /* reload registers */
+ outw(0x3C4, 0x0100); /* re-enable video */
+ clearVideoMemory();
+
+ if (PCIVendor(slot) == S3Vendor) {
+ outb(0x3c2, 0x63); /* MISC */
+ } /* endif */
+
+ #ifdef DEBUG
+ printslots();
+ delayLoop(5);
+ #endif
+
+ delayLoop(1); /* give time for the video monitor to come up */
+ }
+ return (1); /* 'CRT' I/O supported */
+}
+
+static int
+NOP(int x)
+{
+}
+
+/*
+ * Write to VGA Attribute registers.
+ */
+writeAttr(index, data, videoOn)
+ unsigned char index;
+ unsigned char data;
+ unsigned char videoOn; /* video on flag */
+{
+ unsigned char v;
+ v = inb(0x3da); /* reset attr. address toggle */
+ if (videoOn)
+ outb(0x3c0, (index & 0x1F) | 0x20);
+ else
+ outb(0x3c0, (index & 0x1F));
+ outb(0x3c0, data);
+}
+
+setTextRegs(struct VgaRegs *svp)
+{
+ int i;
+
+ /*
+ * saved settings
+ */
+ while( svp->io_port != ENDMK ) {
+ outb(svp->io_port, svp->io_index);
+ outb(svp->io_port+1, svp->io_value);
+ svp++;
+ }
+
+ outb(0x3c2, 0x67); /* MISC */
+ outb(0x3c6, 0xff); /* MASK */
+
+ for ( i = 0; i < 0x10; i++)
+ writeAttr(i, AC[i], 0); /* pallete */
+ writeAttr(0x10, 0x0c, 0); /* text mode */
+ writeAttr(0x11, 0x00, 0); /* overscan color (border) */
+ writeAttr(0x12, 0x0f, 0); /* plane enable */
+ writeAttr(0x13, 0x08, 0); /* pixel panning */
+ writeAttr(0x14, 0x00, 1); /* color select; video on */
+}
+
+setTextCLUT(int shift)
+{
+ int i;
+
+ outb(0x3C6, 0xFF);
+ i = inb(0x3C7);
+ outb(0x3C8, 0);
+ i = inb(0x3C7);
+
+ for ( i = 0; i < 256; i++) {
+ outb(0x3C9, TextCLUT[i].r << shift);
+ outb(0x3C9, TextCLUT[i].g << shift);
+ outb(0x3C9, TextCLUT[i].b << shift);
+ }
+}
+
+
+loadFont(unsigned char *ISA_mem)
+{
+ int i, j;
+ unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+
+ outb(0x3C2, 0x67);
+ /*
+ * Load font
+ */
+ i = inb(0x3DA); /* Reset Attr toggle */
+
+ outb(0x3C0,0x30);
+ outb(0x3C0, 0x01); /* graphics mode */
+
+ outw(0x3C4, 0x0001); /* reset sequencer */
+ outw(0x3C4, 0x0204); /* write to plane 2 */
+ outw(0x3C4, 0x0406); /* enable plane graphics */
+ outw(0x3C4, 0x0003); /* reset sequencer */
+ outw(0x3CE, 0x0402); /* read plane 2 */
+ outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
+ outw(0x3CE, 0x0605); /* set graphics mode */
+
+ for (i = 0; i < sizeof(font); i += 16) {
+ for (j = 0; j < 16; j++) {
+ __asm__ volatile("eieio");
+ font_page[(2*i)+j] = font[i+j];
+ }
+ }
+}
+
+static void
+unlockS3(void)
+{
+ int s3_device_id;
+ outw(0x3d4, 0x3848);
+ outw(0x3d4, 0x39a5);
+ outb(0x3d4, 0x2d);
+ s3_device_id = inb(0x3d5) << 8;
+ outb(0x3d4, 0x2e);
+ s3_device_id |= inb(0x3d5);
+
+ if (s3_device_id != 0x8812) {
+ /* From the S3 manual */
+ outb(0x46E8, 0x10); /* Put into setup mode */
+ outb(0x3C3, 0x10);
+ outb(0x102, 0x01); /* Enable registers */
+ outb(0x46E8, 0x08); /* Enable video */
+ outb(0x3C3, 0x08);
+ outb(0x4AE8, 0x00);
+
+#if 0
+ outb(0x42E8, 0x80); /* Reset graphics engine? */
+#endif
+
+ outb(0x3D4, 0x38); /* Unlock all registers */
+ outb(0x3D5, 0x48);
+ outb(0x3D4, 0x39);
+ outb(0x3D5, 0xA5);
+ outb(0x3D4, 0x40);
+ outb(0x3D5, inb(0x3D5)|0x01);
+ outb(0x3D4, 0x33);
+ outb(0x3D5, inb(0x3D5)&~0x52);
+ outb(0x3D4, 0x35);
+ outb(0x3D5, inb(0x3D5)&~0x30);
+ outb(0x3D4, 0x3A);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x53);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x31);
+ outb(0x3D5, inb(0x3D5)&~0x4B);
+ outb(0x3D4, 0x58);
+
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x54);
+ outb(0x3D5, 0x38);
+ outb(0x3D4, 0x60);
+ outb(0x3D5, 0x07);
+ outb(0x3D4, 0x61);
+ outb(0x3D5, 0x80);
+ outb(0x3D4, 0x62);
+ outb(0x3D5, 0xA1);
+ outb(0x3D4, 0x69); /* High order bits for cursor address */
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x32);
+ outb(0x3D5, inb(0x3D5)&~0x10);
+ } else {
+ outw(0x3c4, 0x0806); /* IBM Portable 860 */
+ outw(0x3c4, 0x1041);
+ outw(0x3c4, 0x1128);
+ outw(0x3d4, 0x4000);
+ outw(0x3d4, 0x3100);
+ outw(0x3d4, 0x3a05);
+ outw(0x3d4, 0x6688);
+ outw(0x3d4, 0x5800); /* disable linear addressing */
+ outw(0x3d4, 0x4500); /* disable H/W cursor */
+ outw(0x3c4, 0x5410); /* enable auto-centering */
+ outw(0x3c4, 0x561f);
+ outw(0x3c4, 0x1b80); /* lock DCLK selection */
+ outw(0x3d4, 0x3900); /* lock S3 registers */
+ outw(0x3d4, 0x3800);
+ } /* endif */
+}
+
+/*
+ * cursor() sets an offset (0-1999) into the 80x25 text area
+ */
+void
+cursor(int x, int y)
+{
+ int pos = (y*cols)+x;
+ outb(0x3D4, 14);
+ outb(0x3D5, pos >> 8);
+ outb(0x3D4, 15);
+ outb(0x3D5, pos);
+}
+
+clearVideoMemory()
+{
+ int i, j;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < cols; j++) {
+ vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */
+ vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */
+ }
+ }
+}
+
+/* ============ */
+
+
+#define NSLOTS 8
+#define NPCIREGS 5
+
+
+/*
+ should use devfunc number/indirect method to be totally safe on
+ all machines, this works for now on 3 slot Moto boxes
+*/
+
+struct PCI_ConfigInfo {
+ unsigned long * config_addr;
+ unsigned long regs[NPCIREGS];
+} PCI_slots [NSLOTS] = {
+
+ { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */
+ { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */
+ { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */
+};
+
+
+
+/*
+ * The following code modifies the PCI Command register
+ * to enable memory and I/O accesses.
+ */
+unlockVideo(slot)
+{
+ volatile unsigned char * ppci;
+
+ ppci = (unsigned char * )PCI_slots[slot].config_addr;
+ ppci[4] = 0x0003; /* enable memory and I/O accesses */
+ ppci[0x10] = 0x00000; /* turn off memory mapping */
+ ppci[0x11] = 0x00000; /* mem_base = 0 */
+ ppci[0x12] = 0x00000;
+ ppci[0x13] = 0x00000;
+ __asm__ volatile("eieio");
+
+ outb(0x3d4, 0x11);
+ outb(0x3d5, 0x0e); /* unlock CR0-CR7 */
+}
+
+long
+SwapBytes(long lv) /* turn little endian into big indian long */
+{
+ long t;
+ t = (lv&0x000000FF) << 24;
+ t |= (lv&0x0000FF00) << 8;
+ t |= (lv&0x00FF0000) >> 8;
+ t |= (lv&0xFF000000) >> 24;
+ return(t);
+}
+
+
+#define DEVID 0
+#define CMD 1
+#define CLASS 2
+#define MEMBASE 4
+
+int
+scanPCI(int start_slt)
+{
+ int slt, r;
+ struct PCI_ConfigInfo *pslot;
+ int theSlot = -1;
+ int highVgaSlot = 0;
+
+ for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
+ pslot = &PCI_slots[slt];
+ for ( r = 0; r < NPCIREGS; r++) {
+ pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
+ }
+ /* card in slot ? */
+ if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
+ /* VGA ? */
+ if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
+ ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
+ highVgaSlot = slt;
+ /* did firmware enable it ? */
+ if ( (pslot->regs[CMD] & 0x03) ) {
+ theSlot = slt;
+ break;
+ }
+ }
+ }
+ }
+
+ return ( theSlot );
+}
+
+/* Delay for a certain number of seconds */
+/* Note: They loop is used since 'udelay' can't handle really long counts! */
+
+int
+delayLoop(int k)
+{
+ int i;
+ while (k-- > 0) {
+ for (i = 0; i < 1000; i++) {
+ udelay(1000);
+ }
+ }
+}
+
+
+/* return Vendor ID of card in the slot */
+static
+int PCIVendor(int slotnum) {
+ struct PCI_ConfigInfo *pslot;
+
+ pslot = &PCI_slots[slotnum];
+
+return (pslot->regs[DEVID] & 0xFFFF);
+}
+
+static
+void printslots(void)
+{
+ int i;
+ struct PCI_ConfigInfo *pslot;
+ for(i=0; i < NSLOTS; i++) {
+#if 0
+ pslot = &PCI_slots[i];
+ printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
+ i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
+#else
+ puts("PCI Slot number: "); puthex(i);
+ puts(" Vendor ID: ");
+ puthex(PCIVendor(i)); puts("\n");
+#endif
+
+ }
+}
+
+/*
+ * OLD vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ * Steve Sellgren
+ * San Francisco Indigo Company
+ * sfindigo!sellgren@uunet.uu.net
*/
unsigned char CRTC[24] = {
0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
-unsigned char AC[21] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x0C, 0x00, 0x0F, 0x08, 0x00};
-
-#include "iso_font.h"
+#if 0
static const unsigned char color_LUT[] =
{
0x00, 0x00, 0x00, /* 0 - black */
0x2A, 0x2A, 0x15, /* 14 - yellow */
0x2A, 0x2A, 0x3F, /* 15 - bright white */
};
-
-static inline
-outw(int port, unsigned short val)
-{
- outb(port, val >> 8);
- outb(port+1, val);
-}
+#endif
-vga_init(unsigned char *ISA_mem)
+old_vga_init(unsigned char *ISA_mem)
{
- int i, j;
- int value;
- unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+ int i, j;
+ int value;
+ unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
- /* See if VGA already in TEXT mode - exit if so! */
- outb(0x3CE, 0x06);
- if ((inb(0x3CF) & 0x01) == 0) return;
+ /* See if VGA already in TEXT mode - exit if so! */
+ outb(0x3CE, 0x06);
+ if ((inb(0x3CF) & 0x01) == 0) return;
- /* From the S3 manual */
- outb(0x46E8, 0x10); /* Put into setup mode */
- outb(0x3C3, 0x10);
- outb(0x102, 0x01); /* Enable registers */
- outb(0x46E8, 0x08); /* Enable video */
- outb(0x3C3, 0x08);
- outb(0x4AE8, 0x00);
-
- outb(0x42E8, 0x80); /* Reset graphics engine? */
-
- outb(0x3D4, 0x38); /* Unlock all registers */
- outb(0x3D5, 0x48);
- outb(0x3D4, 0x39);
- outb(0x3D5, 0xA5);
- outb(0x3D4, 0x40);
- outb(0x3D5, inb(0x3D5)|0x01);
- outb(0x3D4, 0x33);
- outb(0x3D5, inb(0x3D5)&~0x52);
- outb(0x3D4, 0x35);
- outb(0x3D5, inb(0x3D5)&~0x30);
- outb(0x3D4, 0x3A);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x53);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x31);
- outb(0x3D5, inb(0x3D5)&~0x4B);
- outb(0x3D4, 0x58);
- outb(0x3D5, 0);
-
- outb(0x3D4, 0x54);
- outb(0x3D5, 0x38);
- outb(0x3D4, 0x60);
- outb(0x3D5, 0x07);
- outb(0x3D4, 0x61);
- outb(0x3D5, 0x80);
- outb(0x3D4, 0x62);
- outb(0x3D5, 0xA1);
- outb(0x3D4, 0x69); /* High order bits for cursor address */
- outb(0x3D5, 0);
+ /* From the S3 manual */
+ outb(0x46E8, 0x10); /* Put into setup mode */
+ outb(0x3C3, 0x10);
+ outb(0x102, 0x01); /* Enable registers */
+ outb(0x46E8, 0x08); /* Enable video */
+ outb(0x3C3, 0x08);
+ outb(0x4AE8, 0x00);
+
+#if 0
+ outb(0x42E8, 0x80); /* Reset graphics engine? */
+#endif
+
+ outb(0x3D4, 0x38); /* Unlock all registers */
+ outb(0x3D5, 0x48);
+ outb(0x3D4, 0x39);
+ outb(0x3D5, 0xA5);
+ outb(0x3D4, 0x40);
+ outb(0x3D5, inb(0x3D5)|0x01);
+ outb(0x3D4, 0x33);
+ outb(0x3D5, inb(0x3D5)&~0x52);
+ outb(0x3D4, 0x35);
+ outb(0x3D5, inb(0x3D5)&~0x30);
+ outb(0x3D4, 0x3A);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x53);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x31);
+ outb(0x3D5, inb(0x3D5)&~0x4B);
+ outb(0x3D4, 0x58);
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x54);
+ outb(0x3D5, 0x38);
+ outb(0x3D4, 0x60);
+ outb(0x3D5, 0x07);
+ outb(0x3D4, 0x61);
+ outb(0x3D5, 0x80);
+ outb(0x3D4, 0x62);
+ outb(0x3D5, 0xA1);
+ outb(0x3D4, 0x69); /* High order bits for cursor address */
+ outb(0x3D5, 0);
- outb(0x3D4, 0x32);
- outb(0x3D5, inb(0x3D5)&~0x10);
-
- outb(0x3C2, 0x67);
-
- /* Initialize DAC */
- outb(0x3C6,0xFF);
- inb(0x3C7);
- outb(0x3C8,0x00);
- inb(0x3C7);
- for (i=0; i<sizeof(color_LUT); i++) {
- outb(0x3C9, color_LUT[i]);
- }
- for (i; i<768; i += 3) {
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- }
-
- /* Load font */
- NOP(inb(0x3DA)); /* Reset Address/Data FlipFlop for Attribute ctlr */
- outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
- outw(0x3C4, 0x0001); /* reset sequencer */
- outw(0x3C4, 0x0204); /* write to plane 2 */
- outw(0x3C4, 0x0407); /* enable plane graphics */
- outw(0x3C4, 0x0003); /* reset sequencer */
- outw(0x3CE, 0x0402); /* read plane 2 */
- outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
- outw(0x3CE, 0x0600); /* set graphics */
- for (i = 0; i < sizeof(font); i += 16) {
- for (j = 0; j < 16; j++) {
- font_page[(2*i)+j] = font[i+j];
- }
- }
-
- for (i = 0; i < 24; i++) {
- outb(0x3D4, i);
- outb(0x3D5, CRTC[i]);
- }
- for (i = 0; i < 5; i++) {
- outb(0x3C4, i);
- outb(0x3C5, SEQ[i]);
- }
- for (i = 0; i < 9; i++) {
- outb(0x3CE, i);
- outb(0x3CF, GC[i]);
- }
- value = inb(0x3DA); /* reset flip-flop */
- for (i = 0; i < 16; i++) {
- outb(0x3C0, i);
- outb(0x3C0, AC[i]);
- }
- for (i = 16; i < 21; i++) {
- outb(0x3C0, i | 0x20);
- outb(0x3C0, AC[i]);
- }
- outb(0x3C2, 0x23);
-}
+ outb(0x3D4, 0x32);
+ outb(0x3D5, inb(0x3D5)&~0x10);
-static int
-NOP(int x)
-{
+ outb(0x3C2, 0x67);
+
+#if 0
+ /* Initialize DAC */
+ outb(0x3C6,0xFF);
+ inb(0x3C7);
+ outb(0x3C8,0x00);
+ inb(0x3C7);
+ for (i=0; i<sizeof(color_LUT); i++) {
+ outb(0x3C9, color_LUT[i]);
+ }
+ for (i; i<768; i += 3) {
+ outb(0x3C9, 0x3F); /* White? */
+ outb(0x3C9, 0x3F); /* White? */
+ outb(0x3C9, 0x3F); /* White? */
+ }
+
+ /* Load font */
+ NOP(inb(0x3DA)); /* Reset Address/Data FlipFlop for Attribute ctlr */
+ outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
+ outw(0x3C4, 0x0001); /* reset sequencer */
+ outw(0x3C4, 0x0204); /* write to plane 2 */
+ outw(0x3C4, 0x0407); /* enable plane graphics */
+ outw(0x3C4, 0x0003); /* reset sequencer */
+ outw(0x3CE, 0x0402); /* read plane 2 */
+ outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
+ outw(0x3CE, 0x0600); /* set graphics */
+ for (i = 0; i < sizeof(font); i += 16) {
+ for (j = 0; j < 16; j++) {
+ font_page[(2*i)+j] = font[i+j];
+ }
+ }
+#else
+ outw(0x3C4, 0x0120); /* disable video */
+ setTextCLUT(2); /* load color lookup table */
+ loadFont(ISA_mem); /* load font */
+#endif
+
+ for (i = 0; i < 24; i++) {
+ outb(0x3D4, i);
+ outb(0x3D5, CRTC[i]);
+ }
+ for (i = 0; i < 5; i++) {
+ outb(0x3C4, i);
+ outb(0x3C5, SEQ[i]);
+ }
+ for (i = 0; i < 9; i++) {
+ outb(0x3CE, i);
+ outb(0x3CF, GC[i]);
+ }
+ value = inb(0x3DA); /* reset flip-flop */
+ for (i = 0; i < 16; i++) {
+ outb(0x3C0, i);
+ outb(0x3C0, AC[i]);
+ }
+ for (i = 16; i < 21; i++) {
+ outb(0x3C0, i | 0x20);
+ outb(0x3C0, AC[i]);
+ }
+ clearVideoMemory();
+ outw(0x3C4, 0x0100); /* re-enable video */
+ outb(0x3C2, 0x23);
+ return (1); /* Keyboard should work */
}
# For a description of the syntax of this configuration file,
# see the Configure script.
#
-mainmenu_name "Linux Kernel Configuration"
+mainmenu_name "Linux/PowerPC Kernel Configuration"
-mainmenu_option next_comment
-comment 'Code maturity level options'
+if [ "`uname`" != "Linux" ]; then
+ define_bool CONFIG_CROSSCOMPILE y
+else
+ define_bool CONFIG_NATIVE y
+fi
+
+bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
+bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+choice 'Processor type' \
+ "Common CONFIG_MCOMMON \
+ 601 CONFIG_M601 \
+ 603 CONFIG_M603 \
+ 604 CONFIG_M604" Common
-mainmenu_option next_comment
-comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-endmenu
-mainmenu_option next_comment
-comment 'General setup'
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION
+mainmenu_option next_comment
+define_bool CONFIG_PCI y
+bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
-if [ "$CONFIG_PCI" = "y" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
- fi
-fi
-bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+bool 'System V IPC' CONFIG_SYSVIPC
+
+# only elf supported, a.out is not -- Cort
+define_bool CONFIG_BINFMT_ELF y
+define_bool CONFIG_KERNEL_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
- bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
-source drivers/block/Config.in
-if [ "$CONFIG_NET" = "y" ]; then
- source net/Config.in
-fi
+source drivers/pnp/Config.in
+source drivers/block/Config.in
mainmenu_option next_comment
comment 'SCSI support'
-
tristate 'SCSI support' CONFIG_SCSI
-
if [ "$CONFIG_SCSI" != "n" ]; then
source drivers/scsi/Config.in
fi
endmenu
+
if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
comment 'Network device support'
-
+ source net/Config.in
bool 'Network device support' CONFIG_NETDEVICES
if [ "$CONFIG_NETDEVICES" = "y" ]; then
source drivers/net/Config.in
endmenu
fi
+
mainmenu_option next_comment
comment 'ISDN subsystem'
-
tristate 'ISDN support' CONFIG_ISDN
if [ "$CONFIG_ISDN" != "n" ]; then
source drivers/isdn/Config.in
mainmenu_option next_comment
comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
source drivers/cdrom/Config.in
endmenu
source fs/Config.in
-
source drivers/char/Config.in
mainmenu_option next_comment
comment 'Sound'
-
tristate 'Sound card support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
source drivers/sound/Config.in
endmenu
mainmenu_option next_comment
-comment 'Kernel hacking'
-
+#comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Kernel profiling support' CONFIG_PROFILE
-if [ "$CONFIG_PROFILE" = "y" ]; then
- int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
-fi
+#bool 'Kernel profiling support' CONFIG_PROFILE
+#if [ "$CONFIG_PROFILE" = "y" ]; then
+# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+#fi
endmenu
+
--- /dev/null
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
--- /dev/null
+.config
+compile.h
+.version
+.objects
+.blurb
+*.cort
+*.paul
+*.old
+.defines
+version.h
+find_name
+checks
+#*
+.objects
+.object_files
+System.map
+asm
+.menuconfig*
+CVS
+ppc_defs.h
+mk_defs
+mkprep
+*.s
+.depend
+.hdepend
+*~
+*.o
+znetboot
+zvmlinux
+vmlinux
+zImage
+hack-coff
+coffboot
+vmlinux.coff
+.depend
+.cvsignore
+RCS
+SCCS
+CVS.adm
+RCSLOG
+cvslog.*
+tags
+TAGS
+.make.state
+.nse_depinfo
+*~
+#*
+.#*
+,*
+_$*
+*$
+*.old
+*.bak
+*.BAK
+*.orig
+*.rej
+*.a
+*.olb
+*.o
+*.obj
+*.so
+*.exe
+*.Z
+*.elc
+*.ln
HOST_CC = gcc
-OBJS = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
- signal.o ksyms.o time.o syscalls.o usercpy.o\
- support.o ptrace.o
+OBJS = misc.o port_io.o pci.o traps.o process.o \
+ signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
all: head.o kernel.o
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
-head.o: head.s
-head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
+ifeq ($(CONFIG_PREP),y)
+OBJS += prep_setup.o prep_time.o
+endif
+
+ifeq ($(CONFIG_PMAC),y)
+OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+OBJS = ksyms.o
+endif
-ppc_defs.h: mk_defs
- mk_defs $@
-mk_defs: mk_defs.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static ${CFLAGS} -o mk_defs mk_defs.c
+ppc_defs.h: mk_defs.c ppc_defs.head \
+ $(TOPDIR)/include/asm/mmu.h \
+ $(TOPDIR)/include/asm/processor.h \
+ $(TOPDIR)/include/asm/pgtable.h \
+ $(TOPDIR)/include/asm/ptrace.h
+ $(CC) ${CFLAGS} -S mk_defs.c
+ cp ppc_defs.head ppc_defs.h
+ grep '^#define' mk_defs.s >>ppc_defs.h
+ rm mk_defs.s
+checks: checks.c
+ $(HOSTCC) ${CFLAGS} -o checks checks.c
+ checks
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
- sync
-
-dep:
- $(CPP) -M *.c > .depend
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+ $(CPP) -M *.S *.c > .depend
-modules:
+modules:
dummy:
--- /dev/null
+/*
+ * align.c - handle alignment exceptions for the Power PC.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+struct aligninfo {
+ unsigned char len;
+ unsigned char flags;
+};
+
+#define INVALID { 0, 0 }
+
+#define LD 1 /* load */
+#define ST 2 /* store */
+#define SE 4 /* sign-extend value */
+#define F 8 /* to/from fp regs */
+#define U 0x10 /* update index register */
+#define M 0x20 /* multiple load/store */
+#define S 0x40 /* single-precision fp, or byte-swap value */
+#define HARD 0x80 /* string, stwcx. */
+
+/*
+ * The PowerPC stores certain bits of the instruction that caused the
+ * alignment exception in the DSISR register. This array maps those
+ * bits to information about the operand length and what the
+ * instruction would do.
+ */
+static struct aligninfo aligninfo[128] = {
+ { 4, LD }, /* 00 0 0000: lwz / lwarx */
+ INVALID, /* 00 0 0001 */
+ { 4, ST }, /* 00 0 0010: stw */
+ INVALID, /* 00 0 0011 */
+ { 2, LD }, /* 00 0 0100: lhz */
+ { 2, LD+SE }, /* 00 0 0101: lha */
+ { 2, ST }, /* 00 0 0110: sth */
+ { 4, LD+M }, /* 00 0 0111: lmw */
+ { 4, LD+F+S }, /* 00 0 1000: lfs */
+ { 8, LD+F }, /* 00 0 1001: lfd */
+ { 4, ST+F+S }, /* 00 0 1010: stfs */
+ { 8, ST+F }, /* 00 0 1011: stfd */
+ INVALID, /* 00 0 1100 */
+ INVALID, /* 00 0 1101 */
+ INVALID, /* 00 0 1110 */
+ INVALID, /* 00 0 1111 */
+ { 4, LD+U }, /* 00 1 0000: lwzu */
+ INVALID, /* 00 1 0001 */
+ { 4, ST+U }, /* 00 1 0010: stwu */
+ INVALID, /* 00 1 0011 */
+ { 2, LD+U }, /* 00 1 0100: lhzu */
+ { 2, LD+SE+U }, /* 00 1 0101: lhau */
+ { 2, ST+U }, /* 00 1 0110: sthu */
+ { 4, ST+M }, /* 00 1 0111: stmw */
+ { 4, LD+F+S+U }, /* 00 1 1000: lfsu */
+ { 8, LD+F+U }, /* 00 1 1001: lfdu */
+ { 4, ST+F+S+U }, /* 00 1 1010: stfsu */
+ { 8, ST+F+U }, /* 00 1 1011: stfdu */
+ INVALID, /* 00 1 1100 */
+ INVALID, /* 00 1 1101 */
+ INVALID, /* 00 1 1110 */
+ INVALID, /* 00 1 1111 */
+ INVALID, /* 01 0 0000 */
+ INVALID, /* 01 0 0001 */
+ INVALID, /* 01 0 0010 */
+ INVALID, /* 01 0 0011 */
+ INVALID, /* 01 0 0100 */
+ INVALID, /* 01 0 0101: lwax?? */
+ INVALID, /* 01 0 0110 */
+ INVALID, /* 01 0 0111 */
+ { 0, LD+HARD }, /* 01 0 1000: lswx */
+ { 0, LD+HARD }, /* 01 0 1001: lswi */
+ { 0, ST+HARD }, /* 01 0 1010: stswx */
+ { 0, ST+HARD }, /* 01 0 1011: stswi */
+ INVALID, /* 01 0 1100 */
+ INVALID, /* 01 0 1101 */
+ INVALID, /* 01 0 1110 */
+ INVALID, /* 01 0 1111 */
+ INVALID, /* 01 1 0000 */
+ INVALID, /* 01 1 0001 */
+ INVALID, /* 01 1 0010 */
+ INVALID, /* 01 1 0011 */
+ INVALID, /* 01 1 0100 */
+ INVALID, /* 01 1 0101: lwaux?? */
+ INVALID, /* 01 1 0110 */
+ INVALID, /* 01 1 0111 */
+ INVALID, /* 01 1 1000 */
+ INVALID, /* 01 1 1001 */
+ INVALID, /* 01 1 1010 */
+ INVALID, /* 01 1 1011 */
+ INVALID, /* 01 1 1100 */
+ INVALID, /* 01 1 1101 */
+ INVALID, /* 01 1 1110 */
+ INVALID, /* 01 1 1111 */
+ INVALID, /* 10 0 0000 */
+ INVALID, /* 10 0 0001 */
+ { 0, ST+HARD }, /* 10 0 0010: stwcx. */
+ INVALID, /* 10 0 0011 */
+ INVALID, /* 10 0 0100 */
+ INVALID, /* 10 0 0101 */
+ INVALID, /* 10 0 0110 */
+ INVALID, /* 10 0 0111 */
+ { 4, LD+S }, /* 10 0 1000: lwbrx */
+ INVALID, /* 10 0 1001 */
+ { 4, ST+S }, /* 10 0 1010: stwbrx */
+ INVALID, /* 10 0 1011 */
+ { 2, LD+S }, /* 10 0 1100: lhbrx */
+ INVALID, /* 10 0 1101 */
+ { 2, ST+S }, /* 10 0 1110: sthbrx */
+ INVALID, /* 10 0 1111 */
+ INVALID, /* 10 1 0000 */
+ INVALID, /* 10 1 0001 */
+ INVALID, /* 10 1 0010 */
+ INVALID, /* 10 1 0011 */
+ INVALID, /* 10 1 0100 */
+ INVALID, /* 10 1 0101 */
+ INVALID, /* 10 1 0110 */
+ INVALID, /* 10 1 0111 */
+ INVALID, /* 10 1 1000 */
+ INVALID, /* 10 1 1001 */
+ INVALID, /* 10 1 1010 */
+ INVALID, /* 10 1 1011 */
+ INVALID, /* 10 1 1100 */
+ INVALID, /* 10 1 1101 */
+ INVALID, /* 10 1 1110 */
+ { 0, ST+HARD }, /* 10 1 1111: dcbz */
+ { 4, LD }, /* 11 0 0000: lwzx */
+ INVALID, /* 11 0 0001 */
+ { 4, ST }, /* 11 0 0010: stwx */
+ INVALID, /* 11 0 0011 */
+ { 2, LD }, /* 11 0 0100: lhzx */
+ { 2, LD+SE }, /* 11 0 0101: lhax */
+ { 2, ST }, /* 11 0 0110: sthx */
+ INVALID, /* 11 0 0111 */
+ { 4, LD+F+S }, /* 11 0 1000: lfsx */
+ { 8, LD+F }, /* 11 0 1001: lfdx */
+ { 4, ST+F+S }, /* 11 0 1010: stfsx */
+ { 8, ST+F }, /* 11 0 1011: stfdx */
+ INVALID, /* 11 0 1100 */
+ INVALID, /* 11 0 1101 */
+ INVALID, /* 11 0 1110 */
+ INVALID, /* 11 0 1111 */
+ { 4, LD+U }, /* 11 1 0000: lwzux */
+ INVALID, /* 11 1 0001 */
+ { 4, ST+U }, /* 11 1 0010: stwux */
+ INVALID, /* 11 1 0011 */
+ { 2, LD+U }, /* 11 1 0100: lhzux */
+ { 2, LD+SE+U }, /* 11 1 0101: lhaux */
+ { 2, ST+U }, /* 11 1 0110: sthux */
+ INVALID, /* 11 1 0111 */
+ { 4, LD+F+S+U }, /* 11 1 1000: lfsux */
+ { 8, LD+F+U }, /* 11 1 1001: lfdux */
+ { 4, ST+F+S+U }, /* 11 1 1010: stfsux */
+ { 8, ST+F+U }, /* 11 1 1011: stfdux */
+ INVALID, /* 11 1 1100 */
+ INVALID, /* 11 1 1101 */
+ INVALID, /* 11 1 1110 */
+ INVALID, /* 11 1 1111 */
+};
+
+#define SWAP(a, b) (t = (a), (a) = (b), (b) = t)
+
+int
+fix_alignment(struct pt_regs *regs)
+{
+ int instr, nb, flags;
+ int i, t;
+ int reg, areg;
+ unsigned char *addr;
+ union {
+ long l;
+ float f;
+ double d;
+ unsigned char v[8];
+ } data;
+
+ instr = (regs->dsisr >> 10) & 0x7f;
+ nb = aligninfo[instr].len;
+ if (nb == 0)
+ return 0; /* too hard or invalid instruction bits */
+ flags = aligninfo[instr].flags;
+ addr = (unsigned char *) regs->dar;
+ reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */
+
+ /* Verify the address of the operand */
+ if (user_mode(regs)) {
+ if (verify_area((flags & ST? VERIFY_WRITE: VERIFY_READ), addr, nb))
+ return -EFAULT; /* bad address */
+ }
+
+ if ((flags & F) && last_task_used_math == current)
+ giveup_fpu();
+
+ if (flags & M)
+ return 0; /* too hard for now */
+
+ /* If we read the operand, copy it in */
+ if (flags & LD) {
+ if (nb == 2) {
+ data.v[0] = data.v[1] = 0;
+ if (__get_user(data.v[2], addr)
+ || __get_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__get_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ switch (flags & ~U) {
+ case LD+SE:
+ if (data.v[2] >= 0x80)
+ data.v[0] = data.v[1] = -1;
+ /* fall through */
+ case LD:
+ regs->gpr[reg] = data.l;
+ break;
+ case LD+S:
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ regs->gpr[reg] = data.l;
+ break;
+ case ST:
+ data.l = regs->gpr[reg];
+ break;
+ case ST+S:
+ data.l = regs->gpr[reg];
+ if (nb == 2) {
+ SWAP(data.v[2], data.v[3]);
+ } else {
+ SWAP(data.v[0], data.v[3]);
+ SWAP(data.v[1], data.v[2]);
+ }
+ break;
+ case LD+F:
+ current->tss.fpr[reg] = data.d;
+ break;
+ case ST+F:
+ data.d = current->tss.fpr[reg];
+ break;
+ /* these require some floating point conversions... */
+ /* note that giveup_fpu enables the FPU for the kernel */
+ /* we'd like to use the assignment, but we have to compile
+ * the kernel with -msoft-float so it doesn't use the
+ * fp regs for copying 8-byte objects. */
+ case LD+F+S:
+ giveup_fpu();
+ cvt_fd(&data.f, ¤t->tss.fpr[reg]);
+ /* current->tss.fpr[reg] = data.f; */
+ break;
+ case ST+F+S:
+ giveup_fpu();
+ cvt_df(¤t->tss.fpr[reg], &data.f);
+ /* data.f = current->tss.fpr[reg]; */
+ break;
+ default:
+ printk("align: can't handle flags=%x\n", flags);
+ return 0;
+ }
+
+ if (flags & ST) {
+ if (nb == 2) {
+ if (__put_user(data.v[2], addr)
+ || __put_user(data.v[3], addr+1))
+ return -EFAULT;
+ } else {
+ for (i = 0; i < nb; ++i)
+ if (__put_user(data.v[i], addr+i))
+ return -EFAULT;
+ }
+ }
+
+ if (flags & U) {
+ areg = regs->dsisr & 0x1f; /* register to update */
+ regs->gpr[areg] = regs->dar;
+ }
+
+ return 1;
+}
--- /dev/null
+/*
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/kernel.h>
+#include <asm/bitops.h>
+
+/*
+ * I left these here since the problems with "cc" make it difficult to keep
+ * them in bitops.h -- Cort
+ */
+void set_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ or %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void clear_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ andc %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+void change_bit(int nr, volatile void *addr)
+{
+ unsigned int t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2
+ xor %0,%0,%1
+ stwcx. %0,0,%2
+ bne 1b"
+ : "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+}
+
+int test_and_set_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_set_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ or %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_clear_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_clear_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+int test_and_change_bit(int nr, volatile void *addr)
+{
+ unsigned int old, t;
+ unsigned int mask = 1 << (nr & 0x1f);
+ volatile unsigned int *p = ((volatile unsigned int *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk(KERN_ERR "test_and_change_bit(%x, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ : "cc");
+
+ return (old & mask) != 0;
+}
+
+/* I put it in bitops.h -- Cort */
+#if 0
+int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
+}
+
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+int find_first_zero_bit(void * addr, int size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+int find_next_zero_bit(void * addr, int size, int offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+#endif
--- /dev/null
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+
+/*
+ * Do various before compile checks of data structures
+ * -- Cort
+ */
+int main(void)
+{
+ int ret = 0;
+
+ if ( sizeof(struct thread_struct) % 16 )
+ {
+ printf("Thread struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct thread_struct),
+ sizeof(struct thread_struct)%16);
+ ret = -1;
+ }
+
+ if ( sizeof(struct pt_regs) % 16 )
+ {
+ printf("pt_regs struct is not modulo 16 bytes: "
+ "%d bytes total, %d bytes off\n",
+ sizeof(struct pt_regs),
+ sizeof(struct pt_regs)%16);
+ ret = -1;
+
+ }
+
+ printf("Task size : %d bytes\n"
+ "Tss size : %d bytes\n"
+ "pt_regs size : %d bytes\n"
+ "Kernel stack size: %d bytes\n",
+ sizeof(struct task_struct), sizeof(struct thread_struct),
+ sizeof(struct pt_regs),
+ sizeof(union task_union) - sizeof(struct task_struct));
+ return ret;
+}
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <asm/ppc_machine.h>
-
-#define NEWMM 1
-#define SYNC() \
- isync; \
- sync
-
-#define STATS
/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
+ * arch/ppc/kernel/head.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This file contains the low-level support and setup for the
+ * PowerPC platform, including trap and interrupt dispatch.
+ * Also included here is low-level thread/task switch support.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
-#define BUMP(ctr) \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- stw r3,0(r2)
-
-/* The same as 'BUMP' but running unmapped (TLB code) */
-#define BUMP_UNMAPPED(ctr) \
- mfspr r0,XER; \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lis r3,0xF000; \
- andc r2,r2,r3; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- mtspr XER,r0; \
- stw r3,0(r2)
-
-#define DO_RFI_TRACE_UNMAPPED(mark)
-#define DO_RFI_TRACE_MAPPED(mark)
-
-#define DEFAULT_TRAP(offset) \
- li r13,0; \
- ori r13,r13,HID0_ICE; \
- mtspr HID0,r13; \
- lis r13,0xFFF00000>>16; \
- ori r13,r13,offset; \
- mtlr r13; \
- blr
-#define TRACE_TRAP(offset)
-#define DATA_CACHE_OFF() \
- mfspr r2,HID0; \
- li r3,0; \
- ori r3,r3,HID0_DCE; \
- andc r2,r2,r3; \
- mtspr HID0,r2;
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/config.h>
-#define DATA_CACHE_ON() \
- mfspr r2,HID0; \
- ori r2,r2,HID0_DCE; \
- mtspr HID0,r2;
+#define SYNC() \
+ sync; \
+ isync
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
- li r4,64; \
- mtspr CTR,r4; \
- lis r4,0x9000; \
+ li r4,128; \
+ mtctr r4; \
+ lis r4,0xC000; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-/* Validate kernel stack - check for overflow */
-/* all regs are considered scratch since the C function will stomp them */
-#define CHECK_STACK() \
- /*lis r3,current_set@ha; \
- lwz r3,current_set@l(r3); \
- bl _EXTERN(check_stack)*/
-#if 0
-#define _CHECK_STACK() \
- mtspr SPR0,r3; \
- mtspr SPR1,r4; /* use r3,4 as scratch */ \
- lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- lwz r2,KERNEL_STACK_PAGE(r2); \
- /* if kernel stack is sys_stack skip check */ \
- /*lis r3,sys_stack@h; \
- ori r3,r3,sys_stack@l; \
- cmpl 0,r1,r3;*/ \
- /* check for STACK_MAGIC on kernel stack page */ \
- lis r3, 0xdead; /* STACK_MAGIC */ \
- ori r3,r3,0xbeef; \
- lwz r4,0(r2); /* get *kernel_stack_page */ \
- cmpl 0,r4,r3; \
- bne 01f; \
- /* check that ksp is > kernel page */ \
- /*li r3,0x0FFF; \
- andc r2,r2,r3; \
- andc r3,r1,r3; \
- cmp 0,r3,r2; \
- beq 02f;*/ \
- /* check that ksp and kernel stack page are on same page */ \
- cmp 0,r1,r2; \
- bge 02f; \
-01: mr r6,r1; /* setup info for call to bad_stack() */ \
- mr r5,r2; \
- bl _EXTERN(bad_stack); \
-02: mfspr r4,SPR1; \
- mfspr r3,SPR0
-#endif
+#define TOPHYS(x) (x - KERNELBASE)
+
+
+/* this is a very kludgey way of loading up the BATs on the
+ prep system. I'll kill this horrible macro and write
+ something clean when I have a chance -- Cort
+ */
+#define LOAD_BATS(RA,RB) \
+ mfspr RA,PVR ; \
+ srwi r5,r5,16 ; \
+ cmpi 0,RA,1 ; \
+ beq 199f ; \
+ /* load bats for 60x */ ; \
+ lis RA,BAT0@h ; \
+ ori RA,RA,BAT0@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1@h ; \
+ ori RA,RA,BAT1@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2@h ; \
+ ori RA,RA,BAT2@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3@h ; \
+ ori RA,RA,BAT3@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+ b 200f ; \
+199: /*load bats for 601 */ ; \
+ lis RA,BAT0_601@h ; \
+ ori RA,RA,BAT0_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1_601@h ; \
+ ori RA,RA,BAT1_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2_601@h ; \
+ ori RA,RA,BAT2_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3_601@h ; \
+ ori RA,RA,BAT3_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+200:
-/* save fp regs if fp is used */
-/* assumes that r1 contains ptr to regs of task and r2 is scratch
- -- Cort */
-#define SAVE_FP_REGS() \
- /* check if fp has been used by checking msr_fp bit */ \
- lwz r2,_MSR(r1); \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- save fp regs */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/ \
- stfd fr0,TSS_FPR0(r2); \
- stfd fr1,TSS_FPR1(r2); \
- stfd fr2,TSS_FPR2(r2); \
- stfd fr3,TSS_FPR3(r2); \
- stfd fr4,TSS_FPR4(r2); \
- stfd fr5,TSS_FPR5(r2); \
- stfd fr6,TSS_FPR6(r2); \
- stfd fr7,TSS_FPR7(r2); \
- stfd fr8,TSS_FPR8(r2); \
- stfd fr9,TSS_FPR9(r2); \
- stfd fr10,TSS_FPR10(r2); \
- stfd fr11,TSS_FPR11(r2); \
- stfd fr12,TSS_FPR12(r2); \
- stfd fr13,TSS_FPR13(r2); \
- stfd fr14,TSS_FPR14(r2); \
- stfd fr15,TSS_FPR15(r2); \
- stfd fr16,TSS_FPR16(r2); \
- stfd fr17,TSS_FPR17(r2); \
- stfd fr18,TSS_FPR18(r2); \
- stfd fr19,TSS_FPR19(r2); \
- stfd fr20,TSS_FPR20(r2); \
- stfd fr21,TSS_FPR21(r2); \
- stfd fr22,TSS_FPR22(r2); \
- stfd fr23,TSS_FPR23(r2); \
- stfd fr24,TSS_FPR24(r2); \
- stfd fr25,TSS_FPR25(r2); \
- stfd fr26,TSS_FPR26(r2); \
- stfd fr27,TSS_FPR27(r2); \
- stfd fr28,TSS_FPR28(r2); \
- stfd fr29,TSS_FPR29(r2); \
- stfd fr30,TSS_FPR30(r2); \
- stfd fr31,TSS_FPR31(r2); \
-00:
-
-
-/* restores fp regs if fp has been used -- always restores fpscr */
-/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
- what will become the msr when this process executes -- Cort*/
-#define RESTORE_FP_REGS(mark) \
- /* check if restoring from _switch() */ \
- li r2, mark; \
- cmpi 0,r2,0x0f0f; \
- bne 00f; /* only need to save if called from _switch() with 0x0f0f */\
- /* check if fp has been used by checking msr_fp bit */ \
- /* srr1 contains msr */ \
- mfspr r2,SRR1; \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- restore fp regs */ \
- /* Hey, Rocky! Watch me pull fp regs from my stack! */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/\
- lfd fr0,TSS_FPR0(r2); \
- lfd fr1,TSS_FPR1(r2); \
- lfd fr2,TSS_FPR2(r2); \
- lfd fr3,TSS_FPR3(r2); \
- lfd fr4,TSS_FPR4(r2); \
- lfd fr5,TSS_FPR5(r2); \
- lfd fr6,TSS_FPR6(r2); \
- lfd fr7,TSS_FPR7(r2); \
- lfd fr8,TSS_FPR8(r2); \
- lfd fr9,TSS_FPR9(r2); \
- lfd fr10,TSS_FPR10(r2); \
- lfd fr11,TSS_FPR11(r2); \
- lfd fr12,TSS_FPR12(r2); \
- lfd fr13,TSS_FPR13(r2); \
- lfd fr14,TSS_FPR14(r2); \
- lfd fr15,TSS_FPR15(r2); \
- lfd fr16,TSS_FPR16(r2); \
- lfd fr17,TSS_FPR17(r2); \
- lfd fr18,TSS_FPR18(r2); \
- lfd fr19,TSS_FPR19(r2); \
- lfd fr20,TSS_FPR20(r2); \
- lfd fr21,TSS_FPR21(r2); \
- lfd fr22,TSS_FPR22(r2); \
- lfd fr23,TSS_FPR23(r2); \
- lfd fr24,TSS_FPR24(r2); \
- lfd fr25,TSS_FPR25(r2); \
- lfd fr26,TSS_FPR26(r2); \
- lfd fr27,TSS_FPR27(r2); \
- lfd fr28,TSS_FPR28(r2); \
- lfd fr29,TSS_FPR29(r2); \
- lfd fr30,TSS_FPR30(r2); \
- lfd fr31,TSS_FPR31(r2); \
-00:
-
-/* save all registers */
-#define SAVE_ALL_REGS(mark) \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stmw r3,GPR3(r1); /* Save R3..R31 */ \
- stw r3,ORIG_GPR3(r1); \
- stw r0,GPR0(r1); \
- mfspr r2,SPR0; \
- stw r2,GPR1(r1); \
- mfspr r2,SPR1; \
- stw r2,GPR2(r1); \
- mfspr r2,SPR2; \
- stw r2,_NIP(r1); \
- mfspr r2,SPR3; \
- stw r2,_MSR(r1); \
- mfctr r2; \
- stw r2,_CTR(r1); \
- mflr r2; \
- stw r2,_LINK(r1); \
- mfcr r2; \
- stw r2,_CCR(r1); \
- mfspr r2,XER; \
- stw r2,_XER(r1); \
- mffs fr0; \
- stfd fr0,FPCSR(r1); \
- lis r2,_break_lwarx@h; \
- ori r2,r2,_break_lwarx@l; \
- stwcx. r2,0,r2; \
- li r2,mark; \
- stw r2,TRAP(r1); \
- lis r2,0xDEAD; \
- ori r2,r2,0xDEAD; \
- stw r2,MARKER(r1); \
- li r2,0; \
- stw r2,RESULT(r1)
-
-
-/* save registers clobbered by a page fault handler */
-#define SAVE_PAGE_FAULT_REGS(offset) \
- mfspr r2,DAR; \
- stw r2,_DAR(r1); \
- mfspr r2,DSISR; \
- stw r2,_DSISR(r1); \
- mfspr r2,PVR; /* Check for 603/603e */ \
- srwi r2,r2,16; \
- cmpi 0,r2,3; /* 603 */ \
- beq 22f; \
- cmpi 0,r2,6; /* 603e */ \
- bne 24f; \
-22: mfspr r2,HASH1; /* Note: these registers exist only on 603 */ \
- stw r2,_HASH1(r1); \
- mfspr r2,HASH2; \
- stw r2,_HASH2(r1); \
- mfspr r2,IMISS; \
- stw r2,_IMISS(r1); \
- mfspr r2,DMISS; \
- stw r2,_DMISS(r1); \
- mfspr r2,ICMP; \
- stw r2,_ICMP(r1); \
- mfspr r2,DCMP; \
- stw r2,_DCMP(r1); \
-24:
-
-#define SAVE_INT_REGS(mark) \
- mtspr SPR0,r1; /* Save current stack pointer */ \
- mtspr SPR1,r2; /* Scratch */ \
- mfcr r2; \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; /* Interrupt from user/system mode */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* Jump if system - already have stack */ \
- mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,05f@h; \
- ori r2,r2,05f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- rfi; \
-05: lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- mfspr r1,SPR2; \
- stw r1,TSS+LAST_PC(r2); \
- mfspr r1,SPR0; \
- stw r1,TSS+USER_STACK(r2); \
- lwz r1,TSS+KSP(r2); \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stw r1,TSS+PT_REGS(r2); /* Save regs pointer for 'ptrace' */ \
- lwz r1,TSS+KSP(r2); \
- b 20f; \
-10: mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,20f@h; \
- ori r2,r2,20f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- SYNC(); \
- rfi; \
-20: SAVE_ALL_REGS(mark); \
- CHECK_STACK()
-
-#define RETURN_FROM_INT(mark) \
-90: mfmsr r0; /* Disable interrupts */ \
- li r4,0; \
- ori r4,r4,MSR_EE; \
- andc r0,r0,r4; \
- sync; /* Some chip revs need this... */ \
- mtmsr r0; \
- lis r2,intr_count@ha; /* Need to run 'bottom half' */ \
- lwz r3,intr_count@l(r2); \
- cmpi 0,r3,0; \
- bne 00f; \
- lis r4,bh_mask@ha; \
- lwz r4,bh_mask@l(r4); \
- lis r5,bh_active@ha; \
- lwz r5,bh_active@l(r5); \
- and. r4,r4,r5; \
- beq 00f; \
- addi r3,r3,1; \
- stw r3,intr_count@l(r2); \
- bl _EXTERN(_do_bottom_half); \
- lis r2,intr_count@ha; \
- lwz r3,intr_count@l(r2); \
- subi r3,r3,1; \
- stw r3,intr_count@l(r2); \
-00: lwz r2,_MSR(r1); /* Returning to user mode? */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* no - no need to mess with stack */ \
-/* lis r2,kernel_pages_are_copyback@ha; \
- lwz r2,kernel_pages_are_copyback@l(r2); \
- cmpi 0,r2,0; \
- beq 05f; \
- bl _EXTERN(flush_instruction_cache); */ \
-05: lis r3,current_set@ha; /* need to save kernel stack pointer */ \
- lwz r3,current_set@l(r3); \
- /*addi r4,r1,INT_FRAME_SIZE*/; /* size of frame */ \
- lwz r4, KERNEL_STACK_PAGE(r3); \
- addi r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
- /* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
- stw r4,TSS+KSP(r3); \
- lwz r4,STATE(r3); /* If state != 0, can't run */ \
- cmpi 0,r4,0; \
- beq 06f; \
- bl _EXTERN(schedule); \
- b 90b; \
-06: lwz r4,COUNTER(r3); /* Time quantum expired? */ \
- cmpi 0,r4,0; \
- bne 07f; \
- bl _EXTERN(schedule); \
- b 90b; \
-07: lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
- lwz r5,SIGNAL(r3); \
- andc. r0,r5,r4; /* Lets thru any unblocked */ \
- beq 10f; \
- mr r3,r4; \
- mr r4,r1; \
- bl _EXTERN(do_signal); \
-10: lwz r2,_NIP(r1); /* Restore environment */ \
- mtspr SRR0,r2; \
- lwz r2,_MSR(r1); \
- mtspr SRR1,r2; \
- lmw r3,GPR3(r1); \
- lwz r2,_CTR(r1); \
- mtctr r2; \
- lwz r2,_LINK(r1); \
- mtlr r2; \
- lwz r2,_XER(r1); \
- mtspr XER,r2; \
- lfd fr0,FPCSR(r1); \
- mtfsf 0xFF,fr0; \
- RESTORE_FP_REGS(mark) ; \
- lwz r2,_CCR(r1); \
- mtcrf 0xFF,r2; \
- lwz r0,GPR0(r1); \
- lwz r2,GPR2(r1); \
- lwz r1,GPR1(r1); \
- SYNC(); \
- rfi
+
-_TEXT()
+ .text
+ .globl _stext
+_stext:
+
+#ifdef CONFIG_PREP
+ . = 0x100
+_GLOBAL(HardReset)
+ b _start
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
/*
- * This code may be executed by a bootstrap process. If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- * R30: 'BeBx' if this is a BeBox
- *
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
*/
+ .text
.globl _start
- .globl _stext
-_stext:
_start:
- addi r4,r4,0x400 /* Point at start of image */
- li r5,0 /* Load address */
- subi r4,r4,4 /* Adjust for auto-increment */
- subi r5,r5,4
- subi r3,r3,4
-00: lwzu r0,4(r4) /* Fast move */
- stwu r0,4(r5)
- cmp 0,r3,r4
- bne 00b
- li r5,0x100 /* Actual code starts here */
- mtlr r5
- blr
-
-hang:
- ori r0,r0,0
- b hang
+ .long TOPHYS(__start),0,0
/*
- * BeBox CPU #1 vector & code
- */
-_ORG(0x0080)
- .globl BeBox_CPU1_vector
-BeBox_CPU1_vector:
- .long 0
-BeBox_CPU1_reset:
- li r1,BeBox_CPU1_vector@l
- li r2,0
- stw r2,0(r1)
-00: lwz r2,0(r1)
- cmpi 0,r2,0
- bne 10f
- li r2,10000
- mtctr r2
-02: nop
- bdnz 02b
- b 00b
-10: mtlr r1
- blr
-
-_ORG(0x0100)
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address). Address translation is turned on, with the prom
+ * managing the hash table. Interrupts are disabled. The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
+ */
+ .globl __start
+__start:
-/* Hard Reset */
- .globl HardReset
-HardReset:
- b Reset
+/*
+ * Use the first pair of BAT registers to map the 1st 8MB
+ * of RAM to KERNELBASE.
+ */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r7,KERNELBASE@h
+ bne 4f
+ ori r7,r7,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ b 5f
+4: ori r7,r7,0xff /* set up BAT registers for 604 */
+ li r8,2
+ mtspr DBAT0U,r7
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r7
+ mtspr IBAT0L,r8
+ isync
-_ORG(0x0200)
- b MachineCheck
+/*
+ * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
+ * refer to addresses of data items, procedures, etc. normally.
+ */
+ lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PMAC */
-_ORG(0x0300)
- b DataAccess
-_ORG(0x0400)
- b InstructionAccess
-_ORG(0x0500)
- b HardwareInterrupt
-_ORG(0x0600)
- b Alignment
-
-_ORG(0x0700)
- b ProgramCheck
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-_ORG(0x0800)
- b FloatingPointCheck
+/*
+ * Exception entry code. This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
+ */
+#define EXCEPTION_PROLOG \
+0: mtspr SPRG0,r20; \
+ mtspr SPRG1,r21; \
+ mfcr r20; \
+ mfspr r21,SRR1; /* test whether from user or kernel */\
+ andi. r21,r21,MSR_PR; \
+ mr r21,r1; /* from kernel - use current sp */\
+ beq 1f; \
+ mfspr r21,SPRG3; /* from user - load kernel sp */\
+ lwz r21,KSP(r21); \
+1: addis r21,r21,-KERNELBASE@h; /* convert sp to physical */ \
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+ stw r1,GPR1(r21); \
+ stw r1,0(r21); \
+ addis r1,r21,KERNELBASE@h; /* set new kernel sp */ \
+ stw r20,_CCR(r21); /* save registers */ \
+ stw r22,GPR22(r21); \
+ stw r23,GPR23(r21); \
+ mfspr r20,SPRG0; \
+ stw r20,GPR20(r21); \
+ mfspr r22,SPRG1; \
+ stw r22,GPR21(r21); \
+ mflr r20; \
+ stw r20,_LINK(r21); \
+ mfctr r22; \
+ stw r22,_CTR(r21); \
+ mfspr r20,XER; \
+ stw r20,_XER(r21); \
+ mfspr r22,SRR0; \
+ mfspr r23,SRR1; /* we can now take exceptions */\
+ stw r0,GPR0(r21); \
+ stw r2,GPR2(r21); \
+ SAVE_4GPRS(3, r21);
+/*
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
+ */
-/* Decrementer register - ignored for now... */
+/*
+ * Exception vectors.
+ */
+#define STD_EXCEPTION(n, label, hdlr) \
+ . = n; \
+label: \
+ EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r20,MSR_KERNEL; \
+ bl transfer_to_handler; \
+ .long hdlr; \
+ .long int_return
+
+#ifndef CONFIG_PREP
+/* System reset */
+ STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif /* ndef CONFIG_PREP */
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data access exception */
+ . = 0x300
+DataAccess:
+ EXCEPTION_PROLOG
+ mfspr r20,DSISR
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 1f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: stw r20,_DSISR(r21)
+ mr r5,r20
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* Instruction access exception */
+ . = 0x400
+InstructionAccess:
+ EXCEPTION_PROLOG
+ andis. r0,r23,0x4000 /* no pte found? */
+ beq 1f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r22
+ mr r5,r23
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* External interrupt */
+ STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+
+/* Alignment exception */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long AlignmentException
+ .long int_return
+
+/* Program check exception */
+ . = 0x700
+ProgramCheck:
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long ProgramCheckException
+ .long int_return
+
+/* Floating-point unavailable */
+ . = 0x800
+FPUnavailable:
+ EXCEPTION_PROLOG
+ bne load_up_fpu /* if from user, just load it up */
+ li r20,MSR_KERNEL
+ bl transfer_to_handler /* if from kernel, take a trap */
+ .long KernelFP
+ .long int_return
+
+/* Decrementer */
+#ifdef CONFIG_PREP
+/* - ignored for now... */
_ORG(0x0900)
-/* TRACE_TRAP(0x900) */
- mtspr SPR0,r1
+ mtspr SPRG0,r1
lis r1,0x7FFF
ori r1,r1,0xFFFF
mtspr DEC,r1
- mfspr r1,SPR0
-#if 0
- SYNC
-#endif
+ mfspr r1,SPRG0
rfi
-
-_ORG(0x0A00)
-DEFAULT_TRAP(0x0A00)
-_ORG(0x0B00)
-DEFAULT_TRAP(0x0B00)
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+#endif /* CONFIG_PMAC */
-/*
- * System call
- */
-_ORG(0x0C00)
- b SystemCall
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
+
+/* System call */
+ . = 0xc00
+SystemCall:
+ EXCEPTION_PROLOG
+ stw r3,ORIG_GPR3(r21)
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long DoSyscall
+ .long int_return
-_ORG(0x0D00)
- b SingleStep
+/* Single step - not used on 601 */
+ STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
-_ORG(0x0E00)
-DEFAULT_TRAP(0x0E00)
-_ORG(0x0F00)
-DEFAULT_TRAP(0x0F00)
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
/*
- * Handle TLB Miss on an instruction load
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
*/
-_ORG(0x1000)
-/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
-/* could be a 'trace' in progress when the TLB miss occurs. */
-/* TRACE_TRAP(0x1000) */
- b InstructionTLBMiss
+ . = 0x1000
+InstructionTLBMiss:
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,ICMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,IMISS /* Set to update TLB */
+ mtspr RPA,r1
+ tlbli r0
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne InstructionAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
+InstructionAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ or r2,r2,r1
+ mtspr SRR1,r2
+ mfspr r1,IMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b InstructionAccess
/*
- * Handle TLB Miss on a data item load
+ * Handle TLB miss for DATA Load operation on 603/603e
*/
-_ORG(0x1100)
-/* TRACE_TRAP(0x1100) */
- b DataLoadTLBMiss
+ . = 0x1100
+DataLoadTLBMiss:
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,DCMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,DMISS /* Set to update TLB */
+ mtspr RPA,r1
+ tlbld r0
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne DataAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
+DataAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ mtspr SRR1,r2
+ mfspr r1,DMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b DataAccess
/*
- * Handle TLB Miss on a store operation
+ * Handle TLB miss for DATA Store on 603/603e
*/
-_ORG(0x1200)
-/* TRACE_TRAP(0x1200) */
- b DataStoreTLBMiss
-
-_ORG(0x1300)
-InstructionAddressBreakpoint:
- DEFAULT_TRAP(0x1300)
+ . = 0x1200
+DataStoreTLBMiss:
+ mfctr r0 /* Need to save this - CTR can't be touched! */
+ mfspr r2,HASH1 /* Get PTE pointer */
+ mfspr r3,DCMP /* Partial item compare value */
+00: li r1,8 /* 8 items / bucket */
+ mtctr r1
+ subi r2,r2,8 /* Preset pointer */
+10: lwzu r1,8(r2) /* Get next PTE */
+ cmp 0,r1,r3 /* Found entry yet? */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
+ bne 30f /* Try secondary hash if CTR==0 */
+ lwz r1,4(r2) /* Get second word of entry */
+20: mtctr r0 /* Restore CTR */
+ mfspr r3,SRR1 /* Need to restore CR0 */
+ mtcrf 0x80,r3
+ mfspr r0,DMISS /* Set to update TLB */
+ mtspr RPA,r1
+ tlbld r0
+ rfi /* All done */
+/* Secondary hash */
+30: andi. r1,r3,0x40 /* Already doing secondary hash? */
+ bne DataAddressInvalid /* Yes - item not in hash table */
+ mfspr r2,HASH2 /* Get hash table pointer */
+ ori r3,r3,0x40 /* Set secondary hash */
+ b 00b /* Try lookup again */
-_ORG(0x1400)
-SystemManagementInterrupt:
- DEFAULT_TRAP(0x1400)
+/* Instruction address breakpoint exception (on 603/604) */
+ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+
+/* System management exception (603?) */
+ STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+
+/* Run mode exception */
+ STD_EXCEPTION(0x2000, RunMode, RunModeException)
+
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+ . = 0x3000
-_ORG(0x1500)
+/*
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
+ */
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss */
+ beq 2f
+#ifdef CONFIG_PMAC
+ lwz r24,GPR1(r21)
+ stw r22,LAST_PC(r23)
+ stw r24,USER_STACK(r23)
+#endif /* CONFIG_PMAC */
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ addis r2,r2,KERNELBASE@h
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
/*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode. This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream. Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
+ * Continuation of the floating-point unavailable handler.
*/
-#define NUM_CACHE_LINES 128*4
-#define CACHE_LINE_SIZE 32
-cache_flush_buffer:
- .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
+load_up_fpu:
+ bl giveup_fpu_unmapped
+ ori r23,r23,MSR_FP /* enable use of FP after return */
+ mfspr r5,SPRG3 /* current task's TSS (phys) */
+ lfd fr0,TSS_FPSCR-4(r5)
+ mtfsf 0xff,fr0
+ REST_32FPRS(0, r5)
+
+/* use last_task_used_math instead of fpu_tss */
+ lis r3,last_task_used_math@h/*a*/
+ addis r3,r3,-KERNELBASE@h
+ subi r4,r5,TSS
+ addis r4,r4,KERNELBASE@h
+ stw r4,last_task_used_math@l(r3)
+#if 0
+ lis r3,fpu_tss@ha
+ addis r4,r5,KERNELBASE@h
+ addis r3,r3,-KERNELBASE@h
+ stw r4,fpu_tss@l(r3)
+#endif
+ /* restore registers and return */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ REST_GPR(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used ctr or xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
-#if NUM_CACHE_LINES < 512
-_ORG(0x4000)
-#endif
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r3, and r4 contains access flags:
+ * _PAGE_USER (4) if a user-mode access, ored with
+ * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1,
+ * so bit 1 (0x40000000) is set if the exception was due
+ * to no matching PTE being found in the hash table.
+ * r5 contains the physical address of the current task's tss.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address. Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r2 - r6, ctr, lr.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known. These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0x180000
+Hash_bits = 12 /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+ .globl hash_page
+hash_page:
+ /* Get PTE (linux-style) and check access */
+ lwz r5,PG_TABLES(r5) /* task's page tables */
+ lis r2,-KERNELBASE@h
+ add r5,r5,r2 /* convert to phys addr */
+ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
+ lwz r5,0(r5) /* get pmd entry */
+ rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+ beqlr- /* return if no mapping */
+ add r2,r5,r2
+ rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
+ lwz r6,0(r2) /* get linux-style pte */
+ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
+ andc. r0,r4,r6 /* check access & ~permission */
+ bnelr- /* return if access not permitted */
+ ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
+ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
+ rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */
+ or r6,r6,r5
+ stw r6,0(r2) /* update PTE (accessed/dirty bits) */
+
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r4,r4,0xe04 /* clear out reserved bits */
+ andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */
+
+ /* Construct the high word of the PPC-style PTE */
+ mfsrin r5,r3 /* get segment reg for segment */
+ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
+ oris r5,r5,0x8000 /* set V (valid) bit */
+ rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
+
+ /* Get the address of the primary PTE group in the hash table */
+ .globl hash_page_patch_A
+hash_page_patch_A:
+ lis r4,Hash_base@h /* base address of hash table */
+ rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */
+ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */
+ xor r4,r4,r0 /* make primary hash */
+
+ /* See whether it was a PTE not found exception or a
+ protection violation. */
+ andis. r0,r20,0x4000
+ li r2,8 /* PTEs/group */
+ bne 10f /* no PTE: go look for an empty slot */
+ tlbie r3 /* invalidate TLB entry */
+
+ /* Search the primary PTEG for a PTE whose 1st word matches r5 */
+ mtctr r2
+ addi r3,r4,-8
+1: lwzu r0,8(r3) /* get next PTE */
+ cmp 0,r0,r5
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_slot
+
+ /* Search the secondary PTEG for a matching PTE */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_B
+hash_page_patch_B:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmp 0,r0,r5
+ bdnzf 2,2b
+ beq+ found_slot
+ xori r5,r5,0x40 /* clear H bit again */
+
+ /* Search the primary PTEG for an empty slot */
+10: mtctr r2
+ addi r3,r4,-8 /* search primary PTEG */
+1: lwzu r0,8(r3) /* get next PTE */
+ cmpi 0,r0,0 /* empty? */
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_empty
+
+ /* Search the secondary PTEG for an empty slot */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_C
+hash_page_patch_C:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmpi 0,r0,0
+ bdnzf 2,2b
+ beq+ found_empty
+
+ /* Choose an arbitrary slot in the primary PTEG to overwrite */
+ xori r5,r5,0x40 /* clear H bit again */
+ lwz r2,next_slot@l(0)
+ addi r2,r2,8
+ andi. r2,r2,0x38
+ stw r2,next_slot@l(0)
+ add r3,r4,r2
+
+ /* Store PTE in PTEG */
+found_empty:
+ stw r5,0(r3)
+found_slot:
+ stw r6,4(r3)
+ SYNC
+ /* Return from the exception */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ lwz r5,_CTR(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ mtctr r5
+ REST_GPR(0, r21)
+ REST_2GPRS(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
+next_slot:
+ .long 0
-/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
/*
- * Hardware reset [actually from bootstrap]
- * Initialize memory management & call secondary init
- * Registers initialized by bootstrap:
- * R11: Start of command line string
- * R12: End of command line string
- * R28: Residual data
- * R29: Total Memory Size
- * R30: 'BeBx' if this is a BeBox
- */
-Reset:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* set pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- andc r1,r1,r7
-/* changed to use r3 as residual pointer (as firmware does) -- Cort */
-/* this is only a ptr, the actual data is copied in mmu_init */
- stw r3,0(r1)
-
-/* Copy argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- andc r1,r1,r7 /* No MMU yet - need unmapped address */
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
+ * This is where the main kernel code starts.
+ */
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r1,isBeBox@h
- ori r1,r1,isBeBox@l
- andc r1,r1,r7
-/* See if this is a CPU other than CPU#1 */
-/* This [currently] happens on the BeBox */
- lwz r2,0(r1)
- cmpi 0,r2,0
- bne Reset_BeBox_CPU1
-/* Save machine type indicator */
- li r2,0
- lis r3,IS_BE_BOX>>16
- ori r3,r3,IS_BE_BOX&0xFFFF
- cmp 0,r30,r3
- bne 00f
- li r2,1
- mr r11,r28
- mr r12,r29
- lis r5,BeBox_CPU1_vector@h
- ori r5,r5,BeBox_CPU1_vector@l
- andc r5,r5,r7 /* Tell CPU #1 where to go */
-00: stw r2,0(r1)
- stw r30,4(r1)
-
+start_here:
+ /*
+ * Enable caches and 604-specific features if necessary.
+ */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31
+ cmpi 0,r9,1
+ beq 4f /* not needed for 601 */
+ mfspr r7,HID0
+ andi. r0,r7,HID0_DCE
+ ori r7,r7,HID0_ICE|HID0_DCE
+ ori r8,r7,HID0_ICFI
+ bne 3f /* don't invalidate the D-cache */
+ ori r8,r8,HID0_DCI /* unless it wasn't enabled */
+3: sync
+ mtspr HID0,r8 /* enable and invalidate caches */
+ sync
+ mtspr HID0,r7 /* enable caches */
+ sync
+ isync
+ cmpi 0,r9,4 /* check for 604 */
+ cmpi 1,r9,9 /* or 604e */
+ cror 2,2,6
+ bne 4f
+ ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r7 /* superscalar exec & br history tbl */
+4:
+ /* ptr to current */
+ lis r2,init_task_union@h
+ ori r2,r2,init_task_union@l
+ /* ptr to phys current tss */
+ addis r3,r2,-KERNELBASE@h
+ addi r3,r3,TSS /* init task's TSS */
+ mtspr SPRG3,r3
+ /* stack */
+ addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ stwu r0,-STACK_FRAME_OVERHEAD(r1)
+
+ /* Clear out the BSS */
+ lis r7,_end@ha
+ addi r7,r7,_end@l
+ lis r8,__bss_start@ha
+ addi r8,r8,__bss_start@l
+ subf r7,r8,r7
+ addi r7,r7,3
+ rlwinm. r7,r7,30,2,31
+ beq 2f
+ addi r8,r8,-4
+ mtctr r7
+ li r0,0
+3: stwu r0,4(r8)
+ bdnz 3b
+2:
+/*
+ * Initialize the prom stuff (powermacs only) and the MMU.
+ */
+#ifdef CONFIG_PMAC
+ bl prom_init
+#endif /* CONFIG_PMAC */
+ bl MMU_init
-#if 0
- lis r1,sys_stack@h
- ori r1,r1,sys_stack@l
-#else
- lis r1,init_kernel_stack@h
- ori r1,r1,init_kernel_stack@l
-#endif
- addi r1,r1,0x1000 /* top of stack */
-#if 0
- li r2,0x0FFF /* Mask stack address down to page boundary */
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+ lis r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ rfi
+/* Load up the kernel context */
+2:
+#ifdef CONFIG_PREP
+ /* reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r0)
#endif
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
- mtmsr r0
- lis r3,_edata@h /* Clear BSS */
- ori r3,r3,_edata@l
- andc r3,r3,r7 /* make unmapped address */
- lis r4,_end@h
- ori r4,r4,_end@l
- andc r4,r4,r7 /* make unmapped address */
- subi r3,r3,4
- li r0,0
-00: stwu r0,4(r3)
- cmp 0,r3,r4
- blt 00b
-#if 0
-/* Save total memory size (passed from bootstrap) */
- lis r3,_TotalMemory@h
- ori r3,r3,_TotalMemory@l
- andc r3,r3,r7 /* make unmapped address */
- stw r29,0(r3)
-#endif
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
+
+ SYNC /* Force all PTE updates to finish */
+ tlbia /* Clear all TLB entries */
+ mtspr SDR1,r6
+ li r0,16 /* load up segment register values */
+ mtctr r0 /* for context 0 */
+ lis r3,0x2000 /* Ku = 1, VSID = 0 */
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,1 /* increment VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+#ifdef CONFIG_PMAC
+ li r0,0 /* zot the BATs */
+#if 1
mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
mtspr IBAT0L,r0
+ mtspr DBAT0U,r0
mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
+#endif
mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
mtspr IBAT1L,r0
+ mtspr DBAT1U,r0
mtspr DBAT1L,r0
-/* this BAT mapping will cover all of kernel space */
-#ifdef NEWMM
- lis r3,BAT2@h
- ori r3,r3,BAT2@l
-#else
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
-#endif
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
mtspr IBAT2L,r0
+ mtspr DBAT2U,r0
mtspr DBAT2L,r0
-#if 1
- lis r3,BAT3@h
- ori r3,r3,BAT3@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
mtspr IBAT3U,r0
- mtspr DBAT3U,r0
- lwz r0,4(r3)
mtspr IBAT3L,r0
+ mtspr DBAT3U,r0
mtspr DBAT3L,r0
-#endif
-/* Now we can turn on the MMU */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0000)
- SYNC
- rfi /* enables MMU */
-10: bl _EXTERN(MMU_init) /* initialize MMU environment */
-DO_RFI_TRACE_MAPPED(0xDEAD0100)
-/* Withdraw BAT2->RAM mapping */
- lis r7,0xF000 /* To mask upper 4 bits */
- lis r3,20f@h
- ori r3,r3,20f@l
- andc r3,r3,r7 /* make unmapped address */
- mtspr SRR0,r3
- mfmsr r3
- li r4,MSR_DR|MSR_IR
- andc r3,r3,r4
- mtspr SRR1,r3
- SYNC
-DO_RFI_TRACE_MAPPED(0xDEAD0200)
- SYNC
- rfi
-20:
-
-DO_RFI_TRACE_UNMAPPED(0xDEAD0400)
-20: lis r3,BAT2@h
- ori r3,r3,BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Load up the kernel context */
- lis r2,init_task@h
- ori r2,r2,init_task@l
- addi r2,r2,TSS
- andc r2,r2,r7 /* make unmapped address */
- SYNC /* Force all PTE updates to finish */
- tlbia /* Clear all TLB entries */
- lis r3,_SDR1@h
- ori r3,r3,_SDR1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r3,0(r3)
- mtspr SDR1,r3
- lwz r0,MMU_SEG0(r2)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r2)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r2)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r2)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r2)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r2)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r2)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r2)
- mtsr SR7,r0
- lwz r0,MMU_SEG8(r2)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r2)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r2)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r2)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r2)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r2)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r2)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r2)
- mtsr SR15,r0
+#endif
/* Now turn on the MMU for real! */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,30f@h
- ori r3,r3,30f@l
+ li r4,MSR_KERNEL
+ lis r3,start_kernel@h
+ ori r3,r3,start_kernel@l
mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0500)
- SYNC
- rfi /* enables MMU */
-30:
-/* Turn on L1 Data Cache */
- mfspr r3,HID0 /* Caches are controlled by this register */
- ori r4,r3,(HID0_ICE|HID0_ICFI)
- ori r3,r3,(HID0_ICE)
- ori r4,r4,(HID0_DCE|HID0_DCI)
- ori r3,r3,(HID0_DCE)
- sync
- mtspr HID0,r4
- mtspr HID0,r3
-/* L1 cache enable */
- mfspr r2,PVR /* Check for 603/603e */
- srwi r2,r2,16
- cmpi 0,r2,4 /* 604 */
- bne 40f
- mfspr r3,HID0 /* Turn on 604 specific features */
- ori r3,r3,(HID0_SIED|HID0_BHTE)
- mtspr HID0,r3
-40: b _EXTERN(start_kernel) /* call main code */
- .long 0 # Illegal!
+ mtspr SRR1,r4
+ rfi /* enable MMU and jump to start_kernel */
+#ifdef CONFIG_PREP
/*
- * BeBox CPU #2 runs here
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader. The expected layout
+ * of the regs is:
+ * R3: End of image
+ * R4: Start of image - 0x400
+ * R11: Start of command line string
+ * R12: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
*/
-Reset_BeBox_CPU1:
- lis r1,CPU1_stack@h
- ori r1,r1,CPU1_stack@l
- li r2,0x0FFF /* Mask stack address down to page boundary */
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- andc r30,r30,r7
- li r5,1
- stw r5,0(r30)
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
+ .globl __start
+__start:
+ .globl _start
+_start:
+ lis r7,0xF000 /* To mask upper 4 bits */
+/* save pointer to residual data */
+ lis r1,resptr@h
+ ori r1,r1,resptr@l
+ addis r1,r1,-KERNELBASE@h
+ stw r3,0(r1)
+/* save argument string */
+ li r0,0 /* Null terminate string */
+ stb r0,0(r12)
+ lis r1,cmd_line@h
+ ori r1,r1,cmd_line@l
+ addis r1,r1,-KERNELBASE@h
+ subi r1,r1,1
+ subi r11,r11,1
+00: lbzu r0,1(r11)
+ cmpi 0,r0,0
+ stbu r0,1(r1)
+ bne 00b
+/* setup the msr with sane values */
+ li r0,MSR_
mtmsr r0
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
- mtspr IBAT0L,r0
- mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
- mtspr IBAT1L,r0
- mtspr DBAT1L,r0
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Now we can turn on the MMU */
+/* turn on the mmu with bats covering kernel enough to get started */
+ LOAD_BATS(r3,r0)
mfmsr r3
ori r3,r3,MSR_DR|MSR_IR
mtspr SRR1,r3
lis r3,10f@h
ori r3,r3,10f@l
mtspr SRR0,r3
- li r5,2
- stw r5,0(r30)
SYNC
rfi /* enables MMU */
-10:
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- li r5,3
- stw r5,0(r30)
- bl _EXTERN(BeBox_CPU1)
-
-/*
- * Machine Check (Bus Errors, etc)
- */
-MachineCheck:
- TRACE_TRAP(0x0200)
- SAVE_INT_REGS(0x0200)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(MachineCheckException)
- RETURN_FROM_INT(0x0200)
-
-/*
- * Data Access exception
- */
-DataAccess:
- SAVE_INT_REGS(0x0300)
-#if 1
- mfspr r3, DAR
- mfspr r4, DSISR
- li r5, 0 /* not a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(DataAccessException)
-#endif
- RETURN_FROM_INT(0x0300)
-
-/*
- * Instruction Access Exception
- */
-InstructionAccess:
- SAVE_INT_REGS(0x0400)
-#if 1
- mfspr r3, SPR2 /* srr0 was saved here */
- mfspr r4, SPR3 /* srr1 was saved here */
- li r5, 1 /* a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(InstructionAccessException)
-#endif
- RETURN_FROM_INT(0x0400)
-
-/*
- * Hardware Interrupt
- */
-HardwareInterrupt:
- SAVE_INT_REGS(0x0500)
- BUMP(__Hardware_Interrupts)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(handle_IRQ)
- RETURN_FROM_INT(0x0500)
-
-/*
- * Alignment
- */
-Alignment:
- TRACE_TRAP(0x0600)
- SAVE_INT_REGS(0x0600)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(AlignmentException)
- RETURN_FROM_INT(0x0600)
-
+10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PREP */
+
/*
- * Illegal instruction
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
*/
-ProgramCheck:
- TRACE_TRAP(0x0700)
- SAVE_INT_REGS(0x0700)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(ProgramCheckException)
- RETURN_FROM_INT(0x0700)
+KernelFP:
+ lwz r3,_MSR(r1)
+ ori r3,r3,MSR_FP
+ stw r3,_MSR(r1) /* enable use of FP after return */
+ lis r3,86f@h
+ ori r3,r3,86f@l
+ mr r4,r2 /* current */
+ lwz r5,_NIP(r1)
+ bl printk
+ b int_return
+86: .string "floating point used in kernel (task=%p, pc=%x)\n"
+ .align 4
/*
- * Single Step Exception
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * (If giveup_fpu_unmapped uses any integer registers other than
+ * r3 - r6, the return code at load_up_fpu above will have
+ * to be adjusted.)
*/
-SingleStep:
- SAVE_INT_REGS(0x0D00)
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(SingleStepException)
-#if 0
- bl _EXTERN(flush_instruction_cache)
+giveup_fpu_unmapped:
+ lis r6,-KERNELBASE@h
+ b 1f
+
+ .globl giveup_fpu
+giveup_fpu:
+ li r6,0
+1:
+ addis r3,r6,last_task_used_math@h/*a*/
+ lwz r4,last_task_used_math@l(r3)
+#if 0
+ addis r3,r6,fpu_tss@ha
+ lwz r4,fpu_tss@l(r3)
#endif
- RETURN_FROM_INT(0x0D00)
-
-/*
- * Floating point [not available, etc]
- */
-FloatingPointCheck:
- SAVE_INT_REGS(0x0800)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(FloatingPointCheckException)
- cmpi 0,r3,MSR_FP /* check if fp was turned on by handler */
- bne 00f
- RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
-00: RETURN_FROM_INT(0x0200)
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+ cmpi 0,r4,0
+ add r4,r4,r6
+ beqlr /* if no previous owner, done */
+ addi r4,r4,TSS /* want TSS of last_task_used_math */
+ li r5,0
+ stw r5,last_task_used_math@l(r3)
+#if 0
+ stw r5,fpu_tss@l(r3)
+#endif
+ SAVE_32FPRS(0, r4)
+ mffs fr0
+ stfd fr0,TSS_FPSCR-4(r4)
+ lwz r5,PT_REGS(r4)
+ lwz r5,PT_REGS(r4)
+ add r5,r5,r6
+ lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r4,MSR_FP
+ andc r3,r3,r4 /* disable FP for previous task */
+ stw r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ blr
/*
- * System Call exception
+ * Handle a system call.
*/
-SystemCall:
- SAVE_INT_REGS(0x0C00)
- lwz r2,_CCR(r1) /* Clear SO bit in CR */
- lis r9,0x1000
- andc r2,r2,r9
- stw r2,_CCR(r1)
+DoSyscall:
+ stw r0,TSS+LAST_SYSCALL(r2)
+ lwz r11,_CCR(r1) /* Clear SO bit in CR */
+ lis r10,0x1000
+ andc r11,r11,r10
+ stw r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ lis r31,show_syscalls_task@ha
+ lwz r31,show_syscalls_task@l(r31)
+ cmp 0,r2,r31
+ bne 1f
+#endif
+ lis r3,7f@ha
+ addi r3,r3,7f@l
+ lwz r4,GPR0(r1)
+ lwz r5,GPR3(r1)
+ lwz r6,GPR4(r1)
+ lwz r7,GPR5(r1)
+ lwz r8,GPR6(r1)
+ mr r9,r2
+ bl printk
+ lwz r0,GPR0(r1)
+ lwz r3,GPR3(r1)
+ lwz r4,GPR4(r1)
+ lwz r5,GPR5(r1)
+ lwz r6,GPR6(r1)
+ lwz r7,GPR7(r1)
+ lwz r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
- bne+ 10f
- mr r3,r1
- bl _EXTERN(sys_sigreturn)
- cmpi 0,r3,0 /* Check for restarted system call */
- bge 99f
- b 20f
-10: lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- lwz r2,TASK_FLAGS(r2)
- andi. r2,r2,PF_TRACESYS
- bne 50f
-
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
+ beq- 10f
+ lwz r10,TASK_FLAGS(r2)
+ andi. r10,r10,PF_TRACESYS
+ bne- 50f
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
-#if 1
- cmpi 0,r2,0 /* make sure syscall handler not 0 */
- beq 99f
- cmpi 0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
- bgt 99f
-#endif
- mtlr r2
- mr r9,r1
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
blrl /* Call handler */
-
-20: stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 30f
+ .globl syscall_ret_1
+syscall_ret_1:
+20: stw r3,RESULT(r1) /* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ cmp 0,r2,r31
+ bne 91f
+#endif
+ mr r4,r3
+ lis r3,79f@ha
+ addi r3,r3,79f@l
+ bl printk
+ lwz r3,RESULT(r1)
+91:
+#endif
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 30f
neg r3,r3
cmpi 0,r3,ERESTARTNOHAND
bne 22f
li r3,EINTR
-22: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
+22: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
30: stw r3,GPR3(r1) /* Update return value */
- b 99f
+ b int_return
+66: li r3,ENOSYS
+ b 22b
+/* sys_sigreturn */
+10: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(sys_sigreturn)
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge int_return
+ b 20b
/* Traced system call support */
50: bl _EXTERN(syscall_trace)
lwz r0,GPR0(r1) /* Restore original registers */
lwz r7,GPR7(r1)
lwz r8,GPR8(r1)
lwz r9,GPR9(r1)
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
- mtlr r2
- mr r9,r1
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
blrl /* Call handler */
+ .globl syscall_ret_2
+syscall_ret_2:
stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 60f
+ stw r3,GPR0(r1) /* temporary gross hack to make strace work */
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 60f
neg r3,r3
cmpi 0,r3,ERESTARTNOHAND
bne 52f
li r3,EINTR
-52: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
+52: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
60: stw r3,GPR3(r1) /* Update return value */
bl _EXTERN(syscall_trace)
-99:
- RETURN_FROM_INT(0x0C00)
-
-/*
- * Handle TLB miss for instruction
- */
-InstructionTLBMiss:
- BUMP_UNMAPPED(__Instruction_TLB_Misses)
- mfctr r0 /* Need to save this - CTR can't be touched! */
- mfspr r2,HASH1 /* Get PTE pointer */
- mfspr r3,ICMP /* Partial item compare value */
-00: li r1,8 /* 8 items / bucket */
- mtctr r1
- subi r2,r2,8 /* Preset pointer */
-10: lwzu r1,8(r2) /* Get next PTE */
- cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
- bne 30f /* Try secondary hash if CTR==0 */
- lwz r1,4(r2) /* Get second word of entry */
-#if 0
- andi. r3,r1,0x08 /* Check guard bit - invalid access if set */
- bne InstructionFetchError
-#endif
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- bne 20f /* If set, all done */
- ori r1,r1,0x100 /* Set bit */
- stw r1,4(r2) /* Update memory image */
-20: mtctr r0 /* Restore CTR */
- mfspr r3,SRR1 /* Need to restore CR0 */
- mtcrf 0x80,r3
- mfspr r0,IMISS /* Set to update TLB */
- mtspr RPA,r1
- tlbli r0
-#if 0
- SYNC
+ b int_return
+66: li r3,ENOSYS
+ b 52b
+#ifdef SHOW_SYSCALLS
+7: .string "syscall %d(%x, %x, %x, %x), current=%p\n"
+79: .string " -> %x\n"
+ .align 2
#endif
- rfi /* All done */
-/* Secondary hash */
-30: andi. r1,r3,0x40 /* Already doing secondary hash? */
- bne InstructionAddressInvalid /* Yes - item not in hash table */
- mfspr r2,HASH2 /* Get hash table pointer */
- ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
/*
- * Handle TLB miss for DATA Load operation
+ * This routine switches between two different tasks. The process
+ * state of one is saved on its kernel stack. Then the state
+ * of the other is restored from its kernel stack. The memory
+ * management hardware is updated to the second process's state.
+ * Finally, we can return to the second process, via int_return.
+ * On entry, r3 points to the TSS for the current task, r4
+ * points to the TSS for the new task, and r5 contains the
+ * MMU context number for the new task.
+ *
+ * Note: there are two ways to get to the "going out" portion
+ * of this code; either by coming in via the entry (_switch)
+ * or via "fork" which must set up an environment equivalent
+ * to the "_switch" path. If you change this (or in particular, the
+ * SAVE_REGS macro), you'll have to change the fork code also.
+ *
+ * The code which creates the new task context is in 'copy_thread'
+ * in arch/ppc/kernel/process.c
*/
-DataLoadTLBMiss:
- mfctr r0 /* Need to save this - CTR can't be touched! */
- mfspr r2,HASH1 /* Get PTE pointer */
- mfspr r3,DCMP /* Partial item compare value */
-00: li r1,8 /* 8 items / bucket */
- mtctr r1
- subi r2,r2,8 /* Preset pointer */
-10: lwzu r1,8(r2) /* Get next PTE */
- cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
- bne 30f /* Try secondary hash if CTR==0 */
- lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- ori r1,r1,0x100 /* Set bit */
- bne 20f /* If set, all done */
- stw r1,4(r2) /* Update memory image */
-20: mtctr r0 /* Restore CTR */
- mfspr r3,SRR1 /* Need to restore CR0 */
- mtcrf 0x80,r3
- mfspr r0,DMISS /* Set to update TLB */
- mtspr RPA,r1
-/* SYNC() */
- tlbld r0
-#if 0
+_GLOBAL(_switch)
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,GPR0(r1)
+ lwz r0,0(r1)
+ stw r0,GPR1(r1)
+ SAVE_10GPRS(2, r1)
+ SAVE_10GPRS(12, r1)
+ SAVE_10GPRS(22, r1)
+ mflr r20 /* Return to switch caller */
+ mfmsr r22
+ li r0,MSR_FP /* Disable floating-point */
+ andc r22,r22,r0
+ stw r20,_NIP(r1)
+ stw r22,_MSR(r1)
+ stw r20,_LINK(r1)
+ mfcr r20
+ mfctr r22
+ mfspr r23,XER
+ stw r20,_CCR(r1)
+ stw r22,_CTR(r1)
+ stw r23,_XER(r1)
+ li r0,0x0ff0
+ stw r0,TRAP(r1)
+ stw r1,KSP(r3) /* Set old stack pointer */
+ sync
+ addis r0,r4,-KERNELBASE@h
+ mtspr SPRG3,r0 /* Update current TSS phys addr */
+ SYNC
+ lwz r1,KSP(r4) /* Load new stack pointer */
+ addi r2,r4,-TSS /* Update current */
+ /* Set up segment registers for new task */
+ rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
+ addis r5,r5,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r3,0
+3: mtsrin r5,r3
+ addi r5,r5,1 /* next VSID */
+ addis r3,r3,0x1000 /* address of next segment */
+ bdnz 3b
SYNC
-#endif
- rfi /* All done */
-/* Secondary hash */
-30: andi. r1,r3,0x40 /* Already doing secondary hash? */
- bne DataAddressInvalid /* Yes - item not in hash table */
- mfspr r2,HASH2 /* Get hash table pointer */
- ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
+
+/* FALL THROUGH into int_return */
/*
- * Handle TLB miss for DATA STORE
+ * Trap exit.
*/
-DataStoreTLBMiss:
- BUMP_UNMAPPED(__DataStore_TLB_Misses)
- mfctr r0 /* Need to save this - CTR can't be touched! */
- mfspr r2,HASH1 /* Get PTE pointer */
- mfspr r3,DCMP /* Partial item compare value */
-00: li r1,8 /* 8 items / bucket */
- mtctr r1
- subi r2,r2,8 /* Preset pointer */
-10: lwzu r1,8(r2) /* Get next PTE */
- cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
- bne 30f /* Try secondary hash if CTR==0 */
- lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x80 /* Check C bit (changed) */
-#if 0 /* Note: no validation */
- beq 40f /* If not set (first time) validate access */
-#else
- ori r1,r1,0x180 /* Set changed, accessed */
- bne 20f
- stw r1,4(r2)
-#endif
-20: mtctr r0 /* Restore CTR */
- mfspr r3,SRR1 /* Need to restore CR0 */
- mtcrf 0x80,r3
- mfspr r0,DMISS /* Set to update TLB */
- mtspr RPA,r1
- tlbld r0
-#if 0
+ .globl int_return
+int_return:
+0: mfmsr r30 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r30,r30,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r30
SYNC
-#endif
- rfi /* All done */
-/* Secondary hash */
-30: andi. r1,r3,0x40 /* Already doing secondary hash? */
- bne DataAddressInvalid /* Yes - item not in hash table */
- mfspr r2,HASH2 /* Get hash table pointer */
- ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
-/* PTE found - validate access */
-40: rlwinm. r3,r1,30,0,1 /* Extract PP bits */
- bge- 50f /* Jump if PP=0,1 */
- andi. r3,r1,1
- beq+ 70f /* Access OK */
- b WriteProtectError /* Not OK - fail! */
-50: mfspr r3,SRR1 /* Check privilege */
+ lwz r5,_MSR(r1)
+ and. r5,r5,r4
+ beq 2f
+3: lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ beq+ 1f
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ b 3b
+1: lis r4,bh_mask@ha
+ lwz r4,bh_mask@l(r4)
+ lis r5,bh_active@ha
+ lwz r5,bh_active@l(r5)
+ and. r4,r4,r5
+ beq+ 2f
+ ori r31,r30,MSR_EE /* re-enable interrupts */
+ SYNC
+ mtmsr r31
+ SYNC
+ bl _EXTERN(do_bottom_half)
+ SYNC
+ mtmsr r30 /* disable interrupts again */
+ SYNC
+2: lwz r3,_MSR(r1) /* Returning to user mode? */
andi. r3,r3,MSR_PR
- beq+ 60f /* Jump if supervisor mode */
- mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x2000 /* If Kp==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-60: mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x4000 /* If Ks==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-70: ori r1,r1,0x180 /* Set changed, accessed */
- stw r1,4(r2) /* Update PTE in memory */
- b 20b
-
+ beq+ 10f /* no - no need to mess with stack */
+ lis r3,need_resched@ha
+ lwz r3,need_resched@l(r3)
+ cmpi 0,r3,0 /* check need_resched flag */
+ beq+ 7f
+ bl _EXTERN(schedule)
+ b 0b
+7: lwz r3,BLOCKED(r2) /* Check for pending unblocked signals */
+ lwz r5,SIGNAL(r2)
+ andc. r0,r5,r3 /* Lets thru any unblocked */
+ beq+ 8f
+ addi r4,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(do_signal)
+ b 0b
+8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
+ stw r4,TSS+KSP(r2) /* save kernel stack pointer */
+10:
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
/*
- * These routines are error paths/continuations of the exception
- * handlers above. They are placed here to avoid the problems
- * of only 0x100 bytes per exception handler.
+ * Fake an interrupt from kernel mode.
+ * This is used when enable_irq loses an interrupt.
+ * We only fill in the stack frame minimally.
*/
-
-/* Invalid address */
-InstructionAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
-
-/* Fetch from guarded or no-access page */
-InstructionFetchError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,IMISS /* Get failing address */
- rlwinm. r2,r2,0,31,31 /* Check for little endian access */
- beq 20f /* Jump if big endian */
- xori r1,r1,3
-20: mtspr DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b InstructionAccess
-
-/* Invalid address */
-DataAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
+_GLOBAL(fake_interrupt)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,_NIP(r1)
+ stw r0,_LINK(r1)
+ mfmsr r3
+ stw r3,_MSR(r1)
+ li r0,0x0fac
+ stw r0,TRAP(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ lwz r0,4(r1)
+ mtlr r0
+ blr
-/* Write to read-only space */
-WriteProtectError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,DMISS /* Get failing address */
- rlwinm. r2,r2,0,31,31 /* Check for little endian access */
- beq 20f /* Jump if big endian */
- xori r1,r1,3
-20: mtspr DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b DataAccess
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+ rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
+ addis r3,r3,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,1 /* next VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+ SYNC
+ blr
/*
- * Flush instruction cache
- * *** I'm really paranoid here!
+ * Flush instruction cache.
+ * This is a no-op on the 601.
*/
_GLOBAL(flush_instruction_cache)
- mflr r5
- bl _EXTERN(flush_data_cache)
- mfspr r3,HID0 /* Caches are controlled by this register */
- li r4,0
- ori r4,r4,(HID0_ICE|HID0_ICFI)
- or r3,r3,r4 /* Need to enable+invalidate to clear */
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmpi 0,r3,1
+ beqlr /* for 601, do nothing */
+ /* 603/604 processor - use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
mtspr HID0,r3
- andc r3,r3,r4
- ori r3,r3,HID0_ICE /* Enable cache */
- mtspr HID0,r3
- mtlr r5
+ SYNC
blr
/*
- * Flush data cache
- * *** I'm really paranoid here!
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * store_cache_range(unsigned long start, unsigned long stop)
*/
-_GLOBAL(flush_data_cache)
- BUMP(__Cache_Flushes)
- lis r3,cache_is_copyback@ha
- lwz r3,cache_is_copyback@l(r3)
- cmpi 0,r3,0
- beq 10f
-/* When DATA CACHE is copy-back */
- lis r3,cache_flush_buffer@h
- ori r3,r3,cache_flush_buffer@l
- li r4,NUM_CACHE_LINES
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+_GLOBAL(store_cache_range)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
mtctr r4
-00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
- addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
- bdnz 00b
-10: blr
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync
+ isync
+ blr
/*
* Flush a particular page from the DATA cache
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
- * void flush_page(void *page)
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ * void flush_page_to_ram(void *page)
*/
-_GLOBAL(flush_page)
+_GLOBAL(flush_page_to_ram)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
li r4,0x0FFF
andc r3,r3,r4 /* Get page base address */
li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
mtctr r4
-00: dcbf 0,r3 /* Clear line */
- icbi 0,r3
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
addi r3,r3,CACHE_LINE_SIZE
- bdnz 00b
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
blr
/*
- * This routine switches between two different tasks. The process
- * state of one is saved on its kernel stack. Then the state
- * of the other is restored from its kernel stack. The memory
- * management hardware is updated to the second process's state.
- * Finally, we can return to the second process, via the 'return'.
- *
- * Note: there are two ways to get to the "going out" portion
- * of this code; either by coming in via the entry (_switch)
- * or via "fork" which must set up an environment equivalent
- * to the "_switch" path. If you change this (or in particular, the
- * SAVE_ALL_REGS macro), you'll have to change the fork code also.
+ * Flush entries from the hash table with VSIDs in the range
+ * given.
+ */
+_GLOBAL(flush_hash_segments)
+ rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
+ oris r3,r3,0x8000 /* set V bit */
+ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
+ oris r4,r4,0x8000
+ ori r4,r4,0x7f
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
+ lis r6,Hash_size@ha
+ lwz r6,Hash_size@l(r6) /* size in bytes */
+ srwi r6,r6,3 /* # PTEs */
+ mtctr r6
+ addi r5,r5,-8
+ li r0,0
+1: lwzu r6,8(r5) /* get next tag word */
+ cmplw 0,r6,r3
+ cmplw 1,r6,r4
+ cror 0,0,5 /* set cr0.lt if out of range */
+ blt 2f /* branch if out of range */
+ stw r0,0(r5) /* invalidate entry */
+2: bdnz 1b /* continue with loop */
+ sync
+ tlbia
+ isync
+ blr
+
+/*
+ * Flush the entry for a particular page from the hash table.
*
- * The code which creates the new task context is in 'copy_thread'
- * in arch/ppc/kernel/process.c
- */
-_GLOBAL(_switch)
- mtspr SPR0,r1 /* SAVE_ALL_REGS prologue */
- mtspr SPR1,r2
- mflr r2 /* Return to switch caller */
- mtspr SPR2,r2
- mfmsr r2
- mtspr SPR3,r2
- SAVE_ALL_REGS(0x0FF0)
- SAVE_FP_REGS()
- CHECK_STACK()
- SYNC()
- stw r1,KSP(r3) /* Set old stack pointer */
- BUMP(__Context_Switches)
- lwz r1,KSP(r4) /* Load new stack pointer */
- lwz r0,MMU_SEG0(r4)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r4)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r4)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r4)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r4)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r4)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r4)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r4)
- mtsr SR7,r0
-#if 0
- /* segs 8-15 are shared by everyone -- don't need to be changed */
- lwz r0,MMU_SEG8(r4)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r4)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r4)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r4)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r4)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r4)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r4)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r4)
- mtsr SR15,r0
-#endif
- /* no need to invalidate tlb since each process has a distinct
- set of vsid's. -- Cort */
-#if 0
- tlbia /* Invalidate entire TLB */
- BUMP(__TLBIAs)
-#endif
- /* p5.2 603 users manual - with addr transl. enabled,
- the memory access is performed under the control of
- the page table entry. I interpret this to mean that
- it is tagged with the vsid -- so no need to flush here
- since each process has a distinct set of vsid's.
- Of course, my intepretation may be wrong.
- -- Cort */
- /*bl _EXTERN(flush_instruction_cache)*/
- RETURN_FROM_INT(0x0f0f)
-
+ * flush_hash_page(unsigned context, unsigned long va)
+ */
+_GLOBAL(flush_hash_page)
+ rlwinm r3,r3,11,1,20 /* put context into vsid */
+ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
+ oris r3,r3,0x8000 /* set V (valid) bit */
+ rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */
+ rlwinm r7,r4,32-6,10,25 /* get page index << 6 */
+ rlwinm r5,r3,32-1,7,25 /* vsid << 6 */
+ xor r7,r7,r5 /* primary hash << 6 */
+ lis r5,Hash_mask@ha
+ lwz r5,Hash_mask@l(r5) /* hash mask */
+ slwi r5,r5,6 /* << 6 */
+ and r7,r7,r5
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
+ add r6,r6,r7 /* address of primary PTEG */
+ li r8,8
+ mtctr r8
+ addi r7,r6,-8
+1: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */
+ beq 3f /* if we found it */
+ ori r3,r3,0x40 /* set H (alt. hash) bit */
+ xor r6,r6,r5 /* address of secondary PTEG */
+ mtctr r8
+ addi r7,r6,-8
+2: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */
+ bne 4f /* if we didn't find it */
+3: li r0,0
+ stw r0,0(r7) /* invalidate entry */
+4: sync
+ tlbie r4 /* in hw tlb too */
+ isync
+ blr
/*
* This routine is just here to keep GCC happy - sigh...
_GLOBAL(__main)
blr
+#ifdef CONFIG_PMAC
+/*
+ * These exception handlers are used when we have called a prom
+ * routine after we have taken over the exception vectors and MMU.
+ */
+ .globl prom_exc_table
+prom_exc_table:
+ .long TOPHYS(prom_exception) /* 0 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+
+/*
+ * When we come in to these prom exceptions, r1 and lr have been
+ * saved in sprg1 and sprg2, and lr points to a word containing
+ * the vector offset.
+ */
+prom_exception:
+ mr r1,r21 /* save r21 */
+ lis r21,prom_sp@ha /* get a stack to use */
+ addis r21,r21,-KERNELBASE@h
+ lwz r21,prom_sp@l(r21)
+ addis r21,r21,-KERNELBASE@h /* convert to physical addr */
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r0,GPR0(r21)
+ stw r2,GPR2(r21)
+ stw r3,GPR3(r21)
+ stw r4,GPR4(r21)
+ stw r5,GPR5(r21)
+ stw r6,GPR6(r21)
+ stw r20,GPR20(r21)
+ stw r1,GPR21(r21)
+ stw r22,GPR22(r21)
+ stw r23,GPR23(r21)
+ mfspr r1,SPRG1
+ stw r1,GPR1(r21)
+ mfcr r3
+ mfspr r4,SPRG2
+ stw r3,_CCR(r21)
+ stw r4,_LINK(r21)
+ mfctr r3
+ mfspr r4,XER
+ stw r3,_CTR(r21)
+ stw r4,_XER(r21)
+ mfspr r22,SRR0
+ mfspr r23,SRR1
+
+ /* at this point we have set things up pretty much exactly
+ how EXCEPTION_PROLOG does */
+ mflr r3
+ lwz r3,0(r3) /* get exception vector */
+ stw r3,TRAP(r21)
+ cmpi 0,r3,0x300 /* was it a dsi? */
+ bne 1f
+
+ mfspr r20,DSISR /* here on data access exc. */
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 3f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ b 2f
+
+1: cmpi 0,r3,0x400 /* was it an isi? */
+ bne 3f
+ andis. r0,r23,0x4000 /* if so, check if no pte found */
+ beq 3f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+2: lis r5,prom_tss@ha /* phys addr of TSS */
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ bl hash_page
+
+3: addis r1,r21,KERNELBASE@h /* restore kernel stack ptr */
+ addi r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r3,0(r21) /* set stack chain pointer */
+ lis r5,prom_tss@ha
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ mtspr SPRG3,r5 /* reset phys TSS pointer */
+ lwz r4,TRAP(r21) /* the real exception vector */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ bl transfer_to_handler
+ .long PromException
+ .long prom_int_return
+
+ .comm prom_sp,4
+ .comm prom_tss,4
+
+ .globl prom_int_return
+prom_int_return:
+ lis r3,prom_exc_table@ha /* restore sprg3 for prom vectors */
+ addi r3,r3,prom_exc_table@l
+ addis r3,r3,-KERNELBASE@h
+ mtspr SPRG3,r3
+ b int_return
+
+/*
+ * When entering the prom, we have to change to using a different
+ * set of exception vectors.
+ */
+ .globl enter_prom
+enter_prom:
+ stwu r1,-32(r1)
+ mflr r0
+ stw r0,36(r1)
+ stw r29,20(r1)
+ stw r30,24(r1)
+ stw r31,28(r1)
+ lis r8,prom_entry@ha
+ lwz r8,prom_entry@l(r8)
+ mfmsr r31
+ andi. r0,r31,MSR_IP /* using our own vectors yet? */
+ beq 1f /* if so, have to switch */
+ mtlr r8
+ blrl /* if not, can just charge ahead */
+ b 2f
+1: lis r9,prom_sp@ha /* save sp for exception handler */
+ stw r1,prom_sp@l(r9)
+ mfspr r29,SPRG3 /* save physical tss pointer */
+ lis r9,prom_tss@ha
+ stw r29,prom_tss@l(r9)
+ li r9,0
+ ori r9,r9,MSR_EE
+ andc r30,r31,r9
+ lis r9,prom_exc_table@ha /* set pointer to exception table */
+ addi r9,r9,prom_exc_table@l
+ addis r9,r9,-KERNELBASE@h
+ ori r0,r31,MSR_IP
+ sync
+ mtmsr r30 /* disable interrupts */
+ mtspr SPRG3,r9 /* while we update MSR_IP and sprg3 */
+ sync
+ mtmsr r0 /* start using exc. vectors in prom */
+ mtlr r8
+ blrl /* call prom */
+ sync
+ mtmsr r30 /* disable interrupts again */
+ mtspr SPRG3,r29 /* while we restore MSR_IP and sprg3 */
+ sync
+ mtmsr r31 /* reenable interrupts */
+2: lwz r0,36(r1)
+ mtlr r0
+ lwz r29,20(r1)
+ lwz r30,24(r1)
+ lwz r31,28(r1)
+ lwz r1,0(r1)
+ blr
+#endif
+
+/*
+ * We put a few things here that have to be page-aligned.
+ * This stuff goes at the beginning of the data segment,
+ * which is page-aligned.
+ */
.data
.globl sdata
sdata:
.space 2*4096
-
-#if 0
-_GLOBAL(sys_stack)
-sys_stack:
- .space 4096
-#endif
-CPU1_stack:
-
.globl empty_zero_page
empty_zero_page:
.space 4096
swapper_pg_dir:
.space 4096
+#ifdef CONFIG_PREP
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
.globl cmd_line
cmd_line:
.space 512
-
-#ifdef STATS
-/*
- * Miscellaneous statistics - gathered just for performance info
- */
- .globl _INTR_stats
-_INTR_stats:
- .globl __Instruction_TLB_Misses
-__Instruction_TLB_Misses:
- .long 0,0 /* Instruction TLB misses */
- .globl __DataLoad_TLB_Misses
-__DataLoad_TLB_Misses:
- .long 0,0 /* Data [load] TLB misses */
- .globl __DataStore_TLB_Misses
-__DataStore_TLB_Misses:
- .long 0,0 /* Data [store] TLB misses */
- .globl __Instruction_Page_Faults
-__Instruction_Page_Faults:
- .long 0,0 /* Instruction page faults */
- .globl __Data_Page_Faults
-__Data_Page_Faults:
- .long 0,0 /* Data page faults */
- .globl __Cache_Flushes
-__Cache_Flushes:
- .long 0,0 /* Explicit cache flushes */
- .globl __Context_Switches
-__Context_Switches:
- .long 0,0 /* Context switches */
- .globl __Hardware_Interrupts
-__Hardware_Interrupts:
- .long 0,0 /* I/O interrupts (disk, timer, etc) */
- .globl __TLBIAs
- .globl __TLBIAs
-__TLBIAs:
- .long 0,0 /* TLB cache forceably flushed */
- .globl __TLBIEs
-__TLBIEs:
- .long 0,0 /* Specific TLB entry flushed */
-#endif
-
- .globl _TotalMemory
-_TotalMemory:
- .long 0,0
-
-/*
- * This location is used to break any outstanding "lock"s when
- * changing contexts.
- */
-_break_lwarx: .long 0
-
+#endif /* CONFIG_PREP */
/*
- * linux/arch/ppc/kernel/irq.c
+ * arch/ppc/kernel/irq.c
*
- * Copyright (C) 1992 Linus Torvalds
- * Adapted from arch/i386 by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Power Macintosh version
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from arch/i386/kernel/irq.c
+ * Copyright (C) 1992 Linus Torvalds
+ * Adapted from arch/i386 by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*/
-
+
/*
* IRQ's are in fact implemented a bit like signal handlers for the kernel.
* Naturally it's not a 1:1 relation, but there are similarities.
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-inline int get_irq_list(char *);
-void check_irq(void);
-void BeBox_CPU1(void);
-void BeBox_state(void);
-int BeBox_irq(void);
-void show_BeBox_state(void);
-void BeBox_enable_irq(int );
-void BeBox_disable_irq(int );
-void BeBox_init_IRQ(void);
-void _do_bottom_half(void);
-static _NOP(void);
-static _delay(void);
-void hard_disk_LED(int state);
+#define IRQ_FLAG ((unsigned *)0xf3000020)
+#define IRQ_ENABLE ((unsigned *)0xf3000024)
+#define IRQ_ACK ((unsigned *)0xf3000028)
+#define IRQ_LEVEL ((unsigned *)0xf300002c)
+
+#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
+#undef SHOW_IRQ 1
-#define SHOW_IRQ
-#undef SHOW_IRQ
+unsigned lost_interrupts = 0;
+
+unsigned int local_irq_count[NR_CPUS];
+static struct irqaction irq_action[32];
/*
- * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
- * and 16..31 for other BeBox motherboard type interrupts.
+ * This contains the irq mask for both irq controllers
*/
-
-unsigned long isBeBox[];
-unsigned char *BeBox_IO_page;
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21 (((char *)(&cached_irq_mask))[0])
+#define cached_A1 (((char *)(&cached_irq_mask))[1])
+
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
+int __ppc_bh_counter;
-void disable_irq(unsigned int irq_nr)
+void *null_handler(int,void *,struct pt_regs *);
+
+/*
+ * disable and enable intrs in software. This is used
+ * from the non-realtime parts of Linux to disable interrupts.
+ * The realtime part disables/enables intrs in the hardware.
+ * -- Cort
+ */
+unsigned long soft_intr_enable = 1;
+void _soft_cli(void)
{
- unsigned char mask;
- int s = _disable_interrupts();
+ soft_intr_enable = 0;
+}
- if (isBeBox[0] && (irq_nr >= 16))
- {
- BeBox_disable_irq(irq_nr);
- } else
+void _soft_sti(void)
+{
+ soft_intr_enable = 1;
+ if ( lost_interrupts )
{
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8)
- {
- cache_21 |= mask;
- outb(cache_21,0x21);
- } else
- {
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
- }
+ printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
+ fake_interrupt();
}
- _enable_interrupts(s);
}
-void enable_irq(unsigned int irq_nr)
+void *
+null_handler(int a, void *b, struct pt_regs *regs)
+{
+ /*printk("irq.c: null_handler() called. Should not have happened.\n");*/
+}
+
+void
+disable_irq(unsigned int irq_nr)
{
- unsigned char mask;
int s = _disable_interrupts();
+ unsigned char mask;
- if (isBeBox[0] && (irq_nr >= 16))
+#ifdef CONFIG_PMAC
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+#else /* CONFIG_PMAC */
+ mask = 1 << (irq_nr & 7);
+ if (irq_nr < 8)
{
- BeBox_enable_irq(irq_nr);
- _enable_interrupts(s);
- return;
+ cached_21 |= mask;
+ outb(cached_21,0x21);
} else
{
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
- } else
- {
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
- }
- }
+ cached_A1 |= mask;
+ outb(cached_A1,0xA1);
+ }
+#endif /* CONFIG_PMAC */
_enable_interrupts(s);
}
-/*
- * Irq handlers.
- */
-struct irq_action {
- void (*handler)(int, void *dev, struct pt_regs *);
- unsigned long flags;
- unsigned long mask;
- const char *name;
- int notified;
- void *dev_id;
-};
-
-static struct irq_action irq_action[32] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-
-inline int get_irq_list(char *buf)
+void
+enable_irq(unsigned int irq_nr)
{
- int i, len = 0;
- struct irq_action * action = irq_action;
-
- for (i = 0; i < 32; 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 s = _disable_interrupts();
+#ifdef CONFIG_PMAC
+ unsigned bit = 1U << irq_nr;
+
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
+
+ /*
+ * Unfortunately, setting the bit in the enable register
+ * when the device interrupt is already on *doesn't* set
+ * the bit in the flag register or request another interrupt.
+ */
+ if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
+ lost_interrupts |= bit;
+#else /* CONFIG_PMAC */
+ if (irq_nr < 8) {
+ cached_21 &= ~(1 << (irq_nr & 7));
+ outb(cached_21,0x21);
+ } else
+ {
+ cached_A1 &= ~(1 << (irq_nr-8 & 7));
+ outb(cached_A1,0xA1);
+ }
+#endif /* CONFIG_PMAC */
-inline void
-process_IRQ(int irq, int _irq, struct pt_regs *regs)
-{
- struct irq_action *action;
- atomic_inc(&intr_count);
- if (irq < 16)
- {
- /* Mask interrupt */
- if (irq > 7)
- {
- cache_A1 |= (1<<(irq-8));
- outb(cache_A1, 0xA1);
- } else
- {
- cache_21 |= (1<<irq);
- outb(cache_21, 0x21);
- }
- }
- action = irq + irq_action;
- kstat.interrupts[irq]++;
- /* TEMP */
- /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
- if (irq == 0)
- {
- static int count;
- if (++count == 500)
- {
- if (inb(0x64) & 0x01)
- {
- struct irq_action *action;
- action = irq_action + 1; /* Keyboard */
- printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
- inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
- action->handler(1, action->dev_id, regs);
- }
- count = 0;
- }
- }
- if (action->handler)
- {
- action->handler(irq, action->dev_id, regs);
- } else
- {
- printk("Bogus interrupt %d/%x, pc %x regs %x\n",
- irq, _irq,regs->nip,regs);
-#if 0
- printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
- show_BeBox_state();
- cnpause();
-#endif
- }
- if (_disable_interrupts() && !action->notified)
- {
- action->notified = 1;
- printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
- action->name, irq);
- }
- if (irq < 16)
- {
- /* Issue EOI to interrupt controller */
- if (irq > 7)
- {
- outb(0xE0|(irq-8), 0xA0);
- outb(0xE2, 0x20);
- } else
- {
- outb(0xE0|irq, 0x20);
- }
- if (!(action->flags & SA_ONESHOT))
- {
- /* Re-enable interrupt */
- if (irq > 7)
- {
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_A1, 0xA1);
- } else
- {
- cache_21 &= ~(1<<irq);
- outb(cache_21, 0x21);
- }
- }
- } else
- {
- BeBox_enable_irq(irq);
- }
- atomic_dec(&intr_count);
+ _enable_interrupts(s);
}
-asmlinkage inline void handle_IRQ(struct pt_regs *regs)
+
+int get_irq_list(char *buf)
{
- int irq, _irq, s;
- struct irq_action *action;
- static int _ints;
-
- if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
- {
- /* Figure out IRQ#, etc. */
- outb(0x0C, 0x20); /* Poll interrupt controller */
- irq = _irq = inb(0x20);
- irq &= 0x07; /* Caution! */
- if (irq == 2)
- { /* Cascaded interrupt -> IRQ8..IRQ15 */
- outb(0x0C, 0xA0);
- irq = (_irq = inb(0xA0)) & 0x07;
- irq += 8;
- }
- }
- process_IRQ(irq, _irq, regs);
-
- /* Sometimes, the cascaded IRQ controller get's "stuck" */
- if ((irq == 0) && (_ints++ == 100))
- {
- _ints = 0;
- outb(0x0A, 0xA0); _irq = inb(0xA0);
- if (_irq & ~cache_A1)
- { /* Figure out which IRQs are present */
- _irq &= ~cache_A1;
- for (irq = 0; irq < 7; irq++)
- {
- if (_irq & (1<<irq))
- {
-#if 0
- printk("Dropped IRQ #%d\n", irq+8);
-#endif
- process_IRQ(irq+8, _irq, regs);
+ int i, len = 0;
+ struct irqaction * action;
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = irq_action + i;
+ if (!action || !action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %10u %s",
+ i, kstat.interrupts[i], action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
+ }
+ len += sprintf(buf+len, "\n");
}
- }
- }
- }
-}
-
/*
- * Display current IRQ state
+ * Linus - should you add NMI counts here ?????
*/
-
-void
-show_irq_state(void)
-{
- unsigned char state_21, state_A1;
- outb(0x0A, 0x20); state_21 = inb(0x20);
- outb(0x0A, 0xA0); state_A1 = inb(0xA0);
- printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
+#ifdef __SMP_PROF__
+ len+=sprintf(buf+len, "IPI: %8lu received\n",
+ ipi_count);
+#endif
+ return len;
}
-/*
- * Initialize interrupt controllers to a well-known state.
- */
-
-static void
-reset_int_controllers(void)
+asmlinkage void handle_IRQ(struct pt_regs *regs)
{
- /* Initialize interrupt controllers */
- outb(0x11, 0x20); /* Start init sequence */
- outb(0x40, 0x21); /* Vector base */
- outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
- outb(0x01, 0x21); /* Select 8086 mode */
- outb(0xFF, 0x21); /* Mask all */
- outb(0x11, 0xA0); /* Start init sequence */
- outb(0x48, 0xA1); /* Vector base */
- outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
- outb(0x01, 0xA1); /* Select 8086 mode */
- outb(0xFF, 0xA1); /* Mask all */
-#if 0
- outb(0x00, 0x4D0); /* All edge triggered */
- outb(0xCF, 0x4D1); /* Trigger mode */
+ int irq;
+ unsigned bits;
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ hardirq_enter(cpu);
+
+#ifdef CONFIG_PMAC
+ bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+ lost_interrupts = 0;
+
+ for (irq = NR_IRQS; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
+#else /* CONFIG_PMAC */
+#if 1
+ if ( lost_interrupts )
+ {
+ irq = ffz(~lost_interrupts);
+ lost_interrupts &= ~irq;
+ goto retry;
+ }
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+retry_cascade:
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ /* if no intr left */
+ if ( !(irq & 128 ) )
+ goto out;
+ irq = (irq&7) + 8;
+ }
+retry:
+#else
+ /* get the irr from the intr controller */
+ outb(0x0A, 0x20);
+ bits = inb(0x20);
+ /* handle cascade */
+ if ( bits )
+ {
+ bits &= 4;
+ outb(0x0A, 0xA0);
+ bits = inb(0xA0)<<8;
+ }
+ /* get lost interrupts */
+ bits |= lost_interrupts;
+ /* save intrs that are masked out */
+ lost_interrupts = bits & cached_irq_mask;
+ /* get rid of intrs being masked */
+ bits &= ~cached_irq_mask;
+ /* non-specifc eoi */
+ outb(0x20,0x20);
+ if ( bits & 0xff00 )
+ outb(0x20,0xA0);
+
+ printk("bits %04X lost %04X mask %04x\n",
+ bits, lost_interrupts,cached_irq_mask);
+
+ for (irq = NR_IRQS; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
#endif
- outb(cache_A1, 0xA1);
- outb(cache_21, 0x21);
- enable_irq(2); /* Enable cascade interrupt */
+#endif /* CONFIG_PMAC */
+
+ if (irq < 0) {
+ printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+ goto out;
+ }
+
+#ifdef CONFIG_PMAC
+ out_le32(IRQ_ACK, 1U << irq);
+#else /* CONFIG_PMAC */
+ /* mask out the irq while handling it */
+ disable_irq(irq);
+ /*
+ * send eoi to interrupt controller right away or lower
+ * priority intrs would be ignored even if with intrs enabled
+ */
+ if (irq > 7)
+ {
+ outb(0xE0|(irq-8), 0xA0);
+ outb(0xE2, 0x20);
+ } else
+ {
+ outb(0xE0|irq, 0x20);
+ }
+#endif /* !CONFIG_PMAC */
+
+ /*
+ * now that we've acked the irq, if intrs are disabled in software
+ * we're in the real-time system and non-rt linux has disabled them
+ * so we just queue it up and return -- Cort
+ */
+ if ( ! soft_intr_enable )
+ {
+ lost_interrupts |= 1UL << irq;
+ /* can't printk - kernel expects intrs off! */
+ /*printk("irq %d while intrs soft disabled\n", irq);*/
+ goto out;
+ }
+
+ action = irq + irq_action;
+ kstat.interrupts[irq]++;
+ if (action->handler) {
+ action->handler(irq, action->dev_id, regs);
+ _disable_interrupts(); /* in case the handler turned them on */
+ } else {
+ disable_irq( irq );
+ }
+#ifdef CONFIG_PREP
+ /* re-enable if the interrupt was good and isn't one-shot */
+ if ( action->handler && !(action->flags & SA_ONESHOT) )
+ enable_irq(irq);
+ /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+ if ( irq > 7 )
+ goto retry_cascade;
+#endif
+
+ hardirq_exit(cpu);
+ /*
+ * This should be conditional: we should really get
+ * a return code from the irq handler to tell us
+ * whether the handler wants us to do software bottom
+ * half handling or not..
+ */
+ if (1)
+ if (bh_active & bh_mask)
+ do_bottom_half();
+ return;
+out:
+ hardirq_exit(cpu);
+
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
+ unsigned long irqflags, const char * devname, void *dev_id)
{
- struct irq_action * action;
+ struct irqaction * action;
unsigned long flags;
-
-#ifdef SHOW_IRQ
-if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
-#endif
- if (irq > 15)
- {
- if (!isBeBox[0] || (irq > 31))
- return -EINVAL;
- }
+
+#ifdef SHOW_IRQ
+ printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
+ irq,handler,devname,dev_id);
+#endif /* SHOW_IRQ */
+
+ if (irq > NR_IRQS)
+ return -EINVAL;
action = irq + irq_action;
if (action->handler)
return -EBUSY;
void free_irq(unsigned int irq, void *dev_id)
{
- struct irq_action * action = irq + irq_action;
+ struct irqaction * action = irq + irq_action;
unsigned long flags;
- if (irq > 31) {
+#ifdef SHOW_IRQ
+ printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
+#endif /* SHOW_IRQ */
+
+ if (irq > NR_IRQS) {
printk("Trying to free IRQ%d\n",irq);
return;
}
restore_flags(flags);
}
-#define SA_PROBE SA_ONESHOT
-
-static void no_action(int irq, void *dev, struct pt_regs * regs)
-{
-#ifdef DEBUG
- printk("Probe got IRQ: %d\n", irq);
-#endif
-}
-
unsigned long probe_irq_on (void)
{
unsigned int i, irqs = 0, irqmask;
/* first, snaffle up any unassigned irqs */
for (i = 15; i > 0; i--) {
- if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
+ if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
enable_irq(i);
irqs |= (1 << i);
}
for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
for (i = 15; i > 0; i--) {
if (irqs & (1 << i) & irqmask) {
irqs ^= (1 << i);
{
unsigned int i, irqmask;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
for (i = 15; i > 0; i--) {
if (irqs & (1 << i)) {
free_irq(i, NULL);
}
}
-#ifdef DEBUG
+#ifdef SHOW_IRQ
printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
#endif
irqs &= irqmask;
i = -i;
return i;
}
-
-void init_IRQ(void)
-{
- int i;
-
- if ((_get_PVR()>>16) == 1) /* PPC 601 */
- { /* Nobis? */
- reset_int_controllers();
- }
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set the clock to 100 Hz */
- outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
- request_region(0x20,0x20,"pic1");
- request_region(0xa0,0x20,"pic2");
-
- /* Make sure IRQ2 (cascade) interrupt is "level" based */
- outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
-
- /* Set up PCI interrupts */
- route_PCI_interrupts();
-
- if (isBeBox[0])
- {
- BeBox_init_IRQ();
- }
-}
-/*
- * Wrapper for "bottom 1/2" of interrupt processing. This routine
- * is called whenever an interrupt needs non-interrupt-time service.
- */
-
-void _do_bottom_half(void)
-{
- _enable_interrupts(1);
- do_bottom_half();
- _disable_interrupts();
-}
-
-void hard_disk_LED(int state)
-{
- if (_Processor == _PROC_IBM) {
- outb(state, IBM_HDD_LED);
- }
-}
-
-
-/*
- * Support for interrupts on the BeBox
- */
-
-#define CPU0_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x0F0)
-#define CPU1_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x1F0)
-#define INT_SOURCE (volatile unsigned long *)(BeBox_IO_page+0x2F0)
-#define CPU_RESET (volatile unsigned long *)(BeBox_IO_page+0x4F0)
-
-#define _CPU0_INT_MASK (volatile unsigned long *)(0xA0000000+0x0F0)
-#define _CPU1_INT_MASK (volatile unsigned long *)(0xA0000000+0x1F0)
-#define _INT_SOURCE (volatile unsigned long *)(0xA0000000+0x2F0)
-#define _CPU_RESET (volatile unsigned long *)(0xA0000000+0x4F0)
-
-#define CPU_HRESET 0x20000000
-#define CPU_SRESET 0x40000000
-
-#define SCSI_IRQ 16
-
-#define INT_SCSI (1<<21)
-#define INT_8259 (1<<5)
-
-/*
- * Map of pseudo IRQs to actual bits
- * Note: We give out IRQ #16..31 for all interrupt sources which are
- * not found in the 8259 PIC.
- */
-
-unsigned long BeBox_IRQ_map[] =
- {
- INT_SCSI, /* 16 - SCSI */
- 0x00000000, /* 17 - Unused */
- 0x00000000, /* 18 - Unused */
- 0x00000000, /* 19 - Unused */
- 0x00000000, /* 20 - Unused */
- 0x00000000, /* 21 - Unused */
- 0x00000000, /* 22 - Unused */
- 0x00000000, /* 23 - Unused */
- 0x00000000, /* 24 - Unused */
- 0x00000000, /* 25 - Unused */
- 0x00000000, /* 26 - Unused */
- 0x00000000, /* 27 - Unused */
- 0x00000000, /* 28 - Unused */
- 0x00000000, /* 29 - Unused */
- 0x00000000, /* 30 - Unused */
- 0x00000000, /* 31 - Unused */
- };
-
-volatile int CPU1_alive;
-volatile int CPU1_trace;
-
-static
-_NOP(void)
-{
-}
-
-static
-_delay(void)
+void init_IRQ(void)
{
- int i;
- for (i = 0; i < 100; i++) _NOP();
-}
+#ifdef CONFIG_PMAC
+ extern void xmon_irq(int, void *, struct pt_regs *);
-void
-BeBox_init_IRQ(void)
-{
- int tmr;
- volatile extern long BeBox_CPU1_vector;
- *CPU0_INT_MASK = 0x0FFFFFFC; /* Clear all bits? */
- *CPU0_INT_MASK = 0x80000003 | INT_8259;
- *CPU1_INT_MASK = 0x0FFFFFFC;
-printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
- BeBox_CPU1_vector = 0x0100; /* Reset */
- tmr = 0;
- while (CPU1_alive == 0)
- {
- if (++tmr == 1000)
- {
-printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
- break;
- }
- _delay();
- }
-printk("CPU #1 running!\n");
-}
+ *IRQ_ENABLE = 0;
+ request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#else /* CONFIG_PMAC */
+ /* Initialize interrupt controllers */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x40, 0x21); /* Vector base */
+#if 1
+ outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+#else
+ outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
-void
-BeBox_disable_irq(int irq)
-{
- /* Note: this clears the particular bit */
- *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
-}
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x48, 0xA1); /* Vector base */
+#if 1
+ outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+#else
+ outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
-void
-BeBox_enable_irq(int irq)
-{
- int s = _disable_interrupts();
- /* Sets a single bit */
+ /*
+ * Program level mode for irq's that 'can' be level triggered.
+ * This does not effect irq's 0,1,2 and 8 since they must be
+ * edge triggered. This is not the PIC controller. The default
+ * here is for edge trigger mode. -- Cort
+ */
#if 0
-printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+ outb(0xf8, 0x4d0); /* level triggered */
+ outb(0xff, 0x4d1);
#endif
- *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
-#if 0
-printk("/%x\n", *CPU0_INT_MASK);
-#endif
- _enable_interrupts(s);
-}
-
-void
-show_BeBox_state(void)
-{
- unsigned long cpu0_int_mask;
- unsigned long int_state;
- cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
- int_state = cpu0_int_mask & *INT_SOURCE;
- printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-}
-
-int
-BeBox_irq(void)
-{
- int i;
- unsigned long cpu0_int_mask;
- unsigned long int_state;
- cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
- int_state = cpu0_int_mask & *INT_SOURCE;
- if (int_state)
- { /* Determine the pseudo-interrupt # */
#if 0
- printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-#endif
- for (i = 0; i < 16; i++)
- {
- if (BeBox_IRQ_map[i] & int_state)
- {
- return (i+16);
- }
- }
-printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-printk("Can't find BeBox IRQ!\n");
- }
- return (0);
-}
-
-void BeBox_state(void)
-{
- printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
-}
-
-void BeBox_CPU1(void)
-{
- CPU1_alive++;
- while (1) ;
+ outb(0x00, 0x4D0); /* All edge triggered */
+ outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
+ outb(cached_A1, 0xA1);
+ outb(cached_21, 0x21);
+ if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
+ printk("Unable to get IRQ2 for cascade\n");
+ enable_irq(2); /* Enable cascade interrupt */
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ route_pci_interrupts();
+#endif /* CONFIG_PMAC */
}
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void handle_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+unsigned long sys_call_table[];
+
+extern struct task_struct *current_set[1];
/* platform dependent support */
+EXPORT_SYMBOL(current_set);
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(handle_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(FloatingPointCheckException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(sys_call_table);
/*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
-#include "ppc_asm.tmpl"
+#include <linux/config.h>
#include <linux/sys.h>
+#include <asm/unistd.h>
#include <asm/errno.h>
-#include "ppc_defs.h"
#include <asm/processor.h>
-
-/* Keep track of low-level exceptions - rather crude, but informative */
-#define STATS
-
-/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
- */
-#define BUMP(ctr) \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- stw r3,0(r2)
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
-/*#ifdef CONFIG_603*/
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 601 or 603 */
#define tlbia \
- li r4,64; \
+ li r4,128; \
mtspr CTR,r4; \
li r4,0; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-/*#endif*/ /* CONFIG_603*/
_TEXT()
-#define CPU_CTL 0x80000092
-_GLOBAL(hard_reset_now)
- mfmsr r3 /* Disable interrupts */
- li r4,0
- ori r4,r4,MSR_EE
- andc r3,r3,r4
- ori r3,r3,MSR_IP /* Set FLASH/ROM interrupt handlers */
- sync
- mtmsr r3
- lis r3,CPU_CTL>>16
- ori r3,r3,(CPU_CTL&0xFFFF)
- lbz r4,0(r3) /* Turn on SRESET */
- li r5,1
- andc r4,r4,r5 /* Make sure we go from 0->1 */
- stb r4,0(r3)
- ori r4,r4,1
- stb r4,0(r3) /* This should do it! */
-99: nop
- b 99b
-
-#if 0
-/*
- unsigned short
- le16_to_cpu(unsigned short val)
-*/
-_GLOBAL(le16_to_cpu)
- lis r4,_le_scratch@h
- ori r4,r4,_le_scratch@l
- sth r3,0(r4)
- li r5,0
- lhbrx r3,r4,r5
- blr
-
-_GLOBAL(le32_to_cpu)
- lis r4,_le_scratch@h
- ori r4,r4,_le_scratch@l
- stw r3,0(r4)
- li r5,0
- lwbrx r3,r4,r5
- blr
-_GLOBAL(_le_scratch)
- .space 4
-#endif
-#if 1
-/*
-extern int __put_user_8(char, char *);
-extern int __put_user_16(short, short *);
-extern int __put_user_32(long, long *);
-*/
-_GLOBAL(__put_user_8)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- stb r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__put_user_16)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- sth r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-_GLOBAL(__put_user_32)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- stw r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_8)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- lbz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_16)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- lhz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_32)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
- lwz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-#endif
/*
* Disable interrupts
* rc = _disable_interrupts()
*/
_GLOBAL(_disable_interrupts)
+_GLOBAL(__cli)
+_GLOBAL(_hard_cli)
mfmsr r0 /* Get current interrupt state */
rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
li r4,0 /* Need [unsigned] value of MSR_EE */
* turns on interrupts if state = 1.
*/
_GLOBAL(_enable_interrupts)
- mfmsr r0 /* Get current state */
- rlwimi r0,r3,16-1,32-16,32-16 /* Insert bit */
+ cmpi 0,r3,0 /* turning them on? */
+ beqlr /* nothing to do if state == 0 */
+_GLOBAL(__sti)
+_GLOBAL(_hard_sti)
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ mfmsr r3 /* Get current state */
+ ori r3,r3,MSR_EE /* Turn on 'EE' bit */
+ cmpi 0,r4,0 /* lost interrupts to process first? */
+ bne- do_lost_interrupts
sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
- blr
-
-/*
- * Get 'flags' (aka machine status register)
- * __save_flags(long *ptr)
- */
-_GLOBAL(__save_flags)
- mfmsr r0 /* Get current state */
- stw r0,0(r3)
- mr r3,r0
+ mtmsr r3 /* Update machine state */
blr
/*
* __restore_flags(long val)
*/
_GLOBAL(__restore_flags)
- sync /* Some chip revs have problems here... */
+ andi. r0,r3,MSR_EE /* enabling interrupts? */
+ beq 2f
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ bne do_lost_interrupts
+2: sync /* Some chip revs have problems here... */
mtmsr r3
isync
blr
/*
- * Disable interrupts - like an 80x86
- * cli()
- */
-_GLOBAL(cli)
- mfmsr r0 /* Get current interrupt state */
- rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
- li r4,0 /* Need [unsigned] value of MSR_EE */
- ori r4,r4,MSR_EE /* Set to turn off bit */
- andc r0,r0,r4 /* Clears bit in (r4) */
- sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
- blr /* Done */
-
-/*
- * Enable interrupts - like an 80x86
- * sti()
+ * We were about to enable interrupts but we have to simulate
+ * some interrupts that were lost by enable_irq first.
*/
-_GLOBAL(sti)
- mfmsr r0 /* Get current state */
- ori r0,r0,MSR_EE /* Turn on 'EE' bit */
- sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
+do_lost_interrupts:
+ stwu r1,-16(r1)
+ mflr r0
+ stw r0,20(r1)
+ stw r3,8(r1)
+1: bl fake_interrupt
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ bne- 1b
+ lwz r3,8(r1)
+ sync
+ mtmsr r3
+ lwz r0,20(r1)
+ mtlr r0
+ addi r1,r1,16
blr
/*
*/
_GLOBAL(_tlbia)
tlbia
- BUMP(__TLBIAs)
blr
/*
*/
_GLOBAL(_tlbie)
tlbie r3
- BUMP(__TLBIEs)
blr
-
-/*
- * Fetch the current SR register
- * get_SR(int index)
- */
-_GLOBAL(get_SR)
- mfsrin r3,r3
- blr
-
/*
* Atomic [test&set] exchange
*
* void atomic_sub(int c, int *v)
* void atomic_inc(int *v)
* void atomic_dec(int *v)
- * void atomic_dec_and_test(int *v)
+ * int atomic_dec_and_test(int *v)
+ * int atomic_inc_return(int *v)
+ * int atomic_dec_return(int *v)
+ * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
+ * void atomic_set_mask(atomic_t mask, atomic_t *addr);
*/
_GLOBAL(atomic_add)
10: lwarx r5,0,r4 /* Fetch old value & reserve */
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
blr
+_GLOBAL(atomic_inc_return)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ addi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ mr r3,r5 /* Return new value */
+ blr
_GLOBAL(atomic_dec)
10: lwarx r5,0,r3 /* Fetch old value & reserve */
subi r5,r5,1 /* Perform 'add' operation */
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
blr
+_GLOBAL(atomic_dec_return)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ subi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ mr r3,r5 /* Return new value */
+ blr
_GLOBAL(atomic_dec_and_test)
10: lwarx r5,0,r3 /* Fetch old value & reserve */
subi r5,r5,1 /* Perform 'add' operation */
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
cmpi 0,r5,0 /* Return 'true' IFF 0 */
- bne 15f
li r3,1
+ beqlr
+ li r3,0
blr
-15: li r3,0
- blr
-
-
-/*
- * Delay for a specific # of "loops"
- * __delay(int loops)
- */
-_GLOBAL(__delay)
- mtctr r3
-00: addi r3,r3,0 /* NOP */
- bdnz 00b
- blr
-
-/*
- * Delay for a number of microseconds
- * udelay(int usecs)
- */
-_GLOBAL(udelay)
-00: li r0,86 /* Instructions / microsecond? */
- mtctr r0
-10: addi r0,r0,0 /* NOP */
- bdnz 10b
- subic. r3,r3,1
- bne 00b
- blr
-
-/*
- * Atomically increment [intr_count]
- */
-_GLOBAL(start_bh_atomic)
- lis r3,intr_count@h
- ori r3,r3,intr_count@l
-10: lwarx r4,0,r3
- addi r4,r4,1
- stwcx. r4,0,r3
+_GLOBAL(atomic_clear_mask)
+10: lwarx r5,0,r4
+ andc r5,r5,r3
+ stwcx. r5,0,r4
bne- 10b
blr
-
-/*
- * Atomically decrement [intr_count]
- */
-_GLOBAL(end_bh_atomic)
- lis r3,intr_count@h
- ori r3,r3,intr_count@l
-10: lwarx r4,0,r3
- subic r4,r4,1
- stwcx. r4,0,r3
+_GLOBAL(atomic_set_mask)
+10: lwarx r5,0,r4
+ or r5,r5,r3
+ stwcx. r5,0,r4
bne- 10b
blr
*
* insw(port, buf, len)
* outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
*/
_GLOBAL(_insw)
mtctr r5
bdnz 00b
blr
-#if 0
-/*
- *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
- *{
- * unsigned long res;
- * unsigned long *p;
- * unsigned long *addr = vaddr;
- *
- * if (!size)
- * return 0;
- * __asm__ __volatile__ (" moveq #-1,d0\n\t"
- * "1:"
- * " cmpl %1@+,d0\n\t"
- * " bne 2f\n\t"
- * " subql #1,%0\n\t"
- * " bne 1b\n\t"
- * " bra 5f\n\t"
- * "2:"
- * " movel %1@-,d0\n\t"
- * " notl d0\n\t"
- * " bfffo d0{#0,#0},%0\n\t"
- * "5:"
- * : "=d" (res), "=a" (p)
- * : "0" ((size + 31) >> 5), "1" (addr)
- * : "d0");
- * return ((p - addr) << 5) + res;
- *}
- */
-_GLOBAL(find_first_zero_bit)
- li r5,0 /* bit # */
- subi r3,r3,4 /* Adjust pointer for auto-increment */
-00: lwzu r0,4(r3) /* Get next word */
- not. r7,r0 /* Complement to find ones */
- beq 10f /* Jump if all ones */
-02: andi. r7,r0,1 /* Check low-order bit */
- beq 20f /* All done when zero found */
- srawi r0,r0,1
- addi r5,r5,1
- b 02b
-10: addi r5,r5,32 /* Update bit # */
- subic. r4,r4,32 /* Any more? */
- bgt 00b
-20: mr r3,r5 /* Compute result */
+_GLOBAL(_insl)
+ mtctr r5
+ subi r4,r4,4
+00: lwbrx r5,0,r3
+ stwu r5,4(r4)
+ bdnz 00b
blr
-
-/*
- *static inline int find_next_zero_bit (void *vaddr, int size,
- * int offset)
- *{
- * unsigned long *addr = vaddr;
- * unsigned long *p = addr + (offset >> 5);
- * int set = 0, bit = offset & 31, res;
- *
- * if (bit) {
- * // Look for zero in first longword
- * __asm__("bfffo %1{#0,#0},%0"
- * : "=d" (set)
- * : "d" (~*p << bit));
- * if (set < (32 - bit))
- * return set + offset;
- * set = 32 - bit;
- * p++;
- * }
- * // No zero yet, search remaining full bytes for a zero
- * res = find_first_zero_bit (p, size - 32 * (p - addr));
- * return (offset + set + res);
- *}
- */
-_GLOBAL(find_next_zero_bit)
- addi r5,r5,1 /* bump offset to start */
- srawi r6,r5,5 /* word offset */
- add r6,r6,r6 /* byte offset */
- add r6,r6,r6 /* byte offset */
- add r3,r3,r6 /* compute byte position */
- sub r4,r4,r5 /* adjust size by starting index */
- andi. r0,r5,0x1F /* offset in current word? */
- beq 10f /* at start of word */
- lwz r0,0(r3) /* get word */
- sraw r0,r0,r5 /* shift right */
- not. r7,r0
- beq 07f /* jump if only ones remain */
-05: andi. r7,r0,1 /* found zero? */
- beq 90f /* yes - all done */
- srawi r0,r0,1
- addi r5,r5,1
- b 05b
-07: andi. r6,r5,0x1F
- subfic r0,r6,32
- add r5,r5,r0
- sub r4,r4,r0
- b 20f
-10: subi r3,r3,4 /* Adjust pointer for auto-increment */
-20: lwzu r0,4(r3) /* Get next word */
- not. r7,r0 /* Complement to find ones */
- beq 40f /* Jump if all ones */
-30: andi. r7,r0,1 /* Check low-order bit */
- beq 90f /* All done when zero found */
- srawi r0,r0,1
- addi r5,r5,1
- b 30b
-40: addi r5,r5,32 /* Update bit # */
- subic. r4,r4,32 /* Any more? */
- bgt 20b
-90: mr r3,r5 /* Compute result */
+
+_GLOBAL(_outsl)
+ mtctr r5
+ subi r4,r4,4
+00: lwzu r5,4(r4)
+ stwbrx r5,0,r3
+ bdnz 00b
+ blr
+
+#ifdef CONFIG_PMAC
+_GLOBAL(ide_insw)
+ mtctr r5
+ subi r4,r4,2
+00: lhzx r5,0,r3
+ sthu r5,2(r4)
+ bdnz 00b
blr
+
+_GLOBAL(ide_outsw)
+ mtctr r5
+ subi r4,r4,2
+00: lhzu r5,2(r4)
+ sthx r5,0,r3
+ bdnz 00b
+ blr
#endif
-
-/*
- *
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- *
- *extern inline unsigned long ffz(unsigned long word)
- *{
- * __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
- * : "=d" (word)
- * : "d" (~(word)));
- * return word;
- *}
- */
-_GLOBAL(ffz)
- mr r4,r3
- li r3,0
-10: andi. r0,r4,1 /* Find the zero we know is there */
- srawi r4,r4,1
- beq 90f
- addi r3,r3,1
- b 10b
-90: blr
/*
* Extended precision shifts
slw r3,r3,r5 /* YYY--- */
or r3,r3,r7 /* YYYZZZ */
blr
-
-_GLOBAL(abort)
- .long 0
-
-/* in include/asm/string.h now -- Cort */
-#if 0
-_GLOBAL(bzero)
-#define bufp r3
-#define len r4
-#define pat r5
-/* R3 has buffer */
-/* R4 has length */
-/* R5 has pattern */
- cmpi 0,len,0 /* Exit if len <= 0 */
- ble 99f
- andi. r0,bufp,3 /* Must be on longword boundary */
- bne 10f /* Use byte loop if not aligned */
- andi. r0,len,3 /* Check for overrage */
- subi bufp,bufp,4 /* Adjust pointer */
- srawi len,len,2 /* Divide by 4 */
- blt 99f /* If negative - bug out! */
- mtspr CTR,len /* Set up counter */
- li pat,0
-00: stwu pat,4(bufp) /* Store value */
- bdnz 00b /* Loop [based on counter] */
- mr len,r0 /* Get remainder (bytes) */
-10: cmpi 0,len,0 /* Any bytes left */
- ble 99f /* No - all done */
- mtspr CTR,len /* Set up counter */
- subi bufp,bufp,1 /* Adjust pointer */
- li pat,0
-20: stbu pat,1(bufp) /* Store value */
- bdnz 20b /* Loop [based on counter] */
-99: blr
-#endif
-
_GLOBAL(abs)
cmpi 0,r3,0
bge 10f
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
-
-_GLOBAL(_get_SDR1)
- mfspr r3,SDR1
+
+_GLOBAL(_get_PVR)
+ mfspr r3,PVR
blr
-_GLOBAL(_get_SRx)
- mfsrin r3,r3
+_GLOBAL(cvt_fd)
+cvt_fd:
+ lfs 0,0(r3)
+ stfd 0,0(r4)
+ blr
+/*
+ * Fetch the current SR register
+ * get_SR(int index)
+ */
+_GLOBAL(get_SR)
+ mfsrin r4,r3
+ mr r3,r4
blr
-_GLOBAL(_get_PVR)
- mfspr r3,PVR
+
+_GLOBAL(cvt_df)
+cvt_df:
+ lfd 0,0(r3)
+ stfs 0,0(r4)
blr
/*
* Create a kernel thread
* __kernel_thread(flags, fn, arg)
*/
-#if 1
-#define SYS_CLONE 120
_GLOBAL(__kernel_thread)
-__kernel_thread:
- li r0,SYS_CLONE
+ li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
bnelr /* return if parent */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
- blr
- li 0, 1 /* exit after child exits */
- li 3, 0
+ blrl
+ li r0,__NR_exit /* exit after child exits */
+ li r3,0
sc
-#endif
-
+
+#define SYSCALL(name) \
+_GLOBAL(name) \
+ li r0,__NR_##name; \
+ sc; \
+ bnslr; \
+ lis r4,errno@ha; \
+ stw r3,errno@l(r4); \
+ li r3,-1; \
+ blr
+
+#define __NR__exit __NR_exit
+
+SYSCALL(idle)
+SYSCALL(setup)
+SYSCALL(sync)
+SYSCALL(setsid)
+SYSCALL(write)
+SYSCALL(dup)
+SYSCALL(execve)
+SYSCALL(open)
+SYSCALL(close)
+SYSCALL(waitpid)
+
+
/* Why isn't this a) automatic, b) written in 'C'? */
.data
.align 4
.long sys_fork
.long sys_read
.long sys_write
- .long sys_open /* 5 */
+ .long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
- .long sys_unlink /* 10 */
+ .long sys_unlink /* 10 */
.long sys_execve
.long sys_chdir
.long sys_time
.long sys_break
.long sys_stat
.long sys_lseek
- .long sys_getpid /* 20 */
+ .long sys_getpid /* 20 */
.long sys_mount
.long sys_umount
.long sys_setuid
.long sys_pipe
.long sys_times
.long sys_prof
- .long sys_brk /* 45 */
+ .long sys_brk /* 45 */
.long sys_setgid
.long sys_getgid
.long sys_signal
.long sys_geteuid
- .long sys_getegid /* 50 */
+ .long sys_getegid /* 50 */
.long sys_acct
.long sys_phys
.long sys_lock
.long sys_ustat
.long sys_dup2
.long sys_getppid
- .long sys_getpgrp /* 65 */
+ .long sys_getpgrp /* 65 */
.long sys_setsid
.long sys_sigaction
.long sys_sgetmask
.long sys_ssetmask
- .long sys_setreuid /* 70 */
+ .long sys_setreuid /* 70 */
.long sys_setregid
.long sys_sigsuspend
.long sys_sigpending
.long sys_sethostname
- .long sys_setrlimit /* 75 */
+ .long sys_setrlimit /* 75 */
.long sys_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
- .long sys_getgroups /* 80 */
+ .long sys_getgroups /* 80 */
.long sys_setgroups
- .long sys_select
+ .long ppc_select
.long sys_symlink
.long sys_lstat
- .long sys_readlink /* 85 */
+ .long sys_readlink /* 85 */
.long sys_uselib
.long sys_swapon
.long sys_reboot
.long old_readdir /* was sys_readdir */
- .long sys_mmap /* 90 */
+ .long sys_mmap /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
.long sys_fchmod
- .long sys_fchown /* 95 */
+ .long sys_fchown /* 95 */
.long sys_getpriority
.long sys_setpriority
.long sys_profil
.long sys_statfs
- .long sys_fstatfs /* 100 */
+ .long sys_fstatfs /* 100 */
.long sys_ioperm
.long sys_socketcall
.long sys_syslog
.long sys_setitimer
- .long sys_getitimer /* 105 */
+ .long sys_getitimer /* 105 */
.long sys_newstat
.long sys_newlstat
.long sys_newfstat
.long sys_uname
- .long sys_iopl /* 110 */
+ .long sys_iopl /* 110 */
.long sys_vhangup
.long sys_idle
.long sys_vm86
.long sys_wait4
- .long sys_swapoff /* 115 */
+ .long sys_swapoff /* 115 */
.long sys_sysinfo
.long sys_ipc
.long sys_fsync
.long sys_newuname
.long sys_modify_ldt
.long sys_adjtimex
- .long sys_mprotect /* 125 */
+ .long sys_mprotect /* 125 */
.long sys_sigprocmask
.long sys_create_module
.long sys_init_module
.long 0 /* for afs_syscall */
.long sys_setfsuid
.long sys_setfsgid
- .long sys_llseek /* 140 */
+ .long sys_llseek /* 140 */
.long sys_getdents
- .long sys_newselect
+ .long ppc_select
.long sys_flock
.long sys_msync
.long sys_readv /* 145 */
.long sys_mlockall
.long sys_munlockall
.long sys_sched_setparam
- .long sys_sched_getparam /* 155 */
+ .long sys_sched_getparam /* 155 */
.long sys_sched_setscheduler
.long sys_sched_getscheduler
.long sys_sched_yield
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_mremap
- .long SYMBOL_NAME(sys_setresuid)
- .long SYMBOL_NAME(sys_getresuid)
- .long SYMBOL_NAME(sys_nfsservctl)
- .space (NR_syscalls-166)*4
+ .long sys_setresuid
+ .long sys_getresuid /* 165 */
+ .long sys_query_module
+ .long sys_poll
+ .long sys_nfsservctl
+ .long sys_debug
+ .space (NR_syscalls-170)*4
/*
* This program is used to generate definitions needed by
* assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
*/
-#define MK_DEFS
-#include <stdio.h>
-#include <linux/config.h>
+#include <stddef.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/processor.h>
-extern int errno;
+#define DEFINE(sym, val) \
+ asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
-main(int argc, char *argv[])
+void
+main(void)
{
- FILE *out;
- struct task_struct task;
- struct thread_struct tss;
- int i;
- char s[256];
- struct pt_regs regs;
- if (!(out = fopen(argv[1], "w")))
- {
- fprintf(stderr, "Can't create output file: %s\n", strerror(errno));
- exit(1);
- }
- fprintf(out, "/*\n");
- fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n");
- fprintf(out, " */\n");
- put_line(out, "STATE", (int)&task.state-(int)&task);
- put_line(out, "COUNTER", (int)&task.counter-(int)&task);
- put_line(out, "BLOCKED", (int)&task.blocked-(int)&task);
- put_line(out, "SIGNAL", (int)&task.signal-(int)&task);
- put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task);
- put_line(out, "TSS", (int)&task.tss-(int)&task);
- put_line(out, "KSP", (int)&tss.ksp-(int)&tss);
- put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss);
- put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss);
- put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss);
- put_line(out, "PF_TRACESYS", PF_TRACESYS);
- put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task);
- put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss);
- put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss);
- put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss);
- put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss);
- put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss);
- put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss);
- put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss);
- put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss);
- put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss);
- put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss);
- put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss);
- put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss);
- put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss);
- put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
- put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
- put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
- put_line(out, "TSS_EXPC", (int)&tss.expc-(int)&tss);
- put_line(out, "TSS_EXCOUNT", (int)&tss.excount-(int)&tss);
- put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
- put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
- put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
- put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss);
- put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss);
- put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss);
- put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss);
- put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss);
- put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss);
- put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss);
- put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss);
- put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss);
- put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss);
- put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss);
- put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss);
- put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss);
- put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss);
- put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss);
- put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss);
- put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss);
- put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss);
- put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss);
- put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss);
- put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss);
- put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss);
- put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss);
- put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss);
- put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss);
- put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss);
- put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
- put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
- put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
- put_line(out, "TSS_FP_USED", (int)&tss.fp_used-(int)&tss);
- /* Interrupt register frame */
- put_line(out, "INT_FRAME_SIZE", sizeof(regs));
- put_line(out, "GPR0", (int)®s.gpr[0]-(int)®s);
- put_line(out, "GPR1", (int)®s.gpr[1]-(int)®s);
- put_line(out, "GPR2", (int)®s.gpr[2]-(int)®s);
- put_line(out, "GPR3", (int)®s.gpr[3]-(int)®s);
- put_line(out, "GPR4", (int)®s.gpr[4]-(int)®s);
- put_line(out, "GPR5", (int)®s.gpr[5]-(int)®s);
- put_line(out, "GPR6", (int)®s.gpr[6]-(int)®s);
- put_line(out, "GPR7", (int)®s.gpr[7]-(int)®s);
- put_line(out, "GPR8", (int)®s.gpr[8]-(int)®s);
- put_line(out, "GPR9", (int)®s.gpr[9]-(int)®s);
- put_line(out, "GPR10", (int)®s.gpr[10]-(int)®s);
- put_line(out, "GPR11", (int)®s.gpr[11]-(int)®s);
- put_line(out, "GPR12", (int)®s.gpr[12]-(int)®s);
- put_line(out, "GPR13", (int)®s.gpr[13]-(int)®s);
- put_line(out, "GPR14", (int)®s.gpr[14]-(int)®s);
- put_line(out, "GPR15", (int)®s.gpr[15]-(int)®s);
- put_line(out, "GPR16", (int)®s.gpr[16]-(int)®s);
- put_line(out, "GPR17", (int)®s.gpr[17]-(int)®s);
- put_line(out, "GPR18", (int)®s.gpr[18]-(int)®s);
- put_line(out, "GPR19", (int)®s.gpr[19]-(int)®s);
- put_line(out, "GPR20", (int)®s.gpr[20]-(int)®s);
- put_line(out, "GPR21", (int)®s.gpr[21]-(int)®s);
- put_line(out, "GPR22", (int)®s.gpr[22]-(int)®s);
- put_line(out, "GPR23", (int)®s.gpr[23]-(int)®s);
- put_line(out, "GPR24", (int)®s.gpr[24]-(int)®s);
- put_line(out, "GPR25", (int)®s.gpr[25]-(int)®s);
- put_line(out, "GPR26", (int)®s.gpr[26]-(int)®s);
- put_line(out, "GPR27", (int)®s.gpr[27]-(int)®s);
- put_line(out, "GPR28", (int)®s.gpr[28]-(int)®s);
- put_line(out, "GPR29", (int)®s.gpr[29]-(int)®s);
- put_line(out, "GPR30", (int)®s.gpr[30]-(int)®s);
- put_line(out, "GPR31", (int)®s.gpr[31]-(int)®s);
-#if 0
- for ( i = 0 ; i <= 31 ; i++)
- {
- sprintf(s,"FPR%d",i);
- put_line(out, s, (int)®s.fpr[i]-(int)®s);
- }
+ /*DEFINE(KERNELBASE, KERNELBASE);*/
+ DEFINE(STATE, offsetof(struct task_struct, state));
+ DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
+ DEFINE(COUNTER, offsetof(struct task_struct, counter));
+ DEFINE(BLOCKED, offsetof(struct task_struct, blocked));
+ DEFINE(SIGNAL, offsetof(struct task_struct, signal));
+ DEFINE(TSS, offsetof(struct task_struct, tss));
+ DEFINE(KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
+#ifdef CONFIG_PMAC
+ DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
+ DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
+#endif
+ DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+ DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+ DEFINE(PF_TRACESYS, PF_TRACESYS);
+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
+#if 0
+ DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
+ DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
+ DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
+ DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
+ DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
+ DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
+ DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
+ DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
+ DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
+ DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
+ DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
+ DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
+ DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
+ DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
+ DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
+ DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
+ DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
+ DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
+ DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
+ DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
+ DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
+ DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
+ DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
+ DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
+ DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
+ DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
+ DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
+ DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
+ DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
+ DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
+ DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
#endif
- put_line(out, "FPCSR", (int)®s.fpcsr-(int)®s);
- /* Note: these symbols include "_" because they overlap with special register names */
- put_line(out, "_NIP", (int)®s.nip-(int)®s);
- put_line(out, "_MSR", (int)®s.msr-(int)®s);
- /* put_line(out, "_SRR1", (int)®s.srr1-(int)®s);
- put_line(out, "_SRR0", (int)®s.srr0-(int)®s); */
- put_line(out, "_CTR", (int)®s.ctr-(int)®s);
- put_line(out, "_LINK", (int)®s.link-(int)®s);
- put_line(out, "_CCR", (int)®s.ccr-(int)®s);
- put_line(out, "_XER", (int)®s.xer-(int)®s);
- put_line(out, "_DAR", (int)®s.dar-(int)®s);
- put_line(out, "_DSISR", (int)®s.dsisr-(int)®s);
- put_line(out, "_HASH1", (int)®s.hash1-(int)®s);
- put_line(out, "_HASH2", (int)®s.hash2-(int)®s);
- put_line(out, "_IMISS", (int)®s.imiss-(int)®s);
- put_line(out, "_DMISS", (int)®s.dmiss-(int)®s);
- put_line(out, "_ICMP", (int)®s.icmp-(int)®s);
- put_line(out, "_DCMP", (int)®s.dcmp-(int)®s);
- put_line(out, "ORIG_GPR3", (int)®s.orig_gpr3-(int)®s);
- put_line(out, "RESULT", (int)®s.result-(int)®s);
- put_line(out, "TRAP", (int)®s.trap-(int)®s);
- put_line(out, "MARKER", (int)®s.marker-(int)®s);
- exit(0);
-}
-
-put_line(FILE *out, char *name, int offset)
-{
- fprintf(out, "#define %s %d\n", name, offset);
+ DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+ /* Interrupt register frame */
+ DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
+ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+ DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+ DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+ DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+ DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+ DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+ DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+ DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+ DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+ DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+ DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+ DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+ DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+ DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+ DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+ DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+ DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+ DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+ DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+ DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+ DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+ DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+ DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+ DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+ DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+ DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+ DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+ DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+ DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+ DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+ DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+ DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+ DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+ DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+ /* Note: these symbols include _ because they overlap with special register names */
+ DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+ DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+ DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+ DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+ DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+ DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+ DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+ DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+ DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+ DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+ DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
}
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
/*
* PCI interrupt configuration. This is motherboard specific.
*/
-
-
/* Which PCI interrupt line does a given device [slot] use? */
/* Note: This really should be two dimensional based in slot/pin used */
unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
/* How is the 82378 PIRQ mapping setup? */
unsigned char *Motherboard_routes;
/* Motorola PowerStack */
static char Blackhawk_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Blackhawk_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* Motorola MVME16xx */
static char Genesis_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Genesis_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
10, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* Motorola Series-E */
static char Comet_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Comet_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
10, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* BeBox */
static char BeBox_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
0, /* Slot 13 - unused */
0, /* Slot 14 - unused */
0, /* Slot 15 - unused */
- };
+};
static char BeBox_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* IBM Nobis */
static char Nobis_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
0, /* Slot 13 - unused */
0, /* Slot 14 - unused */
0, /* Slot 15 - unused */
- };
+};
static char Nobis_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
13, /* Line 1 */
13, /* Line 2 */
13, /* Line 3 */
13 /* Line 4 */
- };
+};
+
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - FireCoral */
+ 4, /* Slot 12 - Ethernet PCIINTD# */
+ 2, /* Slot 13 - PCI Slot #2 */
+ 2, /* Slot 14 - S3 Video PCIINTD# */
+ 0, /* Slot 15 - onboard SCSI (INDI) [1] */
+ 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+ 0, /* Line 0 - unused */
+ 13, /* Line 1 */
+ 10, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
+ * it really needs some logic to set them to unique IRQ's, or even
+ * add some logic to the drivers to ask an irq.c routine to re-map
+ * the IRQ if it needs one to itself...
+ */
+static char Carolina_PIRQ_routes[] = {
+ 0xad, /* INTB# = 10, INTA# = 13 */
+ 0xff /* INTD# = 15, INTC# = 15 */
+};
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
+#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+#define PCI_DEVICE_ID_IBM_CORAL 0x000a
-#define PCI_DEBUG
#undef PCI_DEBUG
#ifdef PCI_STATS
int PCI_conversions[2];
#endif
-unsigned long pcibios_init(unsigned long mem_start,
- unsigned long mem_end)
-{
- return mem_start;
-}
unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
{
- return mem_start;
-}
-
-
-unsigned long
-_LE_to_BE_long(unsigned long val)
-{
- unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
- PCI_conversions[0]++;
-#endif
- return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0] << 0));
-}
-
-unsigned short
-_LE_to_BE_short(unsigned long val)
-{
- unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
- PCI_conversions[1]++;
-#endif
- return ((p[3] << 8) | (p[2] << 0));
+ return mem_start;
}
int
int
pcibios_read_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int *val)
+ unsigned char dev, unsigned char offset, unsigned int *val)
{
unsigned long _val;
unsigned long *ptr;
#ifdef PCI_DEBUG
printk("[%x] ", ptr);
#endif
- _val = _LE_to_BE_long(*ptr);
+ _val = le32_to_cpu(*ptr);
}
#ifdef PCI_DEBUG
printk("%x\n", _val);
int
pcibios_read_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short *val)
+ unsigned char dev, unsigned char offset, unsigned short *val)
{
unsigned short _val;
unsigned short *ptr;
dev >>= 3;
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
#endif
if ((bus != 0) || (dev < 11) || (dev > 16))
{
- *val = 0xFFFFFFFF;
+ *val = (unsigned short)0xFFFFFFFF;
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("[%x] ", ptr);
#endif
- _val = _LE_to_BE_short(*ptr);
+ _val = le16_to_cpu(*ptr);
}
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("%x\n", _val);
#endif
*val = _val;
int
pcibios_read_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char *val)
+ unsigned char dev, unsigned char offset, unsigned char *val)
{
unsigned char _val;
volatile unsigned char *ptr;
if (Motherboard_map[dev] <= 4)
{
*val = Motherboard_routes[Motherboard_map[dev]];
+ /*printk("dev %d map %d route %d\n",
+ dev,Motherboard_map[dev],
+ Motherboard_routes[Motherboard_map[dev]]);*/
} else
{ /* Pseudo interrupts [for BeBox] */
*val = Motherboard_map[dev];
int
pcibios_write_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int val)
+ unsigned char dev, unsigned char offset, unsigned int val)
{
unsigned long _val;
unsigned long *ptr;
dev >>= 3;
- _val = _LE_to_BE_long(val);
+ _val = le32_to_cpu(val);
#ifdef PCI_DEBUG
printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
#endif
int
pcibios_write_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short val)
+ unsigned char dev, unsigned char offset, unsigned short val)
{
unsigned short _val;
unsigned short *ptr;
dev >>= 3;
- _val = _LE_to_BE_short(val);
+ _val = le16_to_cpu(val);
#ifdef PCI_DEBUG
printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
#endif
int
pcibios_write_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char val)
+ unsigned char dev, unsigned char offset, unsigned char val)
{
unsigned char _val;
unsigned char *ptr;
int
pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *dev)
+ unsigned char *bus, unsigned char *dev)
{
int dev_nr, class, indx;
indx = 0;
*bus = 0;
*dev = dev_nr<<3;
#ifdef PCI_DEBUG
- printk(" - device: %x\n", dev_nr);
+ printk(" - device: %x\n", dev_nr);
#endif
return (0);
}
static char buf[32];
switch (error)
{ case PCIBIOS_SUCCESSFUL:
- return ("PCI BIOS: no error");
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return ("PCI BIOS: function not supported");
- case PCIBIOS_BAD_VENDOR_ID:
- return ("PCI BIOS: bad vendor ID");
- case PCIBIOS_DEVICE_NOT_FOUND:
- return ("PCI BIOS: device not found");
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return ("PCI BIOS: bad register number");
- case PCIBIOS_SET_FAILED:
- return ("PCI BIOS: set failed");
- case PCIBIOS_BUFFER_TOO_SMALL:
- return ("PCI BIOS: buffer too small");
- default:
- sprintf(buf, "PCI BIOS: invalid error #%d", error);
- return(buf);
+ return ("PCI BIOS: no error");
+ case PCIBIOS_FUNC_NOT_SUPPORTED:
+ return ("PCI BIOS: function not supported");
+ case PCIBIOS_BAD_VENDOR_ID:
+ return ("PCI BIOS: bad vendor ID");
+ case PCIBIOS_DEVICE_NOT_FOUND:
+ return ("PCI BIOS: device not found");
+ case PCIBIOS_BAD_REGISTER_NUMBER:
+ return ("PCI BIOS: bad register number");
+ case PCIBIOS_SET_FAILED:
+ return ("PCI BIOS: set failed");
+ case PCIBIOS_BUFFER_TOO_SMALL:
+ return ("PCI BIOS: buffer too small");
+ default:
+ sprintf(buf, "PCI BIOS: invalid error #%d", error);
+ return(buf);
}
}
* Note: This routine has to access the PCI configuration space
* for the PCI bridge chip (Intel 82378).
*/
-
-void route_PCI_interrupts(void)
+unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
+{
+ return mem_start;
+}
+
+unsigned long route_pci_interrupts(void)
{
unsigned char *ibc_pirq = (unsigned char *)0x80800860;
unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
extern unsigned long isBeBox[];
int i;
- /* Decide which motherboard this is & how the PCI interrupts are routed */
- if (isBeBox[0])
- {
- Motherboard_map = BeBox_pci_IRQ_map;
- Motherboard_routes = BeBox_pci_IRQ_routes;
- } else
- if ((_get_PVR()>>16) == 1)
- { /* Nobis */
- Motherboard_map = Nobis_pci_IRQ_map;
- Motherboard_routes = Nobis_pci_IRQ_routes;
- } else
- { /* Motorola hardware */
+
+ if ( _machine == _MACH_Motorola)
+ {
switch (inb(0x800) & 0xF0)
{
- case 0x10: /* MVME16xx */
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
+ case 0x10: /* MVME16xx */
+ Motherboard_map_name = "Genesis";
+ Motherboard_map = Genesis_pci_IRQ_map;
+ Motherboard_routes = Genesis_pci_IRQ_routes;
+ break;
+ case 0x20: /* Series E */
+ Motherboard_map_name = "Series E";
+ Motherboard_map = Comet_pci_IRQ_map;
+ Motherboard_routes = Comet_pci_IRQ_routes;
+ break;
+ case 0x40: /* PowerStack */
+ default: /* Can't hurt, can it? */
+ Motherboard_map_name = "Blackhawk (Powerstack)";
+ Motherboard_map = Blackhawk_pci_IRQ_map;
+ Motherboard_routes = Blackhawk_pci_IRQ_routes;
+ break;
+ }
+ } else
+ {
+ if ( _machine == _MACH_IBM )
+ {
+ unsigned char pl_id;
+ unsigned long flags;
+ unsigned index;
+ unsigned char fn, bus;
+ unsigned int addr;
+ unsigned char dma_mode, ide_mode;
+ int i;
+
+ Motherboard_map_name = "IBM 8xx (Carolina)";
+ Motherboard_map = ibm8xx_pci_IRQ_map;
+ Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ll_printk("before loop\n");
+
+ for (index = 0;
+ !pcibios_find_device (PCI_VENDOR_ID_IBM,
+ PCI_DEVICE_ID_IBM_CORAL,
+ index, &bus, &fn); ++index)
+ {
+ pcibios_read_config_dword(bus, fn, 0x10, &addr);
+ addr &= ~0x3;
+ outb(0x26, addr);
+ dma_mode = inb(addr+4);
+ outb(0x25, addr);
+ ide_mode = inb(addr+4);
+ /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x",
+ addr, dma_mode, ide_mode);*/
+ /* Make CDROM non-DMA */
+ ide_mode = (ide_mode & 0x0F) | 0x20;
+ outb(0x25, addr);
+ outb(ide_mode, addr+4);
+ dma_mode = dma_mode & ~0x80;
+ outb(0x26, addr);
+ outb(dma_mode, addr+4);
+ outb(0x26, addr);
+ dma_mode = inb(addr+4);
+ outb(0x25, addr);
+ ide_mode = inb(addr+4);
+ /*printk("=> DMA mode: %x, IDE mode: %x\n",
+ dma_mode, ide_mode);*/
+ }
+
+ /* Setup the PCI INT mappings for the Carolina */
+ /* These are PCI Interrupt Route Control [1|2] Register */
+ outb(Carolina_PIRQ_routes[0], 0x0890);
+ outb(Carolina_PIRQ_routes[1], 0x0891);
+
+ pl_id=inb(0x0852);
+ /*printk("CPU Planar ID is %#0x\n", pl_id);*/
+
+ if (pl_id == 0x0C) {
+ /* INDI */
+ Motherboard_map[12] = 1;
+ }
+ll_printk("before edge/level\n");
+#if 0
+ /*printk("Changing IRQ mode\n");*/
+ pl_id=inb(0x04d0);
+ /*printk("Low mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask now %#0x\n", pl_id);*/
+#endif
}
}
+
/* Set up mapping from slots */
for (i = 1; i <= 4; i++)
{
}
/* Enable PCI interrupts */
*ibc_pcicon |= 0x20;
-}
+}
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Adapted for Power Macintosh by Paul Mackerras
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from "arch/alpha/kernel/setup.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/ide.h>
+
+extern int root_mountflags;
+
+extern char command_line[];
+char saved_command_line[256];
+
+unsigned char aux_device_present; /* XXX */
+unsigned char kbd_read_mask;
+unsigned char drive_info;
+
+#define DEFAULT_ROOT_DEVICE 0x0801 /* sda1 - slightly silly choice */
+
+extern unsigned long find_available_memory(void);
+
+unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
+{
+ return memory_start;
+}
+
+void setup_arch(char **cmdline_p,
+ unsigned long * memory_start_p, unsigned long * memory_end_p)
+{
+ extern unsigned long *end_of_DRAM;
+ struct device_node *cpu;
+ int *fp;
+
+ strcpy(saved_command_line, command_line);
+ *cmdline_p = command_line;
+
+ *memory_start_p = find_available_memory();
+ *memory_end_p = (unsigned long) end_of_DRAM;
+
+ set_prom_callback();
+
+ *memory_start_p = copy_device_tree(*memory_start_p, *memory_end_p);
+
+ /* Set loops_per_sec to a half-way reasonable value,
+ for use until calibrate_delay gets called. */
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0) {
+ switch (_get_PVR() >> 16) {
+ case 4: /* 604 */
+ loops_per_sec = *fp;
+ break;
+ default: /* 601, 603, etc. */
+ loops_per_sec = *fp / 2;
+ }
+ } else
+ loops_per_sec = 50000000;
+ }
+}
+
+char *bootpath;
+char bootdevice[256];
+void *boot_host;
+int boot_target;
+int boot_part;
+kdev_t boot_dev;
+
+unsigned long
+pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+{
+ struct device_node *chosen_np;
+
+ nvram_init();
+ via_cuda_init();
+ read_rtc_time();
+ pmac_find_display();
+ bootpath = NULL;
+ chosen_np = find_devices("chosen");
+ if (chosen_np != NULL)
+ bootpath = (char *) get_property(chosen_np, "bootpath", NULL);
+ if (bootpath != NULL) {
+ /*
+ * There's a bug in the prom. (Why am I not surprised.)
+ * If you pass a path like scsi/sd@1:0 to canon, it returns
+ * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+ * That is, the scsi target number doesn't get preserved.
+ */
+ call_prom("canon", 3, 1, bootpath, bootdevice, sizeof(bootdevice));
+ }
+ return mem_start;
+}
+
+void
+note_scsi_host(struct device_node *node, void *host)
+{
+ int l;
+ char *p;
+
+ l = strlen(node->full_name);
+ if (strncmp(node->full_name, bootdevice, l) == 0
+ && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+ boot_host = host;
+ p = strstr(bootpath, "/sd@");
+ if (p != NULL) {
+ p += 4;
+ boot_target = simple_strtoul(p, NULL, 10);
+ p = strchr(p, ':');
+ if (p != NULL)
+ boot_part = simple_strtoul(p + 1, NULL, 10);
+ }
+ }
+}
+
+void find_scsi_boot()
+{
+ int dev;
+
+ if (kdev_t_to_nr(ROOT_DEV) != 0)
+ return;
+ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+ if (boot_host == NULL)
+ return;
+ dev = sd_find_target(boot_host, boot_target);
+ if (dev == 0)
+ return;
+ boot_dev = to_kdev_t(dev + boot_part);
+}
+
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+ struct device_node *np;
+ int i;
+ static struct device_node *atas;
+ static int atas_valid;
+
+ *p = 0;
+ *irq = 0;
+ if (!atas_valid) {
+ atas = find_devices("ATA");
+ atas_valid = 1;
+ }
+ for (i = (int)base, np = atas; i > 0 && np != NULL; --i, np = np->next)
+ ;
+ if (np == NULL)
+ return;
+ if (np->n_addrs == 0) {
+ printk("ide: no addresses for device %s\n", np->full_name);
+ return;
+ }
+ if (np->n_intrs == 0) {
+ printk("ide: no intrs for device %s, using 13\n",
+ np->full_name);
+ np->intrs[0] = 13;
+ }
+ base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
+ for (i = 0; i < 8; ++i)
+ *p++ = base + i * 0x10;
+ *p = base + 0x160;
+ *irq = np->intrs[0];
+}
+
+int sys_ioperm(unsigned long from, unsigned long num, int on)
+{
+ return -EIO;
+}
+
+#if 0
+extern char builtin_ramdisk_image;
+extern long builtin_ramdisk_size;
+#endif
+
+void
+builtin_ramdisk_init(void)
+{
+#if 0
+ if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
+ {
+ rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
+ } else
+#endif
+ { /* Not ramdisk - assume root needs to be mounted read only */
+ root_mountflags |= MS_RDONLY;
+ }
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+ int pvr = _get_PVR();
+ char *model;
+ struct device_node *cpu;
+ int l, *fp;
+
+ l = 0;
+ cpu = find_type_devices("cpu");
+ if (cpu != 0) {
+ fp = (int *) get_property(cpu, "clock-frequency", NULL);
+ if (fp != 0)
+ l += sprintf(buffer, "%dMHz ", *fp / 1000000);
+ }
+
+ switch (pvr>>16) {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+ return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
+ (pvr & 0xff) >> 8, pvr & 0xff);
+}
--- /dev/null
+/*
+ * Miscellaneous procedures for dealing with the PowerMac hardware.
+ */
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <asm/ptrace.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+
+void hard_reset_now(void)
+{
+ struct cuda_request req;
+
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+ for (;;)
+ cuda_poll();
+}
+
+void poweroff_now(void)
+{
+ struct cuda_request req;
+
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+ for (;;)
+ cuda_poll();
+}
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs.
+ */
+static int nvram_naddrs;
+static volatile unsigned char *nvram_addr;
+static volatile unsigned char *nvram_data;
+
+void nvram_init(void)
+{
+ struct device_node *dp;
+
+ dp = find_devices("nvram");
+ if (dp == NULL)
+ panic("Can't find NVRAM device");
+ nvram_naddrs = dp->n_addrs;
+ if (nvram_naddrs == 1)
+ nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ else if (nvram_naddrs == 2) {
+ nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
+ nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+ } else {
+ printk("Found %d addresses for NVRAM\n", nvram_naddrs);
+ panic("don't understand NVRAM");
+ }
+}
+
+int nvram_readb(int addr)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ return nvram_data[(addr & 0x1fff) << 4];
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ return nvram_data[(addr & 0x1f) << 4];
+ }
+ return -1;
+}
+
+void nvram_writeb(int addr, int val)
+{
+ switch (nvram_naddrs) {
+ case 1:
+ nvram_data[(addr & 0x1fff) << 4] = val;
+ break;
+ case 2:
+ *nvram_addr = addr >> 5;
+ eieio();
+ nvram_data[(addr & 0x1f) << 4] = val;
+ break;
+ }
+ eieio();
+}
--- /dev/null
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * At present, we use the decrementer register in the 601 CPU
+ * for our periodic interrupts. This will probably have to be
+ * changed for other processors.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+static int get_dec(void);
+static void set_dec(int);
+static unsigned long get_rtc_time(void);
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET 2082844800
+
+/* Accessor functions for the decrementer register. */
+static inline int
+get_dec()
+{
+ int ret;
+
+ asm volatile("mfspr %0,22" : "=r" (ret) :);
+ return ret;
+}
+
+static inline void
+set_dec(int val)
+{
+ asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601 (1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601 1
+#define COUNT_PERIOD_DEN_601 1000
+
+unsigned decrementer_count; /* count value for 1e6/HZ microseconds */
+unsigned count_period_num; /* 1 decrementer count equals */
+unsigned count_period_den; /* count_period_num / count_period_den us */
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += (decrementer_count - get_dec())
+ * count_period_num / count_period_den;
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ int frac_tick;
+
+ frac_tick = tv->tv_usec % (1000000 / HZ);
+ save_flags(flags);
+ cli();
+ xtime.tv_sec = tv->tv_sec;
+ xtime.tv_usec = tv->tv_usec - frac_tick;
+ set_dec(frac_tick * count_period_den / count_period_num);
+ restore_flags(flags);
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+ int dval, d;
+
+ while ((dval = get_dec()) < 0) {
+ /*
+ * Wait for the decrementer to change, then jump
+ * in and add decrementer_count to its value
+ * (quickly, before it changes again!)
+ */
+ while ((d = get_dec()) == dval)
+ ;
+ set_dec(d + decrementer_count);
+ do_timer(regs);
+ }
+
+}
+
+void
+time_init(void)
+{
+ struct device_node *cpu;
+ int freq, *fp, divisor;
+
+ if ((_get_PVR() >> 16) == 1) {
+ /* 601 processor: dec counts down by 128 every 128ns */
+ decrementer_count = DECREMENTER_COUNT_601;
+ count_period_num = COUNT_PERIOD_NUM_601;
+ count_period_den = COUNT_PERIOD_DEN_601;
+ } else {
+ /*
+ * The cpu node should have a timebase-frequency property
+ * to tell us the rate at which the decrementer counts.
+ */
+ cpu = find_type_devices("cpu");
+ if (cpu == 0)
+ panic("can't find cpu node in time_init");
+ fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+ if (fp == 0)
+ panic("can't get cpu timebase frequency");
+ freq = *fp * 60; /* try to make freq/1e6 an integer */
+ divisor = 60;
+ printk("time_init: decrementer frequency = %d/%d\n",
+ freq, divisor);
+ decrementer_count = freq / HZ / divisor;
+ count_period_num = divisor;
+ count_period_den = freq / 1000000;
+ }
+ set_dec(decrementer_count);
+}
+
+/*
+ * We can't do this in time_init, because via_cuda_init hasn't
+ * been called at that stage.
+ */
+void
+read_rtc_time(void)
+{
+ xtime.tv_sec = get_rtc_time();
+ xtime.tv_usec = 0;
+}
+
+static unsigned long
+get_rtc_time()
+{
+ struct cuda_request req;
+
+ /* Get the time from the RTC */
+ cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+ while (!req.got_reply)
+ cuda_poll();
+ if (req.reply_len != 7)
+ panic("get_rtc_time: didn't expect %d byte reply",
+ req.reply_len);
+ return (req.reply[3] << 24) + (req.reply[4] << 16)
+ + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
+}
/*
* I/O 'port' access routines
*/
+#include <asm/byteorder.h>
+#include <asm/io.h>
-/* This is really only correct for the MVME16xx (PreP)? */
+#define inb_asm(port) {( \
+ unsigned char ret; \
+ asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
+ return ret; \
+})
-#define _IO_BASE ((unsigned long)0x80000000)
-
-unsigned char
+inline unsigned char
inb(int port)
{
- return (*((unsigned char *)(_IO_BASE+port)));
+ unsigned char ret;
+ asm("/*inb*/\n");
+ asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
+ return ret;
}
-unsigned short
+inline unsigned short
inw(int port)
{
- return (_LE_to_BE_short(*((unsigned short *)(_IO_BASE+port))));
+ unsigned short ret;
+ asm("/*inw*/\n");
+ asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+ return ret;
}
-unsigned long
+inline unsigned long
inl(int port)
{
- return (_LE_to_BE_long(*((unsigned long *)(_IO_BASE+port))));
+ unsigned long ret;
+ asm("/*inl*/\n");
+ asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+ return ret;
}
-void insb(int port, char *ptr, int len)
+inline unsigned char
+outb(unsigned char val,int port)
{
- unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = *io_ptr;
- }
+ asm("/*outb*/\n");
+ asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
+ return (val);
}
-#if 0
-void insw(int port, short *ptr, int len)
-{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = _LE_to_BE_short(*io_ptr);
- }
-}
-#else
-void insw(int port, short *ptr, int len)
+inline unsigned short
+outw(unsigned short val,int port)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- _insw(io_ptr, ptr, len);
+ asm("/*outw*/\n");
+ asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+ return (val);
}
-#endif
-void insw_unswapped(int port, short *ptr, int len)
+inline unsigned long
+outl(unsigned long val,int port)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = *io_ptr;
- }
+ asm("/*outl*/\n");
+ asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+ return (val);
}
-void insl(int port, long *ptr, int len)
+void insb(int port, char *ptr, int len)
{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = _LE_to_BE_long(*io_ptr);
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
}
-unsigned char inb_p(int port) {return (inb(port)); }
-unsigned short inw_p(int port) {return (inw(port)); }
-unsigned long inl_p(int port) {return (inl(port)); }
-
-unsigned char
-outb(unsigned char val,int port)
+void insw(int port, short *ptr, int len)
{
- *((unsigned char *)(_IO_BASE+port)) = (val);
- return (val);
+ asm ("mtctr %2 \n\t"
+ "subi %1,%1,2 \n\t"
+ "00:\n\t"
+ "lhbrx %2,0,%0 \n\t"
+ "sthu %2,2(%1) \n\t"
+ "bdnz 00b \n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-unsigned short
-outw(unsigned short val,int port)
+void insw_unswapped(int port, short *ptr, int len)
{
- *((unsigned short *)(_IO_BASE+port)) = _LE_to_BE_short(val);
- return (val);
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
}
-unsigned long
-outl(unsigned long val,int port)
+void insl(int port, long *ptr, int len)
{
- *((unsigned long *)(_IO_BASE+port)) = _LE_to_BE_long(val);
- return (val);
+ asm ("mtctr %2 \n\t"
+ "subi %1,%1,4 \n\t"
+ "00:\n\t"
+ "lhbrx %2,0,%0 \n\t"
+ "sthu %2,4(%1) \n\t"
+ "bdnz 00b \n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
void outsb(int port, char *ptr, int len)
{
- unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = *ptr++;
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
}
-#if 0
void outsw(int port, short *ptr, int len)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = _LE_to_BE_short(*ptr++);
- }
+ asm ("mtctr %2\n\t"
+ "subi %1,%1,2\n\t"
+ "00:lhzu %2,2(%1)\n\t"
+ "sthbrx %2,0,%0\n\t"
+ "bdnz 00b\n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-#else
-void outsw(int port, short *ptr, int len)
-{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- _outsw(io_ptr, ptr, len);
-}
-#endif
void outsw_unswapped(int port, short *ptr, int len)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = *ptr++;
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );
}
void outsl(int port, long *ptr, int len)
{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = _LE_to_BE_long(*ptr++);
- }
+ asm ("mtctr %2\n\t"
+ "subi %1,%1,4\n\t"
+ "00:lwzu %2,4(%1)\n\t"
+ "sthbrx %2,0,%0\n\t"
+ "bdnz 00b\n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-unsigned char outb_p(unsigned char val,int port) { return (outb(val,port)); }
-unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-unsigned long outl_p(unsigned long val,int port) { return (outl(val,port)); }
-
+void insl_unswapped(int port, long *ptr, int len)
+{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ while (len-- > 0)
+ {
+ *ptr++ = (*io_ptr);
+ }
+}
-/* makes writing to the ibm acorn power management stuff easier -- Cort */
-/* args in forn of PA.B as in tech spec for ibm carolina */
-void ibm_write(unsigned char val,unsigned int port)
+void outsl_unswapped(int port, long *ptr, int len)
{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ while (len-- > 0)
+ {
+ *io_ptr = (*ptr++);
+ }
}
* This file contains all the macros and symbols which define
* a PowerPC assembly language environment.
*/
-
+#include <linux/config.h>
#define _TEXT()\
.text
-#if 0 /* Old way */
-#define _EXTERN(n) .##n
-
-#define _GLOBAL(n)\
- .globl n;\
-n: .long _EXTERN(n);\
- .globl _EXTERN(n);\
-_EXTERN(n):
-#else
#define _EXTERN(n) n
#define SYMBOL_NAME(x) x
#define _GLOBAL(n)\
.globl n;\
n:
-#endif
#ifndef FALSE
#define FALSE 0
#define SDR1 25 /* MMU hash base register */
#define DAR 19 /* Data Address Register */
#define SPR0 272 /* Supervisor Private Registers */
+#define SPRG0 272
#define SPR1 273
+#define SPRG1 273
#define SPR2 274
+#define SPRG2 274
#define SPR3 275
+#define SPRG3 275
#define DSISR 18
#define SRR0 26 /* Saved Registers (exception) */
#define SRR1 27
#define SR14 14
#define SR15 15
+#define curptr r2
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
/* Missing instructions */
#define bdne bc 0,2,
-#include "asm/ppc_machine.h"
--- /dev/null
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
+#define STATE 0
+#define NEXT_TASK 68
+#define COUNTER 4
+#define BLOCKED 16
+#define SIGNAL 12
+#define TSS 544
+#define KSP 0
+#define PG_TABLES 4
+#define LAST_SYSCALL 288
+#define PT_REGS 280
+#define PF_TRACESYS 32
+#define TASK_FLAGS 20
+#define TSS_FPR0 16
+#define TSS_FPSCR 12
+#define TASK_UNION_SIZE 8192
+#define STACK_FRAME_OVERHEAD 16
+#define INT_FRAME_SIZE 192
+#define GPR0 16
+#define GPR1 20
+#define GPR2 24
+#define GPR3 28
+#define GPR4 32
+#define GPR5 36
+#define GPR6 40
+#define GPR7 44
+#define GPR8 48
+#define GPR9 52
+#define GPR10 56
+#define GPR11 60
+#define GPR12 64
+#define GPR13 68
+#define GPR14 72
+#define GPR15 76
+#define GPR16 80
+#define GPR17 84
+#define GPR18 88
+#define GPR19 92
+#define GPR20 96
+#define GPR21 100
+#define GPR22 104
+#define GPR23 108
+#define GPR24 112
+#define GPR25 116
+#define GPR26 120
+#define GPR27 124
+#define GPR28 128
+#define GPR29 132
+#define GPR30 136
+#define GPR31 140
+#define _NIP 144
+#define _MSR 148
+#define _CTR 152
+#define _LINK 156
+#define _CCR 160
+#define _XER 164
+#define _DAR 168
+#define _DSISR 172
+#define ORIG_GPR3 176
+#define RESULT 180
+#define TRAP 184
--- /dev/null
+/*
+ * WARNING! This file is automatically generated - DO NOT EDIT!
+ */
--- /dev/null
+/*
+ * linux/arch/ppc/kernel/setup.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Adapted from 'alpha' version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/major.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+/* for the mac fs */
+kdev_t boot_dev;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+extern int probingmem;
+extern unsigned long loops_per_sec;
+
+unsigned long empty_zero_page[1024];
+unsigned char aux_device_present;
+
+#ifdef CONFIG_BLK_DEV_RAM
+extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
+extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
+extern int rd_image_start; /* starting block # of image */
+#endif
+
+/* copy of the residual data */
+RESIDUAL res;
+/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
+unsigned long resptr = 0;
+int _machine;
+extern unsigned long _TotalMemory;
+
+#define COMMAND_LINE_SIZE 256
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+char saved_command_line[COMMAND_LINE_SIZE];
+#ifdef HASHSTATS
+unsigned long evicts;
+#endif
+
+struct screen_info screen_info = {
+ 0, 25, /* orig-x, orig-y */
+ { 0, 0 }, /* unused */
+ 0, /* orig-video-page */
+ 0, /* orig-video-mode */
+ 80, /* orig-video-cols */
+ 0,0,0, /* ega_ax, ega_bx, ega_cx */
+ 25, /* orig-video-lines */
+ 1, /* orig-video-isVGA */
+ 16 /* orig-video-points */
+};
+
+void machine_halt(void)
+{
+ machine_restart(NULL);
+}
+
+void machine_power_off(void)
+{
+ machine_restart(NULL);
+}
+
+void machine_restart(char *cmd)
+{
+ unsigned char ctl;
+ unsigned long flags;
+ unsigned long i = 10000;
+
+ _disable_interrupts();
+
+ /* set exception prefix high - to the prom */
+ save_flags( flags );
+ restore_flags( flags|MSR_IP );
+
+ /* make sure bit 0 (reset) is a 0 */
+ outb( inb(0x92) & ~1L , 0x92 );
+ /* signal a reset to system control port A - soft reset */
+ outb( inb(0x92) | 1 , 0x92 );
+
+ while ( i != 0 ) i++;
+ panic("restart failed\n");
+}
+
+int
+get_cpuinfo(char *buffer)
+{
+ extern char *Motherboard_map_name;
+ int i;
+ int pvr = _get_PVR();
+ int len;
+ char *model;
+ PTE *ptr;
+ unsigned long kptes = 0, uptes = 0, overflow = 0;
+ unsigned int ti;
+
+
+ switch (pvr>>16)
+ {
+ case 1:
+ model = "601";
+ break;
+ case 3:
+ model = "603";
+ break;
+ case 4:
+ model = "604";
+ break;
+ case 6:
+ model = "603e";
+ break;
+ case 7:
+ model = "603ev";
+ break;
+ default:
+ model = "unknown";
+ break;
+ }
+
+#ifdef __SMP__
+#define CD(X) (cpu_data[n].X)
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+
+ len = sprintf(buffer,"processor\t: %d\n"
+ "cpu\t\t: %s\n"
+ "revision\t: %d.%d\n"
+ "upgrade\t\t: %s\n"
+ "clock\t\t: %dMHz\n"
+ "bus clock\t: %dMHz\n"
+ "machine\t\t: %s (sn %s)\n"
+ "pci map\t\t: %s\n",
+ CPUN,
+ model,
+ MAJOR(pvr), MINOR(pvr),
+ (inb(IBM_EQUIP_PRESENT) & 2) ? "not upgrade" : "upgrade",
+ (res.VitalProductData.ProcessorHz > 1024) ?
+ res.VitalProductData.ProcessorHz>>20 :
+ res.VitalProductData.ProcessorHz,
+ (res.VitalProductData.ProcessorBusHz > 1024) ?
+ res.VitalProductData.ProcessorBusHz>>20 :
+ res.VitalProductData.ProcessorBusHz,
+ res.VitalProductData.PrintableModel,
+ res.VitalProductData.Serial,
+ Motherboard_map_name
+ );
+
+ /* print info about SIMMs */
+ len += sprintf(buffer+len,"simms\t\t: ");
+ for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+ {
+ if ( res.Memories[i].SIMMSize != 0 )
+ len += sprintf(buffer+len,"%d:%dM ",i,
+ (res.Memories[i].SIMMSize > 1024) ?
+ res.Memories[i].SIMMSize>>20 :
+ res.Memories[i].SIMMSize);
+ }
+ len += sprintf(buffer+len,"\n");
+
+ /* TLB */
+ len += sprintf(buffer+len,"tlb\t\t:");
+ switch(res.VitalProductData.TLBAttrib)
+ {
+ case CombinedTLB:
+ len += sprintf(buffer+len," %d entries\n",
+ res.VitalProductData.TLBSize);
+ break;
+ case SplitTLB:
+ len += sprintf(buffer+len," (split I/D) %d/%d entries\n",
+ res.VitalProductData.I_TLBSize,
+ res.VitalProductData.D_TLBSize);
+ break;
+ case NoneTLB:
+ len += sprintf(buffer+len," not present\n");
+ break;
+ }
+
+ /* L1 */
+ len += sprintf(buffer+len,"l1\t\t: ");
+ switch(res.VitalProductData.CacheAttrib)
+ {
+ case CombinedCAC:
+ len += sprintf(buffer+len,"%dkB LineSize\n",
+ res.VitalProductData.CacheSize,
+ res.VitalProductData.CacheLineSize);
+ break;
+ case SplitCAC:
+ len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+ res.VitalProductData.I_CacheSize,
+ res.VitalProductData.D_CacheSize,
+ res.VitalProductData.D_CacheLineSize,
+ res.VitalProductData.D_CacheLineSize);
+ break;
+ case NoneCAC:
+ len += sprintf(buffer+len,"not present\n");
+ break;
+ }
+
+ /* L2 */
+ if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
+ {
+ int size;
+
+ len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
+ ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
+ (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
+ }
+ else
+ {
+ len += sprintf(buffer+len,"l2\t\t: not present\n");
+ }
+
+
+ len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n",
+ CD(loops_per_sec+2500)/500000,
+ (CD(loops_per_sec+2500)/5000) % 100);
+
+ /*
+ * Ooh's and aah's info about zero'd pages in idle task
+ */
+ {
+ extern unsigned int zerocount, zerototal, zeropage_hits;
+ len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
+ "current: %u (%uKb) hits: %u\n",
+ zerototal, (zerototal*PAGE_SIZE)>>10,
+ zerocount, (zerocount*PAGE_SIZE)>>10,
+ zeropage_hits);
+ }
+
+
+ /* ram/hash table info */
+ len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
+ Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
+
+ /* if booted print info about hash table use (overflows, etc) */
+#ifdef HASHSTATS
+ for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
+ {
+ if (ptr->v)
+ {
+ /* user not allowed read or write */
+ if (ptr->pp == PP_RWXX)
+ kptes++;
+ else
+ uptes++;
+ if (ptr->h == 1)
+ overflow++;
+ }
+ }
+ /*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
+ Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
+ /*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
+ "(%d%%)/%d (%d%% full)\n",
+ uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
+ kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
+ Hash_size/sizeof(PTE),
+ ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
+ len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
+ overflow,evicts);*/
+#endif /* HASHSTATS */
+ return len;
+}
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+ return memory_start;
+}
+
+__initfunc(void
+setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+ unsigned long * memory_end_p))
+{
+ extern char cmd_line[];
+ extern char _etext[], _edata[], _end[];
+ unsigned char reg;
+ extern int panic_timeout;
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ strcpy( saved_command_line, cmd_line );
+ *cmdline_p = cmd_line;
+
+ *memory_start_p = (unsigned long) Hash+Hash_size;
+ (unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_sec = 50000000;
+
+ /* reboot on panic */
+ /*panic_timeout = 180;*/
+
+ init_task.mm->start_code = PAGE_OFFSET;
+ init_task.mm->end_code = (unsigned long) _etext;
+ init_task.mm->end_data = (unsigned long) _edata;
+ init_task.mm->brk = (unsigned long) _end;
+
+ aux_device_present = 0xaa;
+
+ switch ( _machine )
+ {
+ case _MACH_IBM:
+ ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+ break;
+ case _MACH_Motorola:
+ ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+ break;
+ }
+ /*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
+#if 0
+ strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
+#endif
+
+#if 0
+ if ( _machine == _MACH_Motorola )
+ {
+ /* get root via nfs from gordito -- only used for testing */
+ ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* nfs */
+ /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
+ strcpy(cmd_line+strlen(cmd_line),
+ "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
+ "pandora nfsroot=/usr/src/root/");
+ }
+#endif
+
+#ifdef CONFIG_BLK_DEV_RAM
+#if 0
+ ROOT_DEV = to_kdev_t(0x0200); /* floppy */
+ rd_prompt = 1;
+ rd_doload = 1;
+ rd_image_start = 0;
+#endif
+#endif
+
+ request_region(0x20,0x20,"pic1");
+ request_region(0xa0,0x20,"pic2");
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+}
+
--- /dev/null
+/*
+ * linux/arch/i386/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * Adapted for PowerPC (PreP) by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * copied and modified from intel version
+ *
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+/* last time the cmos clock got updated */
+static long last_rtc_update = 0;
+static int set_rtc_mmss(unsigned long nowtime);
+unsigned long get_cmos_time(void);
+static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+ unsigned int, unsigned int, unsigned int);
+#define TIMER_IRQ 0
+
+/* Cycle counter value at the previous timer interrupt.. */
+static unsigned long long last_timer_cc = 0;
+static unsigned long long init_timer_cc = 0;
+
+#define TICK_SIZE tick
+#define FEBRUARY 2
+#define STARTOFTIME 1970
+#define SECDAY 86400L
+#define SECYR (SECDAY * 365)
+#define leapyear(year) ((year) % 4 == 0)
+#define days_in_year(a) (leapyear(a) ? 366 : 365)
+#define days_in_month(a) (month_days[(a) - 1])
+
+static int month_days[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+static unsigned long do_slow_gettimeoffset(void)
+{
+ int count;
+ unsigned long offset = 0;
+
+ /* timer count may underflow right here */
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+ /* we know probability of underflow is always MUCH less than 1% */
+ if (count > (LATCH - LATCH/100)) {
+ /* check for pending timer interrupt */
+ outb_p(0x0a, 0x20);
+ if (inb(0x20) & 1)
+ offset = TICK_SIZE;
+ }
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ count = (count + LATCH/2) / LATCH;
+ return offset + count;
+}
+
+static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+ tv->tv_usec -= do_gettimeoffset();
+
+ if (tv->tv_usec < 0) {
+ tv->tv_usec += 1000000;
+ tv->tv_sec--;
+ }
+
+ xtime = *tv;
+ time_state = TIME_ERROR;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+}
+
+void to_tm(int tim, struct rtc_time * tm)
+{
+ register int i;
+ register long hms, day;
+
+ day = tim / SECDAY;
+ hms = tim % SECDAY;
+
+ /* Hours, minutes, seconds are easy */
+ tm->tm_hour = hms / 3600;
+ tm->tm_min = (hms % 3600) / 60;
+ tm->tm_sec = (hms % 3600) % 60;
+
+ /* Number of years in days */
+ for (i = STARTOFTIME; day >= days_in_year(i); i++)
+ day -= days_in_year(i);
+ tm->tm_year = i;
+
+ /* Number of months in days left */
+ if (leapyear(tm->tm_year))
+ days_in_month(FEBRUARY) = 29;
+ for (i = 1; day >= days_in_month(i); i++)
+ day -= days_in_month(i);
+ days_in_month(FEBRUARY) = 28;
+ tm->tm_mon = i;
+
+ /* Days are what is left over (+1) from all that. */
+ tm->tm_mday = day + 1;
+}
+
+/*
+ * Set the hardware clock. -- Cort
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+ struct rtc_time tm;
+
+ to_tm(nowtime, &tm);
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ tm.tm_year -= 1900;
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_year);
+ }
+ CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
+ CMOS_WRITE(tm.tm_min,RTC_MINUTES);
+ CMOS_WRITE(tm.tm_hour,RTC_HOURS);
+ CMOS_WRITE(tm.tm_mon,RTC_MONTH);
+ CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
+ CMOS_WRITE(tm.tm_year,RTC_YEAR);
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
+ time_state = TIME_OK;
+ return 0;
+}
+
+unsigned long get_cmos_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ int i;
+
+ /* The Linux interpretation of the CMOS clock register contents:
+ * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+ * RTC registers show the second which has precisely just started.
+ * Let's hope other operating systems interpret the RTC the same way.
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+ } while (sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hour);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mon);
+ BCD_TO_BIN(year);
+ }
+ if ((year += 1900) < 1970)
+ year += 100;
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+{
+ do_timer(regs);
+
+ /* update the hw clock if:
+ * the time is marked out of sync (TIME_ERROR)
+ * or ~11 minutes have expired since the last update -- Cort
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+ if ( time_state == TIME_BAD ||
+ xtime.tv_sec > last_rtc_update + 660 )
+ /*if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+ xtime.tv_usec > 500000 - (tick >> 1) &&
+ xtime.tv_usec < 500000 + (tick >> 1))*/
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+#ifdef CONFIG_HEARTBEAT
+ /* use hard disk LED as a heartbeat instead -- much more useful
+ for debugging -- Cort */
+ switch(kstat.interrupts[0] % 101)
+ {
+ /* act like an actual heart beat -- ie thump-thump-pause... */
+ case 0:
+ case 20:
+ outb(1,IBM_HDD_LED);
+ break;
+ case 7:
+ case 27:
+ outb(0,IBM_HDD_LED);
+ break;
+ case 100:
+ break;
+ }
+#endif
+}
+
+
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+static inline unsigned long mktime(unsigned int year, unsigned int mon,
+ unsigned int day, unsigned int hour,
+ unsigned int min, unsigned int sec)
+{
+ if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ mon += 12; /* Puts Feb last since it has leap day */
+ year -= 1;
+ }
+ return (((
+ (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+ year*365 - 719499
+ )*24 + hour /* now have hours */
+ )*60 + min /* now have minutes */
+ )*60 + sec; /* finally seconds */
+}
+
+void time_init(void)
+{
+ void (*irq_handler)(int, void *,struct pt_regs *);
+ xtime.tv_sec = get_cmos_time();
+ xtime.tv_usec = 0;
+
+ /* If we have the CPU hardware time counters, use them */
+ irq_handler = timer_interrupt;
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+ panic("Could not allocate timer IRQ!");
+}
/*
* linux/arch/ppc/kernel/process.c
*
- * Copyright (C) 1995 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/process.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu) and
+ * Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/smp_lock.h>
-#include <asm/ppc_machine.h>
+int dump_fpu(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void print_backtrace(unsigned long *);
+void show_regs(struct pt_regs * regs);
+void inline zero_paged(void);
+extern unsigned long _get_SP(void);
-/*
- * Initial task structure. Make this a per-architecture thing,
- * because different architectures tend to have different
- * alignment requirements and potentially different initial
- * setup.
- */
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+#undef SHOW_TASK_SWITCHES 1
+#undef CHECK_STACK 1
+#undef IDLE_ZERO 1
+
+unsigned long
+kernel_stack_top(struct task_struct *tsk)
+{
+ return ((unsigned long)tsk) + sizeof(union task_union);
+}
+
+unsigned long
+task_top(struct task_struct *tsk)
+{
+ return ((unsigned long)tsk) + sizeof(struct task_struct);
+}
+
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
-
-int dump_fpu(void);
-void hard_reset_now(void);
-void switch_to(struct task_struct *, struct task_struct *);
-void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
- struct pt_regs *);
-void print_backtrace(unsigned long *);
+union task_union init_task_union = { INIT_TASK };
int
dump_fpu(void)
{
- return (1);
+ return (1);
}
-
/* check to make sure the kernel stack is healthy */
int check_stack(struct task_struct *tsk)
{
- extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
- int ret = 0;
- int i;
-
- /* skip check in init_kernel_task -- swapper */
- if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
- return;
- /* check bounds on stack -- above/below kstack page */
- if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
- {
- printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
- ret |= 1;
- }
-
- /* check for magic on kstack */
- if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
- {
- printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
- *(unsigned long *)(tsk->kernel_stack_page));
- ret |= 2;
- }
-
-#ifdef KERNEL_STACK_BUFFER
- /* check extra padding page under kernel stack */
- for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
- {
- struct pt_regs *regs;
-
- if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
- {
- printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
- *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
- regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
- printk("marker %x trap %x\n", regs->marker,regs->trap);
- print_backtrace((unsigned long *)(tsk->tss.ksp));
-
- ret |= 4;
- break;
- }
- }
+ unsigned long stack_top = kernel_stack_top(tsk);
+ unsigned long tsk_top = task_top(tsk);
+ int ret = 0;
+ unsigned long *i;
+
+#if 0
+ /* check tss magic */
+ if ( tsk->tss.magic != TSS_MAGIC )
+ {
+ ret |= 1;
+ printk("tss.magic bad: %08x\n", tsk->tss.magic);
+ }
#endif
-
-#if 0
- if (ret)
- panic("bad stack");
+
+ if ( !tsk )
+ printk("check_stack(): tsk bad tsk %p\n",tsk);
+
+ /* check if stored ksp is bad */
+ if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
+ {
+ printk("stack out of bounds: %s/%d\n"
+ " tsk_top %08x ksp %08x stack_top %08x\n",
+ tsk->comm,tsk->pid,
+ tsk_top, tsk->tss.ksp, stack_top);
+ ret |= 2;
+ }
+
+ /* check if stack ptr RIGHT NOW is bad */
+ if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
+ {
+ printk("current stack ptr out of bounds: %s/%d\n"
+ " tsk_top %08x sp %08x stack_top %08x\n",
+ current->comm,current->pid,
+ tsk_top, _get_SP(), stack_top);
+ ret |= 4;
+ }
+
+#if 0
+ /* check amount of free stack */
+ for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
+ {
+ if ( !i )
+ printk("check_stack(): i = %p\n", i);
+ if ( *i != 0 )
+ {
+ /* only notify if it's less than 900 bytes */
+ if ( (i - (unsigned long *)task_top(tsk)) < 900 )
+ printk("%d bytes free on stack\n",
+ i - task_top(tsk));
+ break;
+ }
+ }
#endif
- return(ret);
-}
+ if (ret)
+ {
+ panic("bad kernel stack");
+ }
+ return(ret);
+}
void
switch_to(struct task_struct *prev, struct task_struct *new)
{
- struct pt_regs *regs;
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- regs = (struct pt_regs *)(new->tss.ksp);
-#if 1
+ struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
+
+#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
- /* if a process has used fp 15 times, then turn
- on the fpu for good otherwise turn it on with the fp
- exception handler as needed.
- skip this for kernel tasks.
- -- Cort */
- if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
- {
-#if 0
- printk("turning off fpu: %s/%d fp_used %d\n",
- new->comm,new->pid,new->tss.fp_used);
-#endif
- regs->msr = regs->msr & ~MSR_FP;
- }
-#if 0
- printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
+ /* turn off fpu for task last to run */
+ /*prev->tss.regs->msr &= ~MSR_FP;*/
+
+#ifdef SHOW_TASK_SWITCHES
+ printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
+ prev->comm,prev->pid,prev->tss.regs->nip,
+ new->comm,new->pid,new->tss.regs->nip,new->mm->context);
#endif
new_tss = &new->tss;
old_tss = ¤t->tss;
- current_set[0] = new;
- _switch(old_tss, new_tss);
+ _switch(old_tss, new_tss, new->mm->context);
+ /* turn off fpu for task last to run */
_enable_interrupts(s);
}
+
+#include <linux/mc146818rtc.h>
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
+{
+#if 1
+ struct task_struct *p;
+ printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
+ printk("last %x\n", last_task_used_math);
+ printk("cur %x regs %x/%x tss %x/%x\n",
+ current, current->tss.regs,regs,¤t->tss,current->tss);
+ for_each_task(p)
+ {
+ if ((long)p < KERNELBASE)
+ {
+ printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
+ print_mm_info();
+ __cli();
+ while(1);
+ }
+ }
+ return regs->gpr[3];
+#endif
+#if 0
+ /* set the time in the cmos clock */
+ unsigned long hwtime, nowtime;
+ struct rtc_time tm;
+
+ hwtime = get_cmos_time();
+ to_tm(hwtime, &tm);
+ printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n",
+ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
+ tm.tm_mday, tm.tm_year);
+ return;
+#endif
+}
-asmlinkage int sys_debug(unsigned long r3)
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0; /* # currently pre-zero'd pages */
+unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0; /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
{
- lock_kernel();
- if (!strcmp(current->comm,"crashme"))
- printk("sys_debug(): r3 (syscall) %d\n", r3);
- unlock_kernel();
+ unsigned long page;
+ unsigned long s;
+
+ if ( zero_list )
+ {
+ /* atomically remove this page from the list */
+ asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
+ " lwz %0,0(%1)\n" /* get next -- new zero_list */
+ " stwcx. %0,0,%2\n" /* update zero_list */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list), "=&r" (page)
+ : "r" (&zero_list)
+ : "cc" );
+ /* we can update zerocount after the fact since it is not
+ * used for anything but control of a loop which doesn't
+ * matter since it won't effect anything if it zero's one
+ * less page -- Cort
+ */
+ atomic_inc((atomic_t *)&zeropage_hits);
+ atomic_dec((atomic_t *)&zerocount);
+ /* zero out the pointer to next in the page */
+ *(unsigned long *)page = 0;
+ return page;
+ }
return 0;
}
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+void inline zero_paged(void)
+{
+ extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+ unsigned long tmp;
+ pte_t ptep;
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ sprintf(current->comm, "zero_paged");
+ printk("Started zero_paged\n");
+ /* want priority over idle task and powerd */
+ current->priority = -98;
+ current->counter = -98;
+ __sti();
+
+ while ( zerocount < 128 )
+ {
+ /*
+ * Mark a page as reserved so we can mess with it
+ * If we're interrupted we keep this page and our place in it
+ * since we validly hold it and it's reserved for us.
+ */
+ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ if ( !pageptr )
+ {
+ printk("!pageptr in zero_paged\n");
+ goto retry;
+ }
+
+ if ( need_resched )
+ schedule();
+
+ /*
+ * Make the page no cache so we don't blow our cache with 0's
+ */
+ dir = pgd_offset( init_task.mm, pageptr );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, pageptr & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ }
+ }
+ }
+
+ /*
+ * Important here to not take time away from real processes.
+ */
+ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+ {
+ if ( need_resched )
+ schedule();
+ *(unsigned long *)(bytecount + pageptr) = 0;
+ }
+
+ /*
+ * If we finished zero-ing out a page add this page to
+ * the zero_list atomically -- we can't use
+ * down/up since we can't sleep in idle.
+ * Disabling interrupts is also a bad idea since we would
+ * steal time away from real processes.
+ * We can also have several zero_paged's running
+ * on different processors so we can't interfere with them.
+ * So we update the list atomically without locking it.
+ * -- Cort
+ */
+ /* turn cache on for this page */
+ pte_cache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+
+ /* atomically add this page to the list */
+ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
+ " stw %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+ " sync\n" /* let store settle */
+#endif
+ " mr %0,%2\n" /* update zero_list in reg */
+ " stwcx. %2,0,%1\n" /* update zero_list in mem */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list)
+ : "r" (&zero_list), "r" (pageptr)
+ : "cc" );
+ /*
+ * This variable is used in the above loop and nowhere
+ * else so the worst that could happen is we would
+ * zero out one more or one less page than we want
+ * per processor on the machine. This is because
+ * we could add our page to the list but not have
+ * zerocount updated yet when another processor
+ * reads it. -- Cort
+ */
+ atomic_inc((atomic_t *)&zerocount);
+ atomic_inc((atomic_t *)&zerototal);
+retry:
+ schedule();
+ }
+}
+
+void powerd(void)
+{
+ unsigned long msr, hid0;
+
+ sprintf(current->comm, "powerd");
+ __sti();
+ while (1)
+ {
+ /* want priority over idle task 'swapper' -- Cort */
+ current->priority = -99;
+ current->counter = -99;
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
+ if ( need_resched )
+ schedule();
+ /*
+ * The ibm carolina spec says that the eagle memory
+ * controller will detect the need for a snoop
+ * and wake up the processor so we don't need to
+ * check for cache operations that need to be
+ * snooped. The ppc book says the run signal
+ * must be asserted while napping for this though.
+ * -- Cort
+ */
+ }
+}
+
asmlinkage int sys_idle(void)
{
int ret = -EPERM;
-
- lock_kernel();
if (current->pid != 0)
goto out;
- /* endless idle loop with no priority at all */
+#ifdef IDLE_ZERO
+ /*
+ * want one per cpu since it would be nice to have all
+ * processors who aren't doing anything
+ * zero-ing pages since this daemon is lock-free
+ * -- Cort
+ */
+ kernel_thread(zero_paged, NULL, 0);
+#endif /* IDLE_ZERO */
+
+#ifdef CONFIG_POWERSAVING
+ /* no powersaving modes on 601 - one per processor */
+ if( (_get_PVR()>>16) != 1 )
+ kernel_thread(powerd, NULL, 0);
+#endif /* CONFIG_POWERSAVING */
+
+ /* endless loop with no priority at all */
+ current->priority = -100;
current->counter = -100;
- for (;;) {
+ for (;;)
+ {
schedule();
}
ret = 0;
out:
- unlock_kernel();
return ret;
}
void show_regs(struct pt_regs * regs)
{
+ int i;
+
+ printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+ regs->nip, regs->xer, regs->link, regs,regs->trap);
+ printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+ printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+ current, current->pid, current->comm, current->mm->pgd);
+ printk("Last syscall: %d ", current->tss.last_syscall);
+ printk("\nlast math %08X\n", last_task_used_math);
+ for (i = 0; i < 32; i++)
+ {
+ long r;
+ if ((i % 8) == 0)
+ {
+ printk("GPR%02d: ", i);
+ }
+
+ if ( get_user(r, &(regs->gpr[i])) )
+ goto out;
+ printk("%08X ", r);
+ if ((i % 8) == 7)
+ {
+ printk("\n");
+ }
+ }
+out:
}
void exit_thread(void)
{
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
}
void flush_thread(void)
{
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
}
void
}
/*
- * Copy a thread..
- */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- struct task_struct * p, struct pt_regs * regs)
+ * Copy a thread..
+ */
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
{
int i;
- SEGREG *segs;
struct pt_regs * childregs;
-
- /* Construct segment registers */
- segs = (SEGREG *)(p->tss.segs);
- for (i = 0; i < 8; i++)
- {
- segs[i].ks = 0;
- segs[i].kp = 1;
-#if 0
- segs[i].vsid = i | (nr << 4);
-#else
- segs[i].vsid = i | ((nr * 10000) << 4);
-#endif
- }
- if ((p->mm->context == 0) || (p->mm->count == 1))
- {
-#if 0
- p->mm->context = ((nr)<<4);
-#else
- p->mm->context = ((nr*10000)<<4);
-#endif
- }
-
- /* Last 8 are shared with kernel & everybody else... */
- for (i = 8; i < 16; i++)
- {
- segs[i].ks = 0;
- segs[i].kp = 1;
- segs[i].vsid = i;
- }
-
/* Copy registers */
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+ childregs = ((struct pt_regs *)
+ ((unsigned long)p + sizeof(union task_union)
+ - STACK_FRAME_OVERHEAD)) - 2;
+ *childregs = *regs;
- *childregs = *regs; /* STRUCT COPY */
+ if ((childregs->msr & MSR_PR) == 0)
+ childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = (unsigned long)(childregs);
+ p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
+ p->tss.regs = (struct pt_regs *)(childregs);
if (usp >= (unsigned long)regs)
{ /* Stack is in kernel space - must adjust */
childregs->gpr[1] = (long)(childregs+1);
{ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
- p->tss.fp_used = 0;
- return 0;
-}
+ p->tss.last_syscall = -1;
-/*
- * fill in the user structure for a core dump..
- */
-void dump_thread(struct pt_regs * regs, struct user * dump)
-{
+ /*
+ * copy fpu info - assume lazy fpu switch now always
+ * this should really be conditional on whether or
+ * not the process has used the fpu
+ * -- Cort
+ */
+ if ( last_task_used_math == current )
+ giveup_fpu();
+
+ memcpy(&p->tss.fpr, ¤t->tss.fpr, sizeof(p->tss.fpr));
+ p->tss.fpscr = current->tss.fpscr;
+ childregs->msr &= ~MSR_FP;
+
+ return 0;
}
-
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
{
int ret;
-
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
unlock_kernel();
}
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs *regs)
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs *regs)
{
int error;
char * filename;
-
- lock_kernel();
- /* getname does it's own verification of the address
- when it calls get_max_filename() but
- it will assume it's valid if get_fs() == KERNEL_DS
- which is always true on the ppc so we check
- it here
-
- this doesn't completely check any of these data structures,
- it just makes sure that the 1st long is in a good area
- and from there we assume that it's safe then
- -- Cort
- */
- /* works now since get_fs/set_fs work properly */
-#if 0
- if ( verify_area(VERIFY_READ,(void *)a0,1)
- && verify_area(VERIFY_READ,(void *)a1,1)
- && verify_area(VERIFY_READ,(void *)a2,1)
- )
- {
- return -EFAULT;
- }
-#endif
- error = getname((char *) a0, &filename);
- if (error)
+ filename = (int) getname((char *) a0);
+ error = PTR_ERR(filename);
+ if(IS_ERR(filename))
goto out;
- flush_instruction_cache();
+ if ( last_task_used_math == current )
+ last_task_used_math = NULL;
error = do_execve(filename, (char **) a1, (char **) a2, regs);
-#if 0
-if (error)
-{
-printk("EXECVE - file = '%s', error = %d\n", filename, error);
-}
-#endif
+
putname(filename);
+
out:
unlock_kernel();
return error;
{
unsigned long clone_flags = p1;
int res;
-
+
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
unlock_kernel();
void
print_backtrace(unsigned long *sp)
{
-#if 0
int cnt = 0;
- printk("... Call backtrace:\n");
- while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
+ int i;
+ printk("Call backtrace: ");
+ while ( !get_user(i, sp) && i)
{
- printk("%08X ", sp[1]);
- sp = (unsigned long *)*sp;
+ if ( get_user( i, &sp[1] ) )
+ return;
+ printk("%08X ", i);
+ if ( get_user( (ulong)sp, sp) )
+ return;
+ if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
if (++cnt == 8)
{
printk("\n");
if (cnt > 32) break;
}
printk("\n");
-#endif
-}
-
-void
-print_user_backtrace(unsigned long *sp)
-{
-#if 0
- int cnt = 0;
- printk("... [User] Call backtrace:\n");
- while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
- {
- printk("%08X ", sp[1]);
- sp = (unsigned long *)*sp;
- if (++cnt == 8)
- {
- printk("\n");
- }
- if (cnt > 16) break;
- }
- printk("\n");
-#endif
}
-void
-print_kernel_backtrace(void)
-{
-#if 0
- unsigned long *_get_SP(void);
- print_backtrace(_get_SP());
-#endif
-}
inline void start_thread(struct pt_regs * regs,
unsigned long eip, unsigned long esp)
{
+ set_fs(USER_DS);
regs->nip = eip;
regs->gpr[1] = esp;
regs->msr = MSR_USER;
- set_fs(USER_DS);
}
+/*
+ * Low level print for debugging - Cort
+ */
+int ll_printk(const char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+ int i;
+
+ va_start(args, fmt);
+ i=sprintf(buf,fmt,args);
+ ll_puts(buf);
+ va_end(args);
+ return i;
+}
+
+char *vidmem = (char *)0xC00B8000;
+int lines = 24, cols = 80;
+int orig_x = 0, orig_y = 0;
+
+void ll_puts(const char *s)
+{
+ int x,y;
+ char c;
+
+ x = orig_x;
+ y = orig_y;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ /*scroll();*/
+ /*y--;*/
+ y = 0;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ /*scroll();*/
+ /*y--;*/
+ y = 0;
+ }
+ }
+ }
+ }
+
+ orig_x = x;
+ orig_y = y;
+}
/*
* linux/arch/ppc/kernel/ptrace.c
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/m68k/kernel/ptrace.c"
* Copyright (C) 1994 by Hamish Macdonald
* Taken from linux/kernel/ptrace.c and modified for M680x0.
* linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
*
- * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
- * PowerPC version by Gary Thomas (gdt@linuxppc.org)
* Modified by Cort Dougan (cort@cs.nmt.edu)
*
* This file is subject to the terms and conditions of the GNU General
* in exit.c or in signal.c.
*/
-/* Find the stack offset for a register, relative to tss.ksp. */
-#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
-/* Mapping from PT_xxx to the stack offset at which the register is
- saved. Notice that usp has no stack-slot and needs to be treated
- specially (see get_reg/put_reg below). */
-static int regoff[] = {
-};
-
/*
* Get contents of register REGNO in task TASK.
*/
static inline long get_reg(struct task_struct *task, int regno)
{
- struct pt_regs *regs = task->tss.regs;
- if (regno <= PT_R31)
- {
- return (regs->gpr[regno]);
- } else
- if (regno == PT_NIP)
- {
- return (regs->nip);
- } else
- if (regno == PT_MSR)
- {
- return (regs->msr);
- } else
- if (regno == PT_ORIG_R3)
- {
- return (regs->orig_gpr3);
- } else
- if (regno == PT_CTR)
- {
- return (regs->ctr);
- } else
- if (regno == PT_LNK)
- {
- return (regs->link);
- } else
- if (regno == PT_XER)
- {
- return (regs->xer);
- } else
- if (regno == PT_CCR)
- {
- return (regs->ccr);
- }
+ if (regno <= PT_CCR)
+ return ((unsigned long *)task->tss.regs)[regno];
return (0);
}
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
- struct pt_regs *regs = task->tss.regs;
- if (regno <= PT_R31)
- {
- regs->gpr[regno] = data;
- } else
- if (regno == PT_NIP)
- {
- regs->nip = data;
- } else
- if (regno == PT_MSR)
- {
- regs->msr = data;
- } else
- if (regno == PT_CTR)
- {
- regs->ctr = data;
- } else
- if (regno == PT_LNK)
- {
- regs->link = data;
- } else
- if (regno == PT_XER)
- {
- regs->xer = data;
- } else
- if (regno == PT_CCR)
- {
- regs->ccr = data;
- } else
- { /* Invalid register */
- return (-1);
+ if (regno <= PT_CCR) {
+ ((unsigned long *)task->tss.regs)[regno] = data;
+ return 0;
}
- return (0);
+ return -1;
}
-static inline
+static inline void
set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->tss.regs;
-printk("Set single step - Task: %x, Regs: %x", task, regs);
-printk(", MSR: %x/", regs->msr);
regs->msr |= MSR_SE;
-printk("%x\n", regs->msr);
}
-static inline
+static inline void
clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->tss.regs;
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
return 0;
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page directory %08lx\n",
- pmd_val(*pgmiddle));
+ printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return 0;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
+ if (MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
return *(unsigned long *) page;
* Now keeps R/W state of page so that a text page stays readonly
* even if a debugger scribbles breakpoints into it. -M.U-
*/
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
- unsigned long data)
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long addr, unsigned long data)
{
pgd_t *pgdir;
pmd_t *pgmiddle;
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
return;
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page directory %08lx\n",
- pmd_val(*pgmiddle));
+ printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 2);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page < high_memory) {
+ if (MAP_NR(page) < max_mapnr)
*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
- }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
- *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+ set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
flush_tlb_all();
}
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- struct user * dummy = NULL;
int ret = -EPERM;
lock_kernel();
case PTRACE_PEEKUSR: {
unsigned long tmp;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- return -EIO;
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ ret = -EIO;
+ goto out;
+ }
ret = verify_area(VERIFY_WRITE, (void *) data,
sizeof(long));
goto out;
tmp = 0; /* Default return condition */
addr = addr >> 2; /* temporary hack. */
- if (addr < PT_FPR0)
+ if (addr < PT_FPR0) {
tmp = get_reg(child, addr);
-#if 0
- else if (addr >= PT_FPR0 && addr < PT_FPR31)
- tmp = child->tss.fpr[addr - PT_FPR0];
-#endif
+ }
+#if 1
+ else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ if (last_task_used_math == child)
+ giveup_fpu();
+ tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
+ }
+#endif
else
ret = -EIO;
- if(!ret)
+ if (!ret)
put_user(tmp,(unsigned long *) data);
goto out;
}
ret = 0;
goto out;
}
-#if 0
- if (addr >= 21 && addr < 48) {
- child->tss.fp[addr - 21] = data;
+ if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ if (last_task_used_math == child)
+ giveup_fpu();
+ ((long *)child->tss.fpr)[addr - PT_FPR0] = data;
ret = 0;
goto out;
}
-#endif
goto out;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+++ /dev/null
-/*
- * linux/arch/ppc/kernel/setup.c
- *
- * Copyright (C) 1995 Linus Torvalds
- * Adapted from 'alpha' version by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-extern unsigned long *end_of_DRAM;
-extern PTE *Hash;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-unsigned long empty_zero_page[1024];
-
-unsigned char aux_device_present;
-#ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */
-extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */
-extern int rd_image_start; /* starting block # of image */
-#endif
-
-#undef HASHSTATS
-
-extern unsigned long isBeBox[];
-
-/* copy of the residual data */
-RESIDUAL res;
-unsigned long resptr = 0; /* ptr to residual data from hw */
-
-/*
- * 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.
- */
- /* this is changed only in minor ways from the original
- -- Cort
- */
-struct screen_info screen_info = {
- 0, 25, /* orig-x, orig-y */
- { 0, 0 }, /* unused */
- 0, /* orig-video-page */
- 0, /* orig-video-mode */
- 80, /* orig-video-cols */
- 0,0,0, /* ega_ax, ega_bx, ega_cx */
- 25, /* orig-video-lines */
- 1, /* orig-video-isVGA */
- 16 /* orig-video-points */
-};
-
-
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- return memory_start;
-}
-
-#ifdef HASHSTATS
-unsigned long *hashhits;
-#endif
-
-extern unsigned long _TotalMemory;
-/* find the physical size of RAM and setup hardware hash table */
-unsigned long *find_end_of_memory(void)
-{
- extern BAT BAT2;
- _TotalMemory = res.TotalMemory;
-
- if (_TotalMemory == 0 )
- {
- printk("Ramsize from residual data was 0 -- Probing for value\n");
- /* this needs be done differently since the bats actually map
- addresses beyond physical memory! -- Cort */
-#if 0
- probingmem = 1;
- while ( probingmem )
- {
- _TotalMemory += 0x00800000; /* 8M */
- *(unsigned long *)_TotalMemory+KERNELBASE;
- }
- _TotalMemory -= 0x00800000;
-#else
- _TotalMemory = 0x03000000;
-#endif
- printk("Ramsize probed to be %dM\n", _TotalMemory>>20);
- }
-
- /* setup BAT2 mapping so that it covers kernelbase to kernelbase+ramsize */
- switch(_TotalMemory)
- {
- case 0x01000000: /* 16M */
- BAT2.batu.bl = BL_16M;
- Hash_size = HASH_TABLE_SIZE_128K;
- Hash_mask = HASH_TABLE_MASK_128K;
- break;
- case 0x00800000: /* 8M */
- BAT2.batu.bl = BL_8M;
- Hash_size = HASH_TABLE_SIZE_64K;
- Hash_mask = HASH_TABLE_MASK_64K;
- break;
- case 0x01800000: /* 24M */
- case 0x02000000: /* 32M */
- BAT2.batu.bl = BL_32M;
- Hash_size = HASH_TABLE_SIZE_256K;
- Hash_mask = HASH_TABLE_MASK_256K;
- break;
- case 0x03000000: /* 48M */
- case 0x04000000: /* 64M */
- BAT2.batu.bl = BL_64M;
- Hash_size = HASH_TABLE_SIZE_512K;
- Hash_mask = HASH_TABLE_MASK_512K;
- break;
- case 0x05000000: /* 80M */
- BAT2.batu.bl = BL_128M;
- Hash_size = HASH_TABLE_SIZE_1M;
- Hash_mask = HASH_TABLE_MASK_1M;
- break;
- default:
- printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n",
- _TotalMemory);
- break;
- }
-
- Hash = (PTE *)((_TotalMemory-Hash_size)+KERNELBASE);
- bzero(Hash, Hash_size);
-
-
-#ifdef HASHSTATS
- hashhits = (unsigned long *)Hash - (Hash_size/sizeof(struct _PTE))/2;
- bzero(hashhits, (Hash_size/sizeof(struct _PTE))/2);
- return ((unsigned long *)hashhits);
-#else
- return ((unsigned long *)Hash);
-#endif
-}
-
-int size_memory;
-
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#ifdef CONFIG_APM
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
-#endif
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-#define RAMDISK_IMAGE_START_MASK 0x07FF
-#define RAMDISK_PROMPT_FLAG 0x8000
-#define RAMDISK_LOAD_FLAG 0x4000
-
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
- char saved_command_line[COMMAND_LINE_SIZE];
-
-
-void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p)
-{
- extern int _end;
- extern char cmd_line[];
- unsigned char reg;
- extern int panic_timeout;
- char inf[512];
- int i;
-
- if (isBeBox[0])
- _Processor = _PROC_Be;
- else
- {
- if (strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- {
- _Processor = _PROC_Motorola;
- }
- else
- _Processor = _PROC_IBM;
- }
-
- get_cpuinfo(&inf);
- printk("%s",inf);
-
- /* Set up floppy in PS/2 mode */
- outb(0x09, SIO_CONFIG_RA);
- reg = inb(SIO_CONFIG_RD);
- reg = (reg & 0x3F) | 0x40;
- outb(reg, SIO_CONFIG_RD);
- outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
-
- switch ( _Processor )
- {
- case _PROC_IBM:
- ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
- break;
- case _PROC_Motorola:
- ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
- break;
- }
- aux_device_present = 0xaa;
-
- panic_timeout = 300; /* reboot on panic */
-
-#if 0
- /* get root via nfs from charon -- was only used for testing */
- ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* nfs */
- /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
- strcpy(cmd_line,
- "nfsaddrs=129.138.6.101:129.138.6.90:129.138.6.1:255.255.255.0:gordito nfsroot=/joplin/ppc/root/");
-#endif
- *cmdline_p = cmd_line;
- *memory_start_p = (unsigned long) &_end;
- (unsigned long *)*memory_end_p = (unsigned long *)end_of_DRAM;
- size_memory = *memory_end_p - KERNELBASE; /* Relative size of memory */
-
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#if 1
- rd_prompt = 1;
- rd_doload = 1;
- rd_image_start = 0;
-#endif
-#endif
-
- /* Save unparsed command line copy for /proc/cmdline */
- memcpy(saved_command_line, cmd_line,strlen(cmd_line)+1);
- printk("Command line: %s\n", cmd_line);
-}
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
- return -EIO;
-}
-
-
-int
-get_cpuinfo(char *buffer)
-{
- extern unsigned long loops_per_sec;
- int i;
- int pvr = _get_PVR();
- int len;
- char *model;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
- PTE *ptr;
-
- switch (pvr>>16)
- {
- case 3:
- model = "603";
- break;
- case 4:
- model = "604";
- break;
- case 6:
- model = "603e";
- break;
- case 7:
- model = "603ev";
- break;
- default:
- model = "unknown";
- break;
- }
-
-#ifdef __SMP__
-#define CD(X) (cpu_data[n].X)
-#else
-#define CD(X) (X)
-#define CPUN 0
-#endif
-
- len = sprintf(buffer, "PowerPC %s/%dMHz revision %d.%d %s\n",
- model,
- (res.VitalProductData.ProcessorHz > 1024) ?
- res.VitalProductData.ProcessorHz>>20 :
- res.VitalProductData.ProcessorHz,
- MAJOR(pvr), MINOR(pvr),
- (inb(IBM_EQUIP_PRESENT) & 2) ? "" : "upgrade");
-#if 1
- if ( res.VitalProductData.PrintableModel[0] )
- len += sprintf(buffer+len,"%s\n",res.VitalProductData.PrintableModel);
-
- len += sprintf(buffer+len,"Bus %dMHz\n",
- (res.VitalProductData.ProcessorBusHz > 1024) ?
- res.VitalProductData.ProcessorBusHz>>20 :
- res.VitalProductData.ProcessorBusHz);
-
- /* make sure loops_per_sec has been setup -- ie not at boottime -- Cort */
- if ( CD(loops_per_sec+2500)/500000 > 0)
- len += sprintf(buffer+len,
- "bogomips: %lu.%02lu\n",
- CD(loops_per_sec+2500)/500000,
- (CD(loops_per_sec+2500)/5000) % 100);
-
-
- len += sprintf(buffer+len,"Total Ram: %dM Hash Table: %dkB (%dk buckets)\n",
- _TotalMemory>>20, Hash_size>>10,
- (Hash_size/(sizeof(PTE)*8)) >> 10);
-
- for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
- {
- if (i == 0)
- len += sprintf(buffer+len,"SIMM Banks: ");
- if ( res.Memories[i].SIMMSize != 0 )
- len += sprintf(buffer+len,"%d:%dM ",i,
- (res.Memories[i].SIMMSize > 1024) ?
- res.Memories[i].SIMMSize>>20 :
- res.Memories[i].SIMMSize);
- if ( i == MAX_MEMS-1)
- len += sprintf(buffer+len,"\n");
- }
-
- /* TLB */
- len += sprintf(buffer+len,"TLB");
- switch(res.VitalProductData.TLBAttrib)
- {
- case CombinedTLB:
- len += sprintf(buffer+len,": %d entries\n",
- res.VitalProductData.TLBSize);
- break;
- case SplitTLB:
- len += sprintf(buffer+len,": (split I/D) %d/%d entries\n",
- res.VitalProductData.I_TLBSize,
- res.VitalProductData.D_TLBSize);
- break;
- case NoneTLB:
- len += sprintf(buffer+len,": not present\n");
- break;
- }
-
- /* L1 */
- len += sprintf(buffer+len,"L1: ");
- switch(res.VitalProductData.CacheAttrib)
- {
- case CombinedCAC:
- len += sprintf(buffer+len,"%dkB LineSize\n",
- res.VitalProductData.CacheSize,
- res.VitalProductData.CacheLineSize);
- break;
- case SplitCAC:
- len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
- res.VitalProductData.I_CacheSize,
- res.VitalProductData.D_CacheSize,
- res.VitalProductData.D_CacheLineSize,
- res.VitalProductData.D_CacheLineSize);
- break;
- case NoneCAC:
- len += sprintf(buffer+len,"not present\n");
- break;
- }
-
- /* L2 */
- if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
- {
- int size;
-
- len += sprintf(buffer+len,"L2: %dkB %s\n",
- ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
- (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
- }
- else
- {
- len += sprintf(buffer+len,"L2: not present\n");
- }
-#if 0
- len+= sprintf(buffer+len,"Equip register %x\n",
- inb(IBM_EQUIP_PRESENT));
- len+= sprintf(buffer+len,"L2Status register %x\n",
- inb(IBM_L2_STATUS));
-#endif
-#endif
-
-
- return len;
-}
/*
* linux/arch/ppc/kernel/signal.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/signal.c"
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
#include <linux/sched.h>
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define DEBUG_SIGNALS
+#undef DEBUG_SIGNALS
+
+#define PAUSE_AFTER_SIGNAL
+#undef PAUSE_AFTER_SIGNAL
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
{
unsigned long mask;
- int ret = -EINTR;
- lock_kernel();
+ spin_lock_irq(¤t->sigmask_lock);
mask = current->blocked;
current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(¤t->sigmask_lock);
+
regs->gpr[3] = -EINTR;
-#if 0
+#ifdef DEBUG_SIGNALS
printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);
#endif
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(mask,regs))
- goto out;
+ if (do_signal(mask,regs)) {
+ /*
+ * If a signal handler needs to be called,
+ * do_signal() has set R3 to the signal number (the
+ * first argument of the signal handler), so don't
+ * overwrite that with EINTR !
+ * In the other cases, do_signal() doesn't touch
+ * R3, so it's still set to -EINTR (see above).
+ */
+ return regs->gpr[3];
+ }
}
-out:
- unlock_kernel();
- return ret;
}
+/*
+ * This sets regs->esp even though we don't actually use sigstacks yet..
+ */
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigcontext_struct *sc;
struct pt_regs *int_regs;
int signo, ret;
- lock_kernel();
#if 1
if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >=KERNELBASE))
+ || (regs->gpr[1] >= KERNELBASE))
goto badframe;
#endif
- sc = (struct sigcontext_struct *)regs->gpr[1];
- current->blocked = sc->oldmask & _BLOCKABLE;
- int_regs = sc->regs;
- signo = sc->signal;
- sc++; /* Pop signal 'context' */
+ sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
+ get_user(current->blocked, &sc->oldmask);
+ current->blocked &= _BLOCKABLE;
+ get_user(int_regs, &sc->regs);
+ get_user(signo, &sc->signal);
+ sc++; /* Pop signal 'context' */
+#ifdef DEBUG_SIGNALS
+printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+#endif
if (sc == (struct sigcontext_struct *)(int_regs)) {
/* Last stacked signal */
-#if 0
- /* This doesn't work - it blows away the return address! */
memcpy(regs, int_regs, sizeof(*regs));
-#else
- /* Don't mess up 'my' stack frame */
- memcpy(®s->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
-#endif
- if ((int)regs->orig_gpr3 >= 0 &&
+ if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR))
- {
+ (int)regs->result == -ERESTARTNOINTR)) {
regs->gpr[3] = regs->orig_gpr3;
regs->nip -= 4; /* Back up & retry system call */
regs->result = 0;
}
- ret = (regs->result);
- } else { /* More signals to go */
- regs->gpr[1] = (unsigned long)sc;
- regs->gpr[3] = sc->signal;
- regs->gpr[4] = sc->regs;
- regs->link = (unsigned long)((sc->regs)+1);
- regs->nip = sc->handler;
- ret = sc->signal;
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ get_user(regs->gpr[3], &sc->signal);
+ get_user(int_regs, (struct pt_regs **) &sc->regs);
+ regs->gpr[4] = (unsigned long) int_regs;
+ regs->link = (unsigned long) (int_regs+1);
+ get_user(regs->nip, &sc->handler);
+ ret = regs->gpr[3];
}
- goto out;
+ return ret;
badframe:
- /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
- regs,current->comm,current->pid);*/
+ lock_kernel();
do_exit(SIGSEGV);
-out:
unlock_kernel();
- return ret;
+ return -EFAULT;
}
unsigned long mask;
unsigned long handler_signal = 0;
unsigned long *frame = NULL;
- unsigned long *trampoline, *regs_ptr;
+ unsigned long *trampoline;
+ unsigned long *regs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
struct sigaction * sa;
- int bitno, s, ret;
+ int bitno;
- lock_kernel();
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
+#if 0
+ signr = ffz(~signr); /* Compute bit # */
+#else
for (bitno = 0; bitno < 32; bitno++)
if (signr & (1<<bitno))
break;
signr = bitno;
-
+#endif
current->signal &= ~(1<<signr); /* Clear bit */
sa = current->sig->action + signr;
signr++;
continue;
if (_S(signr) & current->blocked) {
current->signal |= _S(signr);
+ spin_lock_irq(¤t->sigmask_lock);
+ spin_unlock_irq(¤t->sigmask_lock);
continue;
}
sa = current->sig->action + signr - 1;
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ SA_NOCLDSTOP))
notify_parent(current);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
+ spin_lock_irq(¤t->sigmask_lock);
current->signal |= _S(signr & 0x7f);
+ spin_unlock_irq(¤t->sigmask_lock);
+
+ current->flags |= PF_SIGNALED;
+
+ lock_kernel(); /* 8-( */
do_exit(signr);
+ unlock_kernel();
}
}
-
- /* handle signal */
- if ((int)regs->orig_gpr3 >= 0) {
+ /*
+ * OK, we're invoking a handler
+ */
+ if (regs->trap == 0x0C00 /* System Call! */) {
if ((int)regs->result == -ERESTARTNOHAND ||
((int)regs->result == -ERESTARTSYS &&
!(sa->sa_flags & SA_RESTART)))
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
}
- ret = 0;
- if (!handler_signal) /* no handler will be called - return 0 */
- goto out;
+
+ if (regs->trap == 0x0C00 /* System Call! */ &&
+ ((int)regs->result == -ERESTARTNOHAND ||
+ (int)regs->result == -ERESTARTSYS ||
+ (int)regs->result == -ERESTARTNOINTR)) {
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4; /* Back up & retry system call */
+ regs->result = 0;
+ }
+
+ if (!handler_signal) /* no handler will be called - return 0 */
+ return 0;
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
/* Build trampoline code on stack */
frame -= 2;
trampoline = frame;
-#if 1
/* verify stack is valid for writing regs struct */
if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || (frame >= KERNELBASE ))
+ || ((unsigned long) frame >= KERNELBASE ))
goto badframe;
-#endif
- trampoline[0] = 0x38007777; /* li r0,0x7777 */
- trampoline[1] = 0x44000002; /* sc */
+ put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
+ put_user(0x44000002UL, trampoline+1); /* sc */
frame -= sizeof(*regs) / sizeof(long);
regs_ptr = frame;
- memcpy(regs_ptr, regs, sizeof(*regs));
+ copy_to_user(regs_ptr, regs, sizeof(*regs));
signr = 1;
sa = current->sig->action;
-
+
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-#if 1
if (verify_area(VERIFY_WRITE,(void *)frame,
sizeof(struct sigcontext_struct)/sizeof(long)))
goto badframe;
-#endif
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
-#if 0 /* Old compiler */
- nip = *(unsigned long *)nip;
-#endif
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- sc->handler = nip;
- sc->oldmask = current->blocked;
- sc->regs = (unsigned long)regs_ptr;
- sc->signal = signr;
+ put_user(nip, &sc->handler);
+ put_user(oldmask, &sc->oldmask); /* was current->blocked */
+ put_user(regs_ptr, &sc->regs);
+ put_user(signr, &sc->signal);
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
regs->gpr[4] = (unsigned long)regs_ptr;
}
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc;
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- /* The DATA cache must be flushed here to insure coherency
- * between the DATA & INSTRUCTION caches. Since we just
- * created an instruction stream using the DATA [cache] space
- * and since the instruction cache will not look in the DATA
- * cache for new data, we have to force the data to go on to
- * memory and flush the instruction cache to force it to look
- * there. The following function performs this magic
- */
- flush_instruction_cache();
- ret = 1;
- goto out;
+ /* The DATA cache must be flushed here to insure coherency */
+ /* between the DATA & INSTRUCTION caches. Since we just */
+ /* created an instruction stream using the DATA [cache] space */
+ /* and since the instruction cache will not look in the DATA */
+ /* cache for new data, we have to force the data to go on to */
+ /* memory and flush the instruction cache to force it to look */
+ /* there. The following function performs this magic */
+ store_cache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
+ return 1;
badframe:
-#if 0
- printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
- signr, frame, regs, current->comm, current->pid);
-#endif
+ lock_kernel();
do_exit(SIGSEGV);
-
-out:
unlock_kernel();
- return ret;
+ return 0;
}
--- /dev/null
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ do {
+ c1 = tolower(*s1++);
+ c2 = tolower(*s2++);
+ } while (c1 == c2 && c1 != 0);
+ return c1 - c2;
+}
+++ /dev/null
-/*#include <linux/in.h>*/
-#include <linux/autoconf.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-void sys_iopl(void)
-{
- lock_kernel();
- panic("sys_iopl");
- unlock_kernel();
-}
-void sys_vm86(void)
-{
- lock_kernel();
- panic("sys_vm86");
- unlock_kernel();
-}
-void sys_modify_ldt(void)
-{
- lock_kernel();
- panic("sys_modify_ldt");
- unlock_kernel();
-}
-
-void sys_ipc(void)
-{
- lock_kernel();
- panic("sys_ipc");
- unlock_kernel();
-}
-
-void sys_newselect(void)
-{
- lock_kernel();
- panic("sys_newselect");
- unlock_kernel();
-}
-
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
- lock_kernel();
- panic("scsi_register_module");
- unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
- lock_kernel();
- panic("scsi_unregister_module");
- unlock_kernel();
-}
-#endif
-
-
-
+++ /dev/null
-/*
- * Miscellaneous support routines
- */
-
-#include <asm/bitops.h>
-
-/*extern __inline__*/ int find_first_zero_bit(void *add, int len)
-{
- int mask, nr, i;
- BITFIELD *addr = add;
- nr = 0;
- while (len)
- {
- if (~*addr != 0)
- { /* Contains at least one zero */
- for (i = 0; i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
- return (nr);
- }
- }
- }
- len -= 32;
- addr++;
- nr += 32;
- }
- return (0); /* Shouldn't happen */
-}
-
-/*extern __inline__*/ int find_next_zero_bit(void *add, int last_bit, int nr)
-{
- int mask, i;
- BITFIELD *addr = add;
-#if 0
-printk("Find next (%x, %x)", addr, nr);
-#endif
- addr += nr >> 5;
-#if 0
-printk(" - Pat: %x(%08X)\n", addr, *addr);
-#endif
- if ((nr & 0x1F) != 0)
- {
- if (*addr != 0xFFFFFFFF)
- { /* At least one more bit available in this longword */
- for (i = (nr&0x1F); i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
-#if 0
-printk("(1)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
- return (nr);
- }
- }
- }
- addr++;
- nr = (nr + 0x1F) & ~0x1F;
- }
- while (nr < last_bit)
- {
- if (*addr != 0xFFFFFFFF)
- { /* Contains at least one zero */
- for (i = 0; i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
-#if 0
-printk("(2)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
- return (nr);
- }
- }
- }
- addr++;
- nr += 32;
- }
- return (nr); /* Shouldn't happen */
-}
-
-
* platform.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/ipc.h>
#include <asm/uaccess.h>
+#include <asm/ipc.h>
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
- int error;
- lock_kernel();
- error = verify_area(VERIFY_WRITE,fildes,8);
- if (error)
- goto out;
- error = do_pipe(fildes);
-out:
- unlock_kernel();
- return error;
+void
+check_bugs(void)
+{
}
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
- int flags, int fd, off_t offset)
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
{
- struct file * file = NULL;
- int ret = -EBADF;
+ printk("sys_ioperm()\n");
+ return -EIO;
+}
+int sys_iopl(int a1, int a2, int a3, int a4)
+{
lock_kernel();
- if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
- }
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- ret = do_mmap(file, addr, len, prot, flags, offset);
-out:
+ printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return ret;
+ return (ENOSYS);
}
-/*
- * 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 sys_vm86(int a1, int a2, int a3, int a4)
{
- int error;
- unsigned long flags;
- long a,b,c,d,e;
- struct file * file = NULL;
-
lock_kernel();
- error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
- if (error)
- goto out;
- get_user(flags,buffer+3);
- if (!(flags & MAP_ANONYMOUS)) {
- unsigned long fd;
- get_user(fd,buffer+4);
- error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
- }
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- error = -EFAULT;
- if ( get_user(a,buffer) || get_user(b,buffer+1) ||
- get_user(c,buffer+2)||get_user(d,buffer+5) )
- goto out;
- error = do_mmap(file,a,b,c, flags, d);
-out:
+ printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return error;
+ return (ENOSYS);
}
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-asmlinkage int old_select(unsigned long *buffer)
+int sys_modify_ldt(int a1, int a2, int a3, int a4)
{
- int n;
- fd_set *inp;
- fd_set *outp;
- fd_set *exp;
- struct timeval *tvp;
-
lock_kernel();
- n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
- if (n)
- goto out;
- get_user(n,buffer);
- get_user(inp,buffer+1);
- get_user(outp,buffer+2);
- get_user(exp,buffer+3);
- get_user(tvp,buffer+4);
- n = sys_select(n, inp, outp, exp, tvp);
-out:
+ printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return n;
+ return (ENOSYS);
}
-#if 0
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
ret = -EINVAL;
if (!ptr)
goto out;
- if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
- goto out;
- fourth.__pad = (void *) get_fs_long(ptr);
+ ret = -EFAULT;
+ if (get_user(fourth.__pad, (void **) ptr))
+ goto out;
ret = sys_semctl (first, second, third, fourth);
goto out;
- }
+ }
default:
ret = -EINVAL;
goto out;
ret = -EINVAL;
if (!ptr)
goto out;
- if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
- goto out;
- memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp));
+ ret = -EFAULT;
+ if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
+ sizeof (tmp)))
+ goto out;
ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
goto out;
- }
+ }
case 1: default:
ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
goto out;
switch (version) {
case 0: default: {
ulong raddr;
- if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
- goto out;
ret = sys_shmat (first, (char *) ptr, second, &raddr);
if (ret)
goto out;
- put_fs_long (raddr, (ulong *) third);
- ret = 0;
+ ret = put_user (raddr, (ulong *) third);
goto out;
- }
+ }
case 1: /* iBCS2 emulator entry point */
ret = -EINVAL;
if (get_fs() != get_ds())
unlock_kernel();
return ret;
}
+
+
+#ifndef CONFIG_MODULES
+void
+scsi_register_module(void)
+{
+ lock_kernel();
+ panic("scsi_register_module");
+ unlock_kernel();
+}
+
+void
+scsi_unregister_module(void)
+{
+ lock_kernel();
+ panic("scsi_unregister_module");
+ unlock_kernel();
+}
#endif
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ 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_user(fd[0],0+fildes);
+ put_user(fd[1],1+fildes);
+ return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, off_t offset)
+{
+ struct file * file = NULL;
+ if (!(flags & MAP_ANONYMOUS)) {
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ }
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+ return do_mmap(file, addr, len, prot, flags, offset);
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+/*
+ * Due to some executables calling the wrong select we sometimes
+ * get wrong args. This determines how the args are being passed
+ * (a single ptr to them all args passed) then calls
+ * sys_select() with the appropriate args. -- Cort
+ */
+asmlinkage int
+ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
+{
+ int err;
+ if ( (unsigned long)n >= 4096 )
+ {
+ unsigned long *buffer = (unsigned long *)n;
+ if ( get_user(n, buffer) ||
+ get_user(inp,buffer+1) ||
+ get_user(outp,buffer+2) ||
+ get_user(exp,buffer+3) ||
+ get_user(tvp,buffer+4) )
+ return -EFAULT;
+ }
+ return sys_select(n, inp, outp, exp, tvp);
+}
+++ /dev/null
-/*
- * linux/arch/i386/kernel/time.c
- *
- * Copyright (C) 1991, 1992, 1995 Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02 Alan Modra
- * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26 Markus Kuhn
- * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- * precision CMOS clock update
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/nvram.h>
-#include <asm/mc146818rtc.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-#include <linux/config.h>
-
-extern int isBeBox[];
-
-#define TIMER_IRQ 0
-
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
-
-static inline int CMOS_READ(int addr)
-{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- return (inb(NVRAM_DATA));
-}
-
-static inline int CMOS_WRITE(int addr, int val)
-{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- return (outb(val, NVRAM_DATA));
-}
-
-/* This function must be called with interrupts disabled
- * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
- *
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought.... pjsg (1993-08-28)
- *
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-#define TICK_SIZE tick
-
-static unsigned long do_slow_gettimeoffset(void)
-{
- int count;
- unsigned long offset = 0;
-
- /* timer count may underflow right here */
- outb_p(0x00, 0x43); /* latch the count ASAP */
- count = inb_p(0x40); /* read the latched count */
- count |= inb(0x40) << 8;
- /* we know probability of underflow is always MUCH less than 1% */
- if (count > (LATCH - LATCH/100)) {
- /* check for pending timer interrupt */
- outb_p(0x0a, 0x20);
- if (inb(0x20) & 1)
- offset = TICK_SIZE;
- }
- count = ((LATCH-1) - count) * TICK_SIZE;
- count = (count + LATCH/2) / LATCH;
- return offset + count;
-}
-
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
- cli();
- /* This is revolting. We need to set the xtime.tv_usec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
- tv->tv_usec -= do_gettimeoffset();
-
- if (tv->tv_usec < 0) {
- tv->tv_usec += 1000000;
- tv->tv_sec--;
- }
-
- xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = 0x70000000;
- time_esterror = 0x70000000;
- set_rtc(xtime.tv_sec);
- sti();
-}
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(year) ((year) % 4 == 0)
-#define days_in_year(a) (leapyear(a) ? 366 : 365)
-#define days_in_month(a) (month_days[(a) - 1])
-
-struct _tm
-{
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_day;
- int tm_month;
- int tm_year;
-};
-
-static _to_tm(int tim, struct _tm * tm)
-{
- register int i;
- register long hms, day;
-
- day = tim / SECDAY;
- hms = tim % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_month = i;
-
- /* Days are what is left over (+1) from all that. */
- tm->tm_day = day + 1;
-}
-
-/*
- * Set the time into the CMOS
- */
-static void set_rtc(unsigned long nowtime)
-{
- int retval = 0;
- struct _tm tm;
- unsigned char save_control, save_freq_select;
-
- /*if (_Processor != _PROC_IBM) return;*/
-
- _to_tm(nowtime, &tm);
-
- /* tell the clock it's being set */
- save_control = CMOS_MCRTC_READ(MCRTC_CONTROL);
- CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
- /* stop and reset prescaler */
- save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT);
- CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
- printk("Set RTC H:M:S M/D/Y %d:%02d:%02d %d/%d/%d\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_month, tm.tm_day, tm.tm_year);
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
- BIN_TO_BCD(tm.tm_sec);
- BIN_TO_BCD(tm.tm_min);
- BIN_TO_BCD(tm.tm_hour);
- BIN_TO_BCD(tm.tm_month);
- BIN_TO_BCD(tm.tm_day);
- BIN_TO_BCD(tm.tm_year);
- }
-
- CMOS_MCRTC_WRITE(tm.tm_sec, MCRTC_SECONDS);
- CMOS_MCRTC_WRITE(tm.tm_min, MCRTC_MINUTES);
- CMOS_MCRTC_WRITE(tm.tm_hour, MCRTC_HOURS);
- CMOS_MCRTC_WRITE(tm.tm_month, MCRTC_MONTH);
- CMOS_MCRTC_WRITE(tm.tm_day, MCRTC_MINUTES);
- CMOS_MCRTC_WRITE(tm.tm_year - 1900, MCRTC_MINUTES);
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
- CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- */
-static int set_rtc_mmss(unsigned long nowtime)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- unsigned char save_control, save_freq_select;
-
-#ifdef __powerpc__
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-return (-1); /* Not implemented */
-#else
-
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
- save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); /* tell the clock it's being set */
- CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-
- save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT); /* stop and reset prescaler */
- CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
- cmos_minutes = CMOS_MCRTC_READ(MCRTC_MINUTES);
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD)
- BCD_TO_BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- }
- CMOS_MCRTC_WRITE(real_seconds,MCRTC_SECONDS);
- CMOS_MCRTC_WRITE(real_minutes,MCRTC_MINUTES);
- } else
- retval = -1;
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
- CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-
- return retval;
-#endif
-}
-
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
-{
- static int timeints = 0;
-
- do_timer(regs);
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- */
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-
-
- /* use hard disk LED as a heartbeat instead -- much more useful
- -- Cort */
- switch(timeints)
- {
- /* act like an actual heart beat -- ie thump-thump-pause... */
- case 0:
- case 20:
- hard_disk_LED(1);
- break;
- case 7:
- case 27:
- hard_disk_LED(0);
- break;
- case 100:
- timeints = -1;
- break;
- }
- timeints++;
-}
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
- unsigned int day, unsigned int hour,
- unsigned int min, unsigned int sec)
-{
- if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
- mon += 12; /* Puts Feb last since it has leap day */
- year -= 1;
- }
- return (((
- (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
- year*365 - 719499
- )*24 + hour /* now have hours */
- )*60 + min /* now have minutes */
- )*60 + sec; /* finally seconds */
-}
-
-unsigned long get_cmos_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- int i;
-
- if (_Processor == _PROC_IBM)
- {
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
- min = CMOS_MCRTC_READ(MCRTC_MINUTES);
- hour = CMOS_MCRTC_READ(MCRTC_HOURS);
- day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
- mon = CMOS_MCRTC_READ(MCRTC_MONTH);
- year = CMOS_MCRTC_READ(MCRTC_YEAR);
- } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- } else
- if (_Processor == _PROC_Be)
- {
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
- min = CMOS_MCRTC_READ(MCRTC_MINUTES);
- hour = CMOS_MCRTC_READ(MCRTC_HOURS);
- day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
- mon = CMOS_MCRTC_READ(MCRTC_MONTH);
- year = CMOS_MCRTC_READ(MCRTC_YEAR);
- } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
- } else
- { /* Motorola PowerStack etc. */
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
- } while (sec != CMOS_READ(RTC_SECONDS));
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
-#if 0
-printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
-#endif
- if ((year += 1900) < 1970)
- year += 100;
- return mktime(year, mon, day, hour, min, sec);
-}
-
-void time_init(void)
-{
- void (*irq_handler)(int, struct pt_regs *);
- xtime.tv_sec = get_cmos_time();
- xtime.tv_usec = 0;
-
- /* If we have the CPU hardware time counters, use them */
- irq_handler = timer_interrupt;
- if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-}
-
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/ppc_machine.h>
-
/*
* Trap & Exception support
*/
void
_exception(int signr, struct pt_regs *regs)
{
- /* dump_regs(regs);*/
- force_sig(signr, current);
- if (!user_mode(regs))
- {
- printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
- while (1) ;
- }
+ if (!user_mode(regs))
+ {
+ show_regs(regs);
+ print_backtrace(regs->gpr[1]);
+ panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ }
+ force_sig(signr, current);
}
MachineCheckException(struct pt_regs *regs)
{
- printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
- _exception(SIGSEGV, regs);
-}
-
-ProgramCheckException(struct pt_regs *regs)
-{
-#if 0
- printk("Program check at PC: %x[%x], SR: %x\n",
- regs->nip, va_to_phys(regs->nip), regs->msr);
- #endif
- if (current->flags & PF_PTRACED)
- {
- _exception(SIGTRAP, regs);
- } else
- {
- _exception(SIGILL, regs);
- }
+ if ( !user_mode(regs) )
+ {
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from msr): ");
+ printk("regs %08x ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printk("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printk("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printk("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printk("Address parity signal\n");
+ break;
+ default:
+ printk("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace(regs->gpr[1]);
+ panic("");
+ }
+ _exception(SIGSEGV, regs);
}
-SingleStepException(struct pt_regs *regs)
+void
+UnknownException(struct pt_regs *regs)
{
- regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+ printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
_exception(SIGTRAP, regs);
}
-FloatingPointCheckException(struct pt_regs *regs)
+void
+InstructionBreakpoint(struct pt_regs *regs)
{
- /* if fpu already on -- then exception was generated by an error */
- if ( (unsigned long)(regs->msr) & (unsigned long)MSR_FP )
- {
- _exception(SIGFPE, regs);
- return 0;
- }
-
-#if 0
- printk("fpu off -- turning on: %s pc %x fpscr %x msr %x ksp %x r1 %x\n",
- current->comm,regs->nip,regs->fpcsr,regs->msr,regs,regs->gpr[1]);
+#ifdef CONFIG_XMON
+ if (xmon_iabr_match(regs))
+ return;
#endif
-
- /* if the fpu is off then turn it on and return */
- regs->msr |= MSR_FP;
- current->tss.fp_used++;
- /* tells return_from_int to restore fp regs since fp was turned on
- see head.S -- Cort */
- return MSR_FP;
+ _exception(SIGTRAP, regs);
}
-AlignmentException(struct pt_regs *regs)
+void
+RunModeException(struct pt_regs *regs)
{
-/* printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr);
- dump_regs(regs);
- printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
- _exception(SIGBUS, regs);
+ _exception(SIGTRAP, regs);
}
+ProgramCheckException(struct pt_regs *regs)
+{
+ if (current->flags & PF_PTRACED)
+ _exception(SIGTRAP, regs);
+ else
+ _exception(SIGILL, regs);
+}
-/* see CHECK_STACK macro in head.S for argument definitions */
-bad_stack(unsigned int r3, unsigned int r4, unsigned int r5, unsigned int r6)
+SingleStepException(struct pt_regs *regs)
{
- /* r6 (was r1) kernel stack pointer */
- /* r5 (was r2) kernel stack page */
- /* r4 kernel stack magic */
- /* r3 stack magic or ksp masked to page boundary */
- printk("bad_stack(): Kernel stack bad.\n");
- printk("ksp %x kpage %x stack magic %x r3 %x\n",
- r6,r5,r4,r3);
- printk("current: %s/%d\n",
- current->comm,current->pid);
- while(1);
+ regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+ _exception(SIGTRAP, regs);
}
-dump_regs(struct pt_regs *regs)
+AlignmentException(struct pt_regs *regs)
{
- int i;
- printk("NIP: %08X, MSR: %08X, XER: %08X, LR: %08X, FRAME: %08X\n", regs->nip, regs->msr, regs->xer, regs->link, regs);
-#if 0
- printk("HASH = %08X/%08X, MISS = %08X/%08X, CMP = %08X/%08X\n", regs->hash1, regs->hash2, regs->imiss, regs->dmiss, regs->icmp, regs->dcmp);
-#endif
- printk("TASK = %x[%d] '%s'\n", current, current->pid, current->comm);
- for (i = 0; i < 32; i++)
- {
- if ((i % 8) == 0)
- {
- printk("GPR%02d: ", i);
- }
- printk("%08X ", regs->gpr[i]);
- if ((i % 8) == 7)
- {
- printk("\n");
- }
- }
-#if 0
- if (regs->nip >= 0x1000)
- dump_buf(regs->nip-32, 64);
- dump_buf((regs->nip&0x0FFFFFFF)|KERNELBASE, 32);
-#endif
+ _exception(SIGBUS, regs);
}
trace_syscall(struct pt_regs *regs)
{
static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
+ printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ current, current->pid, regs->nip, regs->link, regs->gpr[0],
+ regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
if (++count == 20)
{
count = 0;
}
}
-
+++ /dev/null
-#include <linux/types.h>
-#include <asm/string.h>
-#include <asm/errno.h>
-#include <linux/sched.h>
-
-/*
- * bad data accesses from these functions should be handled specially
- * since they are to user areas and may or may not be valid.
- * on error -EFAULT should be returned. -- Cort
- */
-int __copy_tofrom_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-
-int __copy_tofrom_user(unsigned long to, unsigned long from, int size)
-{
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__copy_tofrom_user_failure;
-
- if (memcpy( (void *)to, (void *)from, (size_t) size) == -EFAULT )
- {
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return -EFAULT;
- }
- current->tss.excount = 0;
- return 0; /* successful return */
-}
-
-/* Just like strncpy except in the return value:
- *
- * -EFAULT if an exception occurs before the terminator is copied.
- * N if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- */
-asmlinkage int __strncpy_from_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-
-int __strncpy_from_user(unsigned long dest, unsigned long src, int count)
-{
- int i = 0;
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__strncpy_from_user_failure;
-
- while ( i != count )
- {
- *(char *)(dest+i) = *(char *)(src+i);
- if ( *(char *)(src+i) == 0 )
- {
- return i;
- }
- i++;
- }
- *(char *)(dest+i) = (char)0;
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return i;
-}
-
-int __clear_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-int __clear_user(unsigned long addr, int size)
-{
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__clear_user_failure;
-
- if ((int)memset((void *)addr,(int)0, (__kernel_size_t)size) == -EFAULT )
- {
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return -EFAULT;
- }
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return size;
-}
-
-/*
- * Return the length of the string including the NUL terminator
- * (strlen+1) or zero if an error occured.
- */
-size_t strlen_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-size_t strlen_user(char * s)
-{
- size_t i;
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )strlen_user_failure;
-
- i = strlen(s)+1;
-
- if ( i == -EFAULT)
- return -EFAULT;
-
- /* take down exception handler stuff */
- current->tss.excount = 0;
-
- return(i);
-}
-
.text :
{
*(.text)
- *(.rodata)
- *(.rodata1)
+ *(.fixup)
*(.got1)
}
_etext = .;
PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
.dtors : { *(.dtors) }
.data :
{
*(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
CONSTRUCTORS
}
- .data1 : { *(.data1) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
_edata = .;
+/*
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+*/
+ __bss_start = .; /* BSS */
PROVIDE (edata = .);
__bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
.bss :
{
+ *(.sbss) *(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
- /* These are needed for ELF backends which have not yet been
- converted to the new style linker. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- /* These must appear regardless of . */
}
-#
-# Makefile for i386-specific library files..
-#
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+.S.o:
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+ $(AS) $(ASFLAGS) -o $*.o $*.s
+ rm $*.s
+
+HOST_CC = gcc
L_TARGET = lib.o
-L_OBJS = checksum.o cksum_support.o
-CC = gcc -I$(TOPDIR)/include
+L_OBJS = checksum.o cksum_support.o string.o
${L_TARGET}: $(L_OBJS)
$(LD) -r -o ${L_TARGET} $(L_OBJS)
+
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+ $(CPP) -M *.S *.c > .depend
+
+modules:
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
--- /dev/null
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "../kernel/ppc_asm.tmpl"
+#include <asm/errno.h>
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ blelr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
+ .globl __copy_tofrom_user
+__copy_tofrom_user:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ li r3,0 /* success return value */
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+11: lwzu r8,8(r4)
+12: stw r7,4(r6)
+13: stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+14: lwzu r0,4(r4)
+ addi r5,r5,-4
+15: stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+16: stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+17: stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
+ .long 11b,99b
+ .long 12b,99b
+ .long 13b,99b
+ .long 14b,99b
+ .long 15b,99b
+ .long 4b,99b
+ .long 16b,99b
+ .long 6b,99b
+ .long 17b,99b
+.text
+
+ .globl __clear_user
+__clear_user:
+ addi r6,r3,-4
+ li r3,0
+ li r5,0
+ cmplwi 0,r4,4
+ blt 7f
+11: stwu r5,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r4,r0,r4
+ subf r6,r0,r6
+ rlwinm r0,r4,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r5,4(r6)
+ bdnz 1b
+6: andi. r4,r4,3
+7: cmpwi 0,r4,0
+ beqlr
+ mtctr r4
+ addi r6,r6,3
+8: stbu r5,1(r6)
+ bdnz 8b
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 11b,99b
+ .long 1b,99b
+ .long 8b,99b
+.text
+
+ .globl __strncpy_from_user
+__strncpy_from_user:
+ addi r6,r3,-1
+ addi r4,r4,-1
+ cmpwi 0,r5,0
+ beq 2f
+ mtctr r5
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ beq 3f
+2: addi r6,r6,1
+3: subf r3,r3,r6
+ blr
+99: li r3,-EFAULT
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
+.text
+
+ .globl strlen_user
+strlen_user:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ addi r3,r3,1
+ blr
+99: li r3,0
+ blr
+.section __ex_table,"a"
+ .align 2
+ .long 1b,99b
--- /dev/null
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+echo Diff of: $N against $N.ORIG '->' $N-$date-ppc.patch
+diff -uNr -X $N/arch/ppc/ignore $N.ORIG $N > dist/$N-$date-ppc.patch
--- /dev/null
+#!/bin/bash
+
+N=`basename $PWD`
+V=`echo $N | sed 's/linux-//'`
+date=`date +'%y%m%d'`
+mkdir -p ../dist
+mv zImage ../dist/zImage-$V-$date
+mv System.map ../dist/System.map-$V-$date
+
--- /dev/null
+#!/bin/bash
+
+N=`basename $PWD`
+date=`date +'%y%m%d'`
+cd ../
+mkdir -p dist
+tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
.c.s:
$(CC) $(CFLAGS) -S $<
-OBJS = fault.o init.o
+OBJS = fault.o init.o extable.o
mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS)
modules:
dep:
- $(CPP) -M *.c > .depend
-
+
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
#
# include a dependency file if one exists
--- /dev/null
+/*
+ * linux/arch/ppc/mm/extable.c
+ *
+ * from linux/arch/i386/mm/extable.c
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+extern const struct exception_table_entry __start___ex_table[];
+extern const struct exception_table_entry __stop___ex_table[];
+
+static inline unsigned long
+search_one_table(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ long diff;
+
+ mid = (last - first) / 2 + first;
+ diff = mid->insn - value;
+ if (diff == 0)
+ return mid->fixup;
+ else if (diff < 0)
+ first = mid+1;
+ else
+ last = mid-1;
+ }
+ return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr)
+{
+ unsigned long ret;
+
+#if 1 /*ndef CONFIG_MODULES*/
+ /* There is only the kernel to search. */
+ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
+ if (ret) return ret;
+#else
+ /* The kernel is the last "module" -- no need to treat it special. */
+ struct module *mp;
+ for (mp = module_list; mp != NULL; mp = mp->next) {
+ if (mp->ex_table_start == NULL)
+ continue;
+ ret = search_one_table(mp->ex_table_start,
+ mp->ex_table_end - 1, addr);
+ if (ret) return ret;
+ }
+#endif
+
+ return 0;
+}
/*
- * ARCH/ppc/mm/fault.c
+ * arch/ppc/mm/fault.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
* Ported to PPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Modified by Cort Dougan and Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
-extern void die_if_kernel(char *, struct pt_regs *, long);
-extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void new_page_fault(unsigned long address, unsigned long code, unsigned long text,
- struct pt_regs *regs);
-
+#ifdef CONFIG_PMAC
+extern void (*xmon_fault_handler)(void);
+#endif
-#undef SHOW_FAULTS
-#undef NOISY_INSTRFAULT
-#undef NOISY_DATAFAULT
+/* the linux norm for the function name is show_regs() so
+ make it call dump_regs() on the mac -- Cort */
+#ifdef CONFIG_PMAC
+#define show_regs dump_regs
+#endif
-unsigned int probingmem = 0;
-#define NEWMM 1
+extern void die_if_kernel(char *, struct pt_regs *, long);
+void bad_page_fault(struct pt_regs *, unsigned long);
+void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+void print_pte(struct _PTE);
-void new_page_fault(unsigned long address, unsigned long ppc_code,
- unsigned long text, struct pt_regs *regs)
+void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
{
- struct vm_area_struct * vma;
- struct mm_struct *mm = current->mm;
-
- int intel_code = 0;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*
- * bit 0 == 0 means no page found, 1 means protection fault
- * bit 1 == 0 means read, 1 means write
- * bit 2 == 0 means kernel, 1 means user-mode
- */
- if (user_mode(regs)) intel_code |= 0x04;
- if (!text && (ppc_code & 0x02000000)) intel_code |= 0x02; /* Load/store */
- if (!text && (ppc_code & 0x08000000))
- {
- intel_code |= 0x01; /* prot viol */
- goto do_page;
- }
-
- dir = pgd_offset(mm, address & PAGE_MASK);
- if (dir)
- {
- pmd = pmd_offset(dir, address & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, address & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- MMU_hash_page(¤t->tss, address & PAGE_MASK, pte);
- return;
- }
- }
- }
-
+ struct task_struct *tsk = current;
+ extern unsigned _end[];
+ struct vm_area_struct * vma;
+ struct mm_struct *mm = current->mm;
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
+ current->comm,current->pid,address,regs->nip,regs,error_code);*/
+#ifdef CONFIG_PMAC
+ if (xmon_fault_handler && regs->trap == 0x300) {
+ xmon_fault_handler();
+ return;
+ }
+#endif
+ if (in_interrupt()) {
+ static int complained;
+ if (complained < 20) {
+ ++complained;
+ printk("page fault in interrupt handler, addr=%lx\n",
+ address);
+ show_regs(regs);
+ }
+ }
+ if (current == NULL)
+ goto bad_area;
+
do_page:
- down(&mm->mmap_sem);
- vma = find_vma(current->mm, address);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
+ down(&mm->mmap_sem);
+ vma = find_vma(tsk->mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
good_area:
- /* a write */
- if (intel_code & 2) {
- if (!(vma->vm_flags & VM_WRITE))
- {
- goto bad_area;
- }
- /* a read */
- } else {
- /* protection fault */
- if (intel_code & 1)
- {
- printk("prot fault\n");
- goto bad_area;
- }
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- {
- printk("no read or exec\n");
- goto bad_area;
- }
- }
- handle_mm_fault(vma, address, intel_code & 2);
- up(&mm->mmap_sem); flush_page(address); /* Flush & Invalidate cache - note: address is OK now */
- return;
+ if (error_code & 0xb5700000)
+ /* an error such as lwarx to I/O controller space,
+ address matching DABR, eciwx, etc. */
+ goto bad_area;
+
+ /* a write */
+ if (error_code & 0x02000000) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ /* a read */
+ } else {
+ /* protection fault */
+ if ( error_code & 0x08000000 )
+ goto bad_area;
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ handle_mm_fault(current, vma, address, error_code & 0x02000000);
+ up(&mm->mmap_sem);
+ /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
+ current->comm,current->pid,address,regs->msr);*/
+ /* not needed since flush_page_to_ram() works */
+#if 0
+ flush_page(address);
+#endif
+ return;
bad_area:
- up(&mm->mmap_sem);
+ up(¤t->mm->mmap_sem);
+ bad_page_fault(regs, address);
+}
+
+
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address)
+{
+ extern unsigned int probingmem;
+ struct task_struct *tsk = current;
+ unsigned long fixup;
+
+
+ /* Are we prepared to handle this fault? */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ if ( user_mode(regs) )
+ printk("Exception from user mode\n");
+#if 0
+ printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
+#endif
+ regs->nip = fixup;
+ return;
+ }
- /* Did we have an exception handler installed? */
- if(current->tss.excount != 0) {
- if(user_mode(regs)) {
- printk("Exception signalled from user mode!\n");
- } else {
-#if 0
- printk("Exception from kernel mode. pc %x expc %x count %d\n",
- regs->nip,current->tss.expc,current->tss.excount);
-#endif
- current->tss.excount = 0;
- regs->gpr[3] = -EFAULT;
- regs->nip = current->tss.expc;
- return;
- }
- }
+ if ( user_mode(regs) )
+ {
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
- if (user_mode(regs))
- {
- force_sig(SIGSEGV, current);
- return;
- }
- panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
- regs->nip,address,vma->vm_flags);
+bad_kernel_access:
+ /* make sure it's not a bootup probe test */
+ if ( probingmem )
+ {
+ probingmem = 0;
+ return;
+ }
+ /* kernel has accessed a bad area */
+ show_regs(regs);
+ print_backtrace( regs->gpr[1] );
+#ifdef CONFIG_PMAC
+ xmon(regs);
+#endif
+ panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
+ regs->nip,address,tsk->comm,tsk->pid);
}
-va_to_phys(unsigned long address)
+unsigned long va_to_phys(unsigned long address)
{
pgd_t *dir;
pmd_t *pmd;
pte_t *pte;
+
dir = pgd_offset(current->mm, address & PAGE_MASK);
if (dir)
{
return (0);
}
-inline void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t _pte)
+void print_pte(struct _PTE p)
{
- MMU_hash_page(¤t->tss, address & PAGE_MASK, (pte *)&_pte);
+ printk(
+"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n",
+ *((unsigned long *)(&p)), *((long *)&p+1),
+ p.vsid, p.h, p.api, p.rpn,
+ p.r,p.c,p.w,p.i,p.m,p.g,p.pp);
+}
+
+/*
+ * Search the hw hash table for a mapping to the given physical
+ * address. -- Cort
+ */
+unsigned long htab_phys_to_va(unsigned long address)
+{
+ extern PTE *Hash, *Hash_end;
+ PTE *ptr;
+
+ for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
+ {
+ if ( ptr->rpn == (address>>12) )
+ printk("phys %08X -> va ???\n",
+ address);
+ }
}
/*
* arch/ppc/mm/init.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ * and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * Derived from "arch/i386/mm/init.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
*/
#include <linux/config.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/stddef.h>
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#endif
+#include <asm/io.h>
+#include <asm/mmu_context.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_PREP
#include <asm/residual.h>
+#endif
-extern pgd_t swapper_pg_dir[1024];
-extern unsigned long empty_zero_page[1024];
+int next_mmu_context;
+extern pgd_t swapper_pg_dir[];
+extern char _start[], _end[];
+extern char etext[], _stext[];
+/* References to section boundaries */
+extern char __init_begin, __init_end;
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
-void flush_hash_table(void);
+extern unsigned long *find_end_of_memory(void);
-#undef HASHSTATS
+#undef MAP_RAM_WITH_SEGREGS 1
-unsigned long _SDR1; /* Hardware SDR1 image */
-PTE *Hash;
-int Hash_size, Hash_mask;
+#ifdef CONFIG_PMAC
+void *find_mem_piece(unsigned, unsigned);
+static void mapin_ram(void);
+static void inherit_prom_translations(void);
+#endif
+#ifdef CONFIG_PREP
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
+int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);
+#endif
+
+static void hash_init(void);
+static void *MMU_get_page(void);
+void map_page(struct thread_struct *, unsigned long va,
+ unsigned long pa, int flags);
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
unsigned long *end_of_DRAM;
-int cache_is_copyback = 1;
-int kernel_pages_are_copyback = 1;
-/* Note: these need to be in 'data' so they live over the boot */
-unsigned char *BeBox_IO_page = 0;
-unsigned long isBeBox[2] = {0, 0};
+int mem_init_done;
+#ifdef CONFIG_PREP
#ifdef HASHSTATS
-extern unsigned long *hashhits;
-#endif
-
+extern unsigned long evicts;
+#endif /* HASHSTATS */
+/*
+ * these are used to setup the initial page tables
+ * They can waste up to an entire page since the
+ * I'll fix this shortly -- Cort
+ */
+#define MAX_MMU_PAGES 16
+unsigned int probingmem = 0;
+unsigned int mmu_pages_count = 0;
+char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
+unsigned long _TotalMemory;
+#endif /* CONFIG_PREP */
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+unsigned long empty_bad_page_table;
pte_t * __bad_pagetable(void)
{
- panic("__bad_pagetable");
+ memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+ return (pte_t *) empty_bad_page_table;
}
+unsigned long empty_bad_page;
+
pte_t __bad_page(void)
{
- panic("__bad_page");
+ memset((void *)empty_bad_page, 0, PAGE_SIZE);
+ return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+}
+
+#ifdef CONFIG_PMAC
+#define MAX_MEM_REGIONS 32
+phandle memory_pkg;
+
+struct mem_pieces {
+ int n_regions;
+ struct reg_property regions[MAX_MEM_REGIONS];
+};
+
+struct mem_pieces phys_mem;
+struct mem_pieces phys_avail;
+struct mem_pieces prom_mem;
+
+static void get_mem_prop(char *, struct mem_pieces *);
+static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+static void print_mem_pieces(struct mem_pieces *);
+
+unsigned long avail_start;
+int prom_trashed;
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+static void
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+ int s, i;
+
+ s = (int) call_prom("getprop", 4, 1, memory_pkg, name,
+ mp->regions, sizeof(mp->regions));
+ if (s < sizeof(mp->regions[0])) {
+ printk("getprop /memory %s returned %d\n", name, s);
+ abort();
+ }
+ mp->n_regions = s / sizeof(mp->regions[0]);
+
+ /*
+ * Make sure the pieces are sorted.
+ */
+ for (i = 1; i < mp->n_regions; ++i) {
+ unsigned long a, s;
+ int j;
+
+ a = mp->regions[i].address;
+ s = mp->regions[i].size;
+ for (j = i - 1; j >= 0; --j) {
+ if (a >= mp->regions[j].address)
+ break;
+ mp->regions[j+1] = mp->regions[j];
+ }
+ mp->regions[j+1].address = a;
+ mp->regions[j+1].size = s;
+ }
+}
+
+/*
+ * Remove some memory from an array of pieces
+ */
+static void
+remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size,
+ int must_exist)
+{
+ int i, j;
+ unsigned end, rs, re;
+ struct reg_property *rp;
+
+ end = start + size;
+ for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
+ if (end > rp->address && start < rp->address + rp->size)
+ break;
+ }
+ if (i >= mp->n_regions) {
+ if (must_exist)
+ printk("remove_mem_piece: [%x,%x) not in any region\n",
+ start, end);
+ return;
+ }
+ for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
+ rs = rp->address;
+ re = rs + rp->size;
+ if (must_exist && (start < rs || end > re)) {
+ printk("remove_mem_piece: bad overlap [%x,%x) with",
+ start, end);
+ print_mem_pieces(mp);
+ must_exist = 0;
+ }
+ if (start > rs) {
+ rp->size = start - rs;
+ if (end < re) {
+ /* need to split this entry */
+ if (mp->n_regions >= MAX_MEM_REGIONS)
+ panic("eek... mem_pieces overflow");
+ for (j = mp->n_regions; j > i + 1; --j)
+ mp->regions[j] = mp->regions[j-1];
+ ++mp->n_regions;
+ rp[1].address = end;
+ rp[1].size = re - end;
+ }
+ } else {
+ if (end < re) {
+ rp->address = end;
+ rp->size = re - end;
+ } else {
+ /* need to delete this entry */
+ for (j = i; j < mp->n_regions - 1; ++j)
+ mp->regions[j] = mp->regions[j+1];
+ --mp->n_regions;
+ --i;
+ --rp;
+ }
+ }
+ }
+}
+
+static void
+print_mem_pieces(struct mem_pieces *mp)
+{
+ int i;
+
+ for (i = 0; i < mp->n_regions; ++i)
+ printk(" [%x, %x)", mp->regions[i].address,
+ mp->regions[i].address + mp->regions[i].size);
+ printk("\n");
+}
+
+void *
+find_mem_piece(unsigned size, unsigned align)
+{
+ int i;
+ unsigned a, e;
+ struct mem_pieces *mp = &phys_avail;
+
+ for (i = 0; i < mp->n_regions; ++i) {
+ a = mp->regions[i].address;
+ e = a + mp->regions[i].size;
+ a = (a + align - 1) & -align;
+ if (a + size <= e) {
+ remove_mem_piece(mp, a, size, 1);
+ return __va(a);
+ }
+ }
+ printk("Couldn't find %u bytes at %u alignment\n", size, align);
+ abort();
+ return NULL;
+}
+
+/*
+ * Collect information about RAM and which pieces are already in use.
+ * At this point, we have the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long *find_end_of_memory(void)
+{
+ unsigned long a, total;
+ unsigned long h, kstart, ksize;
+ extern char _stext[], _end[];
+ int i;
+
+ memory_pkg = call_prom("finddevice", 1, 1, "/memory");
+ if (memory_pkg == (void *) -1)
+ panic("can't find memory package");
+
+ /*
+ * Find out where physical memory is, and check that it
+ * starts at 0 and is contiguous. It seems that RAM is
+ * always physically contiguous on Power Macintoshes,
+ * because MacOS can't cope if it isn't.
+ */
+ get_mem_prop("reg", &phys_mem);
+ if (phys_mem.n_regions == 0)
+ panic("No RAM??");
+ a = phys_mem.regions[0].address;
+ if (a != 0)
+ panic("RAM doesn't start at physical address 0");
+ total = phys_mem.regions[0].size;
+ for (i = 1; i < phys_mem.n_regions; ++i) {
+ a = phys_mem.regions[i].address;
+ if (a != total) {
+ printk("RAM starting at 0x%lx is not contiguous\n", a);
+ printk("Using RAM from 0 to 0x%lx\n", total-1);
+ phys_mem.n_regions = i;
+ break;
+ }
+ total += phys_mem.regions[i].size;
+ }
+
+ /* record which bits the prom is using */
+ get_mem_prop("available", &phys_avail);
+ prom_mem = phys_mem;
+ for (i = 0; i < phys_avail.n_regions; ++i)
+ remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
+ phys_avail.regions[i].size, 1);
+
+ /*
+ * phys_avail records memory we can use now.
+ * prom_mem records memory allocated by the prom that we
+ * don't want to use now, but we'll reclaim later.
+ * Make sure the kernel text/data/bss is in neither.
+ */
+ kstart = __pa(_stext); /* should be 0 */
+ ksize = PAGE_ALIGN(_end - _stext);
+ remove_mem_piece(&phys_avail, kstart, ksize, 0);
+ remove_mem_piece(&prom_mem, kstart, ksize, 0);
+
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* Find some memory for the hash table. */
+ Hash = find_mem_piece(Hash_size, Hash_size);
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ total >> 20, Hash_size >> 10, Hash);
+
+ return __va(total);
+}
+
+/*
+ * Find some memory for setup_arch to return.
+ * We use the last chunk of available memory as the area
+ * that setup_arch returns, making sure that there are at
+ * least 32 pages unused before this for MMU_get_page to use.
+ */
+unsigned long find_available_memory(void)
+{
+ int i;
+ unsigned long a, free;
+ unsigned long start, end;
+
+ free = 0;
+ for (i = 0; i < phys_avail.n_regions - 1; ++i) {
+ start = phys_avail.regions[i].address;
+ end = start + phys_avail.regions[i].size;
+ free += (end & PAGE_MASK) - PAGE_ALIGN(start);
+ }
+ a = PAGE_ALIGN(phys_avail.regions[i].address);
+ if (free < 32 * PAGE_SIZE)
+ a += 32 * PAGE_SIZE - free;
+ avail_start = (unsigned long) __va(a);
+ return avail_start;
}
+#endif /* CONFIG_PMAC */
void show_mem(void)
{
+ int i,free = 0,total = 0,reserved = 0;
+ int shared = 0;
struct task_struct *p;
- unsigned long i,free = 0,total = 0,reserved = 0;
- unsigned long shared = 0;
- PTE *ptr;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = MAP_NR(high_memory);
+ i = max_mapnr;
while (i-- > 0) {
total++;
if (PageReserved(mem_map+i))
else
shared += atomic_read(&mem_map[i].count) - 1;
}
- printk("%lu pages of RAM\n",total);
- printk("%lu free pages\n",free);
- printk("%lu reserved pages\n",reserved);
- printk("%lu pages shared\n",shared);
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
#endif
-#ifdef HASHSTATS
- printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
- for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
- if ( hashhits[i] >= 20 )
- printk("[%lu] \t %lu\n", i,hashhits[i]);
- }
-#endif
-
- for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
- if (ptr->v) {
- full++;
- if (ptr->h == 1)
- overflow++;
- }
- }
- printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
- Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
- full,Hash_size/sizeof(PTE),
- (full*100)/(Hash_size/sizeof(PTE)),
- overflow);
- printk(" Task context vsid0\n");
- read_lock(&tasklist_lock);
- for_each_task(p) {
- printk("%5d %8x %8x\n",
- p->pid,p->mm->context,
- ((SEGREG *)p->tss.segs)[0].vsid);
+ printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt",
+ "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+ for_each_task(p)
+ {
+ printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+ p->comm,p->pid,
+ p->mm->count,p->mm->context,
+ p->mm->context<<4, p->tss.last_syscall,
+ user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
+ p);
+ if ( p == current )
+ printk(" current");
+ printk("\n");
}
- read_unlock(&tasklist_lock);
}
extern unsigned long free_area_init(unsigned long, unsigned long);
+/*
+ * paging_init() sets up the page tables - in fact we've already done this.
+ */
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
{
- return free_area_init(start_mem, end_mem);
+ /*
+ * Grab some memory for bad_page and bad_pagetable to use.
+ */
+ empty_bad_page = start_mem;
+ empty_bad_page_table = start_mem + PAGE_SIZE;
+ start_mem += 2 * PAGE_SIZE;
+
+ /* note: free_area_init uses its second argument
+ to size the mem_map array. */
+ start_mem = free_area_init(start_mem, end_mem);
+ return start_mem;
}
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
- int codepages = 0;
- int datapages = 0;
- unsigned long tmp;
- extern int etext;
+ unsigned long addr;
+#ifdef CONFIG_PMAC
+ int i;
+ unsigned long lim;
+#endif
+ int codepages = 0;
+ int datapages = 0;
+ int initpages = 0;
+
+ end_mem &= PAGE_MASK;
+ high_memory = (void *) end_mem;
+ num_physpages = max_mapnr = MAP_NR(high_memory);
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
- max_mapnr = MAP_NR(end_mem);
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
/* mark usable pages in the mem_map[] */
- start_mem = PAGE_ALIGN(start_mem);
+ start_mem = PAGE_ALIGN(start_mem);
+
+#ifdef CONFIG_PMAC
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ mem_map[MAP_NR(a)].count = 1;
+ free_page(a);
+ }
+ }
+ phys_avail.n_regions = 0;
- for (tmp = KERNELBASE ; tmp < (long)high_memory ; tmp += PAGE_SIZE)
- {
- if (tmp < start_mem)
+ /* free the prom's memory */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ mem_map[MAP_NR(a)].count = 1;
+ free_page(a);
+ }
+ }
+ prom_trashed = 1;
+#endif /* CONFIG_PMAC */
+
+#ifdef CONFIG_PREP
+ /* mark mem used by kernel as reserved, mark other unreserved */
+ for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
{
- set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
- if (tmp < (unsigned long) &etext)
- {
- codepages++;
- } else
- {
- datapages++;
- }
- continue;
- }
- clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
- atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
- free_page(tmp);
- }
- tmp = nr_free_pages << PAGE_SHIFT;
- printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
- tmp >> 10,
- ((int)high_memory - (int)KERNELBASE) >> 10,
- codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10));
- /* invalidate();*/
- return;
+ /* skip hash table gap */
+ if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+ continue;
+ if ( addr < (ulong) /*Hash_end*/ start_mem )
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ else
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
+
+ for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+ if(PageReserved(mem_map + MAP_NR(addr))) {
+ if (addr < (ulong) etext)
+ codepages++;
+ /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ initpages++;*/
+ else if (addr < (ulong) start_mem)
+ datapages++;
+ continue;
+ }
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (!initrd_start ||
+ (addr < initrd_start || addr >= initrd_end))
+#endif /* CONFIG_BLK_DEV_INITRD */
+ free_page(addr);
+ }
+
+#endif /* CONFIG_PREP */
+ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+ (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+ codepages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10),
+ PAGE_OFFSET, end_mem);
+ mem_init_done = 1;
}
+/*
+ * this should reclaim gap between _end[] and hash table
+ * as well as unused mmu_pages[] on prep systems.
+ * When I get around to it, I'll put initialization functions
+ * (called only at boot) in their own .section and free that -- Cort
+ */
void free_initmem(void)
{
- /* To be written */
+ unsigned long addr;
+ unsigned long a;
+ unsigned long num_freed_pages = 0;
+
+ /* free unused mmu_pages[] */
+ a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE);
+ for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE )
+ {
+ clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags );
+ atomic_set(&mem_map[MAP_NR(a)].count, 1);
+ free_page(a);
+ num_freed_pages++;
+ }
+
+#if 0
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ num_freed_pages++;
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ mem_map[MAP_NR(addr)].count = 1;
+ free_page(addr);
+ }
+#endif
+ printk ("Freeing unused kernel memory: %dk freed\n",
+ (num_freed_pages * PAGE_SIZE) >> 10);
}
void si_meminfo(struct sysinfo *val)
{
int i;
- i = ((int)high_memory & 0x00FFFFFF) >> PAGE_SHIFT;
+ i = max_mapnr;
val->totalram = 0;
val->sharedram = 0;
val->freeram = nr_free_pages << PAGE_SHIFT;
val->totalram++;
if (!atomic_read(&mem_map[i].count))
continue;
- val->sharedram += atomic_read(&mem_map[i].count) - 1;
+ val->sharedram += atomic_read(&mem_map[i].count)-1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
return;
}
+/* Kernel MMU setup & lowest level hardware support */
+
+unsigned long _SDR1; /* Hardware SDR1 image */
+
+#ifdef CONFIG_PREP
+
BAT BAT0 =
- {
- {
- 0x80000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs -- supervisor mode valid */
- 1, /* vp -- user mode valid */
- },
- {
- 0x80000000>>17, /* brpn */
- 1, /* write-through */
- 1, /* cache-inhibited */
- 0, /* memory coherence */
- 1, /* guarded */
- BPP_RW /* protection */
- }
- };
+{
+ {
+ 0x80000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 1, /* vs -- supervisor mode valid */
+ 1, /* vp -- user mode valid */
+ },
+ {
+ 0x80000000>>17, /* brpn */
+ 1, /* write-through */
+ 1, /* cache-inhibited */
+ 0, /* memory coherence */
+ 1, /* guarded */
+ BPP_RW /* protection */
+ }
+};
BAT BAT1 =
- {
- {
- 0xC0000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs */
- 1, /* vp */
- },
- {
- 0xC0000000>>17, /* brpn */
- 1, /* w */
- 1, /* i (cache disabled) */
- 0, /* m */
- 1, /* g */
- BPP_RW /* pp */
- }
- };
+{
+ {
+ 0xC0000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 1, /* vs */
+ 1, /* vp */
+ },
+ {
+ 0xC0000000>>17, /* brpn */
+ 1, /* w */
+ 1, /* i (cache disabled) */
+ 0, /* m */
+ 1, /* g */
+ BPP_RW /* pp */
+ }
+};
BAT BAT2 =
- {
- {
- 0x90000000>>17, /* bepi */
- BL_256M, /* this gets set to amount of phys ram */
- 1, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 0, /* w */
- 0, /* i */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
+{
+ {
+ 0x90000000>>17, /* bepi */
+ BL_256M, /* this gets set to amount of phys ram */
+ 1, /* vs */
+ 0, /* vp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 0, /* w */
+ 0, /* i */
+ 1, /* m */
+ 0, /* g */
+ BPP_RW /* pp */
+ }
+};
BAT BAT3 =
- {
- {
- 0x00000000>>17, /* bepi */
- BL_256M, /* bl */
- 0, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 1, /* w */
- 1, /* i (cache disabled) */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
-BAT TMP_BAT2 =
- { /* 0x9XXXXXXX -> 0x0XXXXXXX */
- {
- 0x90000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs */
- 1, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 1, /* w */
- 0, /* i (cache enabled) */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
-
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/*
- * This code is called to create a minimal mapped environment.
- * It is called with the MMU on, but with only a BAT register
- * set up to cover the code/data. After this routine runs,
- * the BAT mapping is withdrawn and all mappings must be complete.
- */
+{
+ {
+ 0x00000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 0, /* vs */
+ 0, /* vp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 0, /* w */
+ 0, /* i (cache disabled) */
+ 1, /* m */
+ 0, /* g */
+ BPP_RW /* pp */
+ }
+};
+P601_BAT BAT0_601 =
+{
+ {
+ 0x80000000>>17, /* bepi */
+ 1,1,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x80000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
+P601_BAT BAT1_601 =
+{
+ {
+ 0xC0000000>>17, /* bepi */
+ 1,1,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0xC0000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
+P601_BAT BAT2_601 =
+{
+ {
+ 0x90000000>>17, /* bepi */
+ 0,0,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
-extern char _start[], _end[];
-
-void MMU_init(void)
+P601_BAT BAT3_601 =
{
- extern RESIDUAL res;
- extern unsigned long resptr;
- int i, p;
- SEGREG *segs;
-
- /* copy residual data */
- if ( resptr )
- memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
- else
- bzero( &res, sizeof(RESIDUAL) ); /* clearing bss probably clears this but... */
-
- end_of_DRAM = (unsigned long *)find_end_of_memory();
- _SDR1 = ((unsigned long)Hash - KERNELBASE) | Hash_mask;
-#if 0
- printk("Hash %08x\n",(unsigned long)Hash);
- printk("Hash_mask %08x\n",Hash_mask);
- printk("Hash_size %08x\n",Hash_size);
- printk("SDR1 %08x\n",_SDR1);
-#endif
- /* Segment registers */
- segs = (SEGREG *)init_task.tss.segs;
- for (i = 0; i < 16; i++)
{
- segs[i].ks = 0;
- segs[i].kp = 1;
-#if 1
- if ( i < 8 )
- segs[i].vsid = i+10000;
- else
-#else
- if ( i < 8 )
- segs[i].vsid = i<<5;
-#endif
- segs[i].vsid = i;
+ 0x90800000>>17, /* bepi */
+ 0,0,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x00800000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
}
-
-
-
- /* Hard map in any special local resources */
- if (isBeBox[0])
- {
- /* Map in one page for the BeBox motherboard I/O */
- end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - PAGE_SIZE);
-#if 0
- BeBox_IO_page = (unsigned char *)0x7FFFF000;
-#endif
- BeBox_IO_page = (unsigned char *)end_of_DRAM;
- MMU_disable_cache_for_page(&init_task.tss, BeBox_IO_page);
- }
-}
+};
/*
- * Insert(create) a hardware page table entry
+ * This finds the amount of physical ram and does necessary
+ * setup for prep. This is pretty architecture specific so
+ * this will likely stay seperate from the pmac.
+ * -- Cort
*/
-int inline MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
-{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *empty, *slot;
- PTE *slot0, *slot1;
- extern char _etext;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = ((SEGREG *)tss->segs)[segment].vsid;
- empty = slot = (PTE *)NULL;
-
- if ( (va <= _etext) && (va >= KERNELBASE))
- {
- printk("MMU_hash_page: called on kernel page mapped with bats va %x\n",
- va);
- }
+unsigned long *find_end_of_memory(void)
+{
+ extern RESIDUAL res;
+ extern unsigned long resptr;
+ int i, p;
+ unsigned long h;
- /* check first hash bucket */
- h = 0;
- hash = page_index ^ vsid;
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* 8 entries in each bucket */
- _pte = &Hash[hash];
- slot0 = _pte;
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
- {
- slot = _pte;
- goto found_it;
- }
- if ((empty == NULL) && (!_pte->v))
+ /* copy residual data */
+ if ( resptr )
+ memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
+ else
+ /* clearing bss probably clears this but... */
+ memset( &res, sizeof(RESIDUAL), 0 );
+ _TotalMemory = res.TotalMemory;
+
+ /* this really has nothing to do with the mmu_init() but is
+ necessary for early setup -- Cort */
+ if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
{
- empty = _pte;
- _h = h;
+ _machine = _MACH_IBM;
}
- }
-
- /* check second hash bucket */
- h = 1;
- hash = page_index ^ vsid;
- hash = ~hash;
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* 8 entries in each bucket */
- _pte = &Hash[hash];
- slot1 = _pte;
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+ else
+ _machine = _MACH_Motorola;
+
+ /* setup the hash table */
+ if (_TotalMemory == 0 )
{
- slot = _pte;
- goto found_it;
+ /*
+ * I need a way to probe the amount of memory if the residual
+ * data doesn't contain it. -- Cort
+ */
+ printk("Ramsize from residual data was 0 -- Probing for value\n");
+ _TotalMemory = 0x03000000;
+ printk("Ramsize default to be %dM\n", _TotalMemory>>20);
}
- if ((empty == NULL) && (!_pte->v))
+
+#if 0
+ /* linux has trouble with > 64M ram -- Cort */
+ if ( _TotalMemory > 0x04000000 /* 64M */ )
{
- empty = _pte;
- _h = h;
+ printk("Only using first 64M of ram.\n");
+ _TotalMemory = 0x04000000;
}
- }
+#endif
+
+ /* setup the bat2 mapping to cover physical ram */
+ BAT2.batu.bl = 0x1; /* 256k mapping */
+ for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+ h *= 2 )
+ BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* align htab on a Hash_size boundry above _end[] */
+ Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+ memset(Hash, Hash_size, 0 );
- if (empty == (PTE *)NULL)
- {
-#if 1
- printk("Both hash buckets full! va %x vsid %x current %s (%d)\n",
- va,vsid,current->comm,current->pid);
-#endif
- slot = slot1;
- h = 1;
- }
- else
- {
- slot = empty;
- h = _h;
- }
-found_it:
-#ifdef HASHSTATS
- hashhits[hash]++;
-#endif
- _tlbie(va); /* Clear TLB */
- /* Fill in table */
- slot->v = 1;
- slot->vsid = vsid;
- slot->h = h;
- slot->api = api;
- if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
+ /*
+ * if this is a 601, we can only map sizes of 8M with the BAT's
+ * so we have to map what we can't map with the bats with the segregs
+ * head.S will copy in the appropriate BAT's according to the processor
+ * since the 601_BAT{2,3} structures are already setup to map
+ * the first 16M correctly
+ * -- Cort
+ */
+#ifndef MAP_RAM_WITH_SEGREGS /* don't need to do it twice */
+ if ( _get_PVR() == 1 )
{
- slot->rpn = pg->page_num - (KERNELBASE>>12);
- } else
- {
- slot->rpn = pg->page_num;
- }
- slot->r = 0;
- slot->c = 0;
- slot->i = 0;
- slot->g = 0;
- if (cache_is_copyback)
- {
- if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
- { /* All User & Kernel TEXT pages are copy-back */
- slot->w = 0;
- slot->m = 1;
- } else
- { /* Kernel DATA pages are write-thru */
- slot->w = 1;
- slot->m = 0;
- }
- } else
- {
- slot->w = 1;
- slot->m = 0;
- }
- if (pg->flags & _PAGE_USER)
+ /* map in rest of ram with seg regs */
+ if ( _TotalMemory > 0x01000000 /* 16M */)
+ {
+ for (i = KERNELBASE+0x01000000;
+ i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+ }
+ }
+#endif /* MAP_RAM_WITH_SEGREGS */
+
+#ifdef MAP_RAM_WITH_SEGREGS
+ /* turn off bat mapping kernel since being done with segregs */
+ memset(&BAT2, sizeof(BAT2), 0);
+ memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
+ memset(&BAT3_601, sizeof(BAT2), 0);
+ /* map all of ram for kernel with segregs */
+ for (i = KERNELBASE; i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
{
- if (pg->flags & _PAGE_RW)
- { /* Read/write page */
- perms = PP_RWRW;
- } else
- { /* Read only page */
- perms = PP_RWRX;
- perms = PP_RXRX;
- }
- } else
- { /* Kernel pages */
- perms = PP_RWRW;
- perms = PP_RWXX;
- }
- slot->pp = perms;
- return (0);
+ if ( i < (unsigned long)etext )
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
+ else
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+ }
+#endif /* MAP_RAM_WITH_SEGREGS */
+
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ _TotalMemory >> 20, Hash_size >> 10, Hash);
+ return ((unsigned long *)_TotalMemory);
}
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
/*
- * Disable cache for a particular page
+ * Map in all of physical memory starting at KERNELBASE.
*/
-MMU_disable_cache_for_page(struct thread_struct *tss, unsigned long va)
+extern int n_mem_regions;
+extern struct reg_property mem_regions[];
+
+#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+static void mapin_ram()
{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *empty, *slot;
- PTE *slot0, *slot1;
- extern char _etext;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = ((SEGREG *)tss->segs)[segment].vsid;
- empty = slot = (PTE *)NULL;
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- /* Save slot addresses in case we have to purge */
- if (_h)
- {
- slot1 = _pte;
- } else
- {
- slot0 = _pte;
- }
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- h = _h;
- slot = _pte;
- goto found_it;
- }
- if ((empty == (PTE *)NULL) && !_pte->v)
- {
- h = _h;
- empty = _pte;
- }
- }
+ int i;
+ unsigned long v, p, s, f;
+
+ v = KERNELBASE;
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ f = _PAGE_PRESENT | _PAGE_ACCESSED;
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+ map_page(&init_task.tss, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
}
-found_it:
- _tlbie(va); /* Clear TLB */
- slot->i = 1;
- slot->m = 0;
+ }
}
+#define MAX_PROM_TRANSLATIONS 64
-/*
- * invalidate a hardware hash table pte
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
+static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS];
+int n_translations;
+phandle mmu_pkg;
+extern ihandle prom_chosen;
+
+static void inherit_prom_translations()
{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *slot;
- int flags = 0;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = mm->context | segment;
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- _tlbie(va); /* Clear TLB */
- if (_pte->r) flags |= _PAGE_ACCESSED;
- if (_pte->c) flags |= _PAGE_DIRTY;
- _pte->v = 0;
- return (flags);
- }
+ int s, i, f;
+ unsigned long v, p, n;
+ struct translation_property *tp;
+ ihandle mmu_inst;
+
+ if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+ &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst))
+ panic("couldn't get /chosen mmu property");
+ mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst);
+ if (mmu_pkg == (phandle) -1)
+ panic("couldn't get mmu package");
+ s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations",
+ &prom_translations, sizeof(prom_translations));
+ if (s < sizeof(prom_translations[0]))
+ panic("couldn't get mmu translations property");
+ n_translations = s / sizeof(prom_translations[0]);
+
+ for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
+ /* ignore stuff mapped down low */
+ if (tp->virt < 0x10000000)
+ continue;
+ /* map PPC mmu flags to linux mm flags */
+ f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
+ | _PAGE_COHERENT | _PAGE_GUARDED))
+ | pgprot_val(PAGE_KERNEL);
+ /* add these pages to the mappings */
+ v = tp->virt;
+ p = tp->phys;
+ n = tp->size;
+ for (; n != 0; n -= PAGE_SIZE) {
+ map_page(&init_task.tss, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
}
}
- _tlbie(va);
- return (flags);
}
+#endif
-
-inline void
-flush_cache_all(void)
+/*
+ * Initialize the hash table and patch the instructions in head.S.
+ */
+static void hash_init(void)
{
+ int Hash_bits;
+
+ extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
+ hash_page_patch_C[];
+
+ memset(Hash, 0, Hash_size);
+ Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+ /*
+ * Patch up the instructions in head.S:hash_page
+ */
+ Hash_bits = ffz(~Hash_size) - 6;
+ hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+ | (__pa(Hash) >> 16);
+ hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ if (Hash_bits > 16)
+ Hash_bits = 16;
+ hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+ | (Hash_mask >> 10);
+ hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+ | (Hash_mask >> 10);
+
+ /*
+ * Ensure that the locations we've patched have been written
+ * out from the data cache and invalidated in the instruction
+ * cache, on those machines with split caches.
+ */
+ store_cache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_C + 1));
}
-inline void
-flush_cache_mm(struct mm_struct *mm)
+
+
+/*
+ * Do very early mm setup such as finding the size of memory
+ * and setting up the hash table.
+ * A lot of this is prep/pmac specific but a lot of it could
+ * still be merged.
+ * -- Cort
+ */
+void
+MMU_init(void)
{
-}
-inline void
-flush_cache_page(struct vm_area_struct *vma, long va)
+ end_of_DRAM = find_end_of_memory();
+ hash_init();
+ _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+#ifdef CONFIG_PMAC
+ /* Force initial page tables */
+ /* this done by INIT_TSS in processor.h on prep -- Cort */
+ init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
+
+ /* Map in all of RAM starting at KERNELBASE */
+ mapin_ram();
+ /* Copy mappings from the prom */
+ inherit_prom_translations();
+#endif /* CONFIG_PMAC */
+}
+
+static void *
+MMU_get_page()
{
-}
-inline void
-flush_cache_range(struct mm_struct *mm, unsigned long va_start, unsigned long va_end)
+ void *p;
+
+ if (mem_init_done) {
+ p = (void *) __get_free_page(GFP_KERNEL);
+ if (p == 0)
+ panic("couldn't get a page in MMU_get_page");
+ } else {
+#ifdef CONFIG_PREP
+ mmu_pages_count++;
+ if ( mmu_pages_count > MAX_MMU_PAGES )
+ printk("out of mmu pages!\n");
+ p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+ (mmu_pages_count+PAGE_SIZE));
+#endif
+#ifdef CONFIG_PMAC
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+#endif
+ }
+ memset(p, 0, PAGE_SIZE);
+ return p;
+}
+
+#ifdef CONFIG_PMAC
+void *
+ioremap(unsigned long addr, unsigned long size)
{
-}
+ unsigned long p, end = addr + size;
+
+ for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
+ map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ return (void *) addr;
+}
+#endif
-inline void
-cache_mode(char *str, int *ints)
+void
+map_page(struct thread_struct *tss, unsigned long va,
+ unsigned long pa, int flags)
{
- cache_is_copyback = ints[0];
+ pmd_t *pd;
+ pte_t *pg;
+
+ if (tss->pg_tables == NULL) {
+ /* Allocate upper level page map */
+ tss->pg_tables = (unsigned long *) MMU_get_page();
+ }
+ /* Use upper 10 bits of VA to index the first level map */
+ pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+ if (pmd_none(*pd)) {
+ /* Need to allocate second-level table */
+ pg = (pte_t *) MMU_get_page();
+ pmd_val(*pd) = (unsigned long) pg;
+ }
+ /* Use middle 10 bits of VA to index the second-level map */
+ pg = pte_offset(pd, va);
+ set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+ /*flush_hash_page(va >> 28, va);*/
+ flush_hash_page(0, va);
}
/*
* TLB flushing:
*
- * - flush_tlb() flushes the current mm struct TLBs
* - flush_tlb_all() flushes all processes TLBs
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(mm, start, end) flushes a range of pages
*
* since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush them too.
+ * tlb as far as the linux tables are concerned, flush it too.
* -- Cort
*/
-inline void
-flush_tlb(void)
-{
- PTE *ptep;
- int context = current->mm->context;
- struct vm_area_struct *v;
- unsigned int i;
-
- v = current->mm->mmap;
- /* for every virtual memory address in the current context -- flush
- the hash table */
- while ( v != NULL )
- {
- for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
- {
- MMU_invalidate_page(v->vm_mm,i);
- }
- v = v->vm_next;
- }
-
- _tlbia();
-}
-
-/* flush all tlb/hash table entries except for kernels
-
- although the kernel is mapped with the bats, it's dynamic areas
- obtained via kmalloc are mapped by the seg regs
- -- Cort
- */
-inline void
+/*
+ * Flush all tlb/hash table entries except for the kernel's.
+ * We use the fact that only kernel mappings use VSIDs 0 - 15.
+ */
+void
flush_tlb_all(void)
{
- PTE *ptep;
-
- /* flush hash table */
- for ( ptep = Hash ; ptep < (PTE *)((unsigned long)Hash+Hash_size) ; ptep++ )
- {
- /* if not kernel vsids 0-7 (vsid greater than that for process 0)*/
- if ( (ptep->vsid > 7 ) && (ptep->v))
- {
- ptep->v = 0;
- }
- }
+ struct task_struct *tsk;
- _tlbia();
+ read_lock(&tasklist_lock);
+ for_each_task(tsk) {
+ if (tsk->mm)
+ tsk->mm->context = NO_CONTEXT;
+ }
+ read_unlock(&tasklist_lock);
+ get_mmu_context(current);
+ set_context(current->mm->context);
}
-inline void
+
+/*
+ * Flush all the (user) entries for the address space described
+ * by mm. We can't rely on mm->mmap describing all the entries
+ * that might be in the hash table.
+ */
+void
flush_tlb_mm(struct mm_struct *mm)
{
- PTE *ptep;
- int context = mm->context;
- struct vm_area_struct *v;
- unsigned int i;
-
- v = mm->mmap;
- while ( v != NULL )
- {
- for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
- {
- MMU_invalidate_page(v->vm_mm,i);
- }
- v = v->vm_next;
- }
-
- _tlbia();
+ mm->context = NO_CONTEXT;
+ if (mm == current->mm) {
+ get_mmu_context(current);
+ /* done by get_mmu_context() now -- Cort */
+ /*set_context(current->mm->context);*/
+ }
}
-inline void
-flush_tlb_page(struct vm_area_struct *vma, long vmaddr)
+void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
{
- MMU_invalidate_page(vma->vm_mm,vmaddr);
+ unsigned vsid;
+
+ if ( vmaddr < TASK_SIZE) {
+ /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
+ flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
+ /* this is needed on prep at the moment -- don't know why
+ -- Cort*/
+ MMU_invalidate_page(vma->vm_mm,vmaddr);
+ }
+ else
+ {
+ /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
+ }
}
-/* for each page addr in the range, call mmu_invalidat_page()
+/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
but that's for study later.
-- Cort
*/
-inline void
-flush_tlb_range(struct mm_struct *mm, long start, long end)
+void
+flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
- long i;
- for ( i = PAGE_ALIGN(start-PAGE_SIZE) ; i < PAGE_ALIGN(end) ; i += PAGE_SIZE)
- {
- MMU_invalidate_page(mm,i);
- }
+ start &= PAGE_MASK;
+ for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
+ {
+ /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
+ start );*/
+ flush_hash_page(mm->context, start);
+ /* this is needed on prep at the moment -- don't know why
+ -- Cort*/
+ MMU_invalidate_page(mm,start);
+ }
}
-inline void
-flush_page_to_ram(unsigned long page)
+/*
+ * The context counter has overflowed.
+ * We set mm->context to NO_CONTEXT for all mm's in the system.
+ * We assume we can get to all mm's by looking as tsk->mm for
+ * all tasks in the system.
+ */
+void
+mmu_context_overflow(void)
+{
+ struct task_struct *tsk;
+ int nr;
+
+ printk(KERN_INFO "mmu_context_overflow\n");
+ for (nr = 0; nr < NR_TASKS; ++nr) {
+ tsk = task[nr];
+ if (tsk && tsk->mm)
+ tsk->mm->context = NO_CONTEXT;
+ }
+ flush_hash_segments(0x10, 0xffffff);
+ _tlbia();
+ next_mmu_context = 0;
+}
+
+#ifdef CONFIG_PREP
+/*
+ * it's not a simple matter to get rid of these and switch to the
+ * ones paul is using. it will take some time and thought -- Cort
+ */
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
{
+ int hash, page_index, segment, i, h, _h, api, vsid, perms;
+ PTE *_pte, *slot;
+ int flags = 0;
+ page_index = ((int)va & 0x0FFFF000) >> 12;
+ segment = (unsigned int)va >> 28;
+ api = page_index >> 10;
+ vsid = VSID_FROM_CONTEXT(segment,mm->context);
+ for (_h = 0; _h < 2; _h++)
+ {
+ hash = page_index ^ vsid;
+ if (_h)
+ {
+ hash = ~hash; /* Secondary hash uses ones-complement */
+ }
+ hash &= 0x3FF | (Hash_mask /*<< 10*/);
+ hash *= 8; /* Eight entries / hash bucket */
+ _pte = &Hash[hash];
+ for (i = 0; i < 8; i++, _pte++)
+ {
+ if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
+ { /* Found it! */
+ _tlbie(va); /* Clear TLB */
+ if (_pte->r) flags |= _PAGE_ACCESSED;
+ if (_pte->c) flags |= _PAGE_DIRTY;
+ _pte->v = 0;
+ return /*(flags)*/;
+ }
+ }
+ }
+ _tlbie(va);
+ return /*(flags)*/;
+}
+#endif
+
+#include <asm/mmu.h>
+void print_mm_info(void)
+{
+ struct _SEGREG s;
+ long a;
+ struct _BATU bu;
+ struct _BATL bl;
+ unsigned long i;
+
+ for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
+ {
+ a = get_SR(i);
+ memcpy(&s,&a,4);
+ printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x %x\n",
+ i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
+ }
+
+ asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
+ printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
+ bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
}
--- /dev/null
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_NATIVE=y
+# CONFIG_PMAC is not set
+CONFIG_PREP=y
+# CONFIG_HEARTBEAT is not set
+# CONFIG_POWERSAVING is not set
+CONFIG_MCOMMON=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+CONFIG_PCI=y
+CONFIG_PCI_OPTIMIZE=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+# CONFIG_BINFMT_JAVA is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+CONFIG_BLK_DEV_FD=y
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+CONFIG_SCSI_NCR53C7xx=y
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+# CONFIG_SCSI_NCR53C7xx_FAST is not set
+# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+# CONFIG_SCSI_QLOGIC_PMAC is not set
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_INET_PCTCP is not set
+# CONFIG_INET_RARP is not set
+CONFIG_PATH_MTU_DISCOVERY=y
+# CONFIG_IP_NOSR is not set
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_NET_VENDOR_3COM=y
+# CONFIG_EL1 is not set
+# CONFIG_EL2 is not set
+# CONFIG_ELPLUS is not set
+# CONFIG_EL16 is not set
+CONFIG_EL3=y
+# CONFIG_VORTEX is not set
+CONFIG_LANCE=y
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_EISA=y
+CONFIG_PCNET32=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+CONFIG_DE4X5=y
+# CONFIG_DEC_ELCP is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_ZNET is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=y
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_EXT2_FS=y
+CONFIG_BEXT2_FS=y
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+CONFIG_ROOT_NFS=y
+# CONFIG_RNFS_BOOTP is not set
+# CONFIG_RNFS_RARP is not set
+CONFIG_NFSD=y
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_HFS_FS=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+CONFIG_MOUSE=y
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
-#SUN_FB_CREATOR is not set
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
# Filesystems
#
CONFIG_QUOTA=y
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
-CONFIG_UMSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
-/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
+/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
- if (getname (sunos_mount->hostname, &the_name))
- return -EFAULT;
+ the_name = getname(sunos_mount->hostname);
+ if(IS_ERR(the_name))
+ return PTR_ERR(the_name);
strncpy (linux_nfs_mount.hostname, the_name, 254);
linux_nfs_mount.hostname [255] = 0;
-/* $Id: srmmu.c,v 1.148 1997/06/24 15:48:02 jj Exp $
+/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
{
if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
struct vm_area_struct *vmaring;
- struct inode *inode;
+ struct dentry *dentry;
+ struct inode *inode = NULL;
unsigned long flags, offset, vaddr, start;
int alias_found = 0;
pgd_t *pgdp;
save_and_cli(flags);
- inode = vma->vm_inode;
+ dentry = vma->vm_dentry;
+ if(dentry)
+ inode = dentry->d_inode;
if (!inode)
goto done;
offset = (address & PAGE_MASK) - vma->vm_start;
-/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
+/* $Id: sun4c.c,v 1.149 1997/07/20 05:59:38 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
- struct inode *inode;
+ struct dentry *dentry;
+ struct inode *inode = NULL;
pgd_t *pgdp;
pte_t *ptep;
- inode = vma->vm_inode;
+ dentry = vma->vm_dentry;
+ if(dentry)
+ inode = dentry->d_inode;
if(inode) {
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
struct vm_area_struct *vmaring = inode->i_mmap;
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
-# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
+# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+ifdef SMP
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
.S.s:
$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+endif
+
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
unaligned.o sys_sunos32.o sunos_ioctl32.o
OX_OBJS := sparc64_ksyms.o
+ifdef SMP
+O_OBJS += smp.o trampoline.o
+endif
+
ifdef CONFIG_SPARC32_COMPAT
O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
endif
head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
winfixup.S entry.S
- $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
#
# This is just to get the dependencies...
*/
#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <linux/init.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <asm/asi.h>
#include <asm/system.h>
#include <asm/fpumacro.h>
long ver, fpu_vers;
long fprs;
-#ifndef __SMP__
- cpuid = 0;
-#else
-#error SMP not supported on sparc64 yet
- /* cpuid = get_cpuid(); */
-#endif
+ cpuid = smp_processor_id();
fprs = fprs_read ();
fprs_write (FPRS_FEF);
#include <asm/system.h>
#include <asm/smp.h>
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
-/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
+/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
* flushing very quickly.
*/
.align 32
- .globl do_ivec
+ .globl do_ivec, do_ivec_return
do_ivec:
ldxa [%g0] ASI_INTR_RECEIVE, %g1
andcc %g1, 0x20, %g0
-/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
+/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#include <asm/kbio.h>
#include <asm/vuid_event.h>
#include <asm/rtc.h>
+#include <asm/openpromio.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
case RTCGET:
case RTCSET:
+ /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+ * embedded pointers in the arg which we'd need to clean up...
+ */
+ case OPROMGETOPT:
+ case OPROMSETOPT:
+ case OPROMNXTOPT:
+ case OPROMSETOPT2:
+ case OPROMNEXT:
+ case OPROMCHILD:
+ case OPROMGETPROP:
+ case OPROMNXTPROP:
+ case OPROMU2P:
+ case OPROMGETCONS:
+ case OPROMGETFBNAME:
+ case OPROMGETBOOTARGS:
+
/* Socket level stuff */
case FIOSETOWN:
case SIOCSPGRP:
-/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
+/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
- if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+ if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
return;
release_region(vaddr, plen);
-/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
+/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
+#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
}
/* INO number to Sparc PIL level. */
-static unsigned char ino_to_pil[] = {
+unsigned char ino_to_pil[] = {
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
#else
-#error SMP not supported on sparc64 just yet
+
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+static inline void wait_on_irq(int cpu)
+{
+ int local_count = local_irq_count[cpu];
+
+ while(local_count != atomic_read(&global_irq_count)) {
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+ for(;;) {
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (!spin_trylock(&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ do {
+ barrier();
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ wait_on_irq(cpu);
+ global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+
+ __cli();
+ get_irqlock(cpu);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ if (flags & 1) {
+ __global_cli();
+ } else {
+ if (global_irq_holder == (unsigned char) smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if (!(flags & 2))
+ __sti();
+ }
+}
+
+void irq_enter(int cpu, int irq)
+{
+ hardirq_enter(cpu);
+ barrier();
+ while (*((unsigned char *)&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ printk("irq_enter: Frosted Lucky Charms, "
+ "they're magically delicious!\n");
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+void synchronize_irq(void)
+{
+ int cpu = smp_processor_id();
+ int local_count = local_irq_count[cpu];
+ unsigned long flags;
+
+ if (local_count != atomic_read(&global_irq_count)) {
+ save_and_cli(flags);
+ restore_flags(flags);
+ }
+}
+
#endif /* __SMP__ */
void report_spurious_ivec(struct pt_regs *regs)
struct irqaction *action;
int cpu = smp_processor_id();
- /* XXX */
- if(irq != 14)
- clear_softint(1 << irq);
+ clear_softint(1 << irq);
irq_enter(cpu, irq);
action = *(irq + irq_action);
return 0;
}
-/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
- * XXX with mixed MHZ Ultras in the machine. -DaveM
- */
-static unsigned long cpu_cfreq;
-static unsigned long tick_offset;
+struct sun5_timer *linux_timers = NULL;
-/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
-static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+/* This is called from sbus_init() to get the jiffies timer going.
+ * We need to call this after there exists a valid SBus_chain so
+ * that the IMAP/ICLR registers can be accessed.
+ *
+ * XXX That is because the whole startup sequence is broken. I will
+ * XXX fix it all up very soon. -DaveM
+ */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
- if (!(get_softint () & 1)) {
- /* Just to be sure... */
- clear_softint(1 << 14);
- printk("Spurious level14 at %016lx\n", regs->tpc);
- return;
- } else {
- unsigned long compare, tick;
-
- do {
- extern void timer_interrupt(int, void *, struct pt_regs *);
-
- timer_interrupt(irq, dev_id, regs);
-
- /* Acknowledge INT_TIMER */
- clear_softint(1 << 0);
+ struct linux_prom64_registers pregs[3];
+ u32 pirqs[2];
+ int node, err;
- /* Set up for next timer tick. */
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "add %0, %2, %0\n\t"
- "wr %0, 0x0, %%tick_cmpr\n\t"
- "rd %%tick, %1"
- : "=&r" (compare), "=r" (tick)
- : "r" (tick_offset));
- } while(tick >= compare);
+ node = prom_finddevice("/counter-timer");
+ if(node == 0) {
+ prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
+ prom_halt();
}
-}
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
+ prom_halt();
+ }
+ err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'interrupts' "
+ "for counter-timer.\n");
+ prom_halt();
+ }
+ linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
-/* This is called from time_init() to get the jiffies timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
-{
- int node, err;
+ /* Shut it up first. */
+ linux_timers->limit0 = 0;
+
+ /* Register IRQ handler. */
+ err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
+ cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
- /* XXX FIX this for SMP -JJ */
- node = linux_cpus [0].prom_node;
- cpu_cfreq = prom_getint(node, "clock-frequency");
- tick_offset = cpu_cfreq / HZ;
- err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
- "timer", NULL);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
prom_halt();
save_and_cli(flags);
- __asm__ __volatile__("wr %0, 0x0, %%tick_cmpr\n\t"
- "wrpr %%g0, 0x0, %%tick"
- : /* No outputs */
- : "r" (tick_offset));
-
- clear_softint (get_softint ());
+ /* Set things up so user can access tick register for profiling
+ * purposes.
+ */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
+
+ linux_timers->limit0 =
+ (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
+ (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
restore_flags(flags);
}
+
sti();
}
-/* We use this nowhere else, so only define it's layout here. */
-struct sun5_timer {
- volatile u32 count0, _unused0;
- volatile u32 limit0, _unused1;
- volatile u32 count1, _unused2;
- volatile u32 limit1, _unused3;
-} *prom_timers;
+struct sun5_timer *prom_timers;
-static u32 prom_limit0, prom_limit1;
+static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
-/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
+/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
return -EPERM;
/* endless idle loop with no priority at all */
+ current->priority = -100;
current->counter = -100;
- for (;;)
+ for (;;) {
+ run_task_queue(&tq_scheduler);
schedule();
+ }
return 0;
}
/*
* the idle loop on a UltraMultiPenguin...
*/
-asmlinkage int sys_idle(void)
+asmlinkage int cpu_idle(void)
{
- if (current->pid != 0)
- return -EPERM;
-
- /* endless idle loop with no priority at all */
- current->counter = -100;
- schedule();
- return 0;
+ current->priority = -100;
+ while(1) {
+ if(tq_scheduler) {
+ lock_kernel();
+ run_task_queue(&tq_scheduler);
+ unlock_kernel();
+ }
+ current->counter = -100;
+ schedule();
+ }
}
-/* This is being executed in task 0 'user space'. */
-int cpu_idle(void *unused)
+asmlinkage int sys_idle(void)
{
- volatile int *spap = &smp_process_available;
- volatile int cval;
+ if(current->pid != 0)
+ return -EPERM;
- while(1) {
- if(0==*spap)
- continue;
- cli();
- /* Acquire exclusive access. */
- while((cval = smp_swap(spap, -1)) == -1)
- while(*spap == -1)
- ;
- if (0==cval) {
- /* ho hum, release it. */
- *spap = 0;
- sti();
- continue;
- }
- /* Something interesting happened, whee... */
- *spap = (cval - 1);
- sti();
- idle();
- }
+ cpu_idle();
+ return 0;
}
#endif
* allocate the task_struct and kernel stack in
* do_fork().
*/
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
extern void ret_from_syscall(void);
+#endif
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
child_trap_frame = ((char *)p) + stack_offset;
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+#ifdef __SMP__
+ p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+#else
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = regs->u_regs[UREG_G0];
if(regs->tstate & TSTATE_PRIV) {
p->tss.ctx = 0;
p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
+ if(current->tss.flags & SPARC_FLAG_32BIT) {
+ sp &= 0x00000000ffffffff;
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+ }
p->tss.kregs->u_regs[UREG_FP] = sp;
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
-/* $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
+/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
int get_cpuinfo(char *buffer)
{
-#ifndef __SMP__
- int cpuid=0;
-#else
-#error SMP not supported on sparc64 yet
-#endif
+ int cpuid=smp_processor_id();
return sprintf(buffer, "cpu\t\t: %s\n"
"fpu\t\t: %s\n"
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS];
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
void smp_commence(void)
{
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_commenced = 1;
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
}
static void smp_setup_percpu_timer(void);
{
int cpuid = hard_smp_processor_id();
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_setup_percpu_timer();
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
- "flush %g6" : : : "memory");
+ "flush %%g6" : : : "memory");
while(!task[cpuid])
barrier();
return cpu_idle(NULL);
}
+void cpu_panic(void)
+{
+ printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+ panic("SMP bolixed\n");
+}
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern unsigned long sparc64_cpu_startup;
void smp_boot_cpus(void)
{
- int cpucount = 0, i, first, prev;
+ int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
__sti();
continue;
if(cpu_present_map & (1 << i)) {
- extern unsigned long sparc64_cpu_startup;
- unsigned long entry = (unsigned long)&sparc_cpu_startup;
struct task_struct *p;
int timeout;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
- prom_startcpu(linux_cpus[i].prom_node, entry, i);
+ prom_startcpu(linux_cpus[i].prom_node,
+ ((unsigned long)&sparc64_cpu_startup),
+ ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
if(cpu_callin_map[i])
break;
barrier();
}
-/* XXX Make it fast later. */
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+{
+ u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+
+ __asm__ __volatile__("
+ wrpr %0, %1, %%pstate
+ wr %%g0, %2, %%asi
+ stxa %3, [0x40] %%asi
+ stxa %4, [0x50] %%asi
+ stxa %5, [0x60] %%asi
+ stxa %%g0, [%6] %%asi
+ membar #Sync"
+ : /* No outputs */
+ : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+ "r" (data0), "r" (data1), "r" (data2), "r" (target));
+
+ /* NOTE: PSTATE_IE is still clear. */
+ do {
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (result)
+ : "i" (ASI_INTR_DISPATCH_STAT));
+ } while(result & 0x1);
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ if(result & 0x2)
+ panic("Penguin NACK's master!");
+}
+
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask;
- u64 data0 = (((unsigned long)ctx)<<32 |
- (((unsigned long)func) & 0xffffffff));
- u64 pstate;
+ unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- mask = (cpu_present_map & ~(1 << smp_processor_id()));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i)) {
- u64 target = mid<<14 | 0x70;
- u64 result;
-
- __asm__ __volatile__("
- wrpr %0, %1, %%pstate
- wrpr %%g0, %2, %%asi
- stxa %3, [0x40] %%asi
- stxa %4, [0x50] %%asi
- stxa %5, [0x60] %%asi
- stxa %%g0, [%6] %7
- membar #Sync"
- : /* No outputs */
- : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
- "r" (data0), "r" (data1), "r" (data2),
- "r" (target), "i" (ASI_UDB_INTR_W));
-
- /* NOTE: PSTATE_IE is still clear. */
- do {
- __asm__ __volatile__("ldxa [%%g0] %1, %0",
- : "=r" (result)
- : "i" (ASI_INTR_DISPATCH_STAT));
- } while(result & 0x1);
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
- }
+ if(mask & (1 << i))
+ xcall_deliver(data0, data1, data2, pstate, i);
}
-
/* NOTE: Caller runs local copy on master. */
}
}
void smp_flush_cache_all(void)
{
smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+ __flush_cache_all();
}
void smp_flush_tlb_all(void)
{
smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+ __flush_tlb_all();
}
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
__flush_tlb_mm(ctx);
}
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
__flush_tlb_range(ctx, start, end);
}
struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
__flush_tlb_page(ctx, page);
}
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
int cpu = smp_processor_id();
+ int user = user_mode(regs);
- clear_profile_irq(cpu);
- if(!user_mode(regs))
- sparc_do_profile(regs->pc);
+ /* XXX clear_profile_irq(cpu); */
+ if(!user)
+ sparc64_do_profile(regs->tpc);
if(!--prof_counter[cpu]) {
- int user = user_mode(regs);
if(current->pid) {
update_one_process(current, 1, user, !user);
if(--current->counter < 0) {
int setup_profiling_timer(unsigned int multiplier)
{
/* XXX implement me */
+ return 0;
}
-/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
+/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
#include <asm/oplib.h>
#include <asm/mostek.h>
+#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
* NOTE: On SUN5 systems the ticker interrupt comes in using 2
* interrupts, one at level14 and one with softint bit 0.
*/
-void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+extern struct sun5_timer *linux_timers;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
/* last time the cmos clock got updated */
static long last_rtc_update=0;
+ __asm__ __volatile__("ldx [%0], %%g0"
+ : /* no outputs */
+ : "r" (&((linux_timers)->limit0)));
+
do_timer(regs);
/* Determine when to update the Mostek clock. */
__initfunc(void time_init(void))
{
- extern void init_timers(void (*func)(int, void *, struct pt_regs *));
unsigned int year, mon, day, hour, min, sec;
struct mostek48t02 *mregs;
do_get_fast_time = do_gettimeofday;
clock_probe();
- init_timers(timer_interrupt);
mregs = mstk48t02_regs;
if(!mregs) {
mregs->creg &= ~MSTK_CREG_READ;
}
+extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+
+__initfunc(void sun4u_start_timers(void))
+{
+ init_timers(timer_interrupt);
+}
+
static __inline__ unsigned long do_gettimeoffset(void)
{
unsigned long offset = 0;
void do_gettimeofday(struct timeval *tv)
{
- unsigned long flags;
-
- save_and_cli(flags);
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if(tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
+ /* Load doubles must be used on xtime so that what we get
+ * is guarenteed to be atomic, this is why we can run this
+ * with interrupts on full blast. Don't touch this... -DaveM
+ */
+ __asm__ __volatile__("
+ sethi %hi(linux_timers), %o1
+ sethi %hi(xtime), %g2
+ ldx [%o1 + %lo(linux_timers)], %g3
+1: ldd [%g2 + %lo(xtime)], %o4
+ ldx [%g3], %o1
+ ldd [%g2 + %lo(xtime)], %o2
+ xor %o4, %o2, %o2
+ xor %o5, %o3, %o3
+ orcc %o2, %o3, %g0
+ bne,pn %icc, 1b
+ cmp %o1, 0
+ bge,pt %icc, 1f
+ sethi %hi(tick), %o3
+ ld [%o3 + %lo(tick)], %o3
+ sethi %hi(0x1fffff), %o2
+ or %o2, %lo(0x1fffff), %o2
+ add %o5, %o3, %o5
+ and %o1, %o2, %o1
+1: add %o5, %o1, %o5
+ sethi %hi(1000000), %o2
+ or %o2, %lo(1000000), %o2
+ cmp %o5, %o2
+ bl,a,pn %icc, 1f
+ st %o4, [%o0 + 0x0]
+ add %o4, 0x1, %o4
+ sub %o5, %o2, %o5
+ st %o4, [%o0 + 0x0]
+1: st %o5, [%o0 + 0x4]");
}
void do_settimeofday(struct timeval *tv)
--- /dev/null
+/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+ * trampoline.S: Jump start slave processors on sparc64.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/lsu.h>
+#include <asm/pstate.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/spitfire.h>
+#include <asm/asm_offsets.h>
+
+ .text
+ .globl sparc64_cpu_startup
+sparc64_cpu_startup:
+ flushw
+ mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+ wrpr %g0, 15, %pil
+
+ mov %o0, %g6
+
+ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
+ sllx %g5, 32, %g5
+ or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5
+
+ sethi %uhi(_PAGE_PADDR), %g3
+ or %g3, %ulo(_PAGE_PADDR), %g3
+ sllx %g3, 32, %g3
+ sethi %hi(_PAGE_PADDR), %g7
+ or %g7, %lo(_PAGE_PADDR), %g7
+ or %g3, %g7, %g7
+
+ /* Find TLB entry we are executing out of. */
+ clr %l0
+ set 0x1fff, %l2
+ rd %pc, %l3
+ andn %l3, %l2, %g2
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g2
+ be,a,pn %xcc, 2f
+ ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1
+ cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+2: nop
+ nop
+ nop
+ and %g1, %g3, %g1
+ sub %g1, %g2, %g1
+ or %g5, %g1, %g5
+ clr %l0
+ sethi %hi(KERNBASE), %g3
+ sethi %hi(KERNBASE<<1), %g7
+ mov TLB_TAG_ACCESS, %l7
+1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_IMMU
+ stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ clr %l0
+1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1
+ nop
+ nop
+ nop
+ andn %g1, %l2, %g1
+ cmp %g1, %g3
+ blu,pn %xcc, 2f
+ cmp %g1, %g7
+ bgeu,pn %xcc, 2f
+ nop
+ stxa %g0, [%l7] ASI_DMMU
+ stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS
+2: cmp %l0, (63 << 3)
+ blu,pt %xcc, 1b
+ add %l0, (1 << 3), %l0
+
+ nop
+ nop
+ nop
+ sethi %hi(KERNBASE), %g3
+ mov (63 << 3), %g7
+ stxa %g3, [%l7] ASI_DMMU
+ stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+ stxa %g3, [%l7] ASI_IMMU
+ stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+ flush %g6
+ membar #Sync
+ b,pt %xcc, 1f
+ nop
+1: set bounce, %g2
+ jmpl %g2 + %g0, %g0
+ nop
+
+bounce:
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ sethi %uhi(PAGE_OFFSET), %g4
+ sllx %g4, 32, %g4
+
+ mov TLB_TAG_ACCESS, %g2
+ stxa %g3, [%g2] ASI_IMMU
+ stxa %g3, [%g2] ASI_DMMU
+
+ mov (63 << 3), %g7
+ ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS
+ membar #Sync
+
+ ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1
+ andn %g1, (_PAGE_G), %g1
+ stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS
+ membar #Sync
+
+ flush %g6
+ membar #Sync
+
+ mov 1, %g5
+ sllx %g5, (PAGE_SHIFT + 1), %g5
+ sub %g5, (REGWIN_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
+ mov 0, %fp
+
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0, %tl
+
+ /* Setup the trap globals, then we can resurface. */
+ rdpr %pstate, %o1
+ mov %g6, %o2
+ wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate
+ sethi %hi(sparc64_ttable_tl0), %g5
+ wrpr %g5, %tba
+ mov %o2, %g6
+
+ wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate
+ sethi %hi(0x1ff8), %g2
+ or %g2, %lo(0x1ff8), %g2
+ ldx [%o2 + AOFF_task_mm], %g6
+ ldx [%g6 + AOFF_mm_pgd], %g6
+ clr %g7
+
+ wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate
+ sethi %hi(ivector_to_mask), %g5
+ or %g5, %lo(ivector_to_mask), %g1
+ mov 0x40, %g2
+
+ wrpr %g0, 0, %wstate
+ wrpr %o1, PSTATE_IE, %pstate
+
+ mov TSB_REG, %o4
+ mov 1, %o5
+ stxa %o5, [%o4] ASI_DMMU
+ stxa %o5, [%o4] ASI_IMMU
+ membar #Sync
+
+ wrpr %g0, 0, %pil
+ or %o1, PSTATE_IE, %o1
+ wrpr %o1, 0, %pstate
+
+ call smp_callin
+ nop
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
+ nop
+1: b,a,pt %xcc, 1b
-/* $Id: locks.S,v 1.2 1997/03/10 12:28:02 jj Exp $
+/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
* locks.S: SMP low-level lock primitives on Sparc64.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <asm/asm_offsets.h>
#include <asm/ptrace.h>
+#include <asm/smp.h>
.text
- .align 4
-
- .globl __spinlock_waitfor
-__spinlock_waitfor:
-1: orcc %g2, 0x0, %g0
- bne 1b
- ldub [%g1], %g2
- ldstub [%g1], %g2
- jmpl %o7 - 12, %g0
- mov %g5, %o7
-
- .globl ___become_idt
-___become_idt:
-#if 0 /* Don't know how to do this on the Ultra yet... */
-#endif
- jmpl %o7 + 8, %g0
- mov %g5, %o7
+ .align 32
___lk_busy_spin:
- orcc %g2, 0, %g0
- bne ___lk_busy_spin
- ldub [%g1 + 0], %g2
- b 1f
- ldstub [%g1 + 0], %g2
+ orcc %g2, 0, %g0
+ bne,pt %icc, ___lk_busy_spin
+ ldub [%g1 + 0], %g2
+ b,pt %xcc, 1f
+ ldstub [%g1 + 0], %g2
- .globl ___lock_kernel
+ .globl ___lock_kernel
___lock_kernel:
- addcc %g2, -1, %g2
- rdpr %pil, %g3
- bcs,a 9f
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr 15, %pil
- ldstub [%g1 + 0], %g2
-1: orcc %g2, 0, %g0
- bne,a ___lk_busy_spin
- ldub [%g1 + 0], %g2
- ldub [%g1 + 2], %g2
- cmp %g2, %g5
- be 2f
- stb %g5, [%g1 + 1]
- stb %g5, [%g1 + 2]
-#ifdef __SMP__
- /* XXX Figure out how to become interrupt receiver in SMP system. */
-#endif
-2: mov -1, %g2
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, %pil
-9: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
+ addcc %g2, -1, %g2
+ rdpr %pil, %g3
+ bcs,a,pn %icc, 9f
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr %g0, 15, %pil
+ ldstub [%g1 + 0], %g2
+1: brnz,a,pn %g2, ___lk_busy_spin
+ ldub [%g1 + 0], %g2
+ lduw [%g6 + AOFF_task_processor], %g2
+ membar #LoadLoad | #LoadStore
+ stb %g2, [%g1 + 1]
+2: mov -1, %g2
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr %g3, 0, %pil
+9: jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
+
+ .globl ___lock_reacquire_kernel
+___lock_reacquire_kernel:
+ rdpr %pil, %g3
+ wrpr %g0, 15, %pil
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ ldstub [%g1 + 0], %g2
+1: brz,pt %g2, 3f
+ ldub [%g1 + 0], %g2
+2: brnz,a,pt %g2, 2b
+ ldub [%g1 + 0], %g2
+ b,pt %xcc, 1b
+ ldstub [%g1 + 0], %g2
+3: lduw [%g6 + AOFF_task_processor], %g2
+ membar #LoadLoad | #LoadStore
+ stb %g2, [%g1 + 1]
+ wrpr %g3, 0, %pil
+ jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
#undef NO_PROC_ID
#define NO_PROC_ID 0xff
- .globl ___unlock_kernel
+ .globl ___unlock_kernel
___unlock_kernel:
- addcc %g2, 1, %g2
- rdpr %pil, %g3
- bne,a 1f
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr 15, %pil
- mov NO_PROC_ID, %g2
- stb %g2, [%g1 + 1]
- stb %g0, [%g1 + 0]
- st %g0, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, %pil
-1: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
+ addcc %g2, 1, %g2
+ rdpr %pil, %g3
+ bne,a,pn %icc, 1f
+ stw %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr 15, %pil
+ mov NO_PROC_ID, %g2
+ stb %g2, [%g1 + 1]
+ membar #StoreStore | #LoadStore
+ stb %g0, [%g1 + 0]
+ stw %g0, [%g6 + AOFF_task_lock_depth]
+ wrpr %g3, 0, %pil
+1: jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
-# $Id: Makefile,v 1.3 1997/06/27 14:53:38 jj Exp $
+# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $
# Makefile for the linux Sparc64-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
#
# Note 2! The CFLAGS definition is now in the main makefile...
+ifdef SMP
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
.S.s:
$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+endif
+
O_TARGET := mm.o
O_OBJS := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
-/* $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $
+/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
membar("#Sync");
}
+void __flush_cache_all(void)
+{
+ unsigned long va;
+
+ flushw_all();
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32)
+ spitfire_put_icache_tag(va, 0x0);
+}
+
/* If not locked, zap it. */
-void flush_tlb_all(void)
+void __flush_tlb_all(void)
{
unsigned long flags;
int i;
-/* $Id: ultra.S,v 1.8 1997/07/15 05:35:50 davem Exp $
+/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
#include <asm/asi.h>
+#include <asm/pgtable.h>
#include <asm/spitfire.h>
/* All callers check mm->context != NO_CONTEXT for us. */
-/* $Id: console.c,v 1.6 1997/03/18 17:59:59 jj Exp $
+/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
if(strncmp("serial", propb, sizeof("serial")))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
-/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $
+/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
}
#ifdef __SMP__
-void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0)
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
{
p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
}
-/* $Id: p1275.c,v 1.10 1997/06/27 04:18:30 davem Exp $
+/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <linux/string.h>
#include <asm/openprom.h>
static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int acsi_open( struct inode * inode, struct file * filp );
-static void acsi_release( struct inode * inode, struct file * file );
+static int acsi_release( struct inode * inode, struct file * file );
static void acsi_prevent_removal( int target, int flag );
static int acsi_change_blk_size( int target, int lun);
static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
* be forgotten about...
*/
-static void acsi_release( struct inode * inode, struct file * file )
+static int acsi_release( struct inode * inode, struct file * file )
{
int device;
if (--access_count[device] == 0 && acsi_info[device].removable)
acsi_prevent_removal(device, 0);
MOD_DEC_USE_COUNT;
+ return( 0 );
}
/*
{
del_timer( &acsi_timer );
blk_dev[MAJOR_NR].request_fn = 0;
- free_pages( acsi_buffer, ACSI_BUFFER_ORDER );
+ free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER );
if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
printk( KERN_ERR "acsi: cleanup_module failed\n");
static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 };
static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 };
static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 };
+#if 0
static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 };
+#endif
#define MAX_SLM 2
static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int slm_open( struct inode *inode, struct file *file );
-static void slm_release( struct inode *inode, struct file *file );
+static int slm_release( struct inode *inode, struct file *file );
static int slm_req_sense( int device );
static int slm_mode_sense( int device, char *buffer, int abs_flag );
+#if 0
static int slm_mode_select( int device, char *buffer, int len, int
default_flag );
+#endif
static int slm_get_pagesize( int device, int *w, int *h );
/************************* End of Prototypes **************************/
}
-static void slm_release( struct inode *inode, struct file *file )
+static int slm_release( struct inode *inode, struct file *file )
{ int device;
struct slm *sip;
sip->wbusy = 0;
if (file->f_mode & 1)
sip->rbusy = 0;
+
+ return( 0 );
}
}
+#if 0
+/* currently unused */
static int slm_mode_select( int device, char *buffer, int len,
int default_flag )
stdma_release();
return( rv );
}
+#endif
static int slm_get_pagesize( int device, int *w, int *h )
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
endmenu
L_OBJS += rtc.o
endif
+ifeq ($(CONFIG_NVRAM),y)
+M = y
+L_OBJS += nvram.o
+else
+ ifeq ($(CONFIG_NVRAM),m)
+ MM = m
+ M_OBJS += nvram.o
+ endif
+endif
+
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
else
if (remap_page_range(vma->vm_start, vma->vm_offset,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+ vma->vm_dentry = dget(file->f_dentry);
return 0;
}
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
#include <linux/kbd_ll.h>
+#include <linux/sysrq.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
struct pt_regs * kbd_pt_regs;
#ifdef CONFIG_MAGIC_SYSRQ
-#define SYSRQ_KEY 0x54
-extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
static int sysrq_pressed;
#endif
return;
} else if (sysrq_pressed) {
if (!up_flag)
- handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+ handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
return;
}
#endif
*/
if (x86 > 3 && offset >= __pa(high_memory))
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+#ifdef __powerpc__
+ if (offset >= __pa(high_memory))
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
#endif
if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
extern void pcwatchdog_init(void);
extern int rtc_init(void);
extern int dsp56k_init(void);
+extern int nvram_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
+#ifdef CONFIG_NVRAM
+ nvram_init();
+#endif
#endif /* !MODULE */
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
--- /dev/null
+/*
+ * CMOS/NV-RAM driver for Linux
+ *
+ * Copyright (C) 1997 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ * idea by and with help from Richard Jelinek <rj@suse.de>
+ *
+ * This driver allows you to access the contents of the non-volatile memory in
+ * the mc146818rtc.h real-time clock. This chip is built into all PCs and into
+ * many Atari machines. In the former it's called "CMOS-RAM", in the latter
+ * "NVRAM" (NV stands for non-volatile).
+ *
+ * The data are supplied as a (seekable) character device, /dev/nvram. The
+ * size of this file is 50, the number of freely available bytes in the memory
+ * (i.e., not used by the RTC itself).
+ *
+ * Checksums over the NVRAM contents are managed by this driver. In case of a
+ * bad checksum, reads and writes return -EIO. The checksum can be initialized
+ * to a sane state either by ioctl(NVRAM_INIT) (clear whole NVRAM) or
+ * ioctl(NVRAM_SETCKS) (doesn't change contents, just makes checksum valid
+ * again; use with care!)
+ *
+ * This file also provides some functions for other parts of the kernel that
+ * want to access the NVRAM: nvram_{read,write,check_checksum,set_checksum}.
+ * Obviously this can be used only if this driver is always configured into
+ * the kernel and is not a module. Since the functions are used by some Atari
+ * drivers, this is the case on the Atari.
+ *
+ */
+
+#define NVRAM_VERSION "1.0"
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#define PC 1
+#define ATARI 2
+
+/* select machine configuration */
+#if defined(CONFIG_ATARI)
+#define MACH ATARI
+#elif defined(__i386__) /* and others?? */
+#define MACH PC
+#else
+#error Cannot build nvram driver for this machine configuration.
+#endif
+
+#if MACH == PC
+
+/* RTC in a PC */
+#define CHECK_DRIVER_INIT() 1
+
+/* On PCs, the checksum is built only over bytes 2..31 */
+#define PC_CKS_RANGE_START 2
+#define PC_CKS_RANGE_END 31
+#define PC_CKS_LOC 32
+
+#define mach_check_checksum pc_check_checksum
+#define mach_set_checksum pc_set_checksum
+#define mach_proc_infos pc_proc_infos
+
+#endif
+
+#if MACH == ATARI
+
+/* Special parameters for RTC in Atari machines */
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#define RTC_PORT(x) (TT_RTC_BAS + 2*(x))
+#define CHECK_DRIVER_INIT() (MACH_IS_ATARI && ATARIHW_PRESENT(TT_CLK))
+
+/* On Ataris, the checksum is over all bytes except the checksum bytes
+ * themselves; these are at the very end */
+#define ATARI_CKS_RANGE_START 0
+#define ATARI_CKS_RANGE_END 47
+#define ATARI_CKS_LOC 48
+
+#define mach_check_checksum atari_check_checksum
+#define mach_set_checksum atari_set_checksum
+#define mach_proc_infos atari_proc_infos
+
+#endif
+
+/* Note that *all* calls to CMOS_READ and CMOS_WRITE must be done with
+ * interrupts disabled. Due to the index-port/data-port design of the RTC, we
+ * don't want two different things trying to get to it at once. (e.g. the
+ * periodic 11 min sync from time.c vs. this driver.)
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/mc146818rtc.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+
+static int nvram_open_cnt = 0; /* #times opened */
+static int nvram_open_mode; /* special open modes */
+#define NVRAM_WRITE 1 /* opened for writing (exclusive) */
+#define NVRAM_EXCL 2 /* opened with O_EXCL */
+
+#define RTC_FIRST_BYTE 14 /* RTC register number of first NVRAM byte */
+#define NVRAM_BYTES 50 /* number of NVRAM bytes */
+
+
+static int mach_check_checksum( void );
+static void mach_set_checksum( void );
+#ifdef CONFIG_PROC_FS
+static int mach_proc_infos( unsigned char *contents, char *buffer, int *len,
+ off_t *begin, off_t offset, int size );
+#endif
+
+
+/*
+ * These are the internal NVRAM access functions, which do NOT disable
+ * interrupts and do not check the checksum. Both tasks are left to higher
+ * level function, so they need to be done only once per syscall.
+ */
+
+static __inline__ unsigned char nvram_read_int( int i )
+{
+ return( CMOS_READ( RTC_FIRST_BYTE+i ) );
+}
+
+static __inline__ void nvram_write_int( unsigned char c, int i )
+{
+ CMOS_WRITE( c, RTC_FIRST_BYTE+i );
+}
+
+static __inline__ int nvram_check_checksum_int( void )
+{
+ return( mach_check_checksum() );
+}
+
+static __inline__ void nvram_set_checksum_int( void )
+{
+ mach_set_checksum();
+}
+
+#if MACH == ATARI
+
+/*
+ * These non-internal functions are provided to be called by other parts of
+ * the kernel. It's up to the caller to ensure correct checksum before reading
+ * or after writing (needs to be done only once).
+ *
+ * They're only built if CONFIG_ATARI is defined, because Atari drivers use
+ * them. For other configurations (PC), the rest of the kernel can't rely on
+ * them being present (this driver couldn't be configured at all, or as a
+ * module), so they access config information themselves.
+ */
+
+unsigned char nvram_read_byte( int i )
+{
+ unsigned long flags;
+ unsigned char c;
+
+ save_flags(flags);
+ cli();
+ c = nvram_read_int( i );
+ restore_flags(flags);
+ return( c );
+}
+
+void nvram_write_byte( unsigned char c, int i )
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ nvram_write_int( c, i );
+ restore_flags(flags);
+}
+
+int nvram_check_checksum( void )
+{
+ unsigned long flags;
+ int rv;
+
+ save_flags(flags);
+ cli();
+ rv = nvram_check_checksum_int();
+ restore_flags(flags);
+ return( rv );
+}
+
+void nvram_set_checksum( void )
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ nvram_set_checksum_int();
+ restore_flags(flags);
+}
+
+#endif /* MACH == ATARI */
+
+
+/*
+ * The are the file operation function for user access to /dev/nvram
+ */
+
+static long long nvram_llseek( struct inode *inode, struct file *file,
+ loff_t offset, int origin )
+{
+ switch( origin ) {
+ case 0:
+ /* nothing to do */
+ break;
+ case 1:
+ offset += file->f_pos;
+ break;
+ case 2:
+ offset += NVRAM_BYTES;
+ break;
+ }
+ return( (offset >= 0) ? (file->f_pos = offset) : -EINVAL );
+}
+
+static long nvram_read( struct inode * inode, struct file * file,
+ char * buf, unsigned long count )
+{
+ unsigned long flags;
+ unsigned i = file->f_pos;
+ char *tmp = buf;
+
+ save_flags(flags);
+ cli();
+
+ if (!nvram_check_checksum_int()) {
+ restore_flags(flags);
+ return( -EIO );
+ }
+
+ for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp )
+ put_user( nvram_read_int(i), tmp );
+ file->f_pos = i;
+
+ restore_flags(flags);
+ return( tmp - buf );
+}
+
+static long nvram_write( struct inode * inode, struct file * file,
+ const char * buf, unsigned long count )
+{
+ unsigned long flags;
+ unsigned i = file->f_pos;
+ const char *tmp = buf;
+ char c;
+
+ save_flags(flags);
+ cli();
+
+ if (!nvram_check_checksum_int()) {
+ restore_flags(flags);
+ return( -EIO );
+ }
+
+ for( ; count-- > 0 && i < NVRAM_BYTES; ++i, ++tmp ) {
+ get_user( c, tmp );
+ nvram_write_int( c, i );
+ }
+ nvram_set_checksum_int();
+ file->f_pos = i;
+
+ restore_flags(flags);
+ return( tmp - buf );
+}
+
+static int nvram_ioctl( struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg )
+{
+ unsigned long flags;
+ int i;
+
+ switch( cmd ) {
+
+ case NVRAM_INIT: /* initialize NVRAM contents and checksum */
+ if (!suser())
+ return( -EACCES );
+
+ save_flags(flags);
+ cli();
+
+ for( i = 0; i < NVRAM_BYTES; ++i )
+ nvram_write_int( 0, i );
+ nvram_set_checksum_int();
+
+ restore_flags(flags);
+ return( 0 );
+
+ case NVRAM_SETCKS: /* just set checksum, contents unchanged
+ * (maybe useful after checksum garbaged
+ * somehow...) */
+ if (!suser())
+ return( -EACCES );
+
+ save_flags(flags);
+ cli();
+ nvram_set_checksum_int();
+ restore_flags(flags);
+ return( 0 );
+
+ default:
+ return( -EINVAL );
+ }
+}
+
+static int nvram_open( struct inode *inode, struct file *file )
+{
+ if ((nvram_open_cnt && (file->f_flags & O_EXCL)) ||
+ (nvram_open_mode & NVRAM_EXCL) ||
+ ((file->f_mode & 2) && (nvram_open_mode & NVRAM_WRITE)))
+ return( -EBUSY );
+
+ if (file->f_flags & O_EXCL)
+ nvram_open_mode |= NVRAM_EXCL;
+ if (file->f_mode & 2)
+ nvram_open_mode |= NVRAM_WRITE;
+ nvram_open_cnt++;
+ MOD_INC_USE_COUNT;
+ return( 0 );
+}
+
+static int nvram_release( struct inode *inode, struct file *file )
+{
+ nvram_open_cnt--;
+ if (file->f_flags & O_EXCL)
+ nvram_open_mode &= ~NVRAM_EXCL;
+ if (file->f_mode & 2)
+ nvram_open_mode &= ~NVRAM_WRITE;
+
+ MOD_DEC_USE_COUNT;
+ return( 0 );
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+struct proc_dir_entry *proc_nvram;
+
+static int nvram_read_proc( char *buffer, char **start, off_t offset,
+ int size, int *eof, void *data )
+{
+ unsigned long flags;
+ unsigned char contents[NVRAM_BYTES];
+ int i, len = 0;
+ off_t begin = 0;
+
+ save_flags(flags);
+ cli();
+ for( i = 0; i < NVRAM_BYTES; ++i )
+ contents[i] = nvram_read_int( i );
+ restore_flags(flags);
+
+ *eof = mach_proc_infos( contents, buffer, &len, &begin, offset, size );
+
+ if (offset >= begin + len)
+ return( 0 );
+ *start = buffer + (begin - offset);
+ return( size < begin + len - offset ? size : begin + len - offset );
+
+}
+
+/* This macro frees the machine specific function from bounds checking and
+ * this like that... */
+#define PRINT_PROC(fmt,args...) \
+ do { \
+ *len += sprintf( buffer+*len, fmt, ##args ); \
+ if (*begin + *len > offset + size) \
+ return( 0 ); \
+ if (*begin + *len < offset) { \
+ *begin += *len; \
+ *len = 0; \
+ } \
+ } while(0)
+
+#endif
+
+static struct file_operations nvram_fops = {
+ nvram_llseek,
+ nvram_read,
+ nvram_write,
+ NULL, /* No readdir */
+ NULL, /* No poll */
+ nvram_ioctl,
+ NULL, /* No mmap */
+ nvram_open,
+ nvram_release
+};
+
+static struct miscdevice nvram_dev = {
+ NVRAM_MINOR,
+ "nvram",
+ &nvram_fops
+};
+
+
+__initfunc(int nvram_init(void))
+{
+ /* First test whether the driver should init at all */
+ if (!CHECK_DRIVER_INIT())
+ return( -ENXIO );
+
+ printk( "Non-volatile memory driver v%s\n", NVRAM_VERSION );
+ misc_register( &nvram_dev );
+#ifdef CONFIG_PROC_FS
+ if ((proc_nvram = create_proc_entry( "nvram", 0, 0 )))
+ proc_nvram->read_proc = nvram_read_proc;
+#endif
+
+ return( 0 );
+}
+
+#ifdef MODULE
+int init_module (void)
+{
+ return( nvram_init() );
+}
+
+void cleanup_module (void)
+{
+#ifdef CONFIG_PROC_FS
+ if (proc_nvram)
+ remove_proc_entry( "nvram", 0 );
+#endif
+ misc_deregister( &nvram_dev );
+}
+#endif
+
+
+/*
+ * Machine specific functions
+ */
+
+
+#if MACH == PC
+
+static int pc_check_checksum( void )
+{
+ int i;
+ unsigned short sum = 0;
+
+ for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+ sum += nvram_read_int( i );
+ return( (sum & 0xffff) ==
+ ((nvram_read_int(PC_CKS_LOC) << 8) |
+ nvram_read_int(PC_CKS_LOC+1)) );
+}
+
+static void pc_set_checksum( void )
+{
+ int i;
+ unsigned short sum = 0;
+
+ for( i = PC_CKS_RANGE_START; i <= PC_CKS_RANGE_END; ++i )
+ sum += nvram_read_int( i );
+ nvram_write_int( sum >> 8, PC_CKS_LOC );
+ nvram_write_int( sum & 0xff, PC_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static char *floppy_types[] = {
+ "none", "5.25'' 360k", "5.25'' 1.2M", "3.5'' 720k", "3.5'' 1.44M"
+};
+
+static char *gfx_types[] = {
+ "EGA, VGA, ... (with BIOS)",
+ "CGA (40 cols)",
+ "CGA (80 cols)",
+ "monochrome",
+};
+
+static int pc_proc_infos( unsigned char *nvram, char *buffer, int *len,
+ off_t *begin, off_t offset, int size )
+{
+ unsigned long flags;
+ int checksum;
+ int type;
+
+ save_flags(flags);
+ cli();
+ checksum = nvram_check_checksum_int();
+ restore_flags(flags);
+
+ PRINT_PROC( "Checksum status: %svalid\n", checksum ? "" : "not " );
+
+ PRINT_PROC( "# floppies : %d\n",
+ (nvram[6] & 1) ? (nvram[6] >> 6) + 1 : 0 );
+ PRINT_PROC( "Floppy 0 type : " );
+ type = nvram[2] >> 4;
+ if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+ PRINT_PROC( "%s\n", floppy_types[type] );
+ else
+ PRINT_PROC( "%d (unknown)\n", type );
+ PRINT_PROC( "Floppy 1 type : " );
+ type = nvram[2] & 0x0f;
+ if (type < sizeof(floppy_types)/sizeof(*floppy_types))
+ PRINT_PROC( "%s\n", floppy_types[type] );
+ else
+ PRINT_PROC( "%d (unknown)\n", type );
+
+ PRINT_PROC( "HD 0 type : " );
+ type = nvram[4] >> 4;
+ if (type)
+ PRINT_PROC( " %02x\n", type == 0x0f ? nvram[11] : type );
+ else
+ PRINT_PROC( "none\n" );
+
+ PRINT_PROC( "HD 1 type : " );
+ type = nvram[4] & 0x0f;
+ if (type)
+ PRINT_PROC( " %02x\n", type == 0x0f ? nvram[12] : type );
+ else
+ PRINT_PROC( "none\n" );
+
+ PRINT_PROC( "HD type 48 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+ nvram[18] | (nvram[19] << 8),
+ nvram[20], nvram[25],
+ nvram[21] | (nvram[22] << 8),
+ nvram[23] | (nvram[24] << 8) );
+ PRINT_PROC( "HD type 49 data: %d/%d/%d C/H/S, precomp %d, lz %d\n",
+ nvram[39] | (nvram[40] << 8),
+ nvram[41], nvram[46],
+ nvram[42] | (nvram[43] << 8),
+ nvram[44] | (nvram[45] << 8) );
+
+ PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
+ PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
+ nvram[9] | (nvram[10] << 8),
+ nvram[34] | (nvram[35] << 8) );
+
+ PRINT_PROC( "Gfx adapter : %s\n", gfx_types[ (nvram[6] >> 4)&3 ] );
+
+ PRINT_PROC( "FPU : %sinstalled\n",
+ (nvram[6] & 2) ? "" : "not " );
+
+ return( 1 );
+}
+#endif
+
+#endif /* MACH == PC */
+
+#if MACH == ATARI
+
+static int atari_check_checksum( void )
+{
+ int i;
+ unsigned char sum = 0;
+
+ for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+ sum += nvram_read_int( i );
+ return( nvram_read_int( ATARI_CKS_LOC ) == (~sum & 0xff) &&
+ nvram_read_int( ATARI_CKS_LOC+1 ) == (sum & 0xff) );
+}
+
+static void atari_set_checksum( void )
+{
+ int i;
+ unsigned char sum = 0;
+
+ for( i = ATARI_CKS_RANGE_START; i <= ATARI_CKS_RANGE_END; ++i )
+ sum += nvram_read_int( i );
+ nvram_write_int( ~sum, ATARI_CKS_LOC );
+ nvram_write_int( sum, ATARI_CKS_LOC+1 );
+}
+
+#ifdef CONFIG_PROC_FS
+
+static struct {
+ unsigned char val;
+ char *name;
+} boot_prefs[] = {
+ { 0x80, "TOS" },
+ { 0x40, "ASV" },
+ { 0x20, "NetBSD (?)" },
+ { 0x10, "Linux" },
+ { 0x00, "unspecified" }
+};
+
+static char *languages[] = {
+ "English (US)",
+ "German",
+ "French",
+ "English (UK)",
+ "Spanish",
+ "Italian",
+ "6 (undefined)",
+ "Swiss (French)",
+ "Swiss (German)"
+};
+
+static char *dateformat[] = {
+ "MM%cDD%cYY",
+ "DD%cMM%cYY",
+ "YY%cMM%cDD",
+ "YY%cDD%cMM",
+ "4 (undefined)",
+ "5 (undefined)",
+ "6 (undefined)",
+ "7 (undefined)"
+};
+
+static char *colors[] = {
+ "2", "4", "16", "256", "65536", "??", "??", "??"
+};
+
+#define fieldsize(a) (sizeof(a)/sizeof(*a))
+
+static int atari_proc_infos( unsigned char *nvram, char *buffer, int *len,
+ off_t *begin, off_t offset, int size )
+{
+ int checksum = nvram_check_checksum();
+ int i;
+ unsigned vmode;
+
+ PRINT_PROC( "Checksum status : %svalid\n", checksum ? "" : "not " );
+
+ PRINT_PROC( "Boot preference : " );
+ for( i = fieldsize(boot_prefs)-1; i >= 0; --i ) {
+ if (nvram[1] == boot_prefs[i].val) {
+ PRINT_PROC( "%s\n", boot_prefs[i].name );
+ break;
+ }
+ }
+ if (i < 0)
+ PRINT_PROC( "0x%02x (undefined)\n", nvram[1] );
+
+ PRINT_PROC( "SCSI arbitration : %s\n", (nvram[16] & 0x80) ? "on" : "off" );
+ PRINT_PROC( "SCSI host ID : " );
+ if (nvram[16] & 0x80)
+ PRINT_PROC( "%d\n", nvram[16] & 7 );
+ else
+ PRINT_PROC( "n/a\n" );
+
+ /* the following entries are defined only for the Falcon */
+ if ((atari_mch_cookie >> 16) != ATARI_MCH_FALCON)
+ return;
+
+ PRINT_PROC( "OS language : " );
+ if (nvram[6] < fieldsize(languages))
+ PRINT_PROC( "%s\n", languages[nvram[6]] );
+ else
+ PRINT_PROC( "%u (undefined)\n", nvram[6] );
+ PRINT_PROC( "Keyboard language: " );
+ if (nvram[7] < fieldsize(languages))
+ PRINT_PROC( "%s\n", languages[nvram[7]] );
+ else
+ PRINT_PROC( "%u (undefined)\n", nvram[7] );
+ PRINT_PROC( "Date format : " );
+ PRINT_PROC( dateformat[nvram[8]&7],
+ nvram[9] ? nvram[9] : '/', nvram[9] ? nvram[9] : '/' );
+ PRINT_PROC( ", %dh clock\n", nvram[8] & 16 ? 24 : 12 );
+ PRINT_PROC( "Boot delay : " );
+ if (nvram[10] == 0)
+ PRINT_PROC( "default" );
+ else
+ PRINT_PROC( "%ds%s\n", nvram[10],
+ nvram[10] < 8 ? ", no memory test" : "" );
+
+ vmode = (nvram[14] << 8) || nvram[15];
+ PRINT_PROC( "Video mode : %s colors, %d columns, %s %s monitor\n",
+ colors[vmode & 7],
+ vmode & 8 ? 80 : 40,
+ vmode & 16 ? "VGA" : "TV",
+ vmode & 32 ? "PAL" : "NTSC" );
+ PRINT_PROC( " %soverscan, compat. mode %s%s\n",
+ vmode & 64 ? "" : "no ",
+ vmode & 128 ? "on" : "off",
+ vmode & 256 ?
+ (vmode & 16 ? ", line doubling" : ", half screen") : "" );
+
+ return( 1 );
+}
+#endif
+
+#endif /* MACH == ATARI */
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * tab-width: 4
+ * End:
+ */
{
fasync_pad(inode, file, 0);
if (--active)
- return;
+ return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
MOD_DEC_USE_COUNT;
return 0;
};
-static int pc110pad_init(void)
+int pc110pad_init(void)
{
current_params = default_params;
#define PC110PAD_IOCTL_TYPE 0x9a
#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
#endif /* _PC110PAD_H */
#include "pc_keyb.h"
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char pckbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
/*
* In case we run on a non-x86 hardware we need to initialize both the keyboard
* controller and the keyboard. On a x86, the BIOS will already have initialized
* them.
*/
+#ifndef __i386__
+#define INIT_KBD
+#endif
+
#ifdef INIT_KBD
__initfunc(static int kbd_wait_for_input(void))
{
- int n;
- int status, data;
+ int n;
+ int status, data;
+ unsigned long start = jiffies;
- n = KBD_TIMEOUT;
- do {
+ do {
status = inb(KBD_STATUS_REG);
/*
* Wait for input data to become available. This bit will
continue;
}
return (data & 0xff);
- } while (--n);
+ } while (jiffies - start < KBD_INIT_TIMEOUT);
return -1; /* timed-out if fell through to here... */
}
__initfunc(static void initialize_kbd(void))
{
- unsigned long flags;
char *msg;
- save_flags(flags); cli();
+ disable_irq(KEYBOARD_IRQ);
msg = initialize_kbd2();
- restore_flags(flags);
+ enable_irq(KEYBOARD_IRQ);
if (msg)
printk(KERN_WARNING "initialize_kbd: %s\n", msg);
static inline void kb_wait(void)
{
- int i;
+ unsigned long start = jiffies;
- for (i=0; i<KBD_TIMEOUT; i++)
+ do {
if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
return;
+ } while (jiffies - start < KBC_TIMEOUT);
+#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timed out\n");
+#endif
}
/*
}
if (scancode == 0) {
#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "keyboard buffer overflow\n");
+ printk(KERN_INFO "Keyboard buffer overflow\n");
#endif
prev_scancode = 0;
return 0;
#ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR
if (!raw_mode)
- printk(KERN_DEBUG "keyboard error\n");
+ printk(KERN_DEBUG "Keyboard error\n");
#endif
#endif
prev_scancode = 0;
handle_scancode(scancode);
status = inb(KBD_STATUS_REG);
- } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
+ } while (status & KBD_STAT_OBF);
mark_bh(KEYBOARD_BH);
enable_keyboard();
static int send_data(unsigned char data)
{
int retries = 3;
- int i;
+ unsigned long start;
do {
kb_wait();
resend = 0;
reply_expected = 1;
outb_p(data, KBD_DATA_REG);
- for(i=0; i<0x200000; i++) {
- inb_p(KBD_STATUS_REG); /* just as a delay */
+ start = jiffies;
+ do {
if (acknowledge)
return 1;
- if (resend)
- break;
- }
- if (!resend)
- return 0;
+ if (jiffies - start >= KBD_TIMEOUT) {
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "Keyboard timeout\n");
+#endif
+ return 0;
+ }
+ } while (!resend);
} while (retries-- > 0);
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
+#endif
return 0;
}
#define KBD_REPORT_ERR /* Report keyboard errors */
#define KBD_REPORT_UNKN /* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_TIMEOUT 0x100000 /* Timeout for sending of commands */
+
+#define KBD_INIT_TIMEOUT HZ /* Timeout for initializing the keyboard */
+#define KBC_TIMEOUT (HZ/4) /* Timeout for sending to keyboard controller */
+#define KBD_TIMEOUT (HZ/4) /* Timeout for keyboard command acknowledge */
/*
* Internal variables of the driver
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/semaphore.h>
#include <linux/config.h>
schedule();
retries++;
}
- return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
- int retries = 0;
-
- while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) {
- if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
- inb_p(KBD_DATA_REG);
- retries++;
- }
- return !(retries == 1000000);
+ return (retries < MAX_RETRIES);
}
/*
*/
#ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
- poll_aux_status_nosleep();
- outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
- poll_aux_status_nosleep();
- outb_p(val, KBD_DATA_REG);
-}
-
__initfunc(static int aux_write_ack(int val))
{
- aux_write_dev_nosleep(val);
- poll_aux_status_nosleep();
+ aux_write_dev(val);
+ poll_aux_status();
if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
{
outb_p(val, KBD_DATA_REG);
}
+/*
+ * AUX handler critical section start and end.
+ *
+ * Only one process can be in the critical section and all keyboard sends are
+ * deferred as long as we're inside. This is necessary as we may sleep when
+ * waiting for the keyboard controller and other processes / BH's can
+ * preempt us. Please note that the input buffer must be flushed when
+ * aux_end_atomic() is called and the interrupt is no longer enabled as not
+ * doing so might cause the keyboard driver to ignore all incoming keystrokes.
+ */
+
+static struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+ down(&aux_sema4);
+ disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+ enable_bh(KEYBOARD_BH);
+ up(&aux_sema4);
+}
+
/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
fasync_aux(inode, file, 0);
if (--aux_count)
return 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+ aux_start_atomic();
aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
poll_aux_status();
outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
#ifdef CONFIG_MCA
free_irq(AUX_IRQ, inode);
#else
{
if (!aux_present)
return -ENODEV;
- if (aux_count++)
+ aux_start_atomic();
+ if (aux_count++) {
+ aux_end_atomic();
return 0;
- if (!poll_aux_status()) {
+ }
+ if (!poll_aux_status()) { /* FIXME: Race condition */
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
queue->head = queue->tail = 0; /* Flush input queue */
if (request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)) {
#endif
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
MOD_INC_USE_COUNT;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
poll_aux_status();
outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
aux_ready = 0;
return 0;
if (count) {
int written = 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
-
+ aux_start_atomic();
do {
char c;
if (!poll_aux_status())
outb_p(c, KBD_DATA_REG);
written++;
} while (--count);
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
retval = -EIO;
if (written) {
retval = written;
queue->head = queue->tail = 0;
queue->proc_list = NULL;
if (!qp_found) {
+ aux_start_atomic();
#ifdef INITIALIZE_DEVICE
outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
aux_write_ack(AUX_SET_SAMPLE);
aux_write_ack(AUX_SET_RES);
aux_write_ack(3); /* 8 counts per mm */
aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
- poll_aux_status_nosleep();
+ poll_aux_status();
#endif /* INITIALIZE_DEVICE */
outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
- poll_aux_status_nosleep();
- outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
- poll_aux_status_nosleep();
- outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+ poll_aux_status();
+ outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG); /* Disable controller interrupts */
+ poll_aux_status();
+ outb_p(AUX_INTS_OFF, KBD_DATA_REG);
+ poll_aux_status();
+ aux_end_atomic();
}
return 0;
}
/* -*- linux-c -*-
*
- * $Id: sysrq.c,v 1.3 1997/06/18 09:42:12 mj Exp $
+ * $Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
*
* Linux Magic System Request Key Hacks
*
console_loglevel = 7;
printk(KERN_INFO "SysRq: ");
switch (key) {
- case 19: /* R -- Reset raw mode */
- kbd->kbdmode = VC_XLATE;
- printk("Keyboard mode set to XLATE\n");
+ case 'r': /* R -- Reset raw mode */
+ if (kbd) {
+ kbd->kbdmode = VC_XLATE;
+ printk("Keyboard mode set to XLATE\n");
+ }
break;
- case 30: /* A -- SAK */
+ case 'a': /* A -- SAK */
printk("SAK\n");
- do_SAK(tty);
+ if (tty)
+ do_SAK(tty);
reset_vc(fg_console);
break;
- case 48: /* B -- boot immediately */
+ case 'b': /* B -- boot immediately */
printk("Resetting\n");
machine_restart(NULL);
break;
#ifdef __sparc__
- case 35: /* H -- halt immediately */
+ case 'h': /* H -- halt immediately */
printk("Halting\n");
halt_now();
break;
#endif
#ifdef CONFIG_APM
- case 24: /* O -- power off */
+ case 'o': /* O -- power off */
printk("Power off\n");
apm_set_power_state(APM_STATE_OFF);
break;
#endif
- case 31: /* S -- emergency sync */
+ case 's': /* S -- emergency sync */
printk("Emergency Sync\n");
emergency_sync_scheduled = EMERG_SYNC;
wakeup_bdflush(0);
break;
- case 22: /* U -- emergency remount R/O */
+ case 'u': /* U -- emergency remount R/O */
printk("Emergency Remount R/O\n");
emergency_sync_scheduled = EMERG_REMOUNT;
wakeup_bdflush(0);
break;
- case 25: /* P -- show PC */
+ case 'p': /* P -- show PC */
printk("Show Regs\n");
if (pt_regs)
show_regs(pt_regs);
break;
- case 20: /* T -- show task info */
+ case 't': /* T -- show task info */
printk("Show State\n");
show_state();
break;
- case 50: /* M -- show memory info */
+ case 'm': /* M -- show memory info */
printk("Show Memory\n");
show_mem();
break;
- case 2 ... 11: /* 0-9 -- set console logging level */
- key--;
- if (key == 10)
- key = 0;
- orig_log_level = key;
- printk("Log level set to %d\n", key);
+ case '0' ... '9': /* 0-9 -- set console logging level */
+ orig_log_level = key - '0';
+ printk("Log level set to %d\n", orig_log_level);
break;
- case 18: /* E -- terminate all user processes */
+ case 'e': /* E -- terminate all user processes */
printk("Terminate All Tasks\n");
send_sig_all(SIGTERM, 0);
orig_log_level = 8; /* We probably have killed syslogd */
break;
- case 37: /* K -- kill all user processes */
+ case 'k': /* K -- kill all user processes */
printk("Kill All Tasks\n");
send_sig_all(SIGKILL, 0);
orig_log_level = 8;
break;
- case 38: /* L -- kill all processes including init */
+ case 'l': /* L -- kill all processes including init */
printk("Kill ALL Tasks (even init)\n");
send_sig_all(SIGKILL, 1);
orig_log_level = 8;
struct file *file;
for (file = inuse_filps; file; file = file->f_next)
- if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+ if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
file->f_mode &= ~2;
}
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
+#ifdef __powerpc__
+#define VGA_OFFSET 0xC0000000;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
/*
* By replacing the four outb_p with two back to back outw, we can reduce
* the window of opportunity to see text mislocated to the RHS of the
{
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
- video_mem_base = 0xb0000;
+ video_mem_base = 0xb0000 + VGA_OFFSET;
video_port_reg = 0x3b4;
video_port_val = 0x3b5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAM;
- video_mem_term = 0xb8000;
+ video_mem_term = 0xb8000 + VGA_OFFSET;
*display_desc = "EGA+";
request_region(0x3b0,16,"ega");
}
else
{
video_type = VIDEO_TYPE_MDA;
- video_mem_term = 0xb2000;
+ video_mem_term = 0xb2000 + VGA_OFFSET;
*display_desc = "*MDA";
request_region(0x3b0,12,"mda");
request_region(0x3bf, 1,"mda");
else /* If not, it is color. */
{
can_do_color = 1;
- video_mem_base = 0xb8000;
+ video_mem_base = 0xb8000 + VGA_OFFSET;
video_port_reg = 0x3d4;
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
int i ;
- video_mem_term = 0xc0000;
+ video_mem_term = 0xc0000 + VGA_OFFSET;
if (!ORIG_VIDEO_ISVGA) {
video_type = VIDEO_TYPE_EGAC;
* controllers (it seems like setting MM=01
* and COE=1 isn't necessarily a good idea)
*/
- video_mem_base = 0xa0000 ;
- video_mem_term = 0xb0000 ;
+ video_mem_base = 0xa0000 + VGA_OFFSET;
+ video_mem_term = 0xb0000 + VGA_OFFSET;
outb_p (6, 0x3ce) ;
outb_p (6, 0x3cf) ;
#endif
else
{
video_type = VIDEO_TYPE_CGA;
- video_mem_term = 0xba000;
+ video_mem_term = 0xba000 + VGA_OFFSET;
*display_desc = "*CGA";
request_region(0x3d4,2,"cga");
}
mp->rx_skbs[i] = skb;
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- rxd[i].myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd[i].myri_scatters[0].addr = (unsigned long) skb->data;
rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;
rxd[i].ctx = i;
rxd[i].num_sg = 1;
drops++;
DRX(("DROP "));
mp->enet_stats.rx_dropped++;
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
- rxd->myri_scatters[0].addr = (unsigned int) new_skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) new_skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
/* Reuse original ring buffer. */
DRX(("reuse "));
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
txd = &sq->myri_txd[entry];
mp->tx_skbs[entry] = skb;
- txd->myri_gathers[0].addr = (unsigned int) skb->data;
+ txd->myri_gathers[0].addr = (unsigned long) skb->data;
txd->myri_gathers[0].len = len;
txd->num_sg = 1;
txd->chan = KERNEL_CHANNEL;
struct tq_struct deferred;
struct plip_local snd_data;
struct plip_local rcv_data;
- struct ppd *pardev;
+ struct pardevice *pardev;
unsigned long trigger;
unsigned long nibble;
enum plip_connection_state connection;
plip_init_dev(struct device *dev, struct parport *pb))
{
struct net_local *nl;
- struct ppd *pardev;
+ struct pardevice *pardev;
dev->irq = pb->irq;
dev->base_addr = pb->base;
}
pardev = parport_register_device(pb, dev->name, plip_preempt,
- plip_wakeup,
- plip_interrupt, PARPORT_DEV_LURK, dev);
+ plip_wakeup, plip_interrupt,
+ PARPORT_DEV_LURK, dev);
printk(version);
printk("%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
sti();
dma_init_receive(sm);
setup_dma_dsp(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
sti();
dma_init_receive(sm);
setup_dma_wss(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
FB_OBJS += weitek.o
endif
ifdef SUN_FB_CREATOR
+ ifeq ($(ARCH),sparc64)
FB_OBJS += creator.o
+ endif
endif
#ifdef SUN_FB_FAST_ONE
# FB_OBJS += sun_8bit_fast1.o
-/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
* creator.c: Creator/Creator3D frame buffer driver
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
int err;
#ifdef CONFIG_SPARC32_COMPAT
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
#ifdef CONFIG_SPARC32_COMPAT
if (current->tss.flags & SPARC_FLAG_32BIT) {
static int
ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
{
- int i;
-
switch (cmd) {
case FBIO_WID_GET:
return ffb_wid_get (fb, (struct fb_wid_list *)arg);
-/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
+/* $Id: suncons.c,v 1.67 1997/07/20 05:59:42 davem Exp $
*
* suncons.c: Sun SparcStation console support.
*
leo_setup (&fbinfo [n], n, base, io);
break;
#endif
-#ifdef SUN_FB_CREATOR
+#if defined(SUN_FB_CREATOR) && defined(__sparc_v9__)
case FBTYPE_CREATOR:
creator_setup (&fbinfo [n], n, con_node, base, io);
break;
-/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
+/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
* tcx.c: SUNW,tcx 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
if (!fb->base){
- fb->base = (uint)
- sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
- fb->type.fb_size, "tcx_ram", fb->space, 0);
+ fb->base = (unsigned long)
+ sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET],
+ 0, fb->type.fb_size, "tcx_ram", fb->space, 0);
}
if (prom_getbool (node, "hw-cursor")) {
-/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
+/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
* weitek.c: Tadpole P9100/P9000 console driver
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
__initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
{
- extern struct screen_info screen_info;
-
printk ("weitek%d at 0x%8.8x\n", slot, addr);
/* Fill in parameters we left out */
#ifdef CONFIG_SUN_AUXIO
if (sparc_cpu_model == sun4u)
auxio_probe ();
+#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+
+ sun4u_start_timers();
+ }
#endif
return memory_start;
}
* sure what the relationship between the NCR structures
* and host structures were going to be.
*/
- (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
+ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (le32_to_cpu(issue[1])) -
(hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
offsetof(struct NCR53c7x0_cmd, dsa))
/* If the IF TRUE bit is not set, it's a NOP */
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- curr[1] = (u32) virt_to_bus (hostdata->script) +
- hostdata->E_wait_reselect;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE);
+ curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_wait_reselect);
hostdata->reconnect_dsa_head = 0;
hostdata->addr_reconnect_dsa_head = (u32)
- virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+ le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head)));
hostdata->expecting_iid = 0;
hostdata->expecting_sto = 0;
if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
- hostdata->initiate_sdtr = 0xffff;
+ hostdata->initiate_sdtr = le32_to_cpu(0xffff);
else
hostdata->initiate_sdtr = 0;
hostdata->talked_to = 0;
* Returns : 0 on success, -1 on failure.
*/
-static inline int
+static int
NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
int i, ccf, expected_ccf;
* will differ.
*/
int expected_mapping = OPTION_IO_MAPPED;
+
NCR53c7x0_local_setup(host);
switch (hostdata->chip) {
/* Assign constants accessed by NCR */
hostdata->NCR53c7xx_zero = 0;
- hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
- hostdata->NCR53c7xx_msg_abort = ABORT;
- hostdata->NCR53c7xx_msg_nop = NOP;
- hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+ hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT);
+ hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT);
+ hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP);
+ hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24);
if (expected_mapping == -1 ||
(hostdata->options & (OPTION_MEMORY_MAPPED)) !=
search->irq == host->irq && search != host); search=search->next);
if (!search) {
- if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL)) {
+#ifdef __powerpc__
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL))
+#else
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+#endif
+ {
+
+
printk("scsi%d : IRQ%d not free, detaching\n"
" You have either a configuration problem, or a\n"
" broken BIOS. You may wish to manually assign\n"
return -1;
}
+#ifdef __powerpc__
+ if ( ! (command & PCI_COMMAND_MASTER)) {
+ printk("SCSI: PCI Master Bit has not been set. Setting...\n");
+ command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ if (io_port >= 0x10000000) {
+ /* Mapping on PowerPC can't handle this! */
+ unsigned long new_io_port;
+ new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
+ io_port = new_io_port;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ }
+ }
+#endif
/*
* Bit 0 is the address space indicator and must be one for I/O
unsigned char tmp;
int i, ncr_to_memory, memory_to_ncr;
u32 base;
+#ifdef __powerpc__
+ unsigned long *script_ptr;
+#endif
NCR53c7x0_local_setup(host);
printk("scsi%d : NCR dsa_fields start is %d not %d\n",
host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
Ent_dsa_zero);
+#ifdef __powerpc__
+/* The PowerPC is Big Endian - adjust script appropriately */
+ script_ptr = hostdata->script;
+ for (i = 0; i < sizeof(SCRIPT); i += sizeof(long))
+ {
+ *script_ptr++ = le32_to_cpu(*script_ptr);
+ }
+#endif
printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(hostdata->script), hostdata->script);
" 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)
+ else if (hostdata->test_completed != 1)
printk ("scsi%d : test 1 bad interrupt value (%d)\n",
host->host_no, hostdata->test_completed);
else
cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
cmd[4] = sizeof(data);
- dsa[2] = 1;
- dsa[3] = virt_to_bus(&identify);
- dsa[4] = 6;
- dsa[5] = virt_to_bus(&cmd);
- dsa[6] = sizeof(data);
- dsa[7] = virt_to_bus(&data);
- dsa[8] = 1;
- dsa[9] = virt_to_bus(&status);
- dsa[10] = 1;
- dsa[11] = virt_to_bus(&msg);
+/* Need to adjust for endian-ness */
+ dsa[2] = le32_to_cpu(1);
+ dsa[3] = le32_to_cpu(virt_to_bus(&identify));
+ dsa[4] = le32_to_cpu(6);
+ dsa[5] = le32_to_cpu(virt_to_bus(&cmd));
+ dsa[6] = le32_to_cpu(sizeof(data));
+ dsa[7] = le32_to_cpu(virt_to_bus(&data));
+ dsa[8] = le32_to_cpu(1);
+ dsa[9] = le32_to_cpu(virt_to_bus(&status));
+ dsa[10] = le32_to_cpu(1);
+ dsa[11] = le32_to_cpu(virt_to_bus(&msg));
for (i = 0; i < 3; ++i) {
cli();
}
/* SCNTL3 SDID */
- dsa[0] = (0x33 << 24) | (i << 16) ;
+ dsa[0] = le32_to_cpu((0x33 << 24) | (i << 16)) ;
hostdata->idle = 0;
hostdata->test_running = 2;
hostdata->test_completed = -1;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
int i;
+#ifdef __powerpc__
+ int len;
+ unsigned long *dsa_ptr;
+#endif
memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+#ifdef __powerpc__
+ /* Note: the script has already been 'endianized' */
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
/*
* Note : within the NCR 'C' code, dsa points to the _start_
/* XXX - new start stuff */
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+#ifdef __powerpc__
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
}
if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd)
{
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
++found;
break;
}
*/
for (left = host->can_queue,
- ncr_search = hostdata->reconnect_dsa_head,
+ ncr_search = le32_to_cpu(hostdata->reconnect_dsa_head),
ncr_prev = &hostdata->reconnect_dsa_head;
left >= 0 && ncr_search &&
((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
!= (char *) cmd->dsa;
ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
- hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+ hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
if (left < 0)
printk("scsi%d: loop detected in ncr reconnect list\n",
dsps = NCR53c7x0_read32(DSPS_REG);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
- if (hostdata->options & OPTION_DEBUG_INTR)
+ if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
switch (dsps) {
hostdata->msg_buf[4] = 0; /* 0 offset = async */
asynchronous (host, c->target);
}
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, le32_to_cpu(5));
patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
- virt_to_bus ((void *)&hostdata->msg_buf));
+ le32_to_cpu(virt_to_bus ((void *)&hostdata->msg_buf)));
hostdata->dsp = hostdata->script +
hostdata->E_respond_message / sizeof(u32);
hostdata->dsp_changed = 1;
* agrees with this being an untagged queue'd command.
*/
- patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32 (cmd->dsa, dsa_msgout, 0, le32_to_cpu(1));
/*
* Modify the table indirect for COMMAND OUT phase, since
* Request Sense is a six byte command.
*/
- patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+ patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, le32_to_cpu(6));
c->cmnd[0] = REQUEST_SENSE;
c->cmnd[1] &= 0xe0; /* Zero all but LUN */
*/
patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
- virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+ le32_to_cpu(virt_to_bus(hostdata->script) + hostdata->E_other_transfer));
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] = (u32) virt_to_bus(c->sense_buffer);
+ le32_to_cpu(virt_to_bus(cmd->data_transfer_start)));
+ cmd->data_transfer_start[0] = le32_to_cpu((((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
+ DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer));
+ cmd->data_transfer_start[1] = (u32) le32_to_cpu(virt_to_bus(c->sense_buffer));
- cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd->data_transfer_start[2] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->data_transfer_start[3] = (u32) le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
/*
* Currently, this command is flagged as completed, ie
* status, etc are used.
*/
- cmd->cmd->result = 0xffff;
+ cmd->cmd->result = le32_to_cpu(0xffff);
/*
* Restart command as a REQUEST SENSE.
host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt(cmd->saved_data_pointer));
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)));
print_insn (host, hostdata->script + Ent_reselected_ok /
sizeof(u32), "", 1);
printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
if (dsa) {
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
#if 0
printk("scsi%d : template code :\n", host->host_no);
for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
" (temp was 0x%x (virt 0x%p))\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer),
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)),
NCR53c7x0_read32 (TEMP_REG),
bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
}
OPTION_DEBUG_DISCONNECT)) {
printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
print_progress (c);
}
return SPECIFIC_INT_RESTART;
int size;
printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer, bus_to_virt (
- cmd->saved_data_pointer));
+ le32_to_cpu(cmd->saved_data_pointer)));
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)), "", 1);
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)) + size, "", 1);
print_progress (c);
}
#if 0
(int) NCR53c7x0_read8(SCNTL3_REG_800),
datapath_residual (host)) ;
print_insn (host, dsp, "", 1);
- size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
- print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+ size = print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])), "", 1);
+ print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])) + size, "", 1);
}
return SPECIFIC_INT_RESTART;
#endif
case MODE_SELECT:
case WRITE_6:
case WRITE_10:
- case START_STOP: /* also SCAN, which may do DATA OUT */
#if 0
printk("scsi%d : command is ", host->host_no);
print_command(cmd->cmnd);
* These commands do no data transfer, we should force an
* interrupt if a data phase is attempted on them.
*/
+ case START_STOP: /* also SCAN, which may do DATA OUT */
case TEST_UNIT_READY:
datain = dataout = 0;
break;
* will start the data transfer over at the beginning.
*/
- tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
- hostdata->E_data_transfer;
+ tmp->saved_data_pointer = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_data_transfer);
/*
* Initialize Linux specific fields.
tmp->cmd = cmd;
tmp->next = NULL;
tmp->flags = 0;
- tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
- hostdata->dsa_start;
- tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+ tmp->dsa_next_addr = le32_to_cpu(virt_to_bus(tmp->dsa) + hostdata->dsa_next -
+ hostdata->dsa_start);
+ tmp->dsa_addr = le32_to_cpu(virt_to_bus(tmp->dsa) - hostdata->dsa_start);
/*
* Calculate addresses of dynamic code to fill in DSA
if (hostdata->dsa_fixup)
hostdata->dsa_fixup(tmp);
- 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_next, 0, le32_to_cpu(0));
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, le32_to_cpu(virt_to_bus(cmd)));
if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
if (hostdata->sync[cmd->target].select_indirect !=
}
- patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
- select_indirect);
+ patch_dsa_32(tmp->dsa, dsa_select, 0, le32_to_cpu(hostdata->sync[cmd->target].
+ select_indirect));
/*
* Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
* different commands; although it should be trivial to do them
if (hostdata->initiate_wdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
sizeof(wdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(wdtr_message)));
save_flags(flags);
cli();
hostdata->initiate_wdtr &= ~(1 << cmd->target);
} else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
sizeof(sdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(sdtr_message)));
tmp->flags |= CMD_FLAG_SDTR;
save_flags(flags);
cli();
!(hostdata->options & OPTION_NO_ASYNC)) {
memcpy ((void *) (tmp->select + 1), (void *) async_message,
sizeof(async_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(async_message)));
tmp->flags |= CMD_FLAG_SDTR;
}
#endif
else
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1));
hostdata->talked_to |= (1 << cmd->target);
tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
- 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, virt_to_bus(cmd->cmnd));
- patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+ patch_dsa_32(tmp->dsa, dsa_msgout, 1, le32_to_cpu(virt_to_bus(tmp->select)));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, le32_to_cpu(cmd->cmd_len));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 1, le32_to_cpu(virt_to_bus(cmd->cmnd)));
+ patch_dsa_32(tmp->dsa, dsa_dataout, 0, le32_to_cpu(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 (hostdata->script) + hostdata->E_other_transfer));
+ patch_dsa_32(tmp->dsa, dsa_datain, 0, le32_to_cpu(cmd_datain ?
virt_to_bus (cmd_datain)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ : 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, 0, le32_to_cpu(1));
/*
* FIXME : these only works for little endian. We probably want to
* provide message and status fields in the NCR53c7x0_cmd
* structure, and assign them to cmd->result when we're done.
*/
- 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, virt_to_bus(&cmd->result));
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, le32_to_cpu(virt_to_bus(&cmd->result) + 1));
+ patch_dsa_32(tmp->dsa, dsa_status, 0, le32_to_cpu(1));
+ patch_dsa_32(tmp->dsa, dsa_status, 1, le32_to_cpu(virt_to_bus(&cmd->result)));
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, le32_to_cpu(1));
patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+ le32_to_cpu(virt_to_bus(&(hostdata->NCR53c7xx_msg_nop))));
/*
* Generate code for zero or more of the DATA IN, DATA OUT phases
if (datain) {
/* CALL other_in, WHEN NOT DATA_IN */
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
DCMD_TCI_IO) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_datain[1] = virt_to_bus (hostdata->script) +
- hostdata->E_other_in;
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_other_in);
/* MOVE count, buf, WHEN DATA_IN */
- cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
- << 24) | count;
- cmd_datain[3] = buf;
+ cmd_datain[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
+ << 24) | count);
+ cmd_datain[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_datain, "dynamic ", 1);
print_insn (host, cmd_datain + 2, "dynamic ", 1);
}
if (dataout) {
/* CALL other_out, WHEN NOT DATA_OUT */
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_out;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_out);
/* MOVE count, buf, WHEN DATA+OUT */
- cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
- | count;
- cmd_dataout[3] = buf;
+ cmd_dataout[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
+ | count);
+ cmd_dataout[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_dataout, "dynamic ", 1);
print_insn (host, cmd_dataout + 2, "dynamic ", 1);
if (datain) {
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_datain[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_datain, "dynamic jump ", 1);
#endif
}
#endif
if (dataout) {
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_dataout, "dynamic jump ", 1);
#endif
|| hostdata->state == STATE_DISABLED) {
printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
cmd->target, cmd->lun);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
(hostdata->debug_count_limit == 0)) {
printk("scsi%d : maximum commands exceeded\n", host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
}
} else {
if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
hostdata->debug_count_limit != -1)
--hostdata->debug_count_limit;
restore_flags (flags);
- cmd->result = 0xffff; /* The NCR will overwrite message
+ cmd->result = le32_to_cpu(0xffff); /* The NCR will overwrite message
and status with valid data */
cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
}
int i;
NCR53c7x0_local_setup(host);
-#if 0
+#if 0
printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(dsa), dsa);
#endif
if (hostdata->state == STATE_DISABLED) {
printk("scsi%d : driver disabled\n", host->host_no);
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
/* Restore this instruction to a NOP once the command starts */
cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
+ sizeof(u32)] = (u32) le32_to_cpu(virt_to_bus ((void *)curr));
/* Replace the current jump operand. */
curr[1] =
- virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template;
+ le32_to_cpu(virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template);
/* Replace the NOP instruction with a JUMP */
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
} else {
printk ("scsi%d: no free slot\n", host->host_no);
disable(host);
- tmp->result = (DID_ERROR << 16);
+ tmp->result = DID_ERROR << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
if (hostdata->state == STATE_DISABLED) {
tmp = (Scsi_Cmnd *) hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
if (tmp->host_scribble) {
((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
hostdata->free;
(struct NCR53c7x0_cmd *)
tmp->host_scribble);
} else {
+ tmp->result = le32_to_cpu(tmp->result);
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00)) {
printk ("scsi%d : danger Will Robinson!\n",
char buf[80]; /* Debugging sprintf buffer */
size_t buflen; /* Length of same */
#endif
-
do {
done = 1;
for (host = first_host; host; host = host->next)
printk ("scsi%d : looking at result of 0x%x\n",
host->host_no, cmd->cmd->result);
#endif
-
+
+#ifdef __powerpc__
+ if (tmp->result == le32_to_cpu(0xffff))
+ continue;
+ tmp->result = le32_to_cpu(tmp->result);
+#else
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00))
continue;
+#endif
search_found = 1;
printk("scsi%d : no active command\n", host->host_no);
}
}
-
if (istat & ISTAT_SIP) {
if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : ISTAT_SIP\n", host->host_no);
* from normal dynamic code.
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd->residual[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd->residual[1] = virt_to_bus(hostdata->script)
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd->residual[1] = le32_to_cpu(virt_to_bus(hostdata->script)
+ ((dcmd & DCMD_BMI_IO)
- ? hostdata->E_other_in : hostdata->E_other_out);
+ ? hostdata->E_other_in : hostdata->E_other_out));
}
/*
* move instruction, reflecting the pointer and count at the
* time of the phase mismatch.
*/
- cmd->residual[2] = dbc_dcmd + residual;
- cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+ cmd->residual[2] = le32_to_cpu(dbc_dcmd + residual);
+ cmd->residual[3] = le32_to_cpu(NCR53c7x0_read32(DNAD_REG) - residual);
/*
* The third and final instruction is a jump to the instruction
* which follows the instruction which had to be 'split'
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->residual[5] = virt_to_bus(dsp_next);
+ cmd->residual[4] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->residual[5] = le32_to_cpu(virt_to_bus(dsp_next));
}
/*
*/
sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
(prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
- insn[0], insn[1], bus_to_virt (insn[1]));
+ insn[0], insn[1], bus_to_virt (le32_to_cpu(insn[1])));
tmp = buf + strlen(buf);
if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
- bus_to_virt(insn[2]));
+ bus_to_virt(le32_to_cpu(insn[2])));
size = 3;
} else {
sprintf (tmp, "\n");
struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
host->hostdata : NULL;
unsigned long flags;
+ unsigned long result;
struct NCR53c7x0_cmd *curr, **prev;
Scsi_Cmnd *me, **last;
#if 0
&(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
if (curr) {
- if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+ result = le32_to_cpu(cmd->result);
+ if ((result & 0xff) != 0xff && (result & 0xff00) != 0xff00) {
if (prev)
*prev = (struct NCR53c7x0_cmd *) curr->next;
curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
cmd->host_scribble = NULL;
}
- if (((cmd->result & 0xff00) == 0xff00) ||
- ((cmd->result & 0xff) == 0xff)) {
+ result = le32_to_cpu(cmd->result);
+ if (((result & 0xff00) == 0xff00) ||
+ ((result & 0xff) == 0xff)) {
printk ("scsi%d : did this command ever run?\n", host->host_no);
cmd->result = DID_ABORT << 16;
} else {
(insn >= ncmd->residual &&
insn < (ncmd->residual +
sizeof(ncmd->residual))))) {
- ptr = bus_to_virt(insn[3]);
+ ptr = bus_to_virt(le32_to_cpu(insn[3]));
if ((buffers = cmd->use_sg)) {
for (offset = 0,
continue;
if (!i) {
where = "saved";
- ptr = bus_to_virt(ncmd->saved_data_pointer);
+ ptr = bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer));
} else {
where = "active";
ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
cmd->host->host_no, where);
if (ncmd) {
size = print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)), "", 1);
print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)) + size * sizeof(u32),
"", 1);
}
}
" + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
prefix ? prefix : "",
host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
- dsa[hostdata->dsa_msgout / sizeof(u32)],
- dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
- bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]),
+ bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])));
/*
* Only print messages if they're sane in length so we don't
* anything.
*/
- if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
+ if (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]) <
sizeof (hostdata->free->select))
- for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
- ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
+ for (i = le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ ptr = bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
i > 0 && !check_address ((unsigned long) ptr, 1);
ptr += len, i -= len) {
printk(" ");
}
printk(" + %d : select_indirect = 0x%x\n",
- hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ hostdata->dsa_select, le32_to_cpu(dsa[hostdata->dsa_select / sizeof(u32)]));
+ cmd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_cmnd / sizeof(u32)]));
printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
(u32) virt_to_bus(cmd));
if (cmd) {
} else
printk("\n");
printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
- dsa[hostdata->dsa_next / sizeof(u32)]);
+ le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
if (cmd) {
printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
" script : ",
host->host_no, cmd->pid);
/* print_dsa does sanity check on address, no need to check */
else
- print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
- -> dsa, "");
+ print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), "");
} else
printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
host->host_no, cmd->pid, cmd->target, cmd->lun);
left > 0; curr += 2, --left)
if (curr[0] != hostdata->NOP_insn)
/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (curr[1] -
+ print_dsa (host, bus_to_virt (le32_to_cpu(curr[1]) -
(hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template)), "");
printk ("scsi%d : end schedule dsa array\n", host->host_no);
printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
for (left = host->can_queue,
- dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ dsa = bus_to_virt (le32_to_cpu(hostdata->reconnect_dsa_head));
left >= 0 && dsa;
dsa = next_dsa) {
save_flags (flags);
}
else
{
- next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ next_dsa = bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
print_dsa (host, dsa, "");
}
restore_flags(flags);
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
hostdata->curr = NULL;
}
if (hostdata->options & OPTION_DEBUG_DSA) \
printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
#dsa, #symbol, hostdata->##symbol, \
- (word), (u32) (value)); \
+ (word), (u32) le32_to_cpu(value)); \
}
/* Paranoid people could use panic() here. */
aha152x.o: aha152x.c
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
-aic7xxx_asm: aic7xxx_asm.c
- $(HOSTCC) -o $@ aic7xxx_asm.c
-
-aic7xxx.c: aic7xxx_seq.h
-aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
- ./aic7xxx_asm -o $@ aic7xxx.seq
+aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
+ $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
seagate.o: seagate.c
$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c
AIC7xxx Driver for Linux
- April 15, 1996
+ July 20, 1997
Introduction
------------------------
-----------------------
AIC-777x
AIC-785x
+ AIC-786x
AIC-787x
AIC-788x
Dan Eischen deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
Dean Gehnert deang@teleport.com (Linux FTP/patch maintainer)
Jess Johnson jester@frenzy.com (AIC7xxx FAQ author)
+ Doug Ledford dledford@dialnet.net (Stress tester/bug squasher)
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
- Command line options
- ------------------------
+ Command line options ("aic7xxx=option[,option...]")
+ ---------------------------------------------------
"aic7xxx=no_reset" - Eliminate the SCSI reset delay during startup.
Some SCSI devices need some extra time to reset.
+ "aic7xxx=extended" - Force extended translation.
+ "aic7xxx=ultra" - Force Ultra mode
+ "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
+ interrupts. AFAIK, the driver only works with level triggered
+ interrupts. This only applies to EISA adapters.
+ "aic7xxx=verbose" - Enable more bootup messages. PLEASE use this
+ if you have problems with the driver.
/proc support
------------------------
- US Linux mirror of Teleport site
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
- European Linux mirror of Teleport site
+ ftp://ftp.pcnet.com/users/eischen/Linux/
+ - Daniel Eischens experimental/development ftp site that is
+ also home of the Linux aic7xxx sequencer assembler source.
+
+ Sequencer assembler
+ ------------------------
+ The sequencer assembler is no longer being distributed with the
+ Linux kernel. The sequencer assembler (aic7xxx_asm) is now being
+ maintained by Justin Gibbs under a BSD copyright (which pretty
+ much lets you do anything you want with it). I keep a Linux
+ version of the assembler at my ftp site should you wish to hack
+ the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
+ Please note that you do NOT need the assembler to build a kernel
+ with aic7xxx support. The assembler generates the code that is
+ downloaded to the aic7xxx controllers; this code IS part of the
+ Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
+
+ Problems compiling the kernel with aic7xxx support
+ --------------------------------------------------
+ This is probably due to having modified the sequencer files in
+ some way. If you are not modifying the sequencer source (in
+ drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
+ the necessary files from your kernel tarball. Otherwise, visit
+ my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
+ assembler source.
Dean W. Gehnert
deang@teleport.com
-$Revision: 3.0 $
+(Modified by D. Eischen, 7/20/97)
+
+$Revision: 3.1a $
-#define EXPERIMENTAL_FLAGS 0
-
/*+M*************************************************************************
* Adaptec AIC7xxx device driver for Linux.
*
* the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
* ANSI SCSI-2 specification (draft 10c), ...
*
- * ----------------------------------------------------------------
- * Modified to include support for wide and twin bus adapters,
- * DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * --------------------------------------------------------------------------
+ *
+ * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ * Substantially modified to include support for wide and twin bus
+ * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
* SCB paging, and other rework of the code.
*
- * Parts of this driver are based on the FreeBSD driver by Justin
- * T. Gibbs.
+ * Parts of this driver were also based on the FreeBSD driver by
+ * Justin T. Gibbs. His copyright follows:
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ * Thanks also go to (in alphabetical order) the following:
+ *
+ * Rory Bolt - Sequencer bug fixes
+ * Jay Estabrook - Initial DEC Alpha support
+ * Doug Ledford - Much needed abort/reset bug fixes
+ * Kai Makisara - DMAing of SCBs
*
* A Boot time option was also added for not resetting the scsi bus.
*
- * Form: aic7xxx=extended,no_reset
+ * Form: aic7xxx=extended
+ * aic7xxx=no_reset
+ * aic7xxx=ultra
+ * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level
+ * aic7xxx=verbose
*
- * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
*
- * $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
#include "scsi.h"
#include "hosts.h"
#include "aic7xxx.h"
+
+#include "aic7xxx/sequencer.h"
+#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
+#include "aic7xxx_seq.h"
#include <linux/stat.h>
#include <linux/malloc.h> /* for kmalloc() */
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-static struct proc_dir_entry proc_scsi_aic7xxx = {
+struct proc_dir_entry proc_scsi_aic7xxx = {
PROC_SCSI_AIC7XXX, 7, "aic7xxx",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "$Revision: 4.0 $"
+#define AIC7XXX_C_VERSION "$Revision: 4.1 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b) ((a < b) ? a : b)
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define ALL_TARGETS -1
+#define ALL_CHANNELS '\0'
+#define ALL_LUNS -1
#ifndef TRUE
# define TRUE 1
#endif
* support because all PCI dependent code is bracketed with
* "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
*
- * o Twin bus support - this has been tested and does work.
- *
- * o DMAing of SCBs - thanks to Kai Makisara, this now works.
- * This define is now taken out and DMAing of SCBs is always
- * performed (8/12/95 - DE).
+ * o Twin bus support - this has been tested and does work. It is
+ * not an option anymore.
*
* o Tagged queueing - this driver is capable of tagged queueing
* but I am unsure as to how well the higher level driver implements
* LUN using its own heuristic based on the number of available
* SCBs.
*
- * o 3985 support - The 3985 adapter is much like the 3940, but
- * has three 7870 controllers as opposed to two for the 3940.
- * It will get probed and recognized as three different adapters,
- * but all three controllers can share the same external bank of
- * 255 SCBs. If you enable AIC7XXX_SHARE_SCBS, then the driver
- * will attempt to share the common bank of SCBs between the three
- * controllers of the 3985. This is experimental and hasn't
- * been tested. By default, we do not share the bank of SCBs,
- * and force the controllers to use their own internal bank of
- * 16 SCBs. Please let us know if sharing the SCB array works.
+ * o 3985 support - The 3985 adapter is much like the 3940, but has
+ * three 7870 controllers as opposed to two for the 3940. It will
+ * be probed and recognized as three different adapters, but all
+ * three controllers can share the same external bank of 255 SCBs.
+ * If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
+ * to use and share the common bank of SCBs between the three
+ * controllers of the 3985. This is experimental and hasn't been
+ * been tested. By default, we do not use external SCB RAM, and
+ * force the controllers to use their own internal bank of 16 SCBs.
+ * Please let us know if using the external SCB array works.
*
* o SCB paging support - SCB paging is enabled by defining
* AIC7XXX_PAGE_ENABLE. Support for this was taken from the
* Note that sharing of IRQs is not an option any longer. Linux supports
* it so we support it.
*
- * Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
*/
-/* Uncomment this for testing twin bus support. */
-#define AIC7XXX_TWIN_SUPPORT
-
/* Uncomment this for tagged queueing. */
-/* #define AIC7XXX_TAGGED_QUEUEING */
+#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
+#define AIC7XXX_TAGGED_QUEUEING
+#endif
/*
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-/* #define AIC7XXX_CMDS_PER_LUN 8 */
+#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
+#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#endif
/* Set this to the delay in seconds after SCSI bus reset. */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
#define AIC7XXX_RESET_DELAY 15
+#endif
/*
- * Uncomment the following define for collection of SCSI transfer statistics
- * for the /proc filesystem.
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
*
* NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
* NOTE: This does affect performance since it has to maintain statistics.
*/
-/* #define AIC7XXX_PROC_STATS */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
/*
- * Uncomment the following to enable SCB paging.
+ * Enable SCB paging.
*/
-/* #define AIC7XXX_PAGE_ENABLE */
+#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
+#define AIC7XXX_PAGE_ENABLE
+#endif
/*
- * Uncomment the following to enable sharing of the external bank
- * of 255 SCBs for the 3985.
+ * Uncomment the following to enable use of the external bank
+ * of 255 SCBs. For 3985 adapters, this will also enable sharing
+ * of the SCB array across all three controllers.
*/
-#define AIC7XXX_SHARE_SCBS
+#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
+#define AIC7XXX_USE_EXT_SCBRAM
+#endif
/*
* For debugging the abort/reset code.
*/
#define AIC7XXX_DEBUG
+/*
+ * Set this for defining the number of tagged commands on a device
+ * by device, and controller by controller basis. The first set
+ * of tagged commands will be used for the first detected aic7xxx
+ * controller, the second set will be used for the second detected
+ * aic7xxx controller, and so on. These values will *only* be used
+ * for targets that are tagged queueing capable; these values will
+ * be ignored in all other cases. The tag_commands is an array of
+ * 16 to allow for wide and twin adapters. Twin adapters will use
+ * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
+ *
+ * *** Determining commands per LUN ***
+ *
+ * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * own algorithm to determine the commands/LUN. If SCB paging is
+ * enabled, the commands/LUN is 8. When SCB paging is not enabled,
+ * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
+ * and 4 commands/LUN for adapters with 3 or 4 SCBs.
+ *
+ */
+/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
+
+#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+typedef struct
+{
+ char tag_commands[16]; /* Allow for wide/twin channel adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver to use it's own algorithm
+ * for determining commands/LUN (see Determining commands per LUN
+ * above).
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * Modify this as you see fit for your system. By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above). When -1, the driver will
+ * not enable tagged queueing for that particular device. When positive
+ * (> 0) the values in the array are used for the queue_depth. Note
+ * that the maximum value for an entry is 127.
+ *
+ * In this example, the first line will enable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter and tells the driver
+ * to use it's own algorithm for determining commands/LUN.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3. It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+ {DEFAULT_TAG_COMMANDS},
+ {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+#endif
+
+/*
+ * Don't define this unless you have problems with the driver
+ * interrupt handler. The old method would register the drivers
+ * interrupt handler as a "fast" type interrupt handler that would
+ * lock out other interrupts. Since this driver can spend a lot
+ * of time in the interrupt handler, this is _not_ a good idea.
+ * It also conflicts with some of the more common ethernet drivers
+ * that don't use fast interrupts. Currently, Linux does not allow
+ * IRQ sharing unless both drivers can agree on the type of interrupt
+ * handler.
+ */
+/* #define AIC7XXX_OLD_ISR_TYPE */
+
+
/*
* Controller type and options
*/
AIC_7882, /* PCI aic7882 on 3940 Ultra */
AIC_7883, /* PCI aic7883 on 3985 Ultra */
AIC_7884 /* PCI aic7884 on 294x Ultra Differential */
-} aha_type;
+} aha_chip_type;
typedef enum {
AIC_777x, /* AIC-7770 based */
- AIC_785x, /* AIC-7850 based */
+ AIC_785x, /* AIC-7850 based (3 SCBs)*/
+ AIC_786x, /* AIC-7860 based (7850 ultra) */
AIC_787x, /* AIC-7870 based */
- AIC_788x /* AIC-7880 based */
-} aha_chip_type;
+ AIC_788x /* AIC-7880 based (ultra) */
+} aha_chip_class_type;
typedef enum {
AIC_SINGLE, /* Single Channel */
* Don't forget to change this when changing the types!
*/
static const char *board_names[] = {
- "<AIC-7xxx Unknown>", /* AIC_NONE */
- "AIC-7770", /* AIC_7770 */
- "AHA-2740", /* AIC_7771 */
- "AHA-2840", /* AIC_284x */
- "AIC-7850", /* AIC_7850 */
- "AIC-7855", /* AIC_7855 */
- "AIC-7850 Ultra", /* AIC_7860 */
- "AHA-2940A Ultra", /* AIC_7861 */
- "AIC-7870", /* AIC_7870 */
- "AHA-2940", /* AIC_7871 */
- "AHA-3940", /* AIC_7872 */
- "AHA-3985", /* AIC_7873 */
- "AHA-2940 Differential", /* AIC_7874 */
- "AIC-7880 Ultra", /* AIC_7880 */
- "AHA-2940 Ultra", /* AIC_7881 */
- "AHA-3940 Ultra", /* AIC_7882 */
- "AHA-3985 Ultra", /* AIC_7883 */
- "AHA-2940 Ultra Differential" /* AIC_7884 */
+ "AIC-7xxx Unknown", /* AIC_NONE */
+ "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
+ "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
+ "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
+ "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
+ "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
+ "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
+ "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
+ "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
+ "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
+ "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
+ "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
+ "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
+ "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
+ "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
+ "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
+ "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
+ "Adaptec AHA-2944 Ultra SCSI host adapter" /* AIC_7884 */
};
/*
*/
#define DID_RETRY_COMMAND DID_ERROR
+#define HSCSIID 0x07
+#define HWSCSIID 0x0F
+#define SCSI_RESET 0x040
+
/*
* EISA/VL-bus stuff
*/
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
/*
* Standard EISA Host ID regs (Offset from slot base)
#define INTDEF 0x5C /* Interrupt Definition Register */
-/*
- * Some defines for the HCNTRL register.
- */
-#define REQ_PAUSE IRQMS | INTEN | PAUSE
-#define UNPAUSE_274X IRQMS | INTEN
-#define UNPAUSE_284X INTEN
-#define UNPAUSE_294X IRQMS | INTEN
-
/*
* AIC-78X0 PCI registers
*/
* each word, while the C56 and C66 (4096 bits) use 8 bits to
* address each word.
*/
-typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
/*
*
/*
* Host Adapter Control Bits
*/
-/* UNUSED 0x0001 */
+#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
-#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+#define CFSTERM 0x0004 /* SCSI low byte termination */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
-#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
+#define CFRESETB 0x0040 /* reset SCSI bus at boot */
/* UNUSED 0xFF80 */
unsigned short adapter_control; /* word 17 */
unsigned short checksum; /* word 31 */
};
+#define SELBUS_MASK 0x0a
+#define SELNARROW 0x00
+#define SELBUSB 0x08
+#define SINGLE_BUS 0x00
-#define SCSI_RESET 0x040
-
-/*
- * 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) \
- synchronize_irq(); \
- outb(p->pause, HCNTRL + p->base); \
- while ((inb(HCNTRL + p->base) & PAUSE) == 0) \
- ; \
-
-/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p) \
- outb(p->unpause, HCNTRL + p->base)
-
-/*
- * Restart the sequencer program from address zero
- */
-#define RESTART_SEQUENCER(p) \
- do { \
- outb(SEQRESET | FASTMODE, SEQCTL + p->base); \
- } while (inb(SEQADDR0 + p->base) != 0 && \
- inb(SEQADDR1 + p->base) != 0); \
- UNPAUSE_SEQUENCER(p);
+#define SCB_TARGET(scb) \
+ (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb) \
+ ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb) \
+ (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
/*
* If an error occurs during a data transfer phase, run the command
*/
static int aic7xxx_spurious_count;
-/*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 25 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookkeeping.
- */
-
/*
* As of Linux 2.1, the mid-level SCSI code uses virtual addresses
* in the scatter-gather lists. We need to convert the virtual
/*
* Maximum number of SG segments these cards can support.
*/
-#define MAX_SG 256
+#define AIC7XXX_MAX_SG 27
-struct aic7xxx_scb {
+/*
+ * 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 255
+
+
+struct aic7xxx_hwscb {
/* ------------ Begin hardware supported fields ---------------- */
/* 0*/ unsigned char control;
/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */
/* 2*/ unsigned char target_status;
/* 3*/ unsigned char SG_segment_count;
-/* 4*/ unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 4*/ unsigned int SG_list_pointer;
/* 8*/ unsigned char residual_SG_segment_count;
-/* 9*/ unsigned char residual_data_count[3] __attribute__ ((packed));
-/*12*/ unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/ unsigned int data_count __attribute__ ((packed)); /* must be 32 bits */
-/*20*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/* 9*/ unsigned char residual_data_count[3];
+/*12*/ unsigned int data_pointer;
+/*16*/ unsigned int data_count;
+/*20*/ unsigned int SCSI_cmd_pointer;
/*24*/ unsigned char SCSI_cmd_length;
/*25*/ u_char tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
* via PIO to initialize a transaction.
*/
-/*26*/ u_char next; /* Used to thread SCBs awaiting selection
+/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection
* or disconnected down in the sequencer.
*/
- /*-----------------end of hardware supported fields----------------*/
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- struct aic7xxx_scb *q_next; /* next scb in queue */
-#define SCB_FREE 0x00
-#define SCB_ACTIVE 0x01
-#define SCB_ABORTED 0x02
-#define SCB_DEVICE_RESET 0x04
-#define SCB_IMMED 0x08
-#define SCB_SENSE 0x10
-#define SCB_QUEUED_FOR_DONE 0x40
-#define SCB_PAGED_OUT 0x80
-#define SCB_WAITINGQ 0x100
-#define SCB_ASSIGNEDQ 0x200
-#define SCB_SENTORDEREDTAG 0x400
-#define SCB_IN_PROGRESS (SCB_ACTIVE | SCB_PAGED_OUT | \
- SCB_WAITINGQ | SCB_ASSIGNEDQ)
- int state; /* current state of scb */
- unsigned int position; /* Position in scb array */
- struct hw_scatterlist sg_list[MAX_SG]; /* SG list in adapter format */
- unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */
+/*27*/ unsigned char prev;
+/*28*/ unsigned int pad; /*
+ * Unused by the kernel, but we require
+ * the padding so that the array of
+ * hardware SCBs is alligned on 32 byte
+ * boundaries so the sequencer can index
+ */
+};
+
+typedef enum {
+ SCB_FREE = 0x0000,
+ SCB_ACTIVE = 0x0001,
+ SCB_ABORTED = 0x0002,
+ SCB_DEVICE_RESET = 0x0004,
+ SCB_SENSE = 0x0008,
+ SCB_TIMEDOUT = 0x0010,
+ SCB_QUEUED_FOR_DONE = 0x0020,
+ SCB_RECOVERY_SCB = 0x0040,
+ SCB_WAITINGQ = 0x0080,
+ SCB_ASSIGNEDQ = 0x0100,
+ SCB_SENTORDEREDTAG = 0x0200,
+ SCB_MSGOUT_SDTR = 0x0400,
+ SCB_MSGOUT_WDTR = 0x0800,
+ SCB_ABORT = 0x1000,
+ SCB_QUEUED_ABORT = 0x2000
+} scb_flag_type;
+
+struct aic7xxx_scb {
+ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+ struct aic7xxx_scb *q_next; /* next scb in queue */
+ scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char sg_count;
+ unsigned char sense_cmd[6]; /*
+ * Allocate 6 characters for
+ * sense command.
+ */
};
/*
generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
typedef struct {
+ struct aic7xxx_hwscb *hscbs;
scb_queue_type free_scbs; /*
* SCBs assigned to free slot on
* card (no paging required)
*/
- int numscbs; /* current number of scbs */
- int activescbs; /* active scbs */
-} scb_usage_type;
-
-/*
- * 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 255
+ unsigned char numscbs; /* current number of scbs */
+ unsigned char maxhscbs; /* hardware scbs */
+ unsigned char maxscbs; /* max scbs including pageable scbs */
+ struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB];
+ unsigned int reserve[100];
+} scb_data_type;
/*
* Define a structure used for each host adapter, only one per IRQ.
struct aic7xxx_host {
struct Scsi_Host *host; /* pointer to scsi host */
int host_no; /* SCSI host number */
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ int irq; /* IRQ for this adapter */
int base; /* card base address */
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
-#define A_SCANNED 0x0001
-#define B_SCANNED 0x0002
-#define EXTENDED_TRANSLATION 0x0004
-#define HAVE_SEEPROM 0x0008
-#define ULTRA_ENABLED 0x0010
-#define PAGE_ENABLED 0x0020
-#define IN_ISR 0x0040
-#define USE_DEFAULTS 0x0080
+ unsigned int mbase; /* I/O memory address */
+ volatile unsigned char *maddr; /* memory mapped address */
+#define A_SCANNED 0x0001
+#define B_SCANNED 0x0002
+#define EXTENDED_TRANSLATION 0x0004
+#define FLAGS_CHANNEL_B_PRIMARY 0x0008
+#define MULTI_CHANNEL 0x0010
+#define ULTRA_ENABLED 0x0020
+#define PAGE_ENABLED 0x0040
+#define USE_DEFAULTS 0x0080
+#define BIOS_ENABLED 0x0100
+#define IN_ISR 0x0200
+#define IN_TIMEOUT 0x0400
+#define SHARED_SCBDATA 0x0800
+#define HAVE_SEEPROM 0x1000
unsigned int flags;
unsigned int isr_count; /* Interrupt count */
unsigned short needsdtr_copy; /* default config */
unsigned short wdtr_pending;
unsigned short orderedtag;
unsigned short discenable; /* Targets allowed to disconnect */
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
+ aha_chip_type chip_type; /* card type */
+ aha_chip_class_type chip_class;
aha_bus_type bus_type; /* normal/twin/wide bus */
- char * mbase; /* I/O memory address */
- unsigned char chan_num; /* for 3940/3985, channel number */
+ unsigned char chan_num; /* for 39xx, channel number */
unsigned char unpause; /* unpause value for HCNTRL */
unsigned char pause; /* pause value for HCNTRL */
unsigned char qcntmask;
- struct seeprom_config seeprom;
+ unsigned char qfullcount;
+ unsigned char curqincnt;
struct Scsi_Host *next; /* allow for multiple IRQs */
- struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; /* active commands */
- struct aic7xxx_scb *pagedout_ntscbs[16]; /*
- * paged-out, non-tagged scbs
- * indexed by target.
- */
- scb_queue_type page_scbs; /*
- * SCBs that will require paging
- * before use (no assigned slot)
- */
+ unsigned char activescbs; /* active scbs */
scb_queue_type waiting_scbs; /*
- * SCBs waiting to be paged and
- * started.
+ * SCBs waiting for space in
+ * the QINFIFO.
*/
- scb_queue_type assigned_scbs; /*
- * SCBs that were waiting but have
- * have now been assigned a slot
- * by aic7xxx_free_scb
- */
- scb_usage_type scb_usage;
- scb_usage_type *scb_link;
+ scb_data_type *scb_data;
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
#define BUS_DEVICE_RESET_PENDING 0x02
int flags;
int commands_sent;
+ int active_cmds;
} device_status[16];
#ifdef AIC7XXX_PROC_STATS
/*
#endif /* AIC7XXX_PROC_STATS */
};
-struct aic7xxx_host_config {
- int irq; /* IRQ number */
- int mbase; /* memory base address*/
- int base; /* I/O base address*/
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
- int unpause; /* unpause value for HCNTRL */
- int pause; /* pause value for HCNTRL */
- int scsi_id; /* host SCSI ID */
- int scsi_id_b; /* host SCSI ID B channel for twin cards */
- unsigned int flags; /* used the same as struct aic7xxx_host flags */
- int chan_num; /* for 3940/3985, channel number */
- unsigned char busrtime; /* bus release time */
- unsigned char bus_speed; /* bus speed */
- unsigned char qcntmask;
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
- aha_bus_type bus_type; /* normal/twin/wide bus */
- aha_status_type bios; /* BIOS is enabled/disabled */
- aha_status_type parity; /* bus parity enabled/disabled */
- aha_status_type low_term; /* bus termination low byte */
- aha_status_type high_term; /* bus termination high byte (wide cards only) */
-};
-
/*
* Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns to the proper value to
- * stick in the scsiscfr reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
*/
static struct {
short period;
short rate;
const char *english;
} aic7xxx_syncrates[] = {
- { 50, 0x100, "20.0" },
- { 62, 0x110, "16.0" },
- { 75, 0x120, "13.4" },
- { 100, 0x000, "10.0" },
- { 125, 0x010, "8.0" },
- { 150, 0x020, "6.67" },
- { 175, 0x030, "5.7" },
- { 200, 0x040, "5.0" },
- { 225, 0x050, "4.4" },
- { 250, 0x060, "4.0" },
- { 275, 0x070, "3.6" }
+ { 12, 0x100, "20.0" },
+ { 15, 0x110, "16.0" },
+ { 18, 0x120, "13.4" },
+ { 25, 0x000, "10.0" },
+ { 31, 0x010, "8.0" },
+ { 37, 0x020, "6.67" },
+ { 43, 0x030, "5.7" },
+ { 50, 0x040, "5.0" },
+ { 56, 0x050, "4.4" },
+ { 62, 0x060, "4.0" },
+ { 68, 0x070, "3.6" }
};
static int num_aic7xxx_syncrates =
#ifdef CONFIG_PCI
static int number_of_3940s = 0;
static int number_of_3985s = 0;
-#ifdef AIC7XXX_SHARE_SCBS
-static scb_usage_type *shared_3985_scbs = NULL;
-#endif
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
#ifdef AIC7XXX_DEBUG
-static void
-debug_config(struct aic7xxx_host_config *p)
-{
- int scsi_conf;
- unsigned char brelease;
- unsigned char dfthresh;
-
- static int DFT[] = { 0, 50, 75, 100 };
- static int SST[] = { 256, 128, 64, 32 };
- static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
-
- scsi_conf = inb(SCSICONF + p->base);
-
- /*
- * Scale the Data FIFO Threshhold and the Bus Release Time; they are
- * stored in formats compatible for writing to sequencer registers.
- */
- dfthresh = p->bus_speed >> 6;
-
- if (p->chip_type == AIC_777x)
- {
- brelease = p->busrtime >> 2;
- }
- else
- {
- brelease = p->busrtime;
- }
- if (brelease == 0)
- {
- brelease = 2;
- }
-
- switch (p->type)
- {
- case AIC_7770:
- case AIC_7771:
- printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_284x:
- printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
- BUSW[p->bus_type], p->base, p->mbase);
- break;
-
- default:
- panic("aic7xxx: (debug_config) internal error.\n");
- }
-
- printk(" irq %d\n"
- " bus release time %d bclks\n"
- " data fifo threshold %d%%\n",
- p->irq,
- brelease,
- DFT[dfthresh]);
-
- printk(" SCSI CHANNEL A:\n"
- " scsi id %d\n"
- " scsi selection timeout %d ms\n"
- " scsi bus reset at power-on %sabled\n",
- scsi_conf & 0x07,
- SST[(scsi_conf >> 3) & 0x03],
- (scsi_conf & 0x40) ? "en" : "dis");
-
- if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
- {
- /*
- * Set the parity for 7770 based cards.
- */
- p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->parity != AIC_UNKNOWN)
- {
- printk(" scsi bus parity %sabled\n",
- (p->parity == AIC_ENABLED) ? "en" : "dis");
- }
-
- if ((p->type == AIC_7770) || (p->type == AIC_7771))
- {
- p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->low_term != AIC_UNKNOWN)
- {
- printk(" scsi bus termination (low byte) %sabled\n",
- (p->low_term == AIC_ENABLED) ? "en" : "dis");
- }
- if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
- {
- printk(" scsi bus termination (high byte) %sabled\n",
- (p->high_term == AIC_ENABLED) ? "en" : "dis");
- }
-}
-
#if 0
static void
debug_scb(struct aic7xxx_scb *scb)
{
- printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
- scb->control, scb->target_channel_lun, scb->SG_segment_count,
- (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
- (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
- (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
- (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
- scb->SCSI_cmd_length);
- printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
- (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
- scb->residual_SG_segment_count,
- ((scb->residual_data_count[2] << 16) |
- (scb->residual_data_count[1] << 8) |
- (scb->residual_data_count[0]));
- printk("data ptr 0x%x, data count %d, next waiting %d\n",
- (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
- (scb->data_pointer[1] << 8) | scb->data_pointer[0],
- scb->data_count, scb->next_waiting);
- printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
- (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
- scb->position);
+ struct aic7xxx_hwscb *hscb = scb->hscb;
+
+ printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
+ scb,
+ hscb->control,
+ hscb->target_channel_lun,
+ hscb->SCSI_cmd_length,
+ hscb->SCSI_cmd_pointer );
+ printk(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+ hscb->data_count,
+ hscb->data_pointer,
+ hscb->SG_segment_count,
+ hscb->SG_list_pointer);
+ printk(" sg_addr:%lx sg_len:%ld\n",
+ hscb->sg_list[0].address,
+ hscb->sg_list[0].length);
}
#endif
#else
-# define debug_config(x)
# define debug_scb(x)
#endif AIC7XXX_DEBUG
-#define TCL_OF_SCB(x) (((x)->target_channel_lun >> 4) & 0xf), \
- (((x)->target_channel_lun >> 3) & 0x01), \
- ((x)->target_channel_lun & 0x07)
+#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+ ((scb->hscb)->target_channel_lun & 0x07)
-#define TARGET_INDEX(x) ((x)->target | ((x)->channel << 3))
+#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01)
+
+#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+
+#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3))
/*
* 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?
+ * cards in the system. This should be fixed.
*/
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
* 1 use level triggered
*/
static int aic7xxx_enable_ultra = 0; /* enable ultra SCSI speeds */
+static int aic7xxx_verbose = 0; /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * These functions are not used yet, but when we do memory mapped
+ * IO, we'll use them then.
+ *
+ ***************************************************************************/
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+ if (p->maddr != NULL)
+ return (p->maddr[port]);
+ else
+ return (inb(p->base + port));
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+ if (p->maddr != NULL)
+ p->maddr[port] = val;
+ else
+ outb(val, p->base + port);
+}
+
+static inline void
+aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
+{
+ if (p->maddr != NULL)
+ {
+ __asm __volatile("
+ cld;
+ 1: lodsb;
+ movb %%al,(%0);
+ loop 1b" :
+ :
+ "r" ((p)->maddr + (port)),
+ "S" ((valp)), "c" ((size)) :
+ "%esi", "%ecx", "%eax");
+ }
+ else
+ {
+ outsb(p->base + port, valp, size);
+ }
+}
/*+F*************************************************************************
* Function:
{ "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
{ "ultra", &aic7xxx_enable_ultra },
+ { "verbose", &aic7xxx_verbose },
{ NULL, NULL }
};
/*+F*************************************************************************
* Function:
- * aic7xxx_loadseq
+ * pause_sequencer
*
* Description:
- * Load the sequencer code into the controller memory.
+ * Pause the sequencer and wait for it to actually stop - this
+ * is important since the sequencer can disable pausing for critical
+ * sections.
*-F*************************************************************************/
-static void
-aic7xxx_loadseq(int base)
+static inline void
+pause_sequencer(struct aic7xxx_host *p)
{
- 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(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
-
- outsb(SEQRAM + base, seqprog, sizeof(seqprog));
-
- /*
- * 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?)
- */
- do {
- /*
- * Actually, reset it until
- * the address shows up as
- * zero just to be safe..
- */
- outb(SEQRESET | FASTMODE, SEQCTL + base);
- } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
+ outb(p->pause, p->base + HCNTRL);
+ while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+ {
+ ;
+ }
}
/*+F*************************************************************************
* Function:
- * aic7xxx_delay
+ * unpause_sequencer
*
* Description:
- * Delay for specified amount of time.
+ * Unpause the sequencer. Unremarkable, yet done often enough to
+ * warrant an easy way to do it.
*-F*************************************************************************/
-static void
-aic7xxx_delay(int seconds)
+static inline void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
{
- unsigned long i;
-
- i = jiffies + (seconds * HZ); /* compute time to stop */
-
- while (jiffies < i)
+ if (unpause_always ||
+ ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
{
- ; /* Do nothing! */
+ outb(p->unpause, p->base + HCNTRL);
}
}
/*+F*************************************************************************
* Function:
- * rcs_version
+ * restart_sequencer
*
* Description:
- * Return a string containing just the RCS version number from either
- * an Id or Revision RCS clause.
+ * Restart the sequencer program from address zero. This assumes
+ * that the sequencer is already paused.
*-F*************************************************************************/
-static const char *
-rcs_version(const char *version_info)
+static inline void
+restart_sequencer(struct aic7xxx_host *p)
{
- static char buf[10];
- char *bp, *ep;
+ /* Set the sequencer address to 0. */
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
- bp = NULL;
- strcpy(buf, "????");
- if (!strncmp(version_info, "$Id: ", 5))
- {
- if ((bp = strchr(version_info, ' ')) != NULL)
- {
- bp++;
- if ((bp = strchr(bp, ' ')) != NULL)
- {
- bp++;
- }
- }
- }
- else
+ /*
+ * Reset and unpause the sequencer. The reset is suppose to
+ * start the sequencer running, but we do an unpause to make
+ * sure.
+ */
+ outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_next_patch
+ *
+ * Description:
+ * Find the next patch to download.
+ *-F*************************************************************************/
+static struct patch *
+aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+{
+ while (cur_patch != NULL)
{
- if (!strncmp(version_info, "$Revision: ", 11))
+ if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
+ || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
+ || (instrptr >= cur_patch->end))
{
- if ((bp = strchr(version_info, ' ')) != NULL)
+ /*
+ * Either we want to keep this section of code, or we have consumed
+ * this patch. Skip to the next patch.
+ */
+ cur_patch++;
+ if (cur_patch->options == 0)
{
- bp++;
+ /* Out of patches. */
+ cur_patch = NULL;
}
}
- }
-
- if (bp != NULL)
- {
- if ((ep = strchr(bp, ' ')) != NULL)
+ else
{
- register int len = ep - bp;
-
- strncpy(buf, bp, len);
- buf[len] = '\0';
+ /* Found an OK patch. */
+ break;
}
}
-
- return buf;
+ return (cur_patch);
}
+
/*+F*************************************************************************
* Function:
- * aic7xxx_info
+ * aic7xxx_download_instr
*
* Description:
- * Return a string describing the driver.
+ * Find the next patch to download.
*-F*************************************************************************/
-const char *
-aic7xxx_info(struct Scsi_Host *notused)
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
{
- static char buffer[128];
+ unsigned char opcode;
+ struct ins_format3 *instr;
- strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
- strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
- strcat(buffer, "/");
+ instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+ /* Pull the opcode */
+ opcode = instr->opcode_addr >> 1;
+ switch (opcode)
+ {
+ case AIC_OP_JMP:
+ case AIC_OP_JC:
+ case AIC_OP_JNC:
+ case AIC_OP_CALL:
+ case AIC_OP_JNE:
+ case AIC_OP_JNZ:
+ case AIC_OP_JE:
+ case AIC_OP_JZ:
+ {
+ int address_offset;
+ struct ins_format3 new_instr;
+ unsigned int address;
+ struct patch *patch;
+ int i;
+
+ address_offset = 0;
+ new_instr = *instr; /* Strucure copy */
+ address = new_instr.address;
+ address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+ for (i = 0; i < NUMBER(patches); i++)
+ {
+ patch = &patches[i];
+ if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
+ (((patch->options & options) != 0) && (patch->negative == TRUE)))
+ {
+ if (address >= patch->end)
+ {
+ address_offset += patch->end - patch->begin;
+ }
+ }
+ }
+ address -= address_offset;
+ new_instr.address = address &0xFF;
+ new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
+ new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ outsb(p->base + SEQRAM, &new_instr.immediate, 4);
+ break;
+ }
+
+ case AIC_OP_OR:
+ case AIC_OP_AND:
+ case AIC_OP_XOR:
+ case AIC_OP_ADD:
+ case AIC_OP_ADC:
+ case AIC_OP_ROL:
+ outsb(p->base + SEQRAM, &instr->immediate, 4);
+ break;
+
+ default:
+ panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+ break;
+ }
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_loadseq
+ *
+ * Description:
+ * Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(struct aic7xxx_host *p)
+{
+ int options;
+ struct patch *cur_patch;
+ int i;
+ int downloaded;
+
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+ }
+ options = 1; /* Code for all options. */
+ downloaded = 0;
+ if ((p->flags & ULTRA_ENABLED) != 0)
+ options |= ULTRA;
+ if (p->bus_type == AIC_TWIN)
+ options |= TWIN_CHANNEL;
+ if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+ options |= SCB_PAGING;
+
+ cur_patch = patches;
+ outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ for (i = 0; i < sizeof(seqprog) / 4; i++)
+ {
+ cur_patch = aic7xxx_next_patch(cur_patch, options, i);
+ if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+ {
+ /* Skip this instruction for this configuration. */
+ continue;
+ }
+ aic7xxx_download_instr(p, options, i);
+ downloaded++;
+ }
+
+ outb(FASTMODE, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ if (aic7xxx_verbose)
+ {
+ printk(" %d instructions downloaded\n", downloaded);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_delay
+ *
+ * Description:
+ * Delay for specified amount of time. We use udelay because the timer
+ * interrupt is not guaranteed to be enabled. This will cause an
+ * infinite loop since jiffies (clock ticks) is not updated.
+ *-F*************************************************************************/
+static void
+aic7xxx_delay(int seconds)
+{
+ int i;
+
+ /*
+ * Call udelay() for 1 millisecond inside a loop for
+ * the requested amount of seconds.
+ */
+ for (i=0; i < seconds*1000; i++)
+ {
+ udelay(1000); /* Delay for 1 millisecond. */
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * rcs_version
+ *
+ * Description:
+ * Return a string containing just the RCS version number from either
+ * an Id or Revision RCS clause.
+ *-F*************************************************************************/
+const char *
+rcs_version(const char *version_info)
+{
+ static char buf[10];
+ char *bp, *ep;
+
+ bp = NULL;
+ strcpy(buf, "????");
+ if (!strncmp(version_info, "$Id: ", 5))
+ {
+ if ((bp = strchr(version_info, ' ')) != NULL)
+ {
+ bp++;
+ if ((bp = strchr(bp, ' ')) != NULL)
+ {
+ bp++;
+ }
+ }
+ }
+ else
+ {
+ if (!strncmp(version_info, "$Revision: ", 11))
+ {
+ if ((bp = strchr(version_info, ' ')) != NULL)
+ {
+ bp++;
+ }
+ }
+ }
+
+ if (bp != NULL)
+ {
+ if ((ep = strchr(bp, ' ')) != NULL)
+ {
+ register int len = ep - bp;
+
+ strncpy(buf, bp, len);
+ buf[len] = '\0';
+ }
+ }
+
+ return buf;
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_info
+ *
+ * Description:
+ * Return a string describing the driver.
+ *-F*************************************************************************/
+const char *
+aic7xxx_info(struct Scsi_Host *notused)
+{
+ static char buffer[128];
+
+ strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+ strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
+ strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+#if 0
strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
+#endif
return buffer;
}
* aic7xxx_length
*
* Description:
- * 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.
+ * How much data should be transferred for this SCSI command? Assume
+ * all segments are to be transferred except for the last sg_last
+ * segments. This will allow us to compute underflow easily. To
+ * calculate the total length of the command, use sg_last = 0. To
+ * calculate the length of all but the last 2 SG segments, use
+ * sg_last = 2.
*-F*************************************************************************/
static unsigned
aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
if (cmd->use_sg)
{
- for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
+ for (i = length = 0; i < segments; i++)
{
length += sg[i].length;
}
*-F*************************************************************************/
static void
aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
- short period, unsigned char offset, int target, char channel)
+ unsigned char *period, unsigned char *offset, int target, char channel)
{
- int i;
+ int i = num_aic7xxx_syncrates;
unsigned long ultra_enb_addr;
unsigned char ultra_enb, sxfrctl0;
* If the offset is 0, then the device is requesting asynchronous
* transfers.
*/
- if (offset != 0)
+ if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
{
for (i = 0; i < num_aic7xxx_syncrates; i++)
{
- if ((aic7xxx_syncrates[i].period - period) >= 0)
+ if (*period <= aic7xxx_syncrates[i].period)
{
/*
* Watch out for Ultra speeds when ultra is not enabled and
*/
continue;
}
- *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+ *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
+ *period = aic7xxx_syncrates[i].period;
- /*
- * Ensure Ultra mode is set properly for this target.
- */
- ultra_enb_addr = ULTRA_ENB;
- if ((channel == 'B') || (target > 7))
- {
- ultra_enb_addr++;
- }
- ultra_enb = inb(p->base + ultra_enb_addr);
- sxfrctl0 = inb(p->base + SXFRCTL0);
- if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+ if (aic7xxx_verbose)
{
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= ULTRAEN;
+ printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+ "offset %d.\n", p->host_no, target, channel,
+ aic7xxx_syncrates[i].english, *offset);
}
- else
- {
- ultra_enb &= ~(0x01 << (target & 0x07));
- sxfrctl0 &= ~ULTRAEN;
- }
- outb(ultra_enb, p->base + ultra_enb_addr);
- outb(sxfrctl0, p->base + SXFRCTL0);
-
- printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
- "offset %d.\n", p->host_no, target, channel,
- aic7xxx_syncrates[i].english, offset);
- return;
+ break;
}
}
}
- /*
- * Default to asynchronous transfer
- */
- *scsirate = 0;
- printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
- p->host_no, target, channel);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_putscb
- *
- * Description:
- * Transfer a SCB to the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- outb(SCBAUTO, SCBCNT + base);
+ if (i >= num_aic7xxx_syncrates)
+ {
+ /*
+ * Use asynchronous transfers.
+ */
+ *scsirate = 0;
+ *period = 0;
+ *offset = 0;
+ if (aic7xxx_verbose)
+ {
+ printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+ p->host_no, target, channel);
+ }
+ }
/*
- * 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.
- *
- * We can do 16bit transfers on all but 284x.
+ * Ensure Ultra mode is set properly for this target.
*/
- if (p->type == AIC_284x)
+ ultra_enb_addr = ULTRA_ENB;
+ if ((channel == 'B') || (target > 7))
{
- outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+ ultra_enb_addr++;
+ }
+ ultra_enb = inb(p->base + ultra_enb_addr);
+ sxfrctl0 = inb(p->base + SXFRCTL0);
+ if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
+ {
+ ultra_enb |= 0x01 << (target & 0x07);
+ sxfrctl0 |= FAST20;
}
else
{
- outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+ ultra_enb &= ~(0x01 << (target & 0x07));
+ sxfrctl0 &= ~FAST20;
}
-
- outb(0, SCBCNT + base);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_getscb
- *
- * Description:
- * Get a SCB from the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- /*
- * This is almost identical to aic7xxx_putscb().
- */
- outb(SCBAUTO, SCBCNT + base);
- insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
- outb(0, SCBCNT + base);
+ outb(ultra_enb, p->base + ultra_enb_addr);
+ outb(sxfrctl0, p->base + SXFRCTL0);
}
/*+F*************************************************************************
queue->tail = NULL;
}
+/*+F*************************************************************************
+ * Function:
+ * scbq_remove
+ *
+ * Description:
+ * Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+ if (queue->head == scb)
+ {
+ /* At beginning of queue, remove from head. */
+ scbq_remove_head(queue);
+ }
+ else
+ {
+ struct aic7xxx_scb *curscb = queue->head;
+
+ /*
+ * Search until the next scb is the one we're looking for, or
+ * we run out of queue.
+ */
+ while ((curscb != NULL) && (curscb->q_next != scb))
+ {
+ curscb = curscb->q_next;
+ }
+ if (curscb != NULL)
+ {
+ /* Found it. */
+ curscb->q_next = scb->q_next;
+ if (scb->q_next == NULL)
+ {
+ /* Update the tail when removing the tail. */
+ queue->tail = curscb;
+ }
+ }
+ }
+}
+
/*+F*************************************************************************
* Function:
* scbq_insert_tail
* to be reset and all devices on that channel must be aborted.
*-F*************************************************************************/
static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
+ int lun, unsigned char tag)
{
- int targ = (scb->target_channel_lun >> 4) & 0x0F;
- char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+ char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int slun = scb->hscb->target_channel_lun & 0x07;
+ int match;
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
- target, channel, targ, chan);
+ printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
+ scb->cmd->device->host->host_no, target, channel, targ, chan);
#endif
- if (target == ALL_TARGETS)
+ match = ((chan == channel) || (channel == ALL_CHANNELS));
+ if (match != 0)
+ match = ((targ == target) || (target == ALL_TARGETS));
+ if (match != 0)
+ match = ((lun == slun) || (lun == ALL_LUNS));
+ if (match != 0)
+ match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+ return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ * Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+ /*
+ * Invalidate the tag so that aic7xxx_find_scb doesn't think
+ * it's active
+ */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG);
+
+ outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
+ outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ * Removes the current SCB from the disconnected list and adds it
+ * to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+{
+ unsigned char next;
+ unsigned char prev;
+
+ outb(scbptr, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
+ prev = inb(p->base + SCB_PREV);
+
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
+
+ if (prev != SCB_LIST_NULL)
{
- return (chan == channel);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
else
{
- return ((chan == channel) && (targ == target));
+ outb(next, p->base + DISCONNECTED_SCBH);
+ }
+
+ if (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ outb(prev, p->base + SCB_PREV);
}
+ return next;
}
/*+F*************************************************************************
* aic7xxx_busy_target
*
* Description:
- * Set the specified target active.
+ * Set the specified target busy.
*-F*************************************************************************/
static void
-aic7xxx_busy_target(unsigned char target, char channel, int base)
+aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, unsigned char scbid)
+{
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
+
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ outb(scbid, p->base + scb_offset);
+ outb(active_scb, p->base + SCBPTR);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_index_busy_target
+ *
+ * Description:
+ * Returns the index of the busy target, and optionally sets the
+ * target inactive.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, int unbusy)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned char busy_scbid;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
- if ((target > 0x07) || (channel == 'B'))
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ busy_scbid = inb(p->base + scb_offset);
+ if (unbusy)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(SCB_LIST_NULL, p->base + scb_offset);
}
- active = inb(active_port);
- active |= (0x01 << (target & 0x07));
- outb(active, active_port);
+ outb(active_scb, p->base + SCBPTR);
+ return (busy_scbid);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_unbusy_target
+ * aic7xxx_find_scb
*
* Description:
- * Set the specified target inactive.
+ * Look through the SCB array of the card and attempt to find the
+ * hardware SCB that corresponds to the passed in SCB. Return
+ * SCB_LIST_NULL if unsuccessful. This routine assumes that the
+ * card is already paused.
*-F*************************************************************************/
-static void
-aic7xxx_unbusy_target(unsigned char target, char channel, int base)
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char saved_scbptr;
+ unsigned char curindex;
- if ((target > 0x07) || (channel == 'B'))
+ saved_scbptr = inb(p->base + SCBPTR);
+ curindex = 0;
+ for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(curindex, p->base + SCBPTR);
+ if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+ {
+ break;
+ }
+ }
+ outb(saved_scbptr, p->base + SCBPTR);
+ if (curindex >= p->scb_data->maxhscbs)
+ {
+ curindex = SCB_LIST_NULL;
}
- active = inb(active_port);
- active &= ~(0x01 << (target & 0x07));
- outb(active, active_port);
+
+ return (curindex);
}
/*+F*************************************************************************
* aic7xxx_allocate_scb
*
* Description:
- * Get a free SCB either from one already assigned to a hardware
- * slot, or one that will require an SCB to be paged out before
- * use. If there are none, attempt to allocate a new one.
+ * Get an SCB from the free list or by allocating a new one.
*-F*************************************************************************/
static struct aic7xxx_scb *
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
- struct aic7xxx_scb *scbp = NULL;
- int maxscbs;
+ struct aic7xxx_scb *scbp = NULL;
+ struct aic7xxx_hwscb *hscbp = NULL;
+#ifdef AGRESSIVE
+ long processor_flags;
+
+ save_flags(processor_flags);
+ cli();
+#endif
- scbp = p->scb_link->free_scbs.head;
+ scbp = p->scb_data->free_scbs.head;
if (scbp != NULL)
{
- scbq_remove_head(&p->scb_link->free_scbs);
+ scbq_remove_head(&p->scb_data->free_scbs);
}
else
{
- /*
- * This should always be NULL if paging is not enabled.
- */
- scbp = p->page_scbs.head;
- if (scbp != NULL)
- {
- scbq_remove_head(&p->page_scbs);
- }
- else
+ if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
- /*
- * Set limit the SCB allocation to the maximum number of
- * hardware SCBs if paging is not enabled; otherwise use
- * the maximum (255).
- */
- if (p->flags & PAGE_ENABLED)
- maxscbs = p->maxscbs;
- else
- maxscbs = p->maxhscbs;
- if (p->scb_link->numscbs < maxscbs)
- {
- int scb_index = p->scb_link->numscbs;
- int scb_size = sizeof(struct aic7xxx_scb);
+ int scb_index = p->scb_data->numscbs;
+ int scb_size = sizeof(struct aic7xxx_scb) +
+ sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
- p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
- scbp = (p->scb_array[scb_index]);
- if (scbp != NULL)
- {
- memset(scbp, 0, sizeof(*scbp));
- scbp->tag = scb_index;
- if (scb_index < p->maxhscbs)
- scbp->position = scb_index;
- else
- scbp->position = SCB_LIST_NULL;
- p->scb_link->numscbs++;
- }
+ scbp = kmalloc(scb_size, GFP_ATOMIC);
+ if (scbp != NULL)
+ {
+ memset(scbp, 0, sizeof(struct aic7xxx_scb));
+ hscbp = &p->scb_data->hscbs[scb_index];
+ scbp->hscb = hscbp;
+ scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
+ memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
+ hscbp->tag = scb_index;
+ p->scb_data->numscbs++;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[scb_index] = scbp;
}
}
}
+#ifdef AIC7XXX_DEBUG
if (scbp != NULL)
{
-#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs++;
-#endif
+ p->activescbs++;
}
+#endif
+
+#ifdef AGRESSIVE
+ restore_flags(processor_flags);
+#endif
return (scbp);
}
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
+ p->device_status[TARGET_INDEX(cmd)].active_cmds--;
cmd->scsi_done(cmd);
}
p->completeq.tail = NULL;
* aic7xxx_free_scb
*
* Description:
- * Free the scb and update the page, waiting, free scb lists.
+ * Free the scb and insert into the free scb list.
*-F*************************************************************************/
static void
aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_scb *wscb;
+ struct aic7xxx_hwscb *hscb;
+ long flags;
- scb->state = SCB_FREE;
+ hscb = scb->hscb;
+ save_flags(flags);
+ cli();
+
+ scb->flags = SCB_FREE;
scb->cmd = NULL;
- scb->control = 0;
- scb->state = 0;
+ hscb->control = 0;
+ hscb->target_status = 0;
- if (scb->position == SCB_LIST_NULL)
- {
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- /*
- * If there are any SCBS on the waiting queue, assign the slot of this
- * "freed" SCB to the first one. We'll run the waiting queues after
- * all command completes for a particular interrupt are completed or
- * when we start another command.
- */
- wscb = p->waiting_scbs.head;
- if (wscb != NULL)
- {
- scbq_remove_head(&p->waiting_scbs);
- wscb->position = scb->position;
- scbq_insert_tail(&p->assigned_scbs, wscb);
- wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
-
- /*
- * The "freed" SCB will need to be assigned a slot before being
- * used, so put it in the page_scbs queue.
- */
- scb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- scbq_insert_head(&p->scb_link->free_scbs, scb);
- }
+ scbq_insert_head(&p->scb_data->free_scbs, scb);
#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs--; /* For debugging purposes. */
+ p->activescbs--; /* For debugging purposes. */
#endif
- }
+
+ restore_flags(flags);
}
/*+F*************************************************************************
{
Scsi_Cmnd *cmd = scb->cmd;
+ if (scb->flags & SCB_RECOVERY_SCB)
+ {
+ p->flags &= ~IN_TIMEOUT;
+ }
+ if (cmd->result == DID_OK)
+ {
+ if (scb->flags & SCB_ABORTED)
+ {
+ cmd->result = (DID_RESET << 16);
+ }
+ }
+ if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+ {
+ unsigned short mask;
+
+ mask = 0x01 << TARGET_INDEX(scb->cmd);
+ if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ p->wdtr_pending &= ~mask;
+ }
+ if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ p->sdtr_pending &= ~mask;
+ }
+ }
aic7xxx_free_scb(p, scb);
aic7xxx_queue_cmd_complete(p, cmd);
+#ifdef AIC7XXX_PROC_STATS
+ {
+ int actual;
+
+ /*
+ * XXX: we should actually know how much actually transferred
+ * XXX: for each command, but apparently that's too difficult.
+ */
+ actual = aic7xxx_length(cmd, 0);
+ if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
+ && (aic7xxx_error(cmd) == 0))
+ {
+ struct aic7xxx_xferstats *sp;
+ long *ptr;
+ int x;
+
+ sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+ sp->xfers++;
+
+ if (cmd->request.cmd == WRITE)
+ {
+ sp->w_total++;
+ sp->w_total512 += (actual >> 9);
+ ptr = sp->w_bins;
+ }
+ else
+ {
+ sp->r_total++;
+ sp->r_total512 += (actual >> 9);
+ ptr = sp->r_bins;
+ }
+ for (x = 9; x <= 17; x++)
+ {
+ if (actual < (1 << x))
+ {
+ ptr[x - 9]++;
+ break;
+ }
+ }
+ if (x > 17)
+ {
+ ptr[x - 9]++;
+ }
+ }
+ }
+#endif /* AIC7XXX_PROC_STATS */
}
/*+F*************************************************************************
* Function:
- * aic7xxx_done_aborted_scbs
+ * aic7xxx_run_done_queue
*
* Description:
- * Calls the scsi_done() for the Scsi_Cmnd of each scb in the
- * aborted list, and adds each scb to the free list.
+ * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ * aborted list, and adds each scb to the free list. If complete
+ * is TRUE, we also process the commands complete list.
*-F*************************************************************************/
static void
-aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
{
- Scsi_Cmnd *cmd;
struct aic7xxx_scb *scb;
int i;
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if (scb->state & SCB_QUEUED_FOR_DONE)
+ scb = p->scb_data->scb_array[i];
+ if (scb->flags & SCB_QUEUED_FOR_DONE)
{
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ printk("(scsi%d:%d:%d) Aborting scb %d\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
#endif
- /*
- * Process the command after marking the scb as free
- * and adding it to the free list.
- */
- cmd = scb->cmd;
- p->device_status[TARGET_INDEX(cmd)].flags = 0;
- aic7xxx_free_scb(p, scb);
- cmd->scsi_done(cmd); /* call the done function */
+ aic7xxx_done(p, scb);
}
}
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_add_waiting_scb
- *
- * Description:
- * Add this SCB to the head of the "waiting for selection" list.
- *-F*************************************************************************/
-static void
-aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
-{
- unsigned char next;
- unsigned char curscb;
-
- curscb = inb(SCBPTR + base);
- next = inb(WAITING_SCBH + base);
-
- outb(scb->position, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- outb(scb->position, WAITING_SCBH + base);
-
- outb(curscb, SCBPTR + base);
+ if (complete)
+ {
+ aic7xxx_done_cmds_complete(p);
+ }
}
/*+F*************************************************************************
*-F*************************************************************************/
static unsigned char
aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
- unsigned char prev)
+ unsigned char scbpos, unsigned char prev)
{
unsigned char curscb, next;
- int target = (scb->target_channel_lun >> 4) & 0x0F;
- char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
- int base = p->base;
/*
* Select the SCB we want to abort and pull the next pointer out of it.
*/
- curscb = inb(SCBPTR + base);
- outb(scb->position, SCBPTR + base);
- next = inb(SCB_NEXT + base);
+ curscb = inb(p->base + SCBPTR);
+ outb(scbpos, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
/*
* Clear the necessary fields
*/
- outb(0, SCB_CONTROL + base);
- outb(SCB_LIST_NULL, SCB_NEXT + base);
- aic7xxx_unbusy_target(target, channel, base);
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
/*
* Update the waiting list
/*
* First in the list
*/
- outb(next, WAITING_SCBH + base);
+ outb(next, p->base + WAITING_SCBH);
}
else
{
/*
* Select the scb that pointed to us and update its next pointer.
*/
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
/*
* Point us back at the original scb position and inform the SCSI
* system that the command has been aborted.
*/
- outb(curscb, SCBPTR + base);
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ outb(curscb, p->base + SCBPTR);
+ scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scb->flags &= ~SCB_ACTIVE;
scb->cmd->result = (DID_RESET << 16);
return (next);
}
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_search_qinfifo
+ *
+ * Description:
+ * Search the queue-in FIFO for matching SCBs and conditionally
+ * requeue. Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag, int flags, int requeue)
+{
+ unsigned char saved_queue[AIC7XXX_MAXSCB];
+ int queued = inb(p->base + QINCNT) & p->qcntmask;
+ int i;
+ int found;
+ struct aic7xxx_scb *scbp;
+ scb_queue_type removed_scbs;
+
+ found = 0;
+ scbq_init (&removed_scbs);
+ for (i = 0; i < (queued - found); i++)
+ {
+ saved_queue[i] = inb(p->base + QINFIFO);
+ scbp = p->scb_data->scb_array[saved_queue[i]];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ /*
+ * We found an scb that needs to be removed.
+ */
+ if (requeue)
+ {
+ scbq_insert_head(&removed_scbs, scbp);
+ }
+ else
+ {
+ scbp->flags = flags;
+ scbp->flags &= ~SCB_ACTIVE;
+ /*
+ * XXX - Don't know what error to use here.
+ */
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+ }
+ i--;
+ found++;
+ }
+ }
+ /* Now put the saved scbs back. */
+ for (queued = 0; queued < i; queued++)
+ outb(saved_queue[queued], p->base + QINFIFO);
+
+ if (requeue)
+ {
+ scbp = removed_scbs.head;
+ while (scbp != NULL)
+ {
+ scbq_remove_head(&removed_scbs);
+ /*
+ * XXX - Shouldn't we be adding this to the free list?
+ */
+ scbq_insert_head(&p->waiting_scbs, scbp);
+ scbp->flags |= SCB_WAITINGQ;
+ scbp = removed_scbs.head;
+ }
+ }
+
+ return (found);
+}
+
/*+F*************************************************************************
* Function:
* aic7xxx_reset_device
* all active and queued scbs for that target/channel.
*-F*************************************************************************/
static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag)
{
- int base = p->base;
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scbp;
unsigned char active_scb;
int i = 0;
- int found = 0;
+ int found;
/*
* Restore this when we're done
*/
- active_scb = inb(SCBPTR + base);
+ active_scb = inb(p->base + SCBPTR);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
- target, channel, active_scb);
+ printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
+ p->host_no, target, CHAN_TO_INT(channel), active_scb);
#endif
+
/*
- * Search the QINFIFO.
+ * Deal with the busy target and linked next issues.
*/
{
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
+ int min_target, max_target;
+ unsigned char busy_scbid;
- for (i = 0; i < (queued - found); i++)
+ /* Make all targets 'relative' to bus A. */
+ if (target == ALL_TARGETS)
{
- saved_queue[i] = inb(QINFIFO + base);
- outb(saved_queue[i], SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- if (aic7xxx_match_scb(scb, target, channel))
+ switch (channel)
{
- /*
- * We found an scb that needs to be aborted.
- */
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
- saved_queue[i], TCL_OF_SCB(scb));
-#endif
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- outb(0, SCB_CONTROL + base);
- i--;
- found++;
+ case 'A':
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
+ case 'B':
+ min_target = 8;
+ max_target = 15;
+ break;
+ case ALL_CHANNELS:
+ default:
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
}
}
- /*
- * Now put the saved scbs back.
- */
- for (queued = 0; queued < i; queued++)
+ else
+ {
+ min_target = target + channel == 'B' ? 8 : 0;
+ max_target = min_target;
+ }
+
+ for (i = min_target; i <= max_target; i++)
{
- outb(saved_queue[queued], QINFIFO + base);
+ busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
+ if (busy_scbid < p->scb_data->numscbs)
+ {
+ struct aic7xxx_scb *busy_scb;
+ struct aic7xxx_scb *next_scb;
+ unsigned char next_scbid;
+
+ busy_scb = p->scb_data->scb_array[busy_scbid];
+
+ next_scbid = busy_scb->hscb->data_count >> 24;
+
+ if (next_scbid == SCB_LIST_NULL)
+ {
+ busy_scbid = aic7xxx_find_scb(p, busy_scb);
+
+ if (busy_scbid != SCB_LIST_NULL)
+ {
+ outb(busy_scbid, p->base + SCBPTR);
+ next_scbid = inb(p->base + SCB_LINKED_NEXT);
+ }
+ }
+
+ if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+ {
+ aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
+ }
+
+ if (next_scbid != SCB_LIST_NULL)
+ {
+ next_scb = p->scb_data->scb_array[next_scbid];
+ if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ continue;
+ }
+ /* Requeue for later processing */
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
}
}
+ found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+ SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
+
/*
* Search waiting for selection list.
*/
{
- unsigned char next, prev;
+ unsigned char next, prev, scb_index;
- next = inb(WAITING_SCBH + base); /* Start at head of list. */
+ next = inb(p->base + WAITING_SCBH); /* Start at head of list. */
prev = SCB_LIST_NULL;
while (next != SCB_LIST_NULL)
{
- outb(next, SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- /*
- * Select the SCB.
- */
- if (aic7xxx_match_scb(scb, target, channel))
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index >= p->scb_data->numscbs)
{
- next = aic7xxx_abort_waiting_scb(p, scb, prev);
+ panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
+ scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ unsigned char linked_next;
+
+ next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ if (linked_next != SCB_LIST_NULL)
+ {
+ struct aic7xxx_scb *next_scb;
+ /*
+ * Requeue the waiting SCB via the waiting list.
+ */
+ next_scb = p->scb_data->scb_array[linked_next];
+ if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
found++;
}
else
{
prev = next;
- next = inb(SCB_NEXT + base);
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through disconnected list and remove any entries we have queued
+ * for completion, zeroing their control byte too.
+ */
+ {
+ unsigned char next, prev, scb_index;
+
+ next = inb(p->base + DISCONNECTED_SCBH);
+ prev = SCB_LIST_NULL;
+
+ while (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index > p->scb_data->numscbs)
+ {
+ panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
+ "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ next = aic7xxx_rem_scb_from_disc_list(p, next);
+ }
+ else
+ {
+ prev = next;
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through the hardware SCB array looking for commands that
+ * were active but not on any list.
+ */
+ for (i = 0; i < p->scb_data->maxhscbs; i++)
+ {
+ unsigned char scbid;
+
+ outb(i, p->base + SCBPTR);
+ scbid = inb(p->base + SCB_TAG);
+ if (scbid < p->scb_data->numscbs)
+ {
+ scbp = p->scb_data->scb_array[scbid];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ aic7xxx_add_curscb_to_free_list(p);
}
}
}
/*
* Go through the entire SCB array now and look for commands for
- * for this target that are active. These are other (most likely
+ * for this target that are stillactive. These are other (most likely
* tagged) commands that were disconnected when the reset occurred.
*/
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
+ scbp = p->scb_data->scb_array[i];
+ if (((scbp->flags & SCB_ACTIVE) != 0) &&
+ aic7xxx_match_scb(scbp, target, channel, lun, tag))
{
- /*
- * Ensure the target is "free"
- */
- aic7xxx_unbusy_target(target, channel, base);
- if (! (scb->state & SCB_PAGED_OUT))
+ scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scbp->flags &= ~SCB_ACTIVE;
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+
+ found++;
+
+ if ((scbp->flags & SCB_WAITINGQ) != 0)
{
- outb(scb->position, SCBPTR + base);
- outb(0, SCB_CONTROL + base);
+ scbq_remove(&p->waiting_scbs, scbp);
+ scbp->flags &= ~SCB_WAITINGQ;
}
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- found++;
}
}
- outb(active_scb, SCBPTR + base);
+ outb(active_scb, p->base + SCBPTR);
return (found);
}
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_clear_intstat
+ *
+ * Description:
+ * Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+ /* Clear any interrupt conditions this may have caused. */
+ outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
+ outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+ CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+}
+
/*+F*************************************************************************
* Function:
* aic7xxx_reset_current_bus
* Reset the current SCSI bus.
*-F*************************************************************************/
static void
-aic7xxx_reset_current_bus(int base)
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
{
- outb(SCSIRSTO, SCSISEQ + base);
+ unsigned char scsiseq;
+
+ /* Disable reset interrupts. */
+ outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+
+ /* Turn on the bus reset. */
+ scsiseq = inb(p->base + SCSISEQ);
+ outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+
+ udelay(1000);
+
+ /* Turn off the bus reset. */
+ outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+
+ aic7xxx_clear_intstat(p);
+
+ /* Re-enable reset interrupts. */
+ outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+
udelay(1000);
- outb(0, SCSISEQ + base);
}
/*+F*************************************************************************
static int
aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
{
- int base = p->base;
- unsigned char sblkctl;
- char cur_channel;
unsigned long offset, offset_max;
int found;
+ unsigned char sblkctl;
+ char cur_channel;
+ pause_sequencer(p);
/*
- * Clean up all the state information for the
- * pending transactions on this bus.
+ * Clean up all the state information for the pending transactions
+ * on this bus.
*/
- found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
+ found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
if (channel == 'B')
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
p->sdtr_pending &= 0x00FF;
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base + 8;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH + 8;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
p->needwdtr = p->needwdtr_copy;
p->sdtr_pending = 0x0;
p->wdtr_pending = 0x0;
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
+ /* Channel A */
p->needsdtr |= (p->needsdtr_copy & 0x00FF);
p->sdtr_pending &= 0xFF00;
- outb(0, ACTIVE_A + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 8;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 8;
}
}
+
while (offset < offset_max)
{
/*
- * Revert to async/narrow transfers
- * until we renegotiate.
+ * Revert to async/narrow transfers until we renegotiate.
*/
u_char targ_scratch;
- targ_scratch = inb(offset);
+
+ targ_scratch = inb(p->base + offset);
targ_scratch &= SXFR;
- outb(targ_scratch, offset);
+ outb(targ_scratch, p->base + offset);
offset++;
}
/*
* Reset the bus and unpause/restart the controller
*/
-
- /*
- * Case 1: Command for another bus is active
- */
- sblkctl = inb(SBLKCTL + base);
+ sblkctl = inb(p->base + SBLKCTL);
cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
if (cur_channel != channel)
{
+ /*
+ * Case 1: Command for another bus is active
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
- channel);
+ printk("scsi%d: Stealthily resetting channel %c\n",
+ p->host_no, channel);
#endif
/*
- * Stealthily reset the other bus without upsetting the current bus
+ * Stealthily reset the other bus without upsetting the current bus.
*/
- outb(sblkctl ^ SELBUSB, SBLKCTL + base);
+ outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- outb(sblkctl, SBLKCTL + base);
-
- UNPAUSE_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ outb(sblkctl, p->base + SBLKCTL);
+ unpause_sequencer(p, /* unpause_always */ FALSE);
}
- /*
- * Case 2: A command from this bus is active or we're idle
- */
else
{
+ /*
+ * Case 2: A command from this bus is active or we're idle.
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
- channel);
+ printk("scsi%d: Resetting current channel %c\n",
+ p->host_no, channel);
#endif
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+#if 0
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+#endif
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- RESTART_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ restart_sequencer(p);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+ printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
#endif
}
- /*
- * Cause the mid-level SCSI code to delay any further
- * queueing by the bus settle time for us.
- */
- p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-
/*
* Now loop through all the SCBs that have been marked for abortion,
* and call the scsi_done routines.
*/
- aic7xxx_done_aborted_scbs(p);
- return found;
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ return (found);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_page_scb
+ * aic7xxx_run_waiting_queues
*
* Description:
- * Swap in_scbp for out_scbp down in the cards SCB array.
- * We assume that the SCB for out_scbp is already selected in SCBPTR.
- *
+ * Scan the awaiting_scbs queue downloading and starting as many
+ * scbs as we can.
*-F*************************************************************************/
static inline void
-aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
- struct aic7xxx_scb *in_scbp)
+aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
{
- int index;
+ struct aic7xxx_scb *scb;
- /* Page-out */
-#if 0
-printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
- out_scbp->cmd->target, in_scbp->cmd->target);
-#endif
- aic7xxx_getscb(p, out_scbp);
- out_scbp->state |= SCB_PAGED_OUT;
- if (!(out_scbp->control & TAG_ENB))
- {
- /* Stick in non-tagged array */
- index = (out_scbp->target_channel_lun >> 4) |
- (out_scbp->target_channel_lun & SELBUSB);
- p->pagedout_ntscbs[index] = out_scbp;
- }
-
- /* Page-in */
- in_scbp->position = out_scbp->position;
- out_scbp->position = SCB_LIST_NULL;
- aic7xxx_putscb(p, in_scbp);
- in_scbp->state &= ~SCB_PAGED_OUT;
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_run_waiting_queues
- *
- * Description:
- * Scan the assigned_scbs and waiting_scbs queues. For scbs in the
- * assigned_scbs queue, we download and start them. For scbs in the
- * waiting_scbs queue, we page in as many as we can being careful
- * not to cause a deadlock for a reconnecting target.
- *
- *-F*************************************************************************/
-static inline void
-aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
-{
- struct aic7xxx_scb *scb;
- u_char cur_scb, intstat;
- u_long base = p->base;
- long flags;
-
- if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
- return;
-
- save_flags(flags);
- cli();
-
- PAUSE_SEQUENCER(p);
- cur_scb = inb(SCBPTR + base);
- intstat = inb(INTSTAT + base);
+ if (p->waiting_scbs.head == NULL)
+ return;
+ pause_sequencer(p);
/*
* First handle SCBs that are waiting but have been assigned a slot.
*/
- scb = p->assigned_scbs.head;
- while (scb != NULL)
- {
- scbq_remove_head(&(p->assigned_scbs));
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
- outb(scb->position, QINFIFO + base);
- scb = p->assigned_scbs.head;
- }
-
- /* Now deal with SCBs that require paging. */
scb = p->waiting_scbs.head;
- if (scb != NULL)
+ while (scb != NULL)
{
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
- int count = 0;
- u_char next_scb;
-
- while (scb != NULL)
+ if (p->curqincnt >= p->qfullcount)
{
- /* Attempt to page this SCB in */
- if (disc_scb == SCB_LIST_NULL)
- break;
-
- /*
- * Advance disc_scb to the next one in the list.
- */
- outb(disc_scb, SCBPTR + base);
- next_scb = inb(SCB_NEXT + base);
-
- /*
- * We have to be careful about when we allow an SCB to be paged out.
- * There must always be at least one slot availible for a reconnecting
- * target in case it references an SCB that has been paged out. Our
- * heuristic is that either the disconnected list has at least two
- * entries in it or there is one entry and the sequencer is activily
- * working on an SCB which implies that it will either complete or
- * disconnect before another reconnection can occur.
- */
- if ((next_scb != SCB_LIST_NULL) || active)
+ p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
+ if (p->curqincnt >= p->qfullcount)
{
- u_char out_scbi;
- struct aic7xxx_scb *out_scbp;
-
- scbq_remove_head(&(p->waiting_scbs));
-
- /*
- * Find the in-core SCB for the one we're paging out.
- */
- out_scbi = inb(SCB_TAG + base);
- out_scbp = (p->scb_array[out_scbi]);
-
- /* Do the page out and mark the paged in SCB as active. */
- aic7xxx_page_scb(p, out_scbp, scb);
-
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
-
- /* Queue the command */
- outb(scb->position, QINFIFO + base);
- count++;
-
- /* Advance to the next disconnected SCB */
- disc_scb = next_scb;
- scb = p->waiting_scbs.head;
+ break;
}
- else
- scb = NULL;
}
- if (count)
+ /*
+ * We have some space.
+ */
+ scbq_remove_head(&(p->waiting_scbs));
+ scb->flags &= ~SCB_WAITINGQ;
+
+ outb(scb->hscb->tag, p->base + QINFIFO);
+
+ if ((p->flags & PAGE_ENABLED) != 0)
{
- /*
- * Update the head of the disconnected list.
+ /*
+ * We only care about this statistic when paging
+ * since it's impossible to overflow the qinfifo
+ * in the non-paging case.
*/
- outb(disc_scb, DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
- {
- outb(disc_scb, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- }
+ p->curqincnt++;
}
+ scb = p->waiting_scbs.head;
}
- /* Restore old position */
- outb(cur_scb, SCBPTR + base);
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
+ unpause_sequencer(p, FALSE);
+}
- restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_construct_sdtr
+ *
+ * Description:
+ * Constucts a synchronous data transfer message in the message
+ * buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char period, unsigned char offset)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_SDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(period, p->base + MSG_OUT + 3 + start_byte);
+ outb(offset, p->base + MSG_OUT + 4 + start_byte);
+ outb(start_byte + 5, p->base + MSG_LEN);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_isr
+ * aic7xxx_construct_wdtr
*
* Description:
- * SCSI controller interrupt handler.
+ * Constucts a wide data transfer message in the message buffer
+ * on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char bus_width)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_WDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(bus_width, p->base + MSG_OUT + 3 + start_byte);
+ outb(start_byte + 4, p->base + MSG_LEN);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_calc_residual
*
- * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- * be disabled all through this function unless we say otherwise.
+ * Description:
+ * Calculate the residual data not yet transferred.
*-F*************************************************************************/
static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
- struct aic7xxx_host *p;
- struct aic7xxx_scb *scb = NULL;
- short transfer;
- unsigned char ha_flags, scsi_id, bus_width;
- unsigned char offset, rate, scratch, scratch_offset;
- unsigned char max_offset, rej_byte;
- unsigned short target_mask;
- char channel;
- unsigned int addr; /* must be 32 bits */
+ struct aic7xxx_hwscb *hscb;
Scsi_Cmnd *cmd;
+ int actual;
- p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+ cmd = scb->cmd;
+ hscb = scb->hscb;
/*
- * Search for the host with a pending interrupt. If we can't find
- * one, then we've encountered a spurious interrupt.
+ * Don't destroy valid residual information with
+ * residual coming from a check sense operation.
*/
- while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+ if (((scb->hscb->control & DISCONNECTED) == 0) &&
+ (scb->flags & SCB_SENSE) == 0)
{
- if (p->next == NULL)
- {
- p = NULL;
- }
- else
+ /*
+ * We had an 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, hscb->residual_SG_segment_count);
+
+ actual -= (hscb->residual_data_count[2] << 16) |
+ (hscb->residual_data_count[1] << 8) |
+ hscb->residual_data_count[0];
+
+ if (actual < cmd->underflow)
{
- p = (struct aic7xxx_host *) p->next->hostdata;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
+ "Wanted at least %u, got %u, residual SG count %d.\n",
+ p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
+ hscb->residual_SG_segment_count);
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ aic7xxx_status(cmd) = hscb->target_status;
}
}
- if (p == NULL)
- return;
-
/*
- * Keep track of interrupts for /proc/scsi
+ * Clean out the residual information in the SCB for the
+ * next consumer.
*/
- p->isr_count++;
+ hscb->residual_data_count[2] = 0;
+ hscb->residual_data_count[1] = 0;
+ hscb->residual_data_count[0] = 0;
+ hscb->residual_SG_segment_count = 0;
+}
- if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_device_reset
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+{
+ unsigned short targ_mask;
+ unsigned char targ_scratch;
+ int scratch_offset = target;
+ int found;
+
+ if (channel == 'B')
{
- /*
- * We must only have one card at this IRQ and it must have been
- * added to the board data before the spurious interrupt occurred.
- * It is sufficient that we check isr_count and not the spurious
- * interrupt count.
- */
- printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
- return;
+ scratch_offset += 8;
}
-
- base = p->base;
+ targ_mask = (0x01 << scratch_offset);
/*
- * Handle all the interrupt sources - especially for SCSI
- * interrupts, we won't get a second chance at them.
+ * Go back to async/narrow transfers and renegotiate.
*/
- intstat = inb(INTSTAT + base);
+ p->needsdtr |= p->needsdtr_copy & targ_mask;
+ p->needwdtr |= p->needwdtr_copy & targ_mask;
+ p->sdtr_pending &= ~targ_mask;
+ p->wdtr_pending &= ~targ_mask;
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ targ_scratch &= SXFR;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
+ "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
- /*
- * Indicate that we're in the interrupt handler.
- */
- p->flags |= IN_ISR;
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_seqint
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ struct aic7xxx_scb *scb;
+ unsigned short target_mask;
+ unsigned char target, scratch_offset;
+ char channel;
- if (intstat & BRKADRINT)
+ if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
{
- int i;
- unsigned char errno = inb(ERROR + base);
-
- printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
- for (i = 0; i < NUMBER(hard_error); i++)
- {
- if (errno & hard_error[i].errno)
- {
- printk(KERN_ERR " %s\n", hard_error[i].errmesg);
- }
- }
- panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
- inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+ target = (inb(p->base + SELID) >> 4) & 0x0F;
+ }
+ else
+ {
+ target = (inb(p->base + SCSIID) >> 4) & 0x0F;
+ }
+ scratch_offset = target;
+ channel = 'A';
+ if (inb(p->base + SBLKCTL) & SELBUSB)
+ {
+ channel = 'B';
+ scratch_offset += 8;
}
+ target_mask = (0x01 << scratch_offset);
- if (intstat & SEQINT)
+ switch (intstat & SEQINT_MASK)
{
- /*
- * Although the sequencer is paused immediately on
- * a SEQINT, an interrupt for a SCSIINT condition will
- * unpaused the sequencer before this point.
- */
- PAUSE_SEQUENCER(p);
+ case NO_MATCH:
+ {
+ /*
+ * This could be for a normal abort request. Figure out
+ * which SCB we were trying to find and only give an error
+ * if we didn't ask for this to happen.
+ */
+ unsigned char scb_index;
+ unsigned char busy_scbid;
+ unsigned char arg1;
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- scratch_offset = scsi_id;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- scratch_offset += 8;
- }
- target_mask = (0x01 << scratch_offset);
+ busy_scbid = aic7xxx_index_busy_target(p, target, channel,
+ /*unbusy*/ FALSE);
+ arg1 = inb(p->base + ARG_1);
- switch (intstat & SEQINT_MASK)
- {
- case NO_MATCH:
- if (p->flags & PAGE_ENABLED)
+ if (arg1 == SCB_LIST_NULL)
{
- /* SCB Page-in request */
- struct aic7xxx_scb *outscb;
- u_char arg_1 = inb(ARG_1 + base);
- int use_disconnected = FALSE;
-
- /*
- * The sequencer expects this value upon return. Assume
- * we will find the paged out SCB and set the value now.
- * If we don't, and one of the methods used to acquire an
- * SCB calls aic7xxx_done(), we will end up in our queue
- * routine and unpause the sequencer without giving it the
- * correct return value, which causes a hang.
- */
- outb(SCB_PAGEDIN, RETURN_1 + base);
- if (arg_1 == SCB_LIST_NULL)
- {
- /* Non-tagged command */
- int index = scsi_id;
- if (channel == 'B')
- {
- index |= SELBUSB;
- }
- scb = p->pagedout_ntscbs[index];
- }
- else
- scb = (p->scb_array[arg_1]);
+ /* untagged request */
+ scb_index = busy_scbid;
+ }
+ else
+ {
+ scb_index = arg1;
+ }
- if (!(scb->state & SCB_PAGED_OUT))
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb->hscb->control & ABORT_SCB)
{
- printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * We expected this. Let the busfree handler take care
+ * of this when we the abort is finially sent. Set
+ * IDENTIFY_SEEN so that the busfree handler knows that
+ * there is an SCB to cleanup.
+ */
+ outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
+ printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
+ p->host_no, TC_OF_SCB(scb));
break;
}
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
+ "target - Issuing BUS DEVICE RESET.\n",
+ p->host_no, target, CHAN_TO_INT(channel));
+
+ printk(KERN_WARNING " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+ inb(p->base + SAVED_TCL), arg1,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_handle_device_reset(p, target, channel);
+ }
+ break;
- /*
- * Now to pick the SCB to page out. Either take a free SCB, an
- * assigned SCB, an SCB that just completed, or the first one
- * on the disconnected SCB list.
- */
- if (p->scb_link->free_scbs.head != NULL)
- {
- outscb = p->scb_link->free_scbs.head;
- scbq_remove_head(&p->scb_link->free_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, outscb);
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (p->assigned_scbs.head != NULL)
- {
- outscb = p->assigned_scbs.head;
- scbq_remove_head(&p->assigned_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (intstat & CMDCMPLT)
- {
- int scb_index;
+ case NO_MATCH_BUSY:
+ {
+ /*
+ * XXX - Leave this as a panic for the time being since it
+ * indicates a bug in the timeout code for this to happen.
+ */
+ unsigned char scb_index;
- outb(CLRCMDINT, CLRINT + base);
- scb_index = inb(QOUTFIFO + base);
- if (!(inb(QOUTCNT + base) & p->qcntmask))
- {
- intstat &= ~CMDCMPLT;
- }
- outscb = (p->scb_array[scb_index]);
- if (!(outscb->state & SCB_ACTIVE))
+ scb_index = inb(p->base + CUR_SCBID);
+ scb = p->scb_data->scb_array[scb_index];
+
+ panic("scsi%d: Target %d, channel %c, Target busy link failure, "
+ "but busy SCB exists!\n",
+ p->host_no, target, channel);
+ }
+ break;
+
+ case SEND_REJECT:
+ {
+ unsigned char rej_byte;
+
+ rej_byte = inb(p->base + REJBYTE);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
+ "received from target, SEQ_FLAGS=0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel), rej_byte,
+ inb(p->base + SEQ_FLAGS));
+ }
+ break;
+
+ case NO_IDENT:
+ {
+ /*
+ * The reconnecting target either did not send an identify
+ * message, or did, but we didn't find and SCB to match and
+ * before it could respond to our ATN/abort, it hit a dataphase.
+ * The only safe thing to do is to blow it away with a bus
+ * reset.
+ */
+ int found;
+
+ printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
+ "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel),
+ inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+
+ found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+
+ printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
+ "%d SCBs aborted\n", p->host_no, channel, found);
+ }
+ break;
+
+ case BAD_PHASE:
+ if (inb(p->base + LASTPHASE) == P_BUSFREE)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
+ p->host_no, CHAN_TO_INT(channel), target);
+ restart_sequencer(p);
+ }
+ else
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
+ "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+ }
+ break;
+
+ case EXTENDED_MSG:
+ {
+ unsigned char message_length;
+ unsigned char message_code;
+ unsigned char scb_index;
+
+ message_length = inb(p->base + MSGIN_EXT_LEN);
+ message_code = inb(p->base + MSGIN_EXT_OPCODE);
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+
+ switch (message_code)
+ {
+ case MSG_EXT_SDTR:
+ {
+ unsigned char period;
+ unsigned char offset;
+ unsigned char saved_offset;
+ unsigned char targ_scratch;
+ unsigned char max_offset;
+ unsigned char rate;
+
+ if (message_length != MSG_EXT_SDTR_LEN)
{
- printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
- "during NO_MATCH interrupt\n", scb_index, p->host_no);
- use_disconnected = TRUE;
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
}
+
+ period = inb(p->base + MSGIN_EXT_BYTES);
+ saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if (targ_scratch & WIDEXFER)
+ max_offset = MAX_OFFSET_16BIT;
else
+ max_offset = MAX_OFFSET_8BIT;
+ offset = MIN(saved_offset, max_offset);
+
+ aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+
+ /*
+ * Preserve the WideXfer flag.
+ */
+ targ_scratch = rate | (targ_scratch & WIDEXFER);
+
+ /*
+ * Update both the target scratch area and current SCSIRATE.
+ */
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
+
+ /*
+ * See if we initiated Sync Negotiation and didn't have
+ * have to fall down to async transfers.
+ */
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
- if ((outscb->cmd->flags & WAS_SENSE) &&
- !(outscb->cmd->flags & ASKED_FOR_SENSE))
+ /* We started it. */
+ if (saved_offset == offset)
{
- /*
- * Got sense information.
- */
- outscb->cmd->flags &= ASKED_FOR_SENSE;
+ /*
+ * Don't send an SDTR back to the target.
+ */
+ outb(0, p->base + RETURN_1);
}
- p->device_status[TARGET_INDEX(outscb->cmd)].flags
- |= DEVICE_SUCCESS;
- aic7xxx_done(p, outscb);
- }
- }
- else
- {
- use_disconnected = TRUE;
- }
- if (use_disconnected)
- {
- u_char tag;
- u_char next;
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
- {
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- next = inb(SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- outb(disc_scb, SCBPTR + base);
- }
- outb(next, DISCONNECTED_SCBH + base);
- aic7xxx_page_scb(p, outscb, scb);
- }
- else if (inb(QINCNT + base) & p->qcntmask)
- {
- /* Pull one of our queued commands as a last resort. */
- disc_scb = inb(QINFIFO + base);
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- if ((outscb->control & 0x23) != TAG_ENB)
+ else
{
- /*
- * This is not a simple tagged command so its position
- * in the queue matters. Take the command at the end of
- * the queue instead.
- */
- int i;
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
-
- /* Count the command we removed already */
- saved_queue[0] = disc_scb;
- queued++;
-
- /* Empty the input queue. */
- for (i = 1; i < queued; i++)
- {
- saved_queue[i] = inb(QINFIFO + base);
- }
-
- /* Put everyone back but the last entry. */
- queued--;
- for (i = 0; i < queued; i++)
- {
- outb(saved_queue[i], QINFIFO + base);
- }
-
- outb(saved_queue[queued], SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
+ /* We went too low - force async. */
+ outb(SEND_REJ, p->base + RETURN_1);
}
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state |= SCB_WAITINGQ;
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
}
else
{
- printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * Send our own SDTR in reply.
+ *
+ * We want to see this message as we don't expect a target
+ * to send us a SDTR request first.
+ */
+ printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
+ aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
+ outb(SEND_MSG, p->base + RETURN_1);
}
+ /*
+ * Clear the flags.
+ */
+ p->needsdtr &= ~target_mask;
+ break;
}
- }
- else
- {
- printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
- }
- break;
- case BAD_PHASE:
- panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
- break;
+ case MSG_EXT_WDTR:
+ {
+ unsigned char scratch, bus_width;
- case SEND_REJECT:
- rej_byte = inb(REJBYTE + base);
- if ((rej_byte & 0xF0) == 0x20)
- {
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- printk(KERN_WARNING "scsi%d: Tagged message received without identify."
- "Disabling tagged commands for target %d channel %c.\n",
- p->host_no, scsi_id, channel);
- scb->cmd->device->tagged_supported = 0;
- scb->cmd->device->tagged_queue = 0;
- }
- else
- {
- printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
- "from target %d channel %c.\n",
- p->host_no, rej_byte, scsi_id, channel);
- }
- break;
+ if (message_length != MSG_EXT_WDTR_LEN)
+ {
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ }
- case NO_IDENT:
- panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
- "message. SAVED_TCL 0x%x.\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- break;
+ bus_width = inb(p->base + MSGIN_EXT_BYTES);
+ scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
- case SDTR_MSG:
- /*
- * Help the sequencer to translate the negotiated
- * transfer rate. Transfer is 1/4 the period
- * in ns as is returned by the sync negotiation
- * message. So, we must multiply by four.
- */
- transfer = (inb(ARG_1 + base) << 2);
- offset = inb(ACCUM + base);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
+ {
+ /*
+ * Don't send an WDTR back to the target, since we asked first.
+ */
+ outb(0, p->base + RETURN_1);
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_16_BIT:
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ }
+ scratch |= WIDEXFER;
+ break;
+
+ case BUS_32_BIT:
+ outb(SEND_REJ, p->base + RETURN_1);
+ /* No verbose here! We want to see this condition. */
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
+ "requesting 32 bit transfers, rejecting...\n",
+ p->host_no, target, channel);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Send our own WDTR in reply.
+ */
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_32_BIT:
+ case BUS_16_BIT:
+ if (p->bus_type == AIC_WIDE)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ bus_width = BUS_16_BIT;
+ scratch |= WIDEXFER;
+ }
+ else
+ {
+ bus_width = BUS_8_BIT;
+ scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */
+ }
+ break;
+
+ default:
+ break;
+ }
+ aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+ outb(SEND_MSG, p->base + RETURN_1);
+ }
+ p->needwdtr &= ~target_mask;
+ outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(scratch, p->base + SCSIRATE);
+ break;
+ } /* case MSG_EXT_WDTR */
+
+ default:
+ /*
+ * Unknown extended message - reject it.
+ */
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ } /* switch (message_code) */
+ } /* case EXTENDED_MSG */
+ break;
+
+ case REJECT_MSG:
+ {
/*
- * The maximum offset for a wide device is 0x08; for a
- * 8-bit bus device the maximum offset is 0x0F.
+ * What we care about here is if we had an outstanding SDTR
+ * or WDTR message for this target. If we did, this is a
+ * signal that the target is refusing negotiation.
*/
- if (scratch & WIDEXFER)
+ unsigned char targ_scratch;
+ unsigned char scb_index;
+
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
{
- max_offset = 0x08;
+ /*
+ * note 8bit xfers and clear flag
+ */
+ targ_scratch &= 0x7F;
+ p->needwdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+ "negotiation; using 8 bit transfers.\n",
+ p->host_no, target, channel);
}
else
{
- max_offset = 0x0F;
- }
- aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
- scsi_id, channel);
- /*
- * Preserve the wide transfer flag.
- */
- scratch = rate | (scratch & WIDEXFER);
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- if ((scratch & 0x0F) == 0)
- {
- /*
- * One of two things happened. Either the device requested
- * asynchronous data transfers, or it requested a synchronous
- * data transfer rate that was so low that asynchronous
- * transfers are faster (not to mention the controller won't
- * support them). In both cases the synchronous data transfer
- * rate and the offset are set to 0 indicating asynchronous
- * transfers.
- *
- * If the device requested an asynchronous transfer, then
- * accept the request. If the device is being forced to
- * asynchronous data transfers and this is the first time
- * we've seen the request, accept the request. If we've
- * already seen the request, then attempt to force
- * asynchronous data transfers by rejecting the message.
- */
- if ((offset == 0) || (p->sdtr_pending & target_mask))
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
/*
- * Device requested asynchronous transfers or we're
- * forcing asynchronous transfers for the first time.
+ * note asynch xfers and clear flag
*/
- outb(0, RETURN_1 + base);
- }
- else
- {
- /*
- * The first time in forcing asynchronous transfers
- * failed, so we try sending a reject message.
- */
- outb(SEND_REJ, RETURN_1 + base);
+ targ_scratch &= 0xF0;
+ p->needsdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+ "synchronous negotiation; using asynchronous transfers.\n",
+ p->host_no, target, channel);
}
+ /*
+ * Otherwise, we ignore it.
+ */
}
- else
- {
- /*
- * See if we initiated Sync Negotiation
- */
- if (p->sdtr_pending & target_mask)
- {
- /*
- * Don't send an SDTR back to the target.
- */
- outb(0, RETURN_1 + base);
- }
- else
- {
- /*
- * Send our own SDTR in reply.
- */
- printk("aic7xxx: Sending SDTR!!\n");
- outb(SEND_SDTR, RETURN_1 + base);
- }
- }
- /*
- * Clear the flags.
- */
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- break;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
+ }
+ break;
- case WDTR_MSG:
+ case BAD_STATUS:
{
- bus_width = inb(ARG_1 + base);
- printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
- "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ Scsi_Cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
+ */
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ hscb = scb->hscb;
- if (p->wdtr_pending & target_mask)
+ /*
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
+ outb(0, p->base + RETURN_1);
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
- /*
- * Don't send an WDTR back to the target, since we asked first.
- */
- outb(0, RETURN_1 + base);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
-
- case BUS_32_BIT:
- outb(SEND_REJ, RETURN_1 + base);
- printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
- "transfers, rejecting...\n", p->host_no, scsi_id, channel);
- break;
- }
+ printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+ "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
+ intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
}
else
{
- /*
- * Send our own WDTR in reply.
- */
- printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
+ cmd = scb->cmd;
+ hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+ aic7xxx_status(cmd) = hscb->target_status;
- case BUS_32_BIT:
- /*
- * Negotiate 16 bits.
- */
- bus_width = BUS_16_BIT;
- /* Yes, we mean to fall thru here. */
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
- }
- outb(bus_width | SEND_WDTR, RETURN_1 + base);
- }
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
+ cmd->result |= hscb->target_status;
+
+ switch (status_byte(hscb->target_status))
+ {
+ case GOOD:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
+ "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+ break;
+
+ case CHECK_CONDITION:
+ if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+ {
+ unsigned int addr; /* must be 32 bits */
+ /*
+ * XXX - How do we save the residual (if there is one).
+ */
+ aic7xxx_calculate_residual(p, scb);
+
+ /*
+ * Send a sense command to the requesting target.
+ * XXX - revisit this and get rid of the memcopys.
+ */
+ memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+ sizeof(generic_sense));
+
+ scb->sense_cmd[1] = (cmd->lun << 5);
+ scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+ scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+ scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+ /*
+ * XXX - We should allow disconnection, but can't as it
+ * might allow overlapped tagged commands.
+ */
+ /* hscb->control &= DISCENB; */
+ hscb->control = 0;
+ hscb->target_status = 0;
+ hscb->SG_segment_count = 1;
+
+ addr = VIRT_TO_BUS(&scb->sg_list[0]);
+ memcpy(&hscb->SG_list_pointer, &addr,
+ sizeof(hscb->SG_list_pointer));
+
+ memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
+ sizeof(hscb->data_pointer));
+ /* Maintain SCB_LINKED_NEXT */
+ hscb->data_count &= 0xFF000000;
+ hscb->data_count |= scb->sg_list[0].length;
+
+ addr = VIRT_TO_BUS(scb->sense_cmd);
+ memcpy(&hscb->SCSI_cmd_pointer, &addr,
+ sizeof(hscb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+
+ scb->sg_count = hscb->SG_segment_count;
+ scb->flags |= SCB_SENSE;
+ /*
+ * Ensure the target is busy since this will be an
+ * an untagged request.
+ */
+ aic7xxx_busy_target(p, target, channel, hscb->tag);
+ outb(SEND_SENSE, p->base + RETURN_1);
+ } /* first time sense, no errors */
+ else
+ {
+ if (aic7xxx_error(cmd) == 0)
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ }
+ break;
+
+ case QUEUE_FULL:
+#ifdef NOT_YET
+ if (scb->hscb->control & TAG_ENB)
+ {
+ if (cmd->device->queue_depth > 2)
+ {
+ cmd->device->queue_depth--; /* Not correct */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
+ "reduced to %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth);
+ }
+ /*
+ * XXX - Requeue this unconditionally?
+ */
+
+ /*
+ * We'd like to be able to give the SCB some more time
+ * (untimeout, then timeout).
+ */
+ break;
+ }
+#endif
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
+ "queue depth %d, active %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth,
+ p->device_status[TARGET_INDEX(cmd)].active_cmds);
+
+ /* Else treat this as if it was a BUSY condition. */
+ scb->hscb->target_status = (BUSY << 1) |
+ (scb->hscb->target_status & 0x01);
+ /* Fall through to the BUSY case. */
+
+ case BUSY:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
+ p->host_no, TC_OF_SCB(scb));
+ if (!aic7xxx_error(cmd))
+ {
+ /*
+ * The mid-level SCSI code should be fixed to
+ * retry the command at a later time instead of
+ * trying right away.
+ */
+ aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+ }
+ udelay(1000); /* A small pause (1ms) to help the drive */
+ break;
+
+ default:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
+ "status 0x%x.\n", p->host_no,
+ TC_OF_SCB(scb), scb->hscb->target_status);
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ break;
+ } /* end switch */
+ } /* end else of */
}
+ break;
- case REJECT_MSG:
+ case AWAITING_MSG:
{
- /*
- * What we care about here is if we had an
- * outstanding SDTR or WDTR message for this
- * target. If we did, this is a signal that
- * the target is refusing negotiation.
- */
+ unsigned char scb_index;
+ unsigned char message_offset;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
- if (p->wdtr_pending & target_mask)
+ /*
+ * This SCB had a MK_MESSAGE set in its control byte informing
+ * the sequencer that we wanted to send a special message to
+ * this target.
+ */
+ message_offset = inb(p->base + MSG_LEN);
+ if (scb->flags & SCB_DEVICE_RESET)
{
- /*
- * note 8bit xfers and clear flag
- */
- scratch &= 0x7F;
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
- "negotiation; using 8 bit transfers.\n",
- p->host_no, scsi_id, channel);
+ outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
+ p->host_no, TC_OF_SCB(scb));
}
- else
+ else if (scb->flags & SCB_ABORT)
+ {
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+ }
+ outb(message_offset + 1, p->base + MSG_LEN);
+ printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
+ p->host_no, TC_OF_SCB(scb));
+ }
+ else if (scb->flags & SCB_MSGOUT_WDTR)
{
- if (p->sdtr_pending & target_mask)
- {
- /*
- * note asynch xfers and clear flag
- */
- scratch &= 0xF0;
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
- "synchronous negotiation; using asynchronous transfers.\n",
- p->host_no, scsi_id, channel);
- }
- /*
- * Otherwise, we ignore it.
- */
+ aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+ }
+ else if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ unsigned char target_scratch;
+ unsigned short ultra_enable;
+ int i, sxfr;
+
+ /*
+ * Pull the user defined setting from scratch RAM.
+ */
+ target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ sxfr = target_scratch & SXFR;
+ ultra_enable = inb(p->base + ULTRA_ENB) |
+ (inb(p->base + ULTRA_ENB + 1) << 8);
+ if (ultra_enable & target_mask)
+ {
+ sxfr |= 0x100;
+ }
+ for (i = 0; i < num_aic7xxx_syncrates; i++)
+ {
+ if (sxfr == aic7xxx_syncrates[i].rate)
+ break;
+ }
+ aic7xxx_construct_sdtr(p, message_offset,
+ aic7xxx_syncrates[i].period,
+ target_scratch & WIDEXFER ?
+ MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
+ }
+ else
+ {
+ panic("aic7xxx: AWAITING_MSG for an SCB that does "
+ "not have a waiting message.");
}
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
}
+ break;
- case BAD_STATUS:
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencerrunning in the common case of command completes
- * without error.
- */
+ case DATA_OVERRUN:
+ {
+ unsigned char scb_index = inb(p->base + SCB_TAG);
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned int i, overrun;
+
+ scb = (p->scb_data->scb_array[scb_index]);
+ overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
+ (inb(p->base + STCNT + 2) << 16);
+ overrun = 0x00FFFFFF - overrun;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
+ "in %s phase, tag %d; forcing a retry.\n",
+ p->host_no, TC_OF_SCB(scb), overrun,
+ lastphase == P_DATAIN ? "Data-In" : "Data-Out",
+ scb->hscb->tag);
+ printk(KERN_WARNING "%s seen Data Phase. Length = %d, NumSGs = %d.\n",
+ inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+ aic7xxx_length(scb->cmd, 0), scb->sg_count);
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_INFO " sg[%d] - Addr 0x%x : Length %d\n",
+ i, scb->sg_list[i].address, scb->sg_list[i].length);
+ }
+ /*
+ * XXX - What do we really want to do on an overrun? The
+ * mid-level SCSI code should handle this, but for now,
+ * we'll just indicate that the command should retried.
+ */
+ aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
+ }
+ break;
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- outb(0, RETURN_1 + base); /* CHECK_CONDITION may change this */
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- scb->target_status = inb(SCB_TARGET_STATUS + base);
- aic7xxx_status(cmd) = scb->target_status;
+/* #if AIC7XXX_NOT_YET */
+ /* XXX Fill these in later */
+ case MSG_BUFFER_BUSY:
+ printk("aic7xxx: Message buffer busy.\n");
+ break;
+ case MSGIN_PHASEMIS:
+ printk("aic7xxx: Message-in phasemis.\n");
+ break;
+/*#endif */
+
+ case ABORT_CMDCMPLT:
+ /* This interrupt serves to pause the sequencer until we can clean
+ * up the QOUTFIFO allowing us to handle any abort SCBs that may
+ * completed yet still have an SCB in the QINFIFO or waiting for
+ * selection queue. By the time we get here, we should have
+ * already cleaned up the queues, so all we need to do is unpause
+ * the sequencer.
+ */
+ break;
- cmd->result |= scb->target_status;
+ default: /* unknown */
+ printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+ p->host_no, intstat, inb(p->base + SCSISIGI));
+ break;
+ }
- switch (status_byte(scb->target_status))
- {
- case GOOD:
- printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
- break;
+ /*
+ * Clear the sequencer interrupt and unpause the sequencer.
+ */
+ outb(CLRSEQINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+}
- case CHECK_CONDITION:
- if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
- {
- unsigned char tcl;
- unsigned int req_buf; /* must be 32 bits */
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_scsiint
+ *
+ * Description:
+ * Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ unsigned char scb_index;
+ unsigned char status;
+ struct aic7xxx_scb *scb;
- tcl = scb->target_channel_lun;
+ scb_index = inb(p->base + SCB_TAG);
+ status = inb(p->base + SSTAT1);
- /*
- * Send a sense command to the requesting target.
- */
- cmd->flags |= WAS_SENSE;
- memcpy((void *) scb->sense_cmd, (void *) generic_sense,
- sizeof(generic_sense));
-
- scb->sense_cmd[1] = (cmd->lun << 5);
- scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
- scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
- scb->sg_list[0].length = sizeof(cmd->sense_buffer);
- req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- scb->control = scb->control & DISCENB;
- scb->target_channel_lun = tcl;
- addr = VIRT_TO_BUS(scb->sense_cmd);
- scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
- memcpy(scb->SCSI_cmd_pointer, &addr,
- sizeof(scb->SCSI_cmd_pointer));
- scb->SG_segment_count = 1;
- memcpy(scb->SG_list_pointer, &req_buf,
- sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
-
- aic7xxx_putscb(p, scb);
- /*
- * Ensure that the target is "BUSY" so we don't get overlapping
- * commands if we happen to be doing tagged I/O.
- */
- aic7xxx_busy_target(scsi_id, channel, base);
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
+ {
+ scb = NULL;
+ }
+ }
+ else
+ {
+ scb = NULL;
+ }
- aic7xxx_add_waiting_scb(base, scb);
- outb(SEND_SENSE, RETURN_1 + base);
- } /* first time sense, no errors */
- else
- {
- cmd->flags &= ~ASKED_FOR_SENSE;
- if (aic7xxx_error(cmd) == 0)
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- }
- break;
-
- case BUSY:
- printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
- p->host_no, scb->target_channel_lun);
- if (!aic7xxx_error(cmd))
- {
- /* The error code here used to be DID_BUS_BUSY,
- * but after extensive testing, it has been determined
- * that a DID_BUS_BUSY return is a waste of time. If
- * the problem is something that will go away, then it
- * will, if it isn't, then you don't want the endless
- * looping that you get with a DID_BUS_BUSY. Better
- * to be on the safe side and specify an error condition
- * that will eventually lead to a reset or abort of some
- * sort instead of an endless loop.
- */
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
-
- case QUEUE_FULL:
- printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
- scb->state |= SCB_ASSIGNEDQ;
- scbq_insert_tail(&p->assigned_scbs, scb);
- break;
-
- default:
- printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
- p->host_no, scb->target_status);
- if (!aic7xxx_error(cmd))
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
- } /* end switch */
- } /* end else of */
- break;
+ if ((status & SCSIRSTI) != 0)
+ {
+ char channel;
- case RESIDUAL:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * Don't destroy valid residual information with
- * residual coming from a check sense operation.
- */
- if (!(cmd->flags & WAS_SENSE))
- {
- /*
- * We had an 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 -= (inb(SCB_RESID_DCNT2 + base) << 16) |
- (inb(SCB_RESID_DCNT1 + base) << 8) |
- inb(SCB_RESID_DCNT0 + base);
-
- if (actual < cmd->underflow)
- {
- printk(KERN_WARNING "scsi%d: Target %d underflow - "
- "Wanted at least %u, got %u, residual SG count %d.\n",
- p->host_no, cmd->target, cmd->underflow, actual,
- inb(SCB_RESID_SGCNT + base));
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- aic7xxx_status(cmd) = scb->target_status;
- }
- }
- }
- break;
+ channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
- case ABORT_TAG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * We didn't receive a valid tag back from the target
- * on a reconnect.
- */
- printk("scsi%d: Invalid tag received on target %d, channel %c, "
- "lun %d - Sending ABORT_TAG.\n", p->host_no,
- scsi_id, channel, cmd->lun & 0x07);
-
- cmd->result = (DID_RETRY_COMMAND << 16);
- aic7xxx_done(p, scb);
- }
- break;
+ printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+ p->host_no, channel);
+ /*
+ * Go through and abort all commands for the channel, but do not
+ * reset the channel again.
+ */
+ aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+ scb = NULL;
+ }
+ else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
+ {
+ /*
+ * First look at what phase we were last in. If it's message-out,
+ * chances are pretty good that the bus free was in response to
+ * one of our abort requests.
+ */
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
+ char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+ int printerror = TRUE;
- case AWAITING_MSG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- /*
- * This SCB had a zero length command, informing the sequencer
- * that we wanted to send a special message to this target.
- * We only do this for BUS_DEVICE_RESET messages currently.
- */
- if (scb->state & SCB_DEVICE_RESET)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
- scsi_id);
-#endif
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(1, MSG_LEN + base);
- }
- else
- {
- panic("scsi%d: AWAITING_SCB for an SCB that does "
- "not have a waiting message.\n", p->host_no);
- }
- }
- break;
+ outb(0, p->base + SCSISEQ);
+ if (lastphase == P_MESGOUT)
+ {
+ unsigned char sindex;
+ unsigned char message;
- case IMMEDDONE:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
- scsi_id, scb_index, scb->state);
-#endif
- if (scb->state & SCB_DEVICE_RESET)
- {
- int found;
+ sindex = inb(p->base + SINDEX);
+ message = inb(p->base + sindex - 1);
- /*
- * Go back to async/narrow transfers and renegotiate.
- */
- aic7xxx_unbusy_target(scsi_id, channel, base);
- p->needsdtr |= (p->needsdtr_copy & target_mask);
- p->needwdtr |= (p->needwdtr_copy & target_mask);
- p->sdtr_pending &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
- scratch &= SXFR;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- found = aic7xxx_reset_device(p, (int) scsi_id, channel);
- printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
- "aborted.\n", p->host_no, found);
- /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
- run_aborted_queue = TRUE;
+ if (message == MSG_ABORT)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_ABORT_TAG)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_BUS_DEV_RESET)
+ {
+ aic7xxx_handle_device_reset(p, target, channel);
+ scb = NULL;
+ printerror = 0;
+ }
+ }
+ if (printerror != 0)
+ {
+ if (scb != NULL)
+ {
+ unsigned char tag;
+
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ tag = scb->hscb->tag;
}
else
{
- panic("scsi%d: Immediate complete for unknown operation.\n",
- p->host_no);
+ tag = SCB_LIST_NULL;
}
- break;
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+ }
+ else
+ {
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ }
+ printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
+ "SEQADDR = 0x%x\n", p->host_no, lastphase,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ }
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+ outb(CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if ((status & SELTO) != 0)
+ {
+ unsigned char scbptr;
+ unsigned char nextscb;
+ Scsi_Cmnd *cmd;
+
+ scbptr = inb(p->base + WAITING_SCBH);
+ outb(scbptr, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
- case DATA_OVERRUN:
+ scb = NULL;
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
{
- unsigned int overrun;
-
- scb = (p->scb_array[inb(base + SCB_TAG)]);
- overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
- (inb(base + STCNT2) << 16);
- overrun =0x00FFFFFF - overrun;
- printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
- "a retry.\n", p->host_no, overrun);
- aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
- break;
+ scb = NULL;
}
+ }
+ if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
+ p->host_no, scb_index);
+ printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+ "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+ }
+ else
+ {
+ /*
+ * XXX - If we queued an abort tag, go clean up the disconnected list.
+ */
+ cmd = scb->cmd;
+ cmd->result = (DID_TIME_OUT << 16);
+
+ /*
+ * Clear an pending messages for the timed out
+ * target and mark the target as free.
+ */
+ outb(0, p->base + MSG_LEN);
+ aic7xxx_index_busy_target(p, cmd->target,
+ cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
+ outb(0, p->base + SCB_CONTROL);
+
+ /*
+ * Shift the waiting for selection queue forward
+ */
+ nextscb = inb(p->base + SCB_NEXT);
+ outb(nextscb, p->base + WAITING_SCBH);
+
+ /*
+ * Put this SCB back on the free list.
+ */
+ aic7xxx_add_curscb_to_free_list(p);
+ }
+ /*
+ * Stop the selection.
+ */
+ outb(0, p->base + SCSISEQ);
+ outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+ "during scsiint 0x%x scb(%d)\n"
+ " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+ p->host_no, status, scb_index, inb(p->base + SIMODE0),
+ inb(p->base + SIMODE1), inb(p->base + SSTAT0),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ /*
+ * Turn off the interrupt and set status to zero, so that it
+ * falls through the rest of the SCSIINT code.
+ */
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ else if (status & SCSIPERR)
+ {
+ /*
+ * Determine the bus phase and queue an appropriate message.
+ */
+ char *phase;
+ Scsi_Cmnd *cmd;
+ unsigned char mesg_out = MSG_NOOP;
+ unsigned char lastphase = inb(p->base + LASTPHASE);
-#if AIC7XXX_NOT_YET
- /* XXX Fill these in later */
- case MESG_BUFFER_BUSY:
+ cmd = scb->cmd;
+ switch (lastphase)
+ {
+ case P_DATAOUT:
+ phase = "Data-Out";
break;
- case MSGIN_PHASEMIS:
+ case P_DATAIN:
+ phase = "Data-In";
+ mesg_out = MSG_INITIATOR_DET_ERR;
break;
-#endif
+ case P_COMMAND:
+ phase = "Command";
+ break;
+ case P_MESGOUT:
+ phase = "Message-Out";
+ break;
+ case P_STATUS:
+ phase = "Status";
+ mesg_out = MSG_INITIATOR_DET_ERR;
+ break;
+ case P_MESGIN:
+ phase = "Message-In";
+ mesg_out = MSG_PARITY_ERROR;
+ break;
+ default:
+ phase = "unknown";
+ break;
+ }
+
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
+ p->host_no, TC_OF_SCB(scb), phase);
- default: /* unknown */
- printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
- p->host_no, intstat, inb(SCSISIGI + base));
- break;
+ /*
+ * We've set the hardware to assert ATN if we get a parity
+ * error on "in" phases, so all we need to do is stuff the
+ * message buffer with the appropriate message. "In" phases
+ * have set mesg_out to something other than MSG_NOP.
+ */
+ if (mesg_out != MSG_NOOP)
+ {
+ outb(mesg_out, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ scb = NULL;
}
+ else
+ {
+ /*
+ * Should we allow the target to make this decision for us?
+ */
+ cmd->result = DID_RETRY_COMMAND << 16;
+ }
+ outb(CLRSCSIPERR, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ else
+ {
+ /*
+ * We don't know what's going on. Turn off the
+ * interrupt source and try to continue.
+ */
+ printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ if (scb != NULL)
+ {
+ aic7xxx_done(p, scb);
+ aic7xxx_done_cmds_complete(p);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_isr
+ *
+ * Description:
+ * SCSI controller interrupt handler.
+ *
+ * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ * be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct aic7xxx_host *p;
+ unsigned char intstat;
+ unsigned long flags;
- /*
- * Clear the sequencer interrupt and unpause the sequencer.
- */
- outb(CLRSEQINT, CLRINT + base);
- UNPAUSE_SEQUENCER(p);
- }
+ p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
- if (intstat & SCSIINT)
+ /*
+ * Search for the host with a pending interrupt. If we can't find
+ * one, then we've encountered a spurious interrupt.
+ */
+ while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
{
- int status = inb(SSTAT1 + base);
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- }
-
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (status & SCSIRSTI)
- {
- PAUSE_SEQUENCER(p);
- printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
- p->host_no, channel);
- /*
- * Go through and abort all commands for the channel, but do not
- * reset the channel again.
- */
- aic7xxx_reset_channel(p, channel, FALSE);
- run_aborted_queue = TRUE;
- }
- else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ if (p->next == NULL)
{
- printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
- /*
- * Turn off the interrupt and set status to zero, so that it
- * falls through the rest of the SCSIINT code.
- */
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
- scb = NULL;
+ p = NULL;
}
- else if (status & SCSIPERR)
+ else
{
- char *phase;
- unsigned char mesg_out = MSG_NOP;
- unsigned char lastphase = inb(LASTPHASE + base);
-
- cmd = scb->cmd;
- switch (lastphase)
- {
- case P_DATAOUT:
- phase = "Data-Out";
- break;
- case P_DATAIN:
- phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_COMMAND:
- phase = "Command";
- break;
- case P_MESGOUT:
- phase = "Message-Out";
- break;
- case P_STATUS:
- phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_MESGIN:
- phase = "Message-In";
- mesg_out = MSG_MSG_PARITY_ERROR;
- break;
- default:
- phase = "unknown";
- break;
- }
-
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
- "channel %d, lun %d.\n", p->host_no, phase,
- cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
-
- /*
- * We've set the hardware to assert ATN if we get a parity
- * error on "in" phases, so all we need to do is stuff the
- * message buffer with the appropriate message. In phases
- * have set mesg_out to something other than MSG_NOP.
- */
- if (mesg_out != MSG_NOP)
- {
- outb(mesg_out, MSG0 + base);
- outb(1, MSG_LEN + base);
- cmd->result = DID_PARITY << 16;
- }
- else
- {
- /*
- * Should we allow the target to make this decision for us?
- */
- cmd->result = DID_RETRY_COMMAND << 16;
- }
- aic7xxx_done(p, scb);
+ p = (struct aic7xxx_host *) p->next->hostdata;
}
- else if (status & SELTO)
- {
- unsigned char waiting;
+ }
- cmd = scb->cmd;
+ if (p == NULL)
+ return;
- cmd->result = (DID_TIME_OUT << 16);
- /*
- * Clear an pending messages for the timed out
- * target and mark the target as free.
- */
- ha_flags = inb(FLAGS + base);
- outb(0, MSG_LEN + base);
- aic7xxx_unbusy_target(scsi_id, channel, base);
- /*
- * Stop the selection.
- */
- outb(0, SCSISEQ + base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /*
+ * Handle all the interrupt sources - especially for SCSI
+ * interrupts, we won't get a second chance at them.
+ */
+ intstat = inb(p->base + INTSTAT);
- /*
- * Shift the waiting for selection queue forward
- */
- waiting = inb(WAITING_SCBH + base);
- outb(waiting, SCBPTR + base);
- waiting = inb(SCB_NEXT + base);
- outb(waiting, WAITING_SCBH + base);
+ /*
+ * Keep track of interrupts for /proc/scsi
+ */
+ p->isr_count++;
- RESTART_SEQUENCER(p);
- aic7xxx_done(p, scb);
- }
- else if (!(status & BUSFREE))
+ if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+ {
+ /*
+ * We must only have one card at this IRQ and it must have been
+ * added to the board data before the spurious interrupt occurred.
+ * It is sufficient that we check isr_count and not the spurious
+ * interrupt count.
+ */
+ printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
+ if (intstat)
{
- /*
- * We don't know what's going on. Turn off the
- * interrupt source and try to continue.
- */
- printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
+ /* Try clearing all interrupts. */
+ outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
}
+ return;
+ }
+
+ if (p->flags & IN_ISR)
+ {
+ printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+ p->host_no);
+ return;
}
- if (run_aborted_queue)
- aic7xxx_done_aborted_scbs(p);
+ /*
+ * Indicate that we're in the interrupt handler.
+ */
+ save_flags(flags);
+ cli();
+ p->flags |= IN_ISR;
if (intstat & CMDCMPLT)
{
- int complete;
+ struct aic7xxx_scb *scb = NULL;
+ Scsi_Cmnd *cmd;
+ unsigned char qoutcnt;
+ unsigned char scb_index;
+ int i, interrupts_cleared = 0;
/*
* 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(QOUTFIFO + base);
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
- scb = (p->scb_array[complete]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
- " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
- "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
- inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
- scb->position);
- outb(CLRCMDINT, CLRINT + base);
- continue;
- }
- cmd = scb->cmd;
- cmd->result |= (aic7xxx_error(cmd) << 16);
- if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+#if 1
+ if (qoutcnt >= p->qfullcount - 1)
+ printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
+ "qoutcnt = %d.\n", qoutcnt);
+#endif
+ while (qoutcnt > 0)
+ {
+ for (i = 0; i < qoutcnt; i++)
{
- /*
- * Got sense information.
- */
- cmd->flags &= ASKED_FOR_SENSE;
+ scb_index = inb(p->base + QOUTFIFO);
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
+ "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
+ inb(p->base + QOUTCNT), inb(p->base + QINCNT));
+ continue;
+ }
+ else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
+ "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
+ p->host_no, scb_index, inb(p->base + QOUTCNT),
+ inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
+ continue;
+ }
+ cmd = scb->cmd;
+ if (scb->hscb->residual_SG_segment_count != 0)
+ {
+ aic7xxx_calculate_residual(p, scb);
+ }
+ if ((scb->flags & SCB_QUEUED_ABORT) != 0)
+ {
+ /*
+ * Have to clean up any possible entries in the
+ * waiting queue and the QINFIFO.
+ */
+ int target;
+ char channel;
+ int lun;
+ unsigned char tag;
+
+ tag = SCB_LIST_NULL;
+ target = cmd->target;
+ lun = cmd->lun;
+ channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ if (scb->hscb->control & TAG_ENB)
+ {
+ tag = scb->hscb->tag;
+ }
+ aic7xxx_reset_device(p, target, channel, lun, tag);
+ /*
+ * Run the done queue, but don't complete the commands; we
+ * do this once at the end of the loop.
+ */
+ aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+ }
+ cmd->result |= (aic7xxx_error(cmd) << 16);
+ p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+ aic7xxx_done(p, scb);
}
- p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-
/*
* Clear interrupt status before checking the output queue again.
* This eliminates a race condition whereby a command could
* so notification of the command being complete never made it
* back up to the kernel.
*/
- outb(CLRCMDINT, CLRINT + base);
- aic7xxx_done(p, scb);
+ outb(CLRCMDINT, p->base + CLRINT);
+ interrupts_cleared++;
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+ }
-#ifdef AIC7XXX_PROC_STATS
- /*
- * XXX: we should actually know how much actually transferred
- * XXX: for each command, but apparently that's too difficult.
- */
- actual = aic7xxx_length(cmd, 0);
- if (!(cmd->flags & WAS_SENSE) && (actual > 0))
+ if (interrupts_cleared == 0)
+ {
+ outb(CLRCMDINT, p->base + CLRINT);
+ }
+
+ aic7xxx_done_cmds_complete(p);
+ }
+
+ if (intstat & BRKADRINT)
+ {
+ int i;
+ unsigned char errno = inb(p->base + ERROR);
+
+ printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+ for (i = 0; i < NUMBER(hard_error); i++)
+ {
+ if (errno & hard_error[i].errno)
{
- struct aic7xxx_xferstats *sp;
- long *ptr;
- int x;
+ printk(KERN_ERR " %s\n", hard_error[i].errmesg);
+ }
+ }
+ printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+ inb(p->base + ERROR),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ }
+
+ if (intstat & SEQINT)
+ {
+ aic7xxx_handle_seqint(p, intstat);
+ }
+
+ if (intstat & SCSIINT)
+ {
+ aic7xxx_handle_scsiint(p, intstat);
+ }
+
+ if (p->waiting_scbs.head != NULL)
+ {
+ aic7xxx_run_waiting_queues(p);
+ }
+
+ p->flags &= ~IN_ISR;
+ restore_flags(flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_device_queue_depth
+ *
+ * Description:
+ * Determines the queue depth for a given device. There are two ways
+ * a queue depth can be obtained for a tagged queueing device. One
+ * way is the default queue depth which is determined by whether
+ * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used
+ * as the default queue depth. Otherwise, we use either 4 or 8 as the
+ * default queue depth (dependent on the number of hardware SCBs).
+ * The other way we determine queue depth is through the use of the
+ * aic7xxx_tag_info array which is enabled by defining
+ * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized
+ * with queue depths for individual devices. It also allows tagged
+ * queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+ int default_depth = 2;
+
+ device->queue_depth = default_depth;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (device->tagged_supported)
+ {
+ unsigned short target_mask;
+ int tag_enabled = TRUE;
+
+ target_mask = (1 << (device->id | (device->channel << 3)));
- sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
- sp->xfers++;
+#ifdef AIC7XXX_CMDS_PER_LUN
+ default_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+ if (p->scb_data->maxhscbs <= 4)
+ {
+ default_depth = 4; /* Not many SCBs to work with. */
+ }
+ else
+ {
+ default_depth = 8;
+ }
+#endif
+
+ if (!(p->discenable & target_mask))
+ {
+ printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+ "enable tagged queueing.\n",
+ p->host_no, device->id, device->channel);
+ }
+ else
+ {
+#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+ device->queue_depth = default_depth;
+#else
+ if (p->instance > NUMBER(aic7xxx_tag_info))
+ {
+ device->queue_depth = default_depth;
+ }
+ else
+ {
+ unsigned char tindex;
- if (cmd->request.cmd == WRITE)
+ tindex = device->id | (device->channel << 3);
+ if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
{
- sp->w_total++;
- sp->w_total512 += (actual >> 9);
- ptr = sp->w_bins;
+ tag_enabled = FALSE;
+ device->queue_depth = 2; /* Tagged queueing is disabled. */
}
- else
+ else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
{
- sp->r_total++;
- sp->r_total512 += (actual >> 9);
- ptr = sp->r_bins;
+ device->queue_depth = default_depth;
}
- for (x = 9; x <= 17; x++)
+ else
{
- if (actual < (1 << x))
- {
- ptr[x - 9]++;
- break;
- }
+ device->queue_depth =
+ aic7xxx_tag_info[p->instance].tag_commands[tindex];
}
- if (x > 17)
+ }
+#endif
+ if ((device->tagged_queue == 0) && tag_enabled)
+ {
+ if (aic7xxx_verbose)
{
- ptr[x - 9]++;
+ printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+ "queue depth %d.\n", p->host_no,
+ device->id, device->channel, device->queue_depth);
}
+ device->tagged_queue = 1;
+ device->current_tag = SCB_LIST_NULL;
}
-#endif /* AIC7XXX_PROC_STATS */
-
- } while (inb(QOUTCNT + base) & p->qcntmask);
+ }
}
- aic7xxx_done_cmds_complete(p);
- p->flags &= ~IN_ISR;
- aic7xxx_run_waiting_queues(p);
+#endif
}
/*+F*************************************************************************
* algorithm for determining the queue depth based on the maximum
* SCBs for the controller.
*-F*************************************************************************/
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs)
{
- Scsi_Device *device = scsi_devs;
- int tq_depth = 2;
+ Scsi_Device *device;
struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-#ifdef AIC7XXX_CMDS_PER_LUN
- tq_depth = AIC7XXX_CMDS_PER_LUN;
-#else
- {
- if (p->maxhscbs <= 4)
- {
- tq_depth = 4; /* Not many SCBs to work with. */
- }
- else
- {
- tq_depth = 8;
- }
- }
-#endif
-
for (device = scsi_devs; device != NULL; device = device->next)
{
if (device->host == host)
{
- device->queue_depth = 2;
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (device->tagged_supported)
- {
- unsigned short target_mask = (1 << device->id) | device->channel;
-
- if (!(p->discenable & target_mask))
- {
- printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
- "tagged queueing for target %d, channel %d, LUN %d.\n",
- host->host_no, device->id, device->channel, device->lun);
- }
- else
- {
- device->queue_depth = tq_depth;
- if (device->tagged_queue == 0)
- {
- printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
- "channel %d, LUN %d, queue depth %d.\n", host->host_no,
- device->id, device->channel, device->lun,
- device->queue_depth);
- device->tagged_queue = 1;
- device->current_tag = SCB_LIST_NULL;
- }
- }
- }
-#endif
+ aic7xxx_device_queue_depth(p, device);
}
}
}
* The fourth byte's lowest bit seems to be an enabled/disabled
* flag (rest of the bits are reserved?).
*-F*************************************************************************/
-static aha_type
+static aha_chip_type
aic7xxx_probe(int slot, int base, aha_status_type *bios)
{
int i;
static struct {
int n;
unsigned char signature[sizeof(buf)];
- aha_type type;
+ aha_chip_type type;
int bios_disabled;
} AIC7xxx[] = {
{ 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
return (AIC7xxx[i].type);
}
- printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
+ printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+ "disabled at slot %d, ignored.\n", slot);
}
}
* useful in that it gives us an 800 nsec timer. After a read from the
* SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
* later.
- *
*-F*************************************************************************/
static int
-read_2840_seeprom(int base, struct seeprom_config *sc)
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
{
int i = 0, k = 0;
unsigned char temp;
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0) \
+ while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0) \
{ \
; /* Do nothing */ \
} \
- (void) inb(SEECTL_2840 + base);
+ (void) inb(p->base + SEECTL_2840);
/*
* Read the first 32 registers of the seeprom. For the 2840,
/*
* Send chip select for one clock cycle.
*/
- outb(CK_2840 | CS_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
for (i = 0; i < seeprom_read.len; i++)
{
temp = CS_2840 | seeprom_read.bits[i];
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* Send the 6 bit address (MSB first, LSB last).
temp = k;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = CS_2840 | temp;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
for (i = 0; i <= 16; i++)
{
temp = CS_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* The serial EEPROM has a checksum in the last word. Keep a
/*
* Reset the chip select for the next command cycle.
*/
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(CK_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(CK_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
#if 0
}
printk(" 0x%x", seeprom[k]);
}
- printk("\n");
-#endif
-
- if (checksum != sc->checksum)
+ printk("\n");
+#endif
+
+ if (checksum != sc->checksum)
+ {
+ printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+ return (0);
+ }
+
+ return (1);
+#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
+ * acquire_seeprom
+ *
+ * Description:
+ * Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+ int wait;
+
+ /*
+ * Request access of the memory port. When access is
+ * granted, SEERDY will go high. We use a 1 second
+ * timeout which should be near 1 second more than
+ * is needed. Reason: after the 7870 chip reset, there
+ * should be no contention.
+ */
+ outb(SEEMS, p->base + SEECTL);
+ wait = 1000; /* 1000 msec = 1 second */
+ while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+ {
+ wait--;
+ udelay(1000); /* 1 msec */
+ }
+ if ((inb(p->base + SEECTL) & SEERDY) == 0)
{
- printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+ outb(0, p->base + SEECTL);
return (0);
}
-
return (1);
-#undef CLOCK_PULSE
+}
+
+/*+F*************************************************************************
+ * Function:
+ * release_seeprom
+ *
+ * Description:
+ * Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline void
+release_seeprom(struct aic7xxx_host *p)
+{
+ outb(0, p->base + SEECTL);
}
/*+F*************************************************************************
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
*
- * The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
* register. After successful arbitration for the memory port, the
* SEECS bit of the SEECTL register is connected to the chip select.
* The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
* to this is when we first request access to the memory port. The
* SEERDY goes high to signify that access has been granted and, for
* this case, has no implied timing.
- *
*-F*************************************************************************/
static int
-read_seeprom(int base, int offset, struct seeprom_config *sc,
- seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
+ unsigned int len, seeprom_chip_type chip)
{
int i = 0, k;
- unsigned long timeout;
unsigned char temp;
unsigned short checksum = 0;
- unsigned short *seeprom = (unsigned short *) sc;
struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(SEECTL + base) & SEERDY) == 0) \
+ while ((inb(p->base + SEECTL) & SEERDY) == 0) \
{ \
; /* Do nothing */ \
}
/*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the 7870 chip reset, there
- * should be no contention.
+ * Request access of the memory port.
*/
- outb(SEEMS, SEECTL + base);
- timeout = jiffies + 100; /* 1 second timeout */
- while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
- {
- ; /* Do nothing! Wait for access to be granted. */
- }
- if ((inb(SEECTL + base) & SEERDY) == 0)
+ if (acquire_seeprom(p) == 0)
{
- outb(0, SEECTL + base);
return (0);
}
/*
- * Read the first 32 registers of the seeprom. For the 7870,
- * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
- * but only the first 32 are used by Adaptec BIOS. The loop
- * will range from 0 to 31.
+ * Read 'len' registers of the seeprom. For the 7870, the 93C46
+ * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+ * the first 32 are used by Adaptec BIOS. Some adapters use the
+ * 93C56 SEEPROM which is a 2048-bit device. The loop will range
+ * from 0 to 'len' - 1.
*/
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
/*
* Send chip select for one clock cycle.
*/
- outb(SEEMS | SEECK | SEECS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
for (i = 0; i < seeprom_read.len; i++)
{
temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * Send the 6 bit address (MSB first, LSB last).
+ * Send the 6 or 8 bit address (MSB first, LSB last).
*/
for (i = ((int) chip - 1); i >= 0; i--)
{
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
for (i = 0; i <= 16; i++)
{
temp = SEEMS | SEECS;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * The serial EEPROM has a checksum in the last word. Keep a
- * running checksum for all words read except for the last
- * word. We'll verify the checksum after all words have been
- * read.
+ * The serial EEPROM should have a checksum in the last word.
+ * Keep a running checksum for all words read except for the
+ * last word. We'll verify the checksum after all words have
+ * been read.
*/
- if (k < (sizeof(*sc) / 2) - 1)
+ if (k < (len - 1))
{
- checksum = checksum + seeprom[k];
+ checksum = checksum + scarray[k];
}
/*
* Reset the chip select for the next command cycle.
*/
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS | SEECK, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS | SEECK, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
* Release access to the memory port and the serial EEPROM.
*/
- outb(0, SEECTL + base);
+ release_seeprom(p);
#if 0
- printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+ printk("Computed checksum 0x%x, checksum read 0x%x\n",
+ checksum, scarray[len - 1]);
printk("Serial EEPROM:");
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
if (((k % 8) == 0) && (k != 0))
{
printk("\n ");
}
- printk(" 0x%x", seeprom[k]);
+ printk(" 0x%x", scarray[k]);
}
printk("\n");
#endif
- if (checksum != sc->checksum)
+ if (checksum != scarray[len - 1])
{
return (0);
}
/*+F*************************************************************************
* Function:
- * detect_maxscb
+ * write_brdctl
*
* Description:
- * Detects the maximum number of SCBs for the controller and returns
- * the count and a mask in config (config->maxscbs, config->qcntmask).
+ * Writes a value to the BRDCTL register.
*-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host_config *config)
+static inline void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
{
- unsigned char sblkctl_reg;
- int base, i;
-
-#ifdef AIC7XXX_PAGE_ENABLE
- config->flags |= PAGE_ENABLED;
-#endif
- base = config->base;
- switch (config->type)
- {
- case AIC_7770:
- case AIC_7771:
- case AIC_284x:
- /*
- * Check for Rev C or E boards. Rev E boards can supposedly have
- * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
- * It's still not clear extactly what is different about the Rev E
- * boards, but we think it allows 8 bit entries in the QOUTFIFO to
- * support "paging" SCBs (more than 4 commands can be active at once).
- *
- * The Rev E boards have a read/write autoflush bit in the
- * SBLKCTL register, while in the Rev C boards it is read only.
- */
- sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
- outb(sblkctl_reg, SBLKCTL + base);
- if (inb(SBLKCTL + base) == sblkctl_reg)
- {
- /*
- * We detected a Rev E board, we allow paging on this board.
- */
- printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
- board_names[config->type]);
- outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
- }
- else
- {
- /* Do not allow paging. */
- config->flags &= ~PAGE_ENABLED;
- printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
- board_names[config->type]);
- }
- break;
-
- default:
- break;
- }
-
- /*
- * Walk the SCBs to determine how many there are.
- */
- i = 1;
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- while (i < AIC7XXX_MAXSCB)
- {
- outb(i, SCBPTR + base);
- outb(i, SCBARRAY + base);
- if (inb(SCBARRAY + base) != i)
- break;
- outb(0, SCBPTR + base);
- if (inb(SCBARRAY + base) != 0)
- break;
-
- outb(i, SCBPTR + base); /* Clear the control byte. */
- outb(0, SCBARRAY + base);
-
- config->qcntmask |= i; /* Update the count mask. */
- i++;
- }
- outb(i, SCBPTR + base); /* Ensure we clear the control bytes. */
- outb(0, SCBARRAY + base);
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- config->maxhscbs = i;
- config->qcntmask |= i;
- if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
- {
- config->maxscbs = AIC7XXX_MAXSCB;
- }
- else
- {
- config->flags &= ~PAGE_ENABLED; /* Disable paging if we have 255 SCBs!. */
- config->maxscbs = config->maxhscbs;
- }
-
- printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
- if (config->flags & PAGE_ENABLED)
- printk(", %d page-enabled SCBs.\n", config->maxscbs);
- else
- printk(", paging not enabled.\n");
-
+ unsigned char brdctl;
+
+ brdctl = BRDCS | BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl |= value;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDCS;
+ outb(brdctl, p->base + BRDCTL);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_register
+ * read_brdctl
*
* Description:
- * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ * Reads the BRDCTL register.
*-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template,
- struct aic7xxx_host_config *config)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
{
- int i;
- unsigned char sblkctl, flags = 0;
- int max_targets;
- int found = 1;
- unsigned int sram, base;
- unsigned char target_settings;
- unsigned char scsi_conf, host_conf;
- unsigned short ultraenable = 0;
- int have_seeprom = FALSE;
- struct Scsi_Host *host;
- struct aic7xxx_host *p;
- struct seeprom_config sc;
-
- base = config->base;
-
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(base, MAXREG - MINREG, "aic7xxx");
+ outb(BRDRW | BRDCS, p->base + BRDCTL);
+ return (inb(p->base + BRDCTL));
+}
- switch (config->type)
+/*+F*************************************************************************
+ * Function:
+ * configure_termination
+ *
+ * Description:
+ * Configures the termination settings on PCI adapters that have
+ * SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
+ unsigned short adapter_control, unsigned char max_targ)
+{
+ unsigned char brdctl_int, brdctl_ext;
+ int internal50_present;
+ int internal68_present = 0;
+ int external_present = 0;
+ int eprom_present;
+ int high_on;
+ int low_on;
+ int old_verbose;
+
+ if (acquire_seeprom(p))
{
- case AIC_7770:
- case AIC_7771:
- /*
- * Use the boot-time option for the interrupt trigger type. If not
- * supplied (-1), then we use BIOS settings to determine the interrupt
- * trigger type (level or edge) and use this value for pausing and
- * unpausing the sequencer.
- */
- switch (aic7xxx_irq_trigger)
- {
- case 0: config->unpause = INTEN; /* Edge */
- break;
- case 1: config->unpause = IRQMS | INTEN; /* Level */
- break;
- case -1:
- default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN;
- break;
- }
- config->pause = config->unpause | PAUSE;
+ if (adapter_control & CFAUTOTERM)
+ {
+ old_verbose = aic7xxx_verbose;
+ printk(KERN_INFO "aic7xxx: Warning - detected auto-termination. Please "
+ "verify driver");
+ printk(KERN_INFO " detected settings and use manual termination "
+ "if necessary.");
+
+ /* Configure auto termination. */
+ outb(SEECS | SEEMS, p->base + SEECTL);
/*
- * For some 274x boards, we must clear the CHIPRST bit and pause
- * the sequencer. For some reason, this makes the driver work.
- * For 284x boards, we give it a CHIPRST just like the 294x boards.
+ * First read the status of our cables. Set the rom bank to
+ * 0 since the bank setting serves as a multiplexor for the
+ * cable detection logic. BRDDAT5 controls the bank switch.
*/
- outb(config->pause | CHIPRST, HCNTRL + base);
- aic7xxx_delay(1);
- if (inb(HCNTRL + base) & CHIPRST)
- {
- printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
- }
- outb(config->pause, HCNTRL + base);
+ write_brdctl(p, 0);
/*
- * Just to be on the safe side with the 274x, we will re-read the irq
- * since there was some issue about resetting the board.
+ * Now read the state of the internal connectors. The
+ * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
+ * set when cables are not present (BRDDAT6 is INT50 and
+ * BRDDAT7 is INT68).
*/
- config->irq = inb(INTDEF + base) & 0x0F;
- if ((config->type == AIC_7771) &&
- (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
- {
- config->bios = AIC_DISABLED;
- config->flags |= USE_DEFAULTS;
- }
- else
+ brdctl_int = read_brdctl(p);
+ internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+ if (max_targ > 8)
{
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
+ internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
}
/*
- * Setup the FIFO threshold and the bus off time
+ * Set the rom bank to 1 and determine
+ * the other signals.
*/
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
+ write_brdctl(p, BRDDAT5);
/*
- * A reminder until this can be detected automatically.
+ * Now read the state of the external connectors. BRDDAT6 is
+ * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
+ * set when the eprom is present.
*/
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_284x:
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_284X;
- config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
- config->irq = inb(INTDEF + base) & 0x0F;
- host_conf = inb(HOSTCONF + base);
-
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- have_seeprom = read_2840_seeprom(base, &sc);
- if (!have_seeprom)
+ brdctl_ext = read_brdctl(p);
+ external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
+ eprom_present = brdctl_ext & BRDDAT7;
+ if (aic7xxx_verbose)
{
- printk("aic7xxx: Unable to read SEEPROM.\n");
- }
- else
- {
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (sc.bios_control & CF284XEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- if (!(sc.bios_control & CFBIOSEN))
+ if (max_targ > 8)
{
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+ "Ext-68 %s)\n",
+ internal50_present ? "YES" : "NO",
+ internal68_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
else
{
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CF284XSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- /*
- * XXX - Adaptec *does* make 284x wide controllers, but the
- * documents do not say where the high byte termination
- * enable bit is located.
- */
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+ internal50_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
+ printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
+ "brdctl_ext=0x%x\n",
+ eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
}
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
-
- /*
- * Setup the FIFO threshold and the bus off time
- */
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
-
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_7860:
- case AIC_7861:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- /*
- * Remember if Ultra was enabled in case there is no SEEPROM.
- * Fall through to the rest of the AIC_78xx code.
- */
- if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
- config->flags |= ULTRA_ENABLED;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
/*
- * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+ * Now set the termination based on what we found. BRDDAT6
+ * controls wide termination enable.
*/
- config->scsi_id = inb(SCSIID + base) & OID;
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_294X;
- config->pause = config->unpause | PAUSE;
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
+ high_on = FALSE;
+ low_on = FALSE;
+ if ((max_targ > 8) &&
+ ((external_present == 0) || (internal68_present == 0)))
+ {
+ high_on = TRUE;
+ }
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- if ((config->type == AIC_7873) || (config->type == AIC_7883))
+ if ((internal50_present + internal68_present + external_present) <= 1)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c56_66);
+ low_on = TRUE;
}
- else
+
+ if (internal50_present && internal68_present && external_present)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c46);
+ printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
+ " Only two connectors on the adapter may be "
+ "used at a time!\n");
}
- if (!have_seeprom)
+
+ if (high_on == TRUE)
+ write_brdctl(p, BRDDAT6);
+ else
+ write_brdctl(p, 0);
+
+ if (low_on == TRUE)
+ *sxfrctl1 |= STPWEN;
+
+ if (aic7xxx_verbose)
{
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+ if (max_targ > 8)
{
- if (inb(sram) != 0x00)
- break;
- }
- if (sram == base + TARG_SCRATCH)
- {
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
- {
- if (inb(sram) != 0xFF)
- break;
- }
- }
- if ((sram != base + 0x60) && (config->scsi_id != 0))
- {
- config->flags &= ~USE_DEFAULTS;
- printk("\naic7xxx: Unable to read SEEPROM; "
- "using leftover BIOS values.\n");
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ low_on ? "ON" : "OFF",
+ high_on ? "ON" : "OFF");
}
else
{
- printk("\n");
- printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
- "settings.\n");
- config->flags |= USE_DEFAULTS;
- config->flags &= ~ULTRA_ENABLED;
- config->scsi_id = 7;
+ printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
}
- scsi_conf = ENSPCHK | RESET_SCSI;
+ }
+ aic7xxx_verbose = old_verbose;
+ }
+ else
+ {
+ if (adapter_control & CFSTERM)
+ {
+ *sxfrctl1 |= STPWEN;
+ }
+ outb(SEEMS | SEECS, p->base + SEECTL);
+ /*
+ * Configure high byte termination.
+ */
+ if (adapter_control & CFWSTERM)
+ {
+ write_brdctl(p, BRDDAT6);
}
else
{
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (!(sc.bios_control & CFBIOSEN))
- {
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
- scsi_conf = ENSPCHK | RESET_SCSI;
- }
- else
- {
- scsi_conf = 0;
- if (sc.adapter_control & CFRESETB)
- scsi_conf |= RESET_SCSI;
- if (sc.adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- if (sc.bios_control & CFEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- config->scsi_id = (sc.brtime_id & CFSCSIID);
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CFSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->high_term = (sc.adapter_control & CFWSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
- if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
- (config->type == AIC_7882) || (config->type == AIC_7883) ||
- (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
- {
- printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
- "speed.\n");
- config->flags |= ULTRA_ENABLED;
- }
- }
+ write_brdctl(p, 0);
+ }
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ (adapter_control & CFSTERM) ? "ON" : "OFF",
+ (adapter_control & CFWSTERM) ? "ON" : "OFF");
}
+ }
+ release_seeprom(p);
+ }
+}
- outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
- config->bus_speed = DFTHRSH_100;
- outb(config->bus_speed, DSPCISTATUS + base);
+/*+F*************************************************************************
+ * Function:
+ * detect_maxscb
+ *
+ * Description:
+ * Detects the maximum number of SCBs for the controller and returns
+ * the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char max_scbid = 255;
- /*
- * In case we are a wide card...
- */
- outb(config->scsi_id, SCSICONF + base + 1);
+ /*
+ * It's possible that we've already done this for multichannel
+ * adapters.
+ */
+ if (p->scb_data->maxhscbs == 0)
+ {
+ /*
+ * We haven't initialized the SCB settings yet. Walk the SCBs to
+ * determince how many there are.
+ */
+ outb(0, p->base + FREE_SCBH);
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
+ for (i = 0; i < AIC7XXX_MAXSCB; i++)
+ {
+ outb(i, p->base + SCBPTR);
+ outb(i, p->base + SCB_CONTROL);
+ if (inb(p->base + SCB_CONTROL) != i)
+ break;
+ outb(0, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) != 0)
+ break;
- default:
- panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
+ outb(i, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL); /* Clear the control byte. */
+ outb(i + 1, p->base + SCB_NEXT); /* Set the next pointer. */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG); /* Make the tag invalid. */
+
+ /* Make the non-tagged targets not busy. */
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+ }
+
+ /* Make sure the last SCB terminates the free list. */
+ outb(i - 1, p->base + SCBPTR);
+ outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+
+ /* Ensure we clear the first (0) SCBs control byte. */
+ outb(0, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL);
+
+ p->scb_data->maxhscbs = i;
+ }
+
+ if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
+ {
+ /* Determine the number of valid bits in the FIFOs. */
+ outb(max_scbid, p->base + QINFIFO);
+ max_scbid = inb(p->base + QINFIFO);
+ p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
+ }
+ else
+ {
+ p->scb_data->maxscbs = p->scb_data->maxhscbs;
+ }
+ if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
+ {
+ /*
+ * Disable paging if the QINFIFO doesn't allow more SCBs than
+ * we have in hardware.
+ */
+ p->flags &= ~PAGE_ENABLED;
+ }
+
+ /*
+ * Set the Queue Full Count. Some cards have more queue space than
+ * SCBs.
+ */
+ switch (p->chip_class)
+ {
+ case AIC_777x:
+ p->qfullcount = 4;
+ p->qcntmask = 0x07;
+ break;
+ case AIC_785x:
+ case AIC_786x:
+ p->qfullcount = 8;
+ p->qcntmask = 0x0f;
+ break;
+ case AIC_787x:
+ case AIC_788x:
+ if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
+ {
+ p->qfullcount = AIC7XXX_MAXSCB;
+ p->qcntmask = 0xFF;
+ }
+ else
+ {
+ p->qfullcount = 16;
+ p->qcntmask = 0x1F;
+ }
+ break;
}
+}
- detect_maxscb(config);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_register
+ *
+ * Description:
+ * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char sblkctl, flags = 0;
+ int max_targets;
+ int found = 1;
+ char channel_ids[] = {'A', 'B', 'C'};
+ unsigned char target_settings;
+ unsigned char scsi_conf, sxfrctl1;
+ unsigned short ultraenable = 0;
+ struct Scsi_Host *host;
- if (config->chip_type == AIC_777x)
- {
- if (config->pause & IRQMS)
- {
- printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
- }
- else
- {
- printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
- }
- }
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(p->base, MAXREG - MINREG, "aic7xxx");
/*
* Read the bus type from the SBLKCTL register. Set the FLAGS
* register in the sequencer for twin and wide bus cards.
*/
- sblkctl = inb(SBLKCTL + base);
- if (config->flags & PAGE_ENABLED)
+ sblkctl = inb(p->base + SBLKCTL);
+ if (p->flags & PAGE_ENABLED)
flags = PAGESCBS;
switch (sblkctl & SELBUS_MASK)
{
case SELNARROW: /* narrow/normal bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
- config->bus_type = AIC_SINGLE;
- outb(flags | SINGLE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF) & 0x07;
+ p->bus_type = AIC_SINGLE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
break;
case SELWIDE: /* Wide bus */
- config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
- config->bus_type = AIC_WIDE;
- printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
- board_names[config->type]);
- outb(flags | WIDE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
+ p->bus_type = AIC_WIDE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
break;
case SELBUSB: /* Twin bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
-#ifdef AIC7XXX_TWIN_SUPPORT
- config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
- config->bus_type = AIC_TWIN;
- printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
- board_names[config->type]);
- outb(flags | TWIN_BUS, FLAGS + base);
-#else
- config->bus_type = AIC_SINGLE;
- printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
- board_names[config->type]);
- outb(flags, FLAGS + base);
-#endif
+ p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
+ p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
+ p->bus_type = AIC_TWIN;
+ printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+ p->scsi_id, p->scsi_id_b);
+ outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
break;
default:
printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
- "mail deang@teleport.com\n", inb(SBLKCTL + base));
- outb(0, FLAGS + base);
+ "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
+ outb(0, p->base + SEQ_FLAGS);
return (0);
}
/*
- * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
- * take the card out of diagnostic mode and make the host adapter
- * LED follow bus activity (will not always be on).
- */
- outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + 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?
- *
- * The PCI cards get their interrupt from PCI BIOS.
+ * Detect SCB parameters and initialize the SCB array.
*/
- if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
- {
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
- "ignoring.\n");
- return (0);
- }
+ detect_maxscb(p);
+ printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
+ p->scb_data->maxhscbs, p->scb_data->maxscbs,
+ p->qfullcount, p->qcntmask);
- /*
- * 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(config);
+ host = p->host;
- /*
- * 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->maxscbs;
+ host->can_queue = p->scb_data->maxscbs;
host->cmd_per_lun = 2;
+ host->sg_tablesize = AIC7XXX_MAX_SG;
host->select_queue_depths = aic7xxx_select_queue_depth;
- host->this_id = config->scsi_id;
- host->io_port = config->base;
+ host->this_id = p->scsi_id;
+ host->io_port = p->base;
host->n_io_port = 0xFF;
- host->base = (unsigned char *)config->mbase;
- host->irq = config->irq;
- if (config->bus_type == AIC_WIDE)
+ host->base = (unsigned char *) p->mbase;
+ host->irq = p->irq;
+ if (p->bus_type == AIC_WIDE)
{
host->max_id = 16;
}
- if (config->bus_type == AIC_TWIN)
+ if (p->bus_type == AIC_TWIN)
{
host->max_channel = 1;
}
- p = (struct aic7xxx_host *) host->hostdata;
-
p->host = host;
- p->host_no = (int)host->host_no;
+ p->host_no = host->host_no;
p->isr_count = 0;
- p->base = base;
- p->maxscbs = config->maxscbs;
- p->maxhscbs = config->maxhscbs;
- p->qcntmask = config->qcntmask;
- p->mbase = (char *)config->mbase;
- p->type = config->type;
- p->chip_type = config->chip_type;
- p->flags = config->flags;
- p->chan_num = config->chan_num;
- p->scb_link = &(p->scb_usage);
-#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
- if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
- {
- shared_3985_scbs = &(p->scb_usage);
- p->scb_link = &(p->scb_usage);
- }
-#endif
- p->scb_link->numscbs = 0;
- p->bus_type = config->bus_type;
- p->seeprom = sc;
p->next = NULL;
p->completeq.head = NULL;
p->completeq.tail = NULL;
- scbq_init(&p->scb_link->free_scbs);
- scbq_init(&p->page_scbs);
+ scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- scbq_init(&p->assigned_scbs);
-
- p->unpause = config->unpause;
- p->pause = config->pause;
- for (i = 0; i <= 15; i++)
+ for (i = 0; i <= NUMBER(p->device_status); i++)
{
p->device_status[i].commands_sent = 0;
p->device_status[i].flags = 0;
+ p->device_status[i].active_cmds = 0;
p->device_status[i].last_reset = 0;
}
- if (aic7xxx_boards[config->irq] == NULL)
+ if (aic7xxx_boards[p->irq] == NULL)
{
+ int result;
+ int irq_flags = 0;
+
+#ifdef AIC7XXX_OLD_ISR_TYPE
+ irg_flags = SA_INTERRUPT;
+#endif
/*
* Warning! This must be done before requesting the irq. It is
* possible for some boards to raise an interrupt as soon as
* kernel, an interrupt is triggered immediately. Therefore, we
* must ensure the board data is correctly set before the request.
*/
- aic7xxx_boards[config->irq] = host;
+ aic7xxx_boards[p->irq] = host;
/*
- * Register IRQ with the kernel.
+ * Register IRQ with the kernel. Only allow sharing IRQs with
+ * PCI devices.
*/
- if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
- "aic7xxx", NULL))
+ if (p->chip_class == AIC_777x)
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+ }
+ else
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+ "aic7xxx", NULL));
+ }
+ if (result < 0)
{
printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
- config->irq);
- aic7xxx_boards[config->irq] = NULL;
+ p->irq);
+ aic7xxx_boards[p->irq] = NULL;
return (0);
}
}
* registered host adapter. Add this host adapter's Scsi_Host
* to the beginning of the linked list of hosts at the same IRQ.
*/
- p->next = aic7xxx_boards[config->irq];
- aic7xxx_boards[config->irq] = host;
- }
-
- /*
- * 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 :-)
- */
- printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
- aic7xxx_loadseq(base);
-
- /*
- * Set Fast Mode and Enable the board
- */
- outb(FASTMODE, SEQCTL + base);
-
- if (p->chip_type == AIC_777x)
- {
- outb(ENABLE, BCTL + base);
+ p->next = aic7xxx_boards[p->irq];
+ aic7xxx_boards[p->irq] = host;
}
- printk("done.\n");
-
/*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->bus_type == AIC_TWIN)
{
/*
- * Select Channel B.
+ * The controller is gated to channel B after a chip reset; set
+ * bus B values first.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
-
- outb(config->scsi_id_b, SCSIID + base);
- scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+ outb(p->scsi_id_b, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF + 1);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
}
- /*
- * Select Channel A
- */
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus B. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+
+ aic7xxx_reset_current_bus(p);
+ }
+
+ /* Select channel A */
+ outb(SELNARROW, p->base + SBLKCTL);
}
- outb(config->scsi_id, SCSIID + base);
- scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+
+ outb(p->scsi_id, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
+ }
+
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus A. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+
+ aic7xxx_reset_current_bus(p);
+
+ /*
+ * Delay for the reset delay.
+ */
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
/*
/*
* Grab the disconnection disable table and invert it for our needs
*/
- if (have_seeprom)
+ if (p->flags & USE_DEFAULTS)
{
- p->discenable = 0x0;
+ printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
+ "device parameters.\n");
+ p->discenable = 0xFFFF;
}
else
{
- if (config->bios == AIC_DISABLED)
- {
- printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
- "device parameters.\n");
- p->discenable = 0xFFFF;
- }
- else
- {
- p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
- inb(DISC_DSB + base));
- }
+ p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
+ inb(p->base + DISC_DSB));
}
for (i = 0; i < max_targets; i++)
{
- if (config->flags & USE_DEFAULTS)
+ if (p->flags & USE_DEFAULTS)
{
- target_settings = 0; /* 10 MHz */
+ target_settings = 0; /* 10 or 20 MHz depending on Ultra enable */
p->needsdtr_copy |= (0x01 << i);
p->needwdtr_copy |= (0x01 << i);
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ ultraenable |= (0x01 << i);
}
else
{
- if (have_seeprom)
+ target_settings = inb(p->base + TARG_SCRATCH + i);
+ if (target_settings & 0x0F)
{
- target_settings = ((sc.device_flags[i] & CFXFER) << 4);
- if (sc.device_flags[i] & CFSYNCH)
- {
- p->needsdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFWIDEB)
- {
- p->needwdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFDISC)
- {
- p->discenable |= (0x01 << i);
- }
+ p->needsdtr_copy |= (0x01 << i);
+ /*
+ * Default to asynchronous transfers (0 offset)
+ */
+ target_settings &= 0xF0;
}
- else
+ if (target_settings & 0x80)
{
- target_settings = inb(TARG_SCRATCH + base + i);
- if (target_settings & 0x0F)
- {
- p->needsdtr_copy |= (0x01 << i);
- /*
- * Default to asynchronous transfers (0 offset)
- */
- target_settings &= 0xF0;
- }
- if (target_settings & 0x80)
- {
- p->needwdtr_copy |= (0x01 << i);
- target_settings &= 0x7F;
- }
+ p->needwdtr_copy |= (0x01 << i);
+ /*
+ * Clear the wide flag. When wide negotiation is successful,
+ * we'll enable it.
+ */
+ target_settings &= 0x7F;
}
if (p->flags & ULTRA_ENABLED)
{
case 0x20:
ultraenable |= (0x01 << i);
break;
- case 0x40:
+ case 0x40: /* treat 10MHz as 10MHz without Ultra enabled */
target_settings &= ~(0x70);
break;
default:
}
}
}
- outb(target_settings, (TARG_SCRATCH + base + i));
+ outb(target_settings, p->base + TARG_SCRATCH + i);
}
/*
p->needsdtr = p->needsdtr_copy;
p->needwdtr = p->needwdtr_copy;
p->orderedtag = 0;
-#if 0
- printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
- printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
-#endif
- outb(ultraenable & 0xFF, ULTRA_ENB + base);
- outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
+ outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
+ outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
+
+ /*
+ * Set the number of available hardware SCBs.
+ */
+ outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
+
+ /*
+ * 2s compliment of maximum tag value.
+ */
+ i = p->scb_data->maxscbs;
+ outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
+
+ /*
+ * Allocate enough hardware scbs to handle the maximum number of
+ * concurrent transactions we can have. We have to make sure that
+ * the allocated memory is contiguous memory. The Linux kmalloc
+ * routine should only allocate contiguous memory, but note that
+ * this could be a problem if kmalloc() is changed.
+ */
+ if (p->scb_data->hscbs == NULL)
+ {
+ size_t array_size;
+ unsigned int hscb_physaddr;
+
+ array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+ p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
+ if (p->scb_data->hscbs == NULL)
+ {
+ printk("aic7xxx: Unable to allocate hardware SCB array; "
+ "failing detection.\n");
+ release_region(p->base, MAXREG - MINREG);
+ /*
+ * Ensure that we only free the IRQ when there is _not_ another
+ * aic7xxx adapter sharing this IRQ. The adapters are always
+ * added to the beginning of the list, so we can grab the next
+ * pointer and place it back in the board array.
+ */
+ if (p->next == NULL)
+ {
+ free_irq(p->irq, aic7xxx_isr);
+ }
+ aic7xxx_boards[p->irq] = p->next;
+ return(0);
+ }
+ /* At least the control byte of each SCB needs to be 0. */
+ memset(p->scb_data->hscbs, 0, array_size);
+
+ /* Tell the sequencer where it can find the hardware SCB array. */
+ hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+ outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
+ outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
+ outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
+ outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
+ }
+
+ /*
+ * QCount mask to deal with broken aic7850s that sporadically get
+ * garbage in the upper bits of their QCNT registers.
+ */
+ outb(p->qcntmask, p->base + QCNTMASK);
+
+ /*
+ * We don't have any waiting selections or disconnected SCBs.
+ */
+ outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
+ outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
+
+ /*
+ * Message out buffer starts empty
+ */
+ outb(0, p->base + MSG_LEN);
+
+ /*
+ * 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_loadseq(p);
+
+ if (p->chip_class == AIC_777x)
+ {
+ outb(ENABLE, p->base + BCTL); /* Enable the boards BUS drivers. */
+ }
+
+ /*
+ * 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, /* unpause_always */ TRUE);
+
+ return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_chip_reset
+ *
+ * Description:
+ * Perform a chip reset on the aic7xxx SCSI controller. The controller
+ * is paused upon return.
+ *-F*************************************************************************/
+static void
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+ unsigned char hcntrl;
+ int wait;
+
+ /* Retain the IRQ type across the chip reset. */
+ hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+
+ /*
+ * For some 274x boards, we must clear the CHIPRST bit and pause
+ * the sequencer. For some reason, this makes the driver work.
+ */
+ outb(PAUSE | CHIPRST, p->base + HCNTRL);
+
+ /*
+ * In the future, we may call this function as a last resort for
+ * error handling. Let's be nice and not do any unecessary delays.
+ */
+ wait = 1000; /* 1 second (1000 * 1000 usec) */
+ while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+ {
+ udelay(1000); /* 1 msec = 1000 usec */
+ wait = wait - 1;
+ }
+
+ if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+ {
+ printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+ }
+
+ outb(hcntrl | PAUSE, p->base + HCNTRL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_alloc
+ *
+ * Description:
+ * Allocate and initialize a host structure. Returns NULL upon error
+ * and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
+ aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+{
+ struct aic7xxx_host *p = NULL;
+ struct Scsi_Host *host;
+
+ /*
+ * Allocate a storage area by registering us with the mid-level
+ * SCSI layer.
+ */
+ host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+ if (host != NULL)
+ {
+ p = (struct aic7xxx_host *) host->hostdata;
+ memset(p, 0, sizeof(struct aic7xxx_host));
+ p->host = host;
+
+ if (scb_data != NULL)
+ {
+ /*
+ * We are sharing SCB data areas; use the SCB data pointer
+ * provided.
+ */
+ p->scb_data = scb_data;
+ p->flags |= SHARED_SCBDATA;
+ }
+ else
+ {
+ /*
+ * We are not sharing SCB data; allocate one.
+ */
+ p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (p->scb_data != NULL)
+ {
+ memset(p->scb_data, 0, sizeof(scb_data_type));
+ scbq_init (&p->scb_data->free_scbs);
+ }
+ else
+ {
+ /*
+ * For some reason we don't have enough memory. Free the
+ * allocated memory for the aic7xxx_host struct, and return NULL.
+ */
+ scsi_unregister(host);
+ p = NULL;
+ }
+ }
+ if (p != NULL)
+ {
+ p->host_no = host->host_no;
+ p->base = base;
+ p->mbase = mbase;
+ p->maddr = NULL;
+ p->flags = flags;
+ p->chip_type = chip_type;
+ p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+ p->pause = p->unpause | PAUSE;
+ }
+ }
+ return (p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_free
+ *
+ * Description:
+ * Frees and releases all resources associated with an instance of
+ * the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free (struct aic7xxx_host *p)
+{
+ int i;
+
+ /*
+ * We should be careful in freeing the scb_data area. For those
+ * adapters sharing external SCB RAM(398x), there will be only one
+ * scb_data area allocated. The flag SHARED_SCBDATA indicates if
+ * one adapter is sharing anothers SCB RAM.
+ */
+ if (!(p->flags & SHARED_SCBDATA))
+ {
+ /*
+ * Free the allocated hardware SCB space.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
+ /*
+ * Free the driver SCBs. These were allocated on an as-need
+ * basis.
+ */
+ for (i = 0; i < p->scb_data->numscbs; i++)
+ {
+ kfree(p->scb_data->scb_array[i]);
+ }
+ /*
+ * Free the hardware SCBs.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
+ /*
+ * Free the SCB data area.
+ */
+ kfree(p->scb_data);
+ }
/*
- * Set the number of available SCBs.
+ * Free the instance of the device structure.
*/
- outb(config->maxhscbs, SCBCOUNT + base);
+ scsi_unregister(p->host);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_load_seeprom
+ *
+ * Description:
+ * Load the seeprom and configure adapter and target settings.
+ * Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static int
+load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+ int have_seeprom = 0;
+ int i, max_targets;
+ unsigned char target_settings, scsi_conf;
+ unsigned short scarray[128];
+ struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+ }
+ switch (p->chip_type)
+ {
+ case AIC_7770: /* None of these adapters have seeproms. */
+ case AIC_7771:
+ case AIC_7850:
+ case AIC_7855:
+ break;
- /*
- * 2s compliment of maximum tag value.
- */
- i = p->maxscbs;
- outb(-i & 0xFF, COMP_SCBCOUNT + base);
+ case AIC_284x:
+ have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+ break;
- /*
- * Set the QCNT (queue count) mask to deal with broken aic7850s that
- * sporatically get garbage in the upper bits of their QCNT registers.
- */
- outb(config->qcntmask, QCNTMASK + base);
+ case AIC_7861:
+ case AIC_7870:
+ case AIC_7871:
+ case AIC_7872:
+ case AIC_7874:
+ case AIC_7881:
+ case AIC_7882:
+ case AIC_7884:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(*sc)/2, C46);
+ break;
- /*
- * Clear the active flags - no targets are busy.
- */
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
+ case AIC_7860: /* Motherboard Ultra controllers might have RAID port. */
+ case AIC_7880:
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
+ if (!have_seeprom)
+ {
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
+ }
+ break;
- /*
- * We don't have any waiting selections or disconnected SCBs.
- */
- outb(SCB_LIST_NULL, WAITING_SCBH + base);
- outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
+ case AIC_7873: /* The 3985 adapters use the 93c56 serial EEPROM. */
+ case AIC_7883:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(scarray)/2, C56_66);
+ break;
- /*
- * Message out buffer starts empty
- */
- outb(0, MSG_LEN + base);
+ default:
+ break;
+ }
- /*
- * Reset the SCSI bus. Is this necessary?
- * There may be problems for a warm boot without resetting
- * the SCSI bus. Either BIOS settings in scratch RAM
- * will not get reinitialized, or devices may stay at
- * previous negotiated settings (SDTR and WDTR) while
- * the driver will think that no negotiations have been
- * performed.
- *
- * Some devices need a long time to "settle" after a SCSI
- * bus reset.
- */
- if (!aic7xxx_no_reset)
+ if (!have_seeprom)
+ {
+ if (aic7xxx_verbose)
+ {
+ printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+ }
+ p->flags |= USE_DEFAULTS;
+ }
+ else
{
- printk("aic7xxx: Resetting the SCSI bus...");
- if (p->bus_type == AIC_TWIN)
+ if (aic7xxx_verbose)
+ {
+ printk("done\n");
+ }
+ p->flags |= HAVE_SEEPROM;
+
+ /*
+ * Update the settings in sxfrctl1 to match the termination settings.
+ */
+ *sxfrctl1 = 0;
+
+ /*
+ * First process the settings that are different between the VLB
+ * and PCI adapter seeproms.
+ */
+ if (p->chip_class == AIC_777x)
{
+ /* VLB adapter seeproms */
+ if (sc->bios_control & CF284XEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (sc->adapter_control & CF284XSTERM)
+ *sxfrctl1 |= STPWEN;
/*
- * Select Channel B.
+ * The 284x SEEPROM doesn't have a max targets field. We
+ * set it to 16 to make sure we take care of the 284x-wide
+ * adapters. For narrow adapters, going through the extra
+ * 8 target entries will not cause any harm since they will
+ * will not be used.
+ *
+ * XXX - We should probably break out the bus detection
+ * from the register function so we can use it here
+ * to tell us how many targets there really are.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+ max_targets = 16;
+ }
+ else
+ {
+ /* PCI adapter seeproms */
+ if (sc->bios_control & CFEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+ if (sc->adapter_control & CFSTERM)
+ *sxfrctl1 |= STPWEN;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /* Limit to 16 targets just in case. */
+ max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
+ }
- /*
- * Select Channel A.
- */
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ for (i = 0; i < max_targets; i++)
+ {
+ target_settings = (sc->device_flags[i] & CFXFER) << 4;
+ if (sc->device_flags[i] & CFSYNCH)
+ target_settings |= SOFS;
+ if (sc->device_flags[i] & CFWIDEB)
+ target_settings |= WIDEXFER;
+ if (sc->device_flags[i] & CFDISC)
+ p->discenable |= (0x01 << i);
+ outb(target_settings, p->base + TARG_SCRATCH + i);
}
+ outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
+ outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+ p->scsi_id = sc->brtime_id & CFSCSIID;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ scsi_conf = (p->scsi_id & 0x7);
+ if (sc->adapter_control & CFSPARITY)
+ scsi_conf |= ENSPCHK;
+ if (sc->adapter_control & CFRESETB)
+ scsi_conf |= RESET_SCSI;
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ /*
+ * We allow the operator to override ultra enable through
+ * the boot prompt.
+ */
+ if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
+ {
+ /* Treat us as a non-ultra card */
+ p->flags &= ~ULTRA_ENABLED;
+ }
+ }
- printk("done.\n");
- }
+ /* Set the host ID */
+ outb(scsi_conf, p->base + SCSICONF);
+ /* In case we are a wide card */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
- /*
- * 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 (found);
+ if (p->chip_class != AIC_777x)
+ {
+ /*
+ * Update the settings in sxfrctl1 to match the termination
+ * settings.
+ */
+ *sxfrctl1 = 0;
+ configure_termination(p, sxfrctl1, sc->adapter_control,
+ (unsigned char) sc->max_targets & CFMAXTARG);
+ }
+ }
+ return (have_seeprom);
}
/*+F*************************************************************************
*
* Description:
* Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe(). A sequence of
+ * probe(), attach()/detach(), and init() makes more sense than
+ * one do-it-all function. This may be useful when (and if) the
+ * mid-level SCSI code is overhauled.
*-F*************************************************************************/
int
aic7xxx_detect(Scsi_Host_Template *template)
{
- int found = 0, slot, base;
- unsigned char irq = 0;
+ int found = 0;
+ aha_status_type adapter_bios;
+ aha_chip_class_type chip_class;
+ aha_chip_type chip_type;
+ int slot, base;
+ int chan_num = 0;
+ unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
int i;
- struct aic7xxx_host_config config;
-
- template->proc_dir = &proc_scsi_aic7xxx;
- config.chan_num = 0;
+ struct aic7xxx_host *p;
/*
* Since we may allow sharing of IRQs, it is imperative
aic7xxx_boards[i] = NULL;
}
+ template->proc_dir = &proc_scsi_aic7xxx;
+ template->name = aic7xxx_info(NULL);
+ template->sg_tablesize = AIC7XXX_MAX_SG;
+
/*
* Initialize the spurious count to 0.
*/
continue;
}
- config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
- if (config.type != AIC_NONE)
+ chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
+ if (chip_type != AIC_NONE)
{
+
+ switch (chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[chip_type], slot);
+ break;
+ case AIC_284x:
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[chip_type], slot);
+ break;
+ default:
+ break;
+ }
+
/*
* We found a card, allow 1 spurious interrupt.
*/
aic7xxx_spurious_count = 1;
/*
- * We "find" a AIC-7770 if we locate the card
- * signature and we can set it up and register
- * it with the kernel without incident.
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
*/
- config.chip_type = AIC_777x;
- config.base = base;
- config.mbase = 0;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
- config.flags = 0;
- if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
- config.bus_speed = DFTHRSH_100;
- config.busrtime = BOFF;
- found += aic7xxx_register(template, &config);
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ outb(hcntrl | PAUSE, base + HCNTRL);
+
+ irq = inb(INTDEF + base) & 0x0F;
+ switch (irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level, ignoring.\n");
+ irq = 0;
+ break;
+ }
+
+ if (irq != 0)
+ {
+ p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+ p->irq = irq & 0x0F;
+ p->chip_class = AIC_777x;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+ if (aic7xxx_extended)
+ {
+ p->flags |= EXTENDED_TRANSLATION;
+ }
+ aic7xxx_chip_reset(p);
+
+ switch (p->chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ {
+ unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (biosctrl & CHANNEL_B_PRIMARY)
+ {
+ p->flags |= FLAGS_CHANNEL_B_PRIMARY;
+ }
+
+ if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+ {
+ p->flags |= USE_DEFAULTS;
+ }
+ break;
+ }
+
+ case AIC_284x:
+ if (!load_seeprom(p, &sxfrctl1))
+ {
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
+ (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ /*
+ * Check for Rev C or E boards. Rev E boards can supposedly have
+ * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+ * It's still not clear extactly what is different about the Rev E
+ * boards, but we think it allows 8 bit entries in the QOUTFIFO to
+ * support "paging" SCBs (more than 4 commands can be active at once).
+ *
+ * The Rev E boards have a read/write autoflush bit in the
+ * SBLKCTL register, while in the Rev C boards it is read only.
+ */
+ sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
+ outb(sblkctl, p->base + SBLKCTL);
+ if (inb(p->base + SBLKCTL) == sblkctl)
+ {
+ /*
+ * We detected a Rev E board, we allow paging on this board.
+ */
+ printk("Revision >= E\n");
+ outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+ }
+ else
+ {
+ /* Do not allow paging. */
+ p->flags &= ~PAGE_ENABLED;
+ printk("Revision <= C\n");
+ }
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = inb(p->base + HOSTCONF);
+ outb(hostconf & DFTHRSH, p->base + BUSSPD);
+ outb((hostconf << 2) & BOFF, p->base + BUSTIME);
+ /*
+ * Try to initialize the card and register it with the kernel.
+ */
+ if (aic7xxx_register(template, p))
+ {
+ /*
+ * We successfully found a board and registered it.
+ */
+ found = found + 1;
+ }
+ else
+ {
+ /*
+ * Something went wrong; release and free all resources.
+ */
+ aic7xxx_free(p);
+ }
+ }
/*
* Disallow spurious interrupts.
*/
{
struct
{
- unsigned short vendor_id;
- unsigned short device_id;
- aha_type card_type;
- aha_chip_type chip_type;
+ unsigned short vendor_id;
+ unsigned short device_id;
+ aha_chip_type chip_type;
+ aha_chip_class_type chip_class;
} const aic7xxx_pci_devices[] = {
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
};
- int error;
+ int error, flags;
int done = 0;
unsigned int iobase, mbase;
unsigned short index = 0;
unsigned char pci_bus, pci_device_fn;
- unsigned int csize_lattime;
- unsigned int class_revid;
- unsigned int devconfig;
+ unsigned char ultra_enb = 0;
+ unsigned int devconfig, class_revid;
+ scb_data_type *shared_scb_data = NULL;
char rev_id[] = {'B', 'C', 'D'};
for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
}
else /* Found an Adaptec PCI device. */
{
- config.type = aic7xxx_pci_devices[i].card_type;
- config.chip_type = aic7xxx_pci_devices[i].chip_type;
- config.chan_num = 0;
- config.bios = AIC_ENABLED; /* Assume bios is enabled. */
- config.flags = 0;
- config.busrtime = 40;
- switch (config.type)
+ chip_class = aic7xxx_pci_devices[i].chip_class;
+ chip_type = aic7xxx_pci_devices[i].chip_type;
+ chan_num = 0;
+ flags = 0;
+ switch (aic7xxx_pci_devices[i].chip_type)
{
case AIC_7850:
case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- config.bios = AIC_DISABLED;
- config.flags |= USE_DEFAULTS;
- config.bus_speed = DFTHRSH_100;
+ flags |= USE_DEFAULTS;
break;
case AIC_7872: /* 3940 */
case AIC_7882: /* 3940-Ultra */
- config.chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
+ flags |= MULTI_CHANNEL;
+ chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
number_of_3940s++;
break;
case AIC_7873: /* 3985 */
case AIC_7883: /* 3985-Ultra */
- config.chan_num = number_of_3985s; /* Has 3 controllers */
+ chan_num = number_of_3985s; /* Has 3 controllers */
+ flags |= MULTI_CHANNEL;
number_of_3985s++;
if (number_of_3985s == 3)
{
number_of_3985s = 0;
+ shared_scb_data = NULL;
}
break;
PCI_INTERRUPT_LINE, &irq);
error += pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, &mbase);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, &devconfig);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ CLASS_PROGIF_REVID, &class_revid);
+
+ printk("aic7xxx: <%s> at PCI %d\n",
+ board_names[chip_type], PCI_SLOT(pci_device_fn));
/*
- * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+ * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
* we mask it off.
*/
iobase &= PCI_BASE_ADDRESS_IO_MASK;
+ p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
+ shared_scb_data);
+
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+
+ /* Remember to set the channel number, irq, and chip class. */
+ p->chan_num = chan_num;
+ p->irq = irq;
+ p->chip_class = chip_class;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+
/*
- * Read the PCI burst size and latency timer.
+ * Remember how the card was setup in case there is no seeprom.
*/
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CSIZE_LATTIME, &csize_lattime);
- printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
- "PCLKS\n", (int) (csize_lattime & CACHESIZE),
- (csize_lattime >> 8) & 0x000000ff);
+ p->scsi_id = inb(p->base + SCSIID) & OID;
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ p->flags |= ULTRA_ENABLED;
+ ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+ }
+ sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CLASS_PROGIF_REVID, &class_revid);
- if ((class_revid & DEVREVID) < 3)
+ aic7xxx_chip_reset(p);
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
+ if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
- rev_id[class_revid & DEVREVID]);
+ printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+ "access.\n");
+ /*
+ * XXX - Assume 9 bit SRAM and enable parity checking.
+ */
+ devconfig |= EXTSCBPEN;
+
+ /*
+ * XXX - Assume fast SRAM and only enable 2 cycle access if we
+ * are sharing the SRAM across multiple adapters (398x).
+ */
+ if ((devconfig & MPORTMODE) == 0)
+ {
+ devconfig |= EXTSCBTIME;
+ }
+ devconfig &= ~SCBRAMSEL;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, devconfig);
}
+#endif
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, &devconfig);
- if (error)
+ if ((p->flags & USE_DEFAULTS) == 0)
+ {
+ load_seeprom(p, &sxfrctl1);
+ }
+
+ /*
+ * Take the LED out of diagnostic mode
+ */
+ sblkctl = inb(p->base + SBLKCTL);
+ outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+
+ /*
+ * We don't know where this is set in the SEEPROM or by the
+ * BIOS, so we default to 100%.
+ */
+ outb(DFTHRSH_100, p->base + DSPCISTATUS);
+
+ if (p->flags & USE_DEFAULTS)
{
- panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
- error);
+ int j;
+ /*
+ * Default setup; should only be used if the adapter does
+ * not have a SEEPROM.
+ */
+ /*
+ * Check the target scratch area to see if someone set us
+ * up already. We are previously set up if the scratch
+ * area contains something other than all zeroes and ones.
+ */
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + j) != 0x00) /* Check for all zeroes. */
+ break;
+ }
+ if (j == TARG_SCRATCH)
+ {
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + 1) != 0xFF) /* Check for all ones. */
+ break;
+ }
+ }
+ if ((j != 0x60) && (p->scsi_id != 0))
+ {
+ p->flags &= ~USE_DEFAULTS;
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
+ }
+ }
+ else
+ {
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: No BIOS found; using default "
+ "settings.\n");
+ }
+ /*
+ * Assume only one connector and always turn on
+ * termination.
+ */
+ sxfrctl1 = STPWEN;
+ p->scsi_id = 7;
+ }
+ outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+ p->base + SCSICONF);
+ /* In case we are a wide card. */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
+ if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
+ {
+ /*
+ * If there wasn't a BIOS or the board wasn't in this mode
+ * to begin with, turn off Ultra.
+ */
+ p->flags &= ~ULTRA_ENABLED;
+ }
}
- printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
+ /*
+ * Print some additional information about the adapter.
+ */
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
+ "IO Mem 0x%x, IRQ %d",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en",
+ p->base, p->mbase, p->irq);
+ if ((class_revid & DEVREVID) < 3)
+ {
+ printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+ }
+ printk("\n");
/*
* I don't think we need to bother with allowing
*/
aic7xxx_spurious_count = 1;
- config.base = iobase;
- config.mbase = mbase;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
-#ifdef AIC7XXX_SHARE_SCBs
- if (devconfig & RAMPSM)
-#else
- if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
- (config.type != AIC_7883))
-#endif
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Put our termination setting into sxfrctl1 now that the
+ * generic initialization is complete.
+ */
+ sxfrctl1 |= inb(p->base + SXFRCTL1);
+ outb(sxfrctl1, p->base + SXFRCTL1);
+
+ if (aic7xxx_register(template, p) == 0)
+ {
+ aic7xxx_free(p);
+ }
+ else
{
+ found = found + 1;
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
/*
- * External SRAM present. The probe will walk the SCBs to see
- * how much SRAM we have and set the number of SCBs accordingly.
- * We have to turn off SCBRAMSEL to access the external SCB
- * SRAM.
+ * Set the shared SCB data once we've successfully probed a
+ * 398x adapter.
*
- * It seems that early versions of the aic7870 didn't use these
- * bits, hence the hack for the 3940 above. I would guess that
- * recent 3940s using later aic7870 or aic7880 chips do actually
- * set RAMPSM.
- *
- * The documentation isn't clear, but it sounds like the value
- * written to devconfig must not have RAMPSM set. The second
- * sixteen bits of the register are R/O anyway, so it shouldn't
- * affect RAMPSM either way.
+ * Note that we can only do this if the use of external
+ * SCB RAM is enabled.
*/
- printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
- "access.\n");
- devconfig &= ~(RAMPSM | SCBRAMSEL);
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, devconfig);
+ if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+ {
+ if (shared_scb_data == NULL)
+ {
+ shared_scb_data = p->scb_data;
+ }
+ }
+#endif
}
- found += aic7xxx_register(template, &config);
+ index++;
/*
* Disable spurious interrupts.
*/
- aic7xxx_spurious_count = 0;
-
- index++;
+ aic7xxx_spurious_count = 0;
} /* Found an Adaptec PCI device. */
}
}
}
#endif CONFIG_PCI
- template->name = aic7xxx_info(NULL);
return (found);
}
aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct aic7xxx_scb *scb)
{
- unsigned int addr; /* must be 32 bits */
unsigned short mask;
+ struct aic7xxx_hwscb *hscb;
mask = (0x01 << TARGET_INDEX(cmd));
+ hscb = scb->hscb;
+
/*
* Setup the control byte if we need negotiation and have not
* already requested it.
*/
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (cmd->device->tagged_queue)
+ if (p->discenable & mask)
{
- cmd->tag = scb->tag;
- cmd->device->current_tag = scb->tag;
- scb->control |= TAG_ENB;
- p->device_status[TARGET_INDEX(cmd)].commands_sent++;
- if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
- {
- scb->control |= 0x02;
- p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
- }
-#if 0
- if (p->orderedtag & mask)
+ hscb->control |= DISCENB;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (cmd->device->tagged_queue)
{
- scb->control |= 0x02;
- p->orderedtag = p->orderedtag & ~mask;
+ cmd->tag = hscb->tag;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+ if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+ {
+ hscb->control |= MSG_SIMPLE_Q_TAG;
+ }
+ else
+ {
+ hscb->control |= MSG_ORDERED_Q_TAG;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+ }
}
-#endif
- }
-#endif
- if (p->discenable & mask)
- {
- scb->control |= DISCENB;
+#endif /* Tagged queueing */
}
+
if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
{
p->wdtr_pending |= mask;
- scb->control |= NEEDWDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_WDTR;
#if 0
- printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending WDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
else
if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
{
p->sdtr_pending |= mask;
- scb->control |= NEEDSDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_SDTR;
#if 0
- printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending SDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
}
-
#if 0
printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
"mask(0x%x).\n",
cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
#endif
- scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+ hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
/*
* XXX - this relies on the host data being stored in a
* little-endian format.
*/
- addr = VIRT_TO_BUS(cmd->cmnd);
- scb->SCSI_cmd_length = cmd->cmd_len;
- memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = cmd->cmd_len;
+ hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
if (cmd->use_sg)
{
scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
scb->sg_list[i].length = (unsigned int) sg[i].length;
}
- scb->SG_segment_count = cmd->use_sg;
- addr = VIRT_TO_BUS(scb->sg_list);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
- scb->data_count = scb->sg_list[0].length;
+ hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+ hscb->SG_segment_count = cmd->use_sg;
+ scb->sg_count = hscb->SG_segment_count;
+
+ /* Copy the first SG into the data pointer area. */
+ hscb->data_pointer = scb->sg_list[0].address;
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
#if 0
printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
- cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
+ cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
#endif
}
else
printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
(unsigned long) cmd->request_buffer, cmd->request_bufflen);
#endif
- if (cmd->request_bufflen == 0)
+ if (cmd->request_bufflen)
{
- /*
- * In case the higher level SCSI code ever tries to send a zero
- * length command, ensure the SCB indicates no data. The driver
- * will interpret a zero length command as a Bus Device Reset.
- */
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
+ hscb->SG_segment_count = 1;
+ scb->sg_count = 1;
+ scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+ scb->sg_list[0].length = cmd->request_bufflen;
+ hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+ hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
}
else
{
- scb->SG_segment_count = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
- scb->sg_list[0].length = cmd->request_bufflen;
- addr = VIRT_TO_BUS(&scb->sg_list[0]);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- addr = VIRT_TO_BUS(cmd->request_buffer);
- memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
+ hscb->SG_segment_count = 0;
+ scb->sg_count = 0;
+ hscb->SG_list_pointer = 0;
+ hscb->data_pointer = 0;
+ hscb->data_count = SCB_LIST_NULL << 24;
}
}
}
long processor_flags;
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
- u_char curscb, intstat;
p = (struct aic7xxx_host *) cmd->host->hostdata;
if (p->host != cmd->host)
cmd->lun & 0x07);
#endif
- /*
- * This is a critical section, since we don't want the interrupt
- * routine mucking with the host data or the card. For this reason
- * it is nice to know that this function can only be called in one
- * of two ways from scsi.c First, as part of a routine queue command,
- * in which case, the irq for our card is disabled before this
- * function is called. This doesn't help us if there is more than
- * one card using more than one IRQ in our system, therefore, we
- * should disable all interrupts on these grounds alone. Second,
- * this can be called as part of the scsi_done routine, in which case
- * we are in the aic7xxx_isr routine already and interrupts are
- * disabled, therefore we should saveflags first, then disable the
- * interrupts, do our work, then restore the CPU flags. If it weren't
- * for the possibility of more than one card using more than one IRQ
- * in our system, we wouldn't have to touch the interrupt flags at all.
- */
- save_flags(processor_flags);
- cli();
-
+ if (p->device_status[TARGET_INDEX(cmd)].active_cmds
+ > cmd->device->queue_depth)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
+ p->host_no, cmd->target, cmd->channel);
+ }
scb = aic7xxx_allocate_scb(p);
if (scb == NULL)
{
- panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
+ panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
}
else
{
scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->tag;
+ aic7xxx_position(cmd) = scb->hscb->tag;
#if 0
debug_scb(scb);
#endif;
aic7xxx_buildscb(p, cmd, scb);
#if 0
- if (scb != (p->scb_array[scb->position]))
+ if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
{
printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
"address.\n");
}
printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
- scb->position, (unsigned int) scb->cmd,
- scb->state, (unsigned int) p->free_scb);
+ scb->hscb->tag, (unsigned int) scb->cmd,
+ scb->flags, (unsigned int) p->free_scb);
#endif
/*
cmd->host_scribble = NULL;
memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- if (scb->position != SCB_LIST_NULL)
- {
- /* We've got a valid slot, yeah! */
- if (p->flags & IN_ISR)
- {
- scbq_insert_tail(&p->assigned_scbs, scb);
- scb->state |= SCB_ASSIGNEDQ;
- }
- else
- {
- /*
- * 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);
- intstat = inb(INTSTAT + p->base);
-
- /*
- * 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.
- */
- curscb = inb(SCBPTR + p->base);
- outb(scb->position, SCBPTR + p->base);
- aic7xxx_putscb(p, scb);
- outb(curscb, SCBPTR + p->base);
- outb(scb->position, QINFIFO + p->base);
- scb->state |= SCB_ACTIVE;
+ scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
- }
- }
- else
+ save_flags(processor_flags);
+ cli();
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
{
- scb->state |= SCB_WAITINGQ;
- scbq_insert_tail(&p->waiting_scbs, scb);
- if (!(p->flags & IN_ISR))
- {
- aic7xxx_run_waiting_queues(p);
- }
+ aic7xxx_run_waiting_queues(p);
}
+ restore_flags(processor_flags);
#if 0
printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
- (long) cmd, (long) scb->cmd, scb->position);
+ (long) cmd, (long) scb->cmd, scb->hscb->tag);
#endif;
- restore_flags(processor_flags);
}
return (0);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_abort_reset
+ * aic7xxx_bus_device_reset
*
* Description:
* Abort or reset the current SCSI command(s). If the scb has not
static int
aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scb;
+ struct aic7xxx_hwscb *hscb;
unsigned char bus_state;
- int base, result = -1;
+ int result = -1;
char channel;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
- base = p->base;
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+ hscb = scb->hscb;
+
+ /*
+ * Ensure that the card doesn't do anything behind our back.
+ * Also make sure that we didn't just miss an interrupt that
+ * could affect this abort/reset.
+ */
+ pause_sequencer(p);
+ while (inb(p->base + INTSTAT) & INT_PEND);
+ {
+ aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
+ pause_sequencer(p);
+ }
+ if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ return(result);
+ }
- channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
- if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
+
+ printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
+ p->host_no, TC_OF_SCB(scb), scb->flags);
+ bus_state = inb(p->base + LASTPHASE);
+
+ switch (bus_state)
{
+ case P_DATAOUT:
+ printk("Data-Out phase, ");
+ break;
+ case P_DATAIN:
+ printk("Data-In phase, ");
+ break;
+ case P_COMMAND:
+ printk("Command phase, ");
+ break;
+ case P_MESGOUT:
+ printk("Message-Out phase, ");
+ break;
+ case P_STATUS:
+ printk("Status phase, ");
+ break;
+ case P_MESGIN:
+ printk("Message-In phase, ");
+ break;
+ default:
+ /*
+ * We're not in a valid phase, so assume we're idle.
+ */
+ printk("while idle, LASTPHASE = 0x%x, ", bus_state);
+ break;
+ }
+ printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
+ inb(p->base + SCSISIGI),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
- if (scb->state & SCB_IN_PROGRESS)
+ channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+ /*
+ * Determine our course of action.
+ */
+ if (scb->flags & SCB_ABORT)
+ {
+ /*
+ * Been down this road before; do a full bus reset.
+ */
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
+ }
+#if 0
+ else if (hscb->control & TAG_ENB)
{
/*
- * Ensure that the card doesn't do anything
- * behind our back.
+ * We could be starving this command; try sending and ordered tag
+ * command to the target we come from.
*/
- PAUSE_SEQUENCER(p);
+ scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
+ p->orderedtag = p->orderedtag | 0xFF;
+ result = SCSI_RESET_PENDING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
+ p->host_no);
+ }
+#endif
+ else
+ {
+ unsigned char active_scb_index, saved_scbptr;
+ struct aic7xxx_scb *active_scb;
- printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
- bus_state = inb(LASTPHASE + p->base);
+ /*
+ * Send an Abort Message:
+ * The target that is holding up the bus may not be the same as
+ * the one that triggered this timeout (different commands have
+ * different timeout lengths). Our strategy here is to queue an
+ * abort message to the timed out target if it is disconnected.
+ * Otherwise, if we have an active target we stuff the message buffer
+ * with an abort message and assert ATN in the hopes that the target
+ * will let go of the bus and go to the mesgout phase. If this
+ * fails, we'll get another timeout a few seconds later which will
+ * attempt a bus reset.
+ */
+ saved_scbptr = inb(p->base + SCBPTR);
+ active_scb_index = inb(p->base + SCB_TAG);
+ active_scb = p->scb_data->scb_array[active_scb_index];
- switch (bus_state)
+ if (bus_state != P_BUSFREE)
+ {
+ if (active_scb_index >= p->scb_data->numscbs)
{
- case P_DATAOUT:
- printk("Data-Out phase, ");
- break;
- case P_DATAIN:
- printk("Data-In phase, ");
- break;
- case P_COMMAND:
- printk("Command phase, ");
- break;
- case P_MESGOUT:
- printk("Message-Out phase, ");
- break;
- case P_STATUS:
- printk("Status phase, ");
- break;
- case P_MESGIN:
- printk("Message-In phase, ");
- break;
- default:
- printk("while idle, LASTPHASE = 0x%x, ", bus_state);
- /*
- * We're not in a valid phase, so assume we're idle.
- */
- bus_state = 0;
- break;
+ /*
+ * Perform a bus reset.
+ *
+ * XXX - We want to queue an abort for the timedout SCB
+ * instead.
+ */
+ result = -1;
+ printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
+ "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
}
- printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
-
- /*
- * First, determine if we want to do a bus reset or simply a bus device
- * reset. If this is the first time that a transaction has timed out
- * and the SCB is not paged out, just schedule a bus device reset.
- * Otherwise, we reset the bus and abort all pending I/Os on that bus.
- */
- if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
+ else
{
-#if 0
- if (scb->control & TAG_ENB)
- {
+ /* Send the abort message to the active SCB. */
+ outb(1, p->base + MSG_LEN);
+ if (active_scb->hscb->control & TAG_ENB)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT);
+ }
+ outb(bus_state | ATNO, p->base + SCSISIGO);
+ printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
+ p->host_no);
+ active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
+ if (active_scb != scb)
+ {
/*
- * We could be starving this command; try sending and ordered tag
- * command to the target we come from.
+ * XXX - We would like to increment the timeout on scb, but
+ * access to that routine is denied because it is hidden
+ * in scsi.c. If we were able to do this, it would give
+ * scb a new lease on life.
*/
- scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
- p->orderedtag = p->orderedtag | 0xFF;
result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
- }
-#endif
- unsigned char active_scb, control;
- struct aic7xxx_scb *active_scbp;
+ aic7xxx_error(active_scb->cmd) = DID_RESET;
+ }
+ else
+ {
+ aic7xxx_error(scb->cmd) = DID_RESET;
+ result = SCSI_RESET_PENDING;
+ }
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ }
+ else
+ {
+ unsigned char hscb_index, linked_next;
+ int disconnected;
- /*
- * Send a Bus Device Reset Message:
- * The target we select to send the message to may be entirely
- * different than the target pointed to by the scb that timed
- * out. If the command is in the QINFIFO or the waiting for
- * selection list, its not tying up the bus and isn't responsible
- * for the delay so we pick off the active command which should
- * be the SCB selected by SCBPTR. If its disconnected or active,
- * we device reset the target scbp points to. Although it may
- * be that this target is not responsible for the delay, it may
- * may also be that we're timing out on a command that just takes
- * too much time, so we try the bus device reset there first.
- */
- active_scb = inb(SCBPTR + base);
- active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
- control = inb(SCB_CONTROL + base);
+ disconnected = FALSE;
+ hscb_index = aic7xxx_find_scb(p, scb);
+ if (hscb_index == SCB_LIST_NULL)
+ {
+ disconnected = TRUE;
+ linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+ }
+ else
+ {
+ outb(hscb_index, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+ {
+ disconnected = TRUE;
+ }
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ }
+ if (disconnected)
+ {
+ /*
+ * Simply set the ABORT_SCB control bit and preserve the
+ * linked next pointer.
+ */
+ scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+ scb->hscb->data_count &= ~0xFF000000;
+ scb->hscb->data_count |= linked_next << 24;
+ if ((p->flags & PAGE_ENABLED) == 0)
+ {
+ scb->hscb->control &= ~DISCONNECTED;
+ }
+ scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+ if (hscb_index != SCB_LIST_NULL)
+ {
+ unsigned char scb_control;
- /*
- * Test to see if scbp is disconnected
- */
- outb(scb->position, SCBPTR + base);
- if (inb(SCB_CONTROL + base) & DISCONNECTED)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) scb %d is disconnected; "
- "bus device reset message queued.\n", scb->position);
-#endif
- if (p->flags & PAGE_ENABLED)
- {
- /* Pull this SCB out of the disconnected list. */
- u_char prev = inb(SCB_PREV + base);
- u_char next = inb(SCB_NEXT + base);
- if (prev == SCB_LIST_NULL)
- {
- /* Head of list */
- outb(next, DISCONNECTED_SCBH + base);
- }
- else
- {
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(prev, SCB_PREV + base);
- }
- outb(scb->position, SCBPTR + base);
- }
- }
- scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- scb->control = scb->control & DISCENB;
- scb->SCSI_cmd_length = 0;
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
- aic7xxx_putscb(p, scb);
- aic7xxx_add_waiting_scb(base, scb);
- outb(active_scb, SCBPTR + base);
- result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- }
- else
- {
- /*
- * Is the active SCB really active?
- */
- if ((active_scbp->state & SCB_ACTIVE) && bus_state)
- {
- /*
- * Load the message buffer and assert attention.
- */
- active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- outb(1, MSG_LEN + base);
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(bus_state | ATNO, SCSISIGO + base);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) asserted ATN - "
- "bus device reset in message buffer.\n");
-#endif
- if (active_scbp != scb)
- {
- /*
- * XXX - We would like to increment the timeout on scb, but
- * access to that routine is denied because it is hidden
- * in scsi.c. If we were able to do this, it would give
- * scb a new lease on life.
- */
- ;
- }
- aic7xxx_error(scb->cmd) = DID_RESET;
- /*
- * Restore the active SCB and unpause the sequencer.
- */
- outb(active_scb, SCBPTR + base);
- if (active_scbp != scb)
- {
- /*
- * The mid-level SCSI code requested us to reset a command
- * different from the one that we actually reset. Return
- * a "not running" indication and hope that the SCSI code
- * will Do the Right Thing (tm).
- */
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
- {
- result = SCSI_RESET_PENDING;
- }
- UNPAUSE_SEQUENCER(p);
- }
- }
+ scb_control = inb(p->base + SCB_CONTROL);
+ outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+ }
+ /*
+ * Actually requeue this SCB in case we can select the
+ * device before it reconnects. If the transaction we
+ * want to abort is not tagged, unbusy it first so that
+ * we don't get held back from sending the command.
+ */
+ if ((scb->hscb->control & TAG_ENB) == 0)
+ {
+ unsigned char target;
+ int lun;
+
+ target = scb->cmd->target;
+ lun = scb->cmd->lun;
+ aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
+ 0, /* requeue */ TRUE);
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
+ p->host_no, TC_OF_SCB(scb));
+ scbq_insert_head(&p->waiting_scbs, scb);
+ scb->flags |= SCB_WAITINGQ;
+ outb(saved_scbptr, p->base + SCBPTR);
+ if ((p->flags & IN_ISR) == 0)
+ {
+ /*
+ * Processing the waiting queue may unpause us.
+ */
+ aic7xxx_run_waiting_queues(p);
+ /*
+ * If we are using AAP, aic7xxx_run_waiting_queues() will not
+ * unpause us, so ensure we are unpaused.
+ */
+ unpause_sequencer(p, /*unpause_always*/ FALSE);
+ }
+ else
+ {
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+ }
+ result = SCSI_RESET_PENDING;
+ }
+ else
+ {
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
}
}
}
- /* Make sure the sequencer is unpaused upon return. */
- if (result == -1)
- {
- UNPAUSE_SEQUENCER(p);
- }
return (result);
}
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
int base, result;
+ unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
+ save_flags(processor_flags);
+ cli();
+
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Abort called with no SCB for cmd.\n");
+ }
#endif
+ if (p->flags & IN_TIMEOUT)
+ {
+ /*
+ * We've already started a recovery operation.
+ */
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+ {
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_PENDING);
+ }
+ else
+ {
+ /*
+ * This is the second time we've tried to abort the recovery
+ * SCB. We want the mid-level SCSI code to call the reset
+ * function to reset the SCSI bus.
+ */
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_NOT_RUNNING);
+ }
+ }
if (cmd->serial_number != cmd->serial_number_at_timeout)
{
result = SCSI_ABORT_NOT_RUNNING;
{
result = SCSI_ABORT_NOT_RUNNING;
}
- else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+ else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
{
result = SCSI_ABORT_NOT_RUNNING;
}
else
{
- result = SCSI_ABORT_SNOOZE;
+ /*
+ * XXX - Check use of IN_TIMEOUT to see if we're Doing the
+ * Right Thing with it.
+ */
+ p->flags |= IN_TIMEOUT;
+ result = aic7xxx_bus_device_reset(p, scb->cmd);
+ switch (result)
+ {
+ case SCSI_RESET_NOT_RUNNING:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_NOT_RUNNING;
+ break;
+ case SCSI_RESET_PENDING:
+ result = SCSI_ABORT_PENDING;
+ break;
+ default:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_SNOOZE;
+ break;
+ }
}
+ restore_flags(processor_flags);
return (result);
}
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
- int base, found, tindex, min_target, max_target, result = -1;
+ int base, found, tindex, min_target, max_target;
+ int result = -1;
char channel = 'A';
unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
tindex = (cmd->channel << 4) | cmd->target;
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Reset called with no SCB for cmd.\n");
+ }
#endif
/*
if (scb->cmd != cmd)
scb = NULL;
- if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
- && (scb != NULL))
+ if (p->flags & IN_TIMEOUT)
{
/*
- * Attempt a bus device reset if commands have completed successfully
- * since the last bus device reset, or it has been less than 100ms
- * since the last reset.
+ * We've already started a recovery operation.
*/
- if ((p->flags & DEVICE_SUCCESS) ||
- ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
{
- if (cmd->serial_number != cmd->serial_number_at_timeout)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
+ restore_flags(processor_flags);
+ return (SCSI_RESET_PENDING);
+ }
+ }
+ else
+ {
+ if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+ && (scb != NULL))
+ {
+ /*
+ * Attempt a bus device reset if commands have completed successfully
+ * since the last bus device reset, or it has been less than 100ms
+ * since the last reset.
+ */
+ if ((p->flags & DEVICE_SUCCESS) ||
+ ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
{
- if (scb == NULL)
+ if (cmd->serial_number != cmd->serial_number_at_timeout)
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ }
+ else if (scb == NULL)
{
result = SCSI_RESET_NOT_RUNNING;
}
else if (flags & SCSI_RESET_ASYNCHRONOUS)
{
- if (scb->state & SCB_ABORTED)
+ if (scb->flags & SCB_ABORTED)
{
result = SCSI_RESET_PENDING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
if ((flags & SCSI_RESET_SYNCHRONOUS) &&
(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
{
- scb->state |= SCB_ABORTED;
+ scb->flags |= SCB_ABORTED;
result = SCSI_RESET_PENDING;
}
else
{
+ p->flags |= IN_TIMEOUT;
result = aic7xxx_bus_device_reset(p, cmd);
if (result == 0)
+ {
+ p->flags &= ~IN_TIMEOUT;
result = SCSI_RESET_PENDING;
+ }
}
- }
+ }
}
}
}
-
if (result == -1)
{
/*
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if ((scb->state & SCB_ABORTED) &&
+ else if ((scb->flags & SCB_ABORTED) &&
(!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
{
result = SCSI_RESET_PENDING;
/*
* The reset channel function assumes that the sequencer is paused.
*/
- PAUSE_SEQUENCER(p);
+ pause_sequencer(p);
found = aic7xxx_reset_channel(p, channel, TRUE);
+ p->flags = p->flags & ~IN_TIMEOUT;
/*
* If this is a synchronous reset and there is no SCB for this
}
result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+ p->flags &= ~IN_TIMEOUT;
}
}
+ aic7xxx_run_waiting_queues(p);
restore_flags(processor_flags);
return (result);
}
aic7xxx_info, \
NULL, \
aic7xxx_queue, \
- aic7xxx_abort, \
+ NULL, \
aic7xxx_reset, \
NULL, \
aic7xxx_biosparam, \
-1, /* max simultaneous cmds */\
-1, /* scsi id of host adapter */\
- SG_ALL, /* max scatter-gather cmds */\
+ 0, /* max scatter-gather cmds */\
2, /* cmds per lun (linked cmds) */\
0, /* number of 7xxx's present */\
0, /* no memory DMA restrictions */\
extern int aic7xxx_biosparam(Disk *, kdev_t, 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 *, unsigned int);
extern const char *aic7xxx_info(struct Scsi_Host *);
+++ /dev/null
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux and FreeBSD.
- *
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- *
- *Modifications/enhancements:
- * Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
- *
- * 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, 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; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other
- * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
- *
- * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
- *
- *-M*************************************************************************/
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
-
-#ifdef linux
-#include "aic7xxx_reg.h"
-#else
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#endif
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'. This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
-
-/* After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration. The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time. This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection. The solution used here is to
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
- * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets,
- * SCB_LIST_NULL is 0xff which is out of range. The kernel driver must
- * add an entry to this list every time a request sense occurs. The sequencer
- * will automatically consume the entries.
- */
-
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
-reset:
- clr DFCNTRL
- clr SCSISIGO /* De-assert BSY */
-/*
- * We jump to start after every bus free.
- */
-start:
- and FLAGS,0x0f /* clear target specific flags */
- mvi SCSISEQ,ENRSELI /* Always allow reselection */
- clr SCSIRATE /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
-poll_for_work:
- /*
- * Are we a twin channel device?
- * For fairness, we check the other bus first,
- * since we just finished a transaction on the
- * current channel.
- */
- test FLAGS,TWIN_BUS jz start2
- xor SBLKCTL,SELBUSB /* Toggle to the other bus */
- test SSTAT0,SELDI jnz reselect
- xor SBLKCTL,SELBUSB /* Toggle to the original bus */
-start2:
- test SSTAT0,SELDI jnz reselect
- cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting
- mov A, QCNTMASK
- test QINCNT,A jz poll_for_work
-
-/*
- * We have at least one queued SCB now and we don't have any
- * SCBs in the list of SCBs awaiting selection. Set the SCB
- * pointer from the FIFO so we see the right bank of SCB
- * registers.
- */
- mov SCBPTR,QINFIFO
-
-/*
- * See if there is not already an active SCB for this target. This code
- * locks out on a per target basis instead of target/lun. Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands. It may be beneficial to make findscb a more general procedure
- * to see if the added cost of the search is negligible. This code also
- * assumes that the kernel driver will clear the active flags on board
- * initialization, board reset, and a target SELTO. Tagged commands
- * don't set the active bits since you can queue more than one command
- * at a time. We do, however, look to see if there are any non-tagged
- * I/Os in progress, and requeue the command if there are. Tagged and
- * non-tagged commands cannot be mixed to a single target.
- */
-
-test_busy:
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz test_a /* Id < 8 && A channel */
-
- test ACTIVE_B,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_B,A
- jmp start_scb
-
-/* Place the currently active SCB back on the queue for later processing */
-requeue:
- mov QINFIFO, SCBPTR
- jmp poll_for_work
-
-/*
- * Pull the first entry off of the waiting for selection list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the waiting_scb list.
- */
-start_waiting:
- mov SCBPTR,WAITING_SCBH
- jmp start_scb2
-
-test_a:
- test ACTIVE_A,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_A,A
-
-start_scb:
- mov SCB_NEXT,WAITING_SCBH
- mov WAITING_SCBH, SCBPTR
-start_scb2:
- and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */
- and A,0x08,SCB_TCL /* Get new channel bit */
- or SINDEX,A
- mov SBLKCTL,SINDEX /* select channel */
- mov SCB_TCL call initialize_scsiid
-
-/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection. We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
- */
-start_selection:
- mvi SCSISEQ,0x58 /* ENSELO|ENAUTOATNO|ENRSELI */
-
-/*
- * 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.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
- test SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached. This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
- mvi INTSTAT,AWAITING_MSG
- jmp wait_for_selection
-
-mk_identify:
- and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */
-
- and MSG0,0x7,SCB_TCL /* lun */
- or MSG0,A /* or in disconnect privledge */
- or MSG0,MSG_IDENTIFY
- mvi MSG_LEN, 1
-
- test SCB_CONTROL,0xb0 jz !message /* WDTR, SDTR or TAG?? */
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-
-mk_tag:
- mvi DINDEX, MSG1
- test SCB_CONTROL,TAG_ENB jz mk_tag_done
- and DINDIR,0x23,SCB_CONTROL
- mov DINDIR,SCB_TAG
-
- add MSG_LEN,COMP_MSG0,DINDEX /* update message length */
-
-mk_tag_done:
-
- test SCB_CONTROL,0x90 jz !message /* NEEDWDTR|NEEDSDTR */
- mov DINDEX call mk_dtr /* build DTR message if needed */
-
-!message:
-wait_for_selection:
- test SSTAT0,SELDO jnz select
- test SSTAT0,SELDI jz wait_for_selection
-
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target
- * yet.
- */
-reselect:
- clr MSG_LEN /* Don't have anything in the mesg buffer */
- mov SELID call initialize_scsiid
- or FLAGS,RESELECTED
- jmp select2
-
-/*
- * After the selection, remove this SCB from the "waiting for selection"
- * list. This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH. Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
- mov WAITING_SCBH,SCB_NEXT
- or FLAGS,SELECTED
-select2:
-/*
- * 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.
- */
- or SXFRCTL0,CLRCHN
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
- call ndx_dtr
- mov SCSIRATE,SINDIR
-
-/*
- * Initialize Ultra mode setting.
- */
- mov FUNCTION1,SCSIID
- mov A,FUNCTION1
- and SINDEX,0xdf,SXFRCTL0 /* default to Ultra disabled */
- test SCSIID, 0x80 jnz ultra_b /* Target ID > 7 */
- test SBLKCTL, SELBUSB jnz ultra_b /* Second channel device */
- test ULTRA_ENB,A jz set_sxfrctl0
- or SINDEX, ULTRAEN jmp set_sxfrctl0
-ultra_b:
- test ULTRA_ENB_B,A jz set_sxfrctl0
- or SINDEX, ULTRAEN
-
-set_sxfrctl0:
- mov SXFRCTL0,SINDEX
-
- mvi SCSISEQ,ENAUTOATNP /*
- * ATN on parity errors
- * for "in" phases
- */
- mvi CLRSINT1,CLRBUSFREE
- mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */
-/*
- * 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.
- *
- */
-ITloop:
- test SSTAT1,BUSFREE jnz p_busfree
- test SSTAT1,REQINIT jz ITloop
-
- and A,PHASE_MASK,SCSISIGI
- mov LASTPHASE,A
- mov SCSISIGO,A
-
- cmp ALLZEROS,A je p_dataout
- cmp A,P_DATAIN je p_datain
- cmp A,P_COMMAND je p_command
- cmp A,P_MESGOUT je p_mesgout
- cmp A,P_STATUS je p_status
- cmp A,P_MESGIN je p_mesgin
-
- mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */
- jmp ITloop /* Try reading the bus again. */
-
-p_dataout:
- mvi DMAPARAMS,0x7d /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * DIRECTION|FIFORESET
- */
- jmp data_phase_init
-
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-data_phase_reinit:
- mov STCNT0,SCB_RESID_DCNT0
- mov STCNT1,SCB_RESID_DCNT1
- mov STCNT2,SCB_RESID_DCNT2
- jmp data_phase_loop
-
-p_datain:
- mvi DMAPARAMS,0x79 /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * !DIRECTION|FIFORESET
- */
-data_phase_init:
- call assert
-
- test FLAGS, DPHASE jnz data_phase_reinit
- call sg_scb2ram
- or FLAGS, DPHASE /* We have seen a data phase */
-
-data_phase_loop:
-/* Guard against overruns */
- test SG_COUNT, 0xff jnz data_phase_inbounds
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
- or SXFRCTL1,BITBUCKET
- mvi STCNT0,0xff
- mvi STCNT1,0xff
- mvi STCNT2,0xff
-
-data_phase_inbounds:
-/* If we are the last SG block, don't set wideodd. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd
- and DMAPARAMS, 0xbf /* Turn off WIDEODD */
-data_phase_wideodd:
- mov DMAPARAMS call dma
-
-/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun
-
-/* Exit if we had an underrun */
- test SSTAT0,SDONE jz data_phase_finish /* underrun STCNT != 0 */
-
-/*
- * Advance the scatter-gather pointers if needed
- */
-sg_advance:
- dec SG_COUNT /* one less segment to go */
-
- test SG_COUNT, 0xff jz data_phase_finish /* Are we done? */
-
- clr A /* add sizeof(struct scatter) */
- add SG_NEXT0,SG_SIZEOF,SG_NEXT0
- adc SG_NEXT1,A,SG_NEXT1
-
-/*
- * Load a struct scatter 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 all DMA's, assumes a little-endian host data storage.
- */
-sg_load:
- clr HCNT2
- clr HCNT1
- mvi HCNT0,SG_SIZEOF
-
- mov HADDR0,SG_NEXT0
- mov HADDR1,SG_NEXT1
- mov HADDR2,SG_NEXT2
- mov HADDR3,SG_NEXT3
-
- or 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.
- */
-dma_finish:
- test DFSTATUS,HDONE jz dma_finish
- /* Turn off DMA preserving WIDEODD */
- and DFCNTRL,WIDEODD
-dma_finish2:
- test DFCNTRL,HDMAENACK jnz dma_finish2
-
-/*
- * Copy data from FIFO into SCB data pointer and data count. In
- * both FreeBSD and Linux, the scatter list entry is 8 bytes.
- *
- * struct ahc_dma_seg {
- * physaddr addr; four bytes, little-endian order
- * long len; four bytes, little endian order
- * };
- */
-
- mov HADDR0,DFDAT
- mov HADDR1,DFDAT
- mov HADDR2,DFDAT
- mov HADDR3,DFDAT
- mov HCNT0,DFDAT
- mov HCNT1,DFDAT
- mov HCNT2,DFDAT
-
-/* Load STCNT as well. It is a mirror of HCNT */
- mov STCNT0,HCNT0
- mov STCNT1,HCNT1
- mov STCNT2,HCNT2
- test SSTAT1,PHASEMIS jz data_phase_loop
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes
- * were transferred on the SCSI (as opposed to the host) bus.
- */
- mov SCB_RESID_DCNT0,STCNT0
- mov SCB_RESID_DCNT1,STCNT1
- mov SCB_RESID_DCNT2,STCNT2
- mov SCB_RESID_SGCNT, SG_COUNT
- jmp ITloop
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
- and SXFRCTL1,0x7f /* ~BITBUCKET */
- mvi INTSTAT,DATA_OVERRUN
- jmp ITloop
-
-/*
- * Command phase. Set up the DMA registers and let 'er rip.
- */
-p_command:
- call assert
-
-/*
- * Load HADDR and HCNT.
- */
- mov HADDR0, SCB_CMDPTR0
- mov HADDR1, SCB_CMDPTR1
- mov HADDR2, SCB_CMDPTR2
- mov HADDR3, SCB_CMDPTR3
- mov HCNT0, SCB_CMDLEN
- clr HCNT1
- clr HCNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- 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 SCB_TARGET_STATUS call inb_first
- jmp mesgin_done
-
-/*
- * Message out phase. If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
- */
-p_mesgout:
- test MSG_LEN, 0xff jnz p_mesgout_start
- mvi MSG_NOP call mk_mesg /* build NOP message */
-
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG0. Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
- mvi SINDEX,MSG0
- mov DINDEX,MSG_LEN
-
-/*
- * 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.
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- test SSTAT0,SPIORDY jz p_mesgout_loop
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- cmp DINDEX,1 jne p_mesgout_outb /* last byte? */
- mvi CLRSINT1,CLRATNO /* drop ATN */
-p_mesgout_outb:
- dec DINDEX
- or CLRSINT0, CLRSPIORDY
- mov SCSIDATL,SINDIR
-
-p_mesgout4:
- test DINDEX,0xff jnz p_mesgout_loop
-
-/*
- * 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_mesgout_snoop:
- test SSTAT1,BUSFREE jnz p_mesgout_done
- test SSTAT1,REQINIT jz p_mesgout_snoop
-
- test SSTAT1,PHASEMIS jnz p_mesgout_done
-
- or SCSISIGO,ATNO /* turn on ATNO */
-
- jmp ITloop
-
-p_mesgout_phasemis:
- mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */
-p_mesgout_done:
- clr MSG_LEN /* no active msg */
- jmp ITloop
-
-/*
- * Message in phase. Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
- mvi A call inb_first /* read the 1st message byte */
- mov REJBYTE,A /* save it for the driver */
-
- test A,MSG_IDENTIFY jnz mesgin_identify
- cmp A,MSG_DISCONNECT je mesgin_disconnect
- cmp A,MSG_SDPTRS je mesgin_sdptrs
- cmp ALLZEROS,A je mesgin_complete
- cmp A,MSG_RDPTRS je mesgin_rdptrs
- cmp A,MSG_EXTENDED je mesgin_extended
- cmp A,MSG_REJECT je mesgin_reject
-
-rej_mesgin:
-/*
- * 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.
- */
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,SEND_REJECT /* let driver know */
-
- mvi MSG_REJECT call mk_mesg
-
-mesgin_done:
- call inb_last /*ack & turn auto PIO back on*/
- jmp ITloop
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
- * and trigger a completion interrupt. Check status for non zero return
- * and interrupt driver if needed. This allows the driver to interpret
- * errors only when they occur instead of always uploading the scb. If
- * the status is SCSI_CHECK, the driver will download a new scb requesting
- * sense to replace the old one, modify the "waiting for selection" SCB list
- * and set RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE the
- * sequencer imediately jumps to main loop where it will run down the waiting
- * SCB list and process the sense request. If the kernel driver does not
- * wish to request sense, it need only clear RETURN_1, and the command is
- * allowed to complete. We don't bother to post to the QOUTFIFO in the
- * error case since it would require extra work in the kernel driver to
- * ensure that the entry was removed before the command complete code tried
- * processing it.
- *
- * First check for residuals
- */
- test SCB_RESID_SGCNT,0xff jz check_status
-/*
- * If we have a residual count, interrupt and tell the host. Other
- * alternatives are to pause the sequencer on all command completes (yuck),
- * dma the resid directly to the host (slick, we may have space to do it now)
- * or have the sequencer pause itself when it encounters a non-zero resid
- * (unnecessary pause just to flag the command -yuck-, but takes one instruction
- * and since it shouldn't happen that often is good enough for our purposes).
- */
-resid:
- mvi INTSTAT,RESIDUAL
-
-check_status:
- test SCB_TARGET_STATUS,0xff jz status_ok /* Good Status? */
- mvi INTSTAT,BAD_STATUS /* let driver know */
- cmp RETURN_1, SEND_SENSE jne status_ok
- jmp mesgin_done
-
-status_ok:
-/* First, mark this target as free. */
- test SCB_CONTROL,TAG_ENB jnz test_immediate /*
- * Tagged commands
- * don't busy the
- * target.
- */
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz clear_a
- xor ACTIVE_B,A
- jmp test_immediate
-
-clear_a:
- xor ACTIVE_A,A
-
-test_immediate:
- test SCB_CMDLEN,0xff jnz complete /* Immediate message complete */
-/*
- * Pause the sequencer until the driver gets around to handling the command
- * complete. This is so that any action that might require careful timing
- * with the completion of this command can occur.
- */
- mvi INTSTAT,IMMEDDONE
- jmp start
-complete:
- mov QOUTFIFO,SCB_TAG
- mvi INTSTAT,CMDCMPLT
- jmp mesgin_done
-
-
-/*
- * Is it an extended message? We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
- */
-mesgin_extended:
- mvi ARG_1 call inb_next /* extended message length */
- mvi REJBYTE_EXT call inb_next /* extended message code */
-
- cmp REJBYTE_EXT,MSG_SDTR je p_mesginSDTR
- cmp REJBYTE_EXT,MSG_WDTR je p_mesginWDTR
- jmp rej_mesgin
-
-p_mesginWDTR:
- cmp ARG_1,2 jne rej_mesgin /* extended mesg length=2 */
- mvi ARG_1 call inb_next /* Width of bus */
- mvi INTSTAT,WDTR_MSG /* let driver know */
- test RETURN_1,0xff jz mesgin_done /* Do we need to send WDTR? */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Bus width was too large
- * Reject it.
- */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
- and RETURN_1,0x7f /* Clear the SEND_WDTR Flag */
- mvi DINDEX,MSG0
- mvi MSG0 call mk_wdtr /* build WDTR message */
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-p_mesginSDTR:
- cmp ARG_1,3 jne rej_mesgin /* extended mesg length=3 */
- mvi ARG_1 call inb_next /* xfer period */
- mvi A call inb_next /* REQ/ACK offset */
- mvi INTSTAT,SDTR_MSG /* call driver to convert */
-
- test RETURN_1,0xff jz mesgin_done /* Do we need to mk_sdtr/rej */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Requested SDTR too small
- * Reject it.
- */
- clr ARG_1 /* Use the scratch ram rate */
- mvi DINDEX, MSG0
- mvi MSG0 call mk_sdtr
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-/*
- * Is it a disconnect message? Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
- or SCB_CONTROL,DISCONNECTED
- test FLAGS, PAGESCBS jz mesgin_done
-/*
- * Link this SCB into the DISCONNECTED list. This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
- mvi SCB_PREV, SCB_LIST_NULL
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- mov SCB_NEXT, DISCONNECTED_SCBH
- mov DISCONNECTED_SCBH, SCBPTR
- cmp SCB_NEXT,SCB_LIST_NULL je linkdone
- mov SCBPTR,SCB_NEXT
- mov SCB_PREV,DISCONNECTED_SCBH
- mov SCBPTR,DISCONNECTED_SCBH
-linkdone:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- jmp mesgin_done
-
-/*
- * Save data pointers message? Copy working values into the SCB,
- * usually in preparation for a disconnect.
- */
-mesgin_sdptrs:
- call sg_ram2scb
- jmp mesgin_done
-
-/*
- * Restore pointers message? Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
- and FLAGS,0xef /*
- * !DPHASE we'll reload them
- * the next time through
- */
- jmp 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.
- */
-mesgin_identify:
- test A,0x78 jnz rej_mesgin /*!DiscPriv|!LUNTAR|!Reserved*/
-
- and A,0x07 /* lun in lower three bits */
- or SAVED_TCL,A,SELID
- and SAVED_TCL,0xf7
- and A,SELBUSB,SBLKCTL /* B Channel?? */
- or SAVED_TCL,A
- call inb_last /* ACK */
-
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to find the proper
- * SCB. With SCB paging, this requires using findSCB for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
- */
- mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */
-snoop_tag_loop:
- test SSTAT1,BUSFREE jnz use_findSCB
- test SSTAT1,REQINIT jz snoop_tag_loop
- test SSTAT1,PHASEMIS jnz use_findSCB
- mvi A call inb_first
- cmp A,MSG_SIMPLE_TAG jne use_findSCB
-get_tag:
- mvi ARG_1 call inb_next /* tag value */
-/*
- * See if the tag is in range. The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incoming tag and there is
- * no carry.
- */
- mov A,COMP_SCBCOUNT
- add SINDEX,A,ARG_1
- jc abort_tag
-
-/*
- * Ensure that the SCB the tag points to is for a SCB transaction
- * to the reconnecting target.
- */
- test FLAGS, PAGESCBS jz index_by_tag
- call inb_last /* Ack Tag */
-use_findSCB:
- mov ALLZEROS call findSCB /* Have to search */
-setup_SCB:
- and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */
- or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */
- jmp ITloop
-index_by_tag:
- mov SCBPTR,ARG_1
- mov A,SAVED_TCL
- cmp SCB_TCL,A jne abort_tag
- test SCB_CONTROL,TAG_ENB jz abort_tag
- call inb_last /* Ack Successful tag */
- jmp setup_SCB
-
-abort_tag:
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,ABORT_TAG /* let driver know */
- mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */
- jmp mesgin_done
-
-/*
- * Message reject? Let the kernel driver handle this. If we have an
- * outstanding WDTR or SDTR negotiation, assume that it's a response from
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
- mvi INTSTAT, REJECT_MSG
- jmp mesgin_done
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * 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,CLRATNO
- clr LASTPHASE
-
-/*
- * if this is an immediate command, perform a pseudo command complete to
- * notify the driver.
- */
- test SCB_CMDLEN,0xff jz status_ok
- jmp start
-
-/*
- * 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,0x50 /* PAUSEDIS|FASTMODE */
- test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */
-
- /*
- * Hmmm. For some reason the mesg buffer is in use.
- * Tell the driver. It should look at SINDEX to find
- * out what we wanted to use the buffer for and resolve
- * the conflict.
- */
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- mvi INTSTAT,MSG_BUFFER_BUSY
-
-mk_mesg1:
- mvi MSG_LEN,1 /* length = 1 */
- mov MSG0,SINDEX /* 1-byte message */
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * 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_next:
- or CLRSINT0, CLRSPIORDY
- mov NONE,SCSIDATL /*dummy read from latch to ACK*/
-inb_next_wait:
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- test SSTAT0,SPIORDY jz inb_next_wait /* wait for next byte */
-inb_first:
- mov DINDEX,SINDEX
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/
-inb_last:
- mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/
-
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
- mvi INTSTAT, MSGIN_PHASEMIS
- jmp ITloop
-
-/*
- * 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:
- test SSTAT0,DMADONE jnz dma3
- test SSTAT1,PHASEMIS jz dma1 /* 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,DIRECTION jnz dma5
-dma4:
- test DFSTATUS,FIFOEMP jz dma4
-
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are
- * actually off first lest we get an ILLSADDR.
- */
-dma5:
- /* disable DMA, but maintain WIDEODD */
- and DFCNTRL,WIDEODD
-dma6:
- test DFCNTRL,0x38 jnz dma6 /* SCSIENACK|SDMAENACK|HDMAENACK */
-
- 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_scsiid:
- and SINDEX,0xf0 /* Get target ID */
- and A,0x0f,SCSIID
- or SINDEX,A
- mov SCSIID,SINDEX ret
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
- test FLAGS,RESELECTED jz return /* reselected? */
- test FLAGS,IDENTIFY_SEEN jnz return /* seen IDENTIFY? */
-
- mvi INTSTAT,NO_IDENT ret /* no - cause a kernel panic */
-
-/*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
- * value in ARG_1. If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
- * SCB. Have the kernel print a warning message if it can't be found, and
- * generate an ABORT/ABORT_TAG message to the target. SINDEX should be
- * cleared on call.
- */
-findSCB:
- mov A,SAVED_TCL
- mov SCBPTR,SINDEX /* switch to next SCB */
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- cmp SCB_TCL,A jne findSCB1 /* target ID/channel/lun match? */
- test SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
- test SCB_CONTROL,TAG_ENB jnz findTaggedSCB
- cmp ARG_1,SCB_LIST_NULL je foundSCB
- jmp findSCB1
-findTaggedSCB:
- mov A, ARG_1 /* Tag passed in ARG_1 */
- cmp SCB_TAG,A jne findSCB1 /* Found it? */
-foundSCB:
- test FLAGS,PAGESCBS jz foundSCB_ret
-/* Remove this SCB from the disconnection list */
- cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev
- mov SAVED_LINKPTR, SCB_PREV
- mov SCBPTR, SCB_NEXT
- mov SCB_PREV, SAVED_LINKPTR
- mov SCBPTR, SINDEX
-unlink_prev:
- cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */
- mov SAVED_LINKPTR, SCB_NEXT
- mov SCBPTR, SCB_PREV
- mov SCB_NEXT, SAVED_LINKPTR
- mov SCBPTR, SINDEX
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-rHead:
- mov DISCONNECTED_SCBH,SCB_NEXT
-foundSCB_ret:
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-findSCB1:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- inc SINDEX
- mov A,SCBCOUNT
- cmp SINDEX,A jne findSCB
-
- mvi INTSTAT,NO_MATCH /* not found - signal kernel */
- cmp RETURN_1,SCB_PAGEDIN je return
- or SCSISIGO,ATNO /* assert ATNO */
- cmp ARG_1,SCB_LIST_NULL jne find_abort_tag
- mvi MSG_ABORT call mk_mesg
- jmp ITloop
-find_abort_tag:
- mvi MSG_ABORT_TAG call mk_mesg
- jmp ITloop
-
-/*
- * Make a working copy of the scatter-gather parameters from the SCB.
- */
-sg_scb2ram:
- mov HADDR0, SCB_DATAPTR0
- mov HADDR1, SCB_DATAPTR1
- mov HADDR2, SCB_DATAPTR2
- mov HADDR3, SCB_DATAPTR3
- mov HCNT0, SCB_DATACNT0
- mov HCNT1, SCB_DATACNT1
- mov HCNT2, SCB_DATACNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- mov SG_COUNT,SCB_SGCOUNT
-
- mov SG_NEXT0, SCB_SGPTR0
- mov SG_NEXT1, SCB_SGPTR1
- mov SG_NEXT2, SCB_SGPTR2
- mov SG_NEXT3, SCB_SGPTR3 ret
-
-/*
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them. This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-sg_ram2scb:
- test FLAGS, DPHASE jz return
- mov SCB_SGCOUNT,SG_COUNT
-
- mov SCB_SGPTR0,SG_NEXT0
- mov SCB_SGPTR1,SG_NEXT1
- mov SCB_SGPTR2,SG_NEXT2
- mov SCB_SGPTR3,SG_NEXT3
-
- mov SCB_DATAPTR0,SHADDR0
- mov SCB_DATAPTR1,SHADDR1
- mov SCB_DATAPTR2,SHADDR2
- mov SCB_DATAPTR3,SHADDR3
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer
- */
- mov SCB_DATACNT0,SCB_RESID_DCNT0
- mov SCB_DATACNT1,SCB_RESID_DCNT1
- mov SCB_DATACNT2,SCB_RESID_DCNT2 ret
-
-/*
- * Add the array base TARG_SCRATCH 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_dtr:
- shr A,SCSIID,4
- test SBLKCTL,SELBUSB jz ndx_dtr_2
- or A,0x08 /* Channel B entries add 8 */
-ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX. DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiate one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culprit.
- */
-mk_dtr:
- test SCB_CONTROL,NEEDWDTR jnz mk_wdtr_16bit
- mvi ARG_1, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,3 /* extended message length = 3 */
- mvi DINDIR,1 /* SDTR code */
- call sdtr_to_rate
- mov DINDIR,RETURN_1 /* REQ/ACK transfer period */
- cmp ARG_1, MAXOFFSET je mk_sdtr_max_offset
- and DINDIR,0x0f,SINDIR /* Sync Offset */
-
-mk_sdtr_done:
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
- /* Talking to a WIDE device? */
- test SCSIRATE, WIDEXFER jnz wmax_offset
- mvi DINDIR, MAX_OFFSET_8BIT
- jmp mk_sdtr_done
-
-wmax_offset:
- mvi DINDIR, MAX_OFFSET_16BIT
- jmp mk_sdtr_done
-
-mk_wdtr_16bit:
- mvi ARG_1,BUS_16_BIT
-mk_wdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,2 /* extended message length = 2 */
- mvi DINDIR,3 /* WDTR code */
- mov DINDIR,ARG_1 /* bus width */
-
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-sdtr_to_rate:
- call ndx_dtr /* index scratch space for target */
- shr A,SINDIR,0x4
- dec SINDEX /* Preserve SINDEX */
- and A,0x7
- clr RETURN_1
-sdtr_to_rate_loop:
- test A,0x0f jz sdtr_to_rate_done
- add RETURN_1,0x19
- dec A
- jmp sdtr_to_rate_loop
-sdtr_to_rate_done:
- shr RETURN_1,0x2
- add RETURN_1,0x19
- test SXFRCTL0,ULTRAEN jz return
- shr RETURN_1,0x1
-return:
- ret
--- /dev/null
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+ address 0x000
+ access_mode RW
+ bit TEMODE 0x80
+ bit ENSELO 0x40
+ bit ENSELI 0x20
+ bit ENRSELI 0x10
+ bit ENAUTOATNO 0x08
+ bit ENAUTOATNI 0x04
+ bit ENAUTOATNP 0x02
+ bit SCSIRSTO 0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+ address 0x001
+ access_mode RW
+ bit DFON 0x80
+ bit DFPEXP 0x40
+ bit FAST20 0x20
+ bit CLRSTCNT 0x10
+ bit SPIOEN 0x08
+ bit SCAMEN 0x04
+ bit CLRCHN 0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+ address 0x002
+ access_mode RW
+ bit BITBUCKET 0x80
+ bit SWRAPEN 0x40
+ bit ENSPCHK 0x20
+ mask STIMESEL 0x18
+ bit ENSTIMER 0x04
+ bit ACTNEGEN 0x02
+ bit STPWEN 0x01 /* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+ address 0x003
+ access_mode RO
+ bit CDI 0x80
+ bit IOI 0x40
+ bit MSGI 0x20
+ bit ATNI 0x10
+ bit SELI 0x08
+ bit BSYI 0x04
+ bit REQI 0x02
+ bit ACKI 0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ mask P_MESGIN CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus. Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+ address 0x003
+ access_mode WO
+ bit CDO 0x80
+ bit IOO 0x40
+ bit MSGO 0x20
+ bit ATNO 0x10
+ bit SELO 0x08
+ bit BSYO 0x04
+ bit REQO 0x02
+ bit ACKO 0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ mask P_MESGIN CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers. Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+ address 0x004
+ access_mode RW
+ bit WIDEXFER 0x80 /* Wide transfer control */
+ mask SXFR 0x70 /* Sync transfer rate */
+ mask SOFS 0x0f /* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID {
+ address 0x005
+ access_mode RW
+ mask TID 0xf0 /* Target ID mask */
+ mask OID 0x0f /* Our ID mask */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode. SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+ address 0x006
+ access_mode RW
+}
+
+register SCSIDATH {
+ address 0x007
+ access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus. The counter is decremented only once
+ * the data has been safely transferred. SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */
+register STCNT {
+ address 0x008
+ size 3
+ access_mode RW
+}
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+ address 0x00b
+ access_mode WO
+ bit CLRSELDO 0x40
+ bit CLRSELDI 0x20
+ bit CLRSELINGO 0x10
+ bit CLRSWRAP 0x08
+ bit CLRSPIORDY 0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0 {
+ address 0x00b
+ access_mode RO
+ bit TARGET 0x80 /* Board acting as target */
+ bit SELDO 0x40 /* Selection Done */
+ bit SELDI 0x20 /* Board has been selected */
+ bit SELINGO 0x10 /* Selection In Progress */
+ bit SWRAP 0x08 /* 24bit counter wrap */
+ bit SDONE 0x04 /* STCNT = 0x000000 */
+ bit SPIORDY 0x02 /* SCSI PIO Ready */
+ bit DMADONE 0x01 /* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+ address 0x00c
+ access_mode WO
+ bit CLRSELTIMEO 0x80
+ bit CLRATNO 0x40
+ bit CLRSCSIRSTI 0x20
+ bit CLRBUSFREE 0x08
+ bit CLRSCSIPERR 0x04
+ bit CLRPHASECHG 0x02
+ bit CLRREQINIT 0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1 {
+ address 0x00c
+ access_mode RO
+ bit SELTO 0x80
+ bit ATNTARG 0x40
+ bit SCSIRSTI 0x20
+ bit PHASEMIS 0x10
+ bit BUSFREE 0x08
+ bit SCSIPERR 0x04
+ bit PHASECHG 0x02
+ bit REQINIT 0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+ address 0x00d
+ access_mode RO
+ bit OVERRUN 0x80
+ mask SFCNT 0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+ address 0x00e
+ access_mode RO
+ mask SCSICNT 0xf0
+ mask OFFCNT 0x0f
+}
+
+/*
+ * SCSI Test Control (p. 3-27)
+ */
+register SCSITEST {
+ address 0x00f
+ access_mode RW
+ bit RQAKCNT 0x04
+ bit CNTRTEST 0x02
+ bit CMODE 0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+ address 0x010
+ access_mode RW
+ bit ENSELDO 0x40
+ bit ENSELDI 0x20
+ bit ENSELINGO 0x10
+ bit ENSWRAP 0x08
+ bit ENSDONE 0x04
+ bit ENSPIORDY 0x02
+ bit ENDMADONE 0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+ address 0x011
+ access_mode RW
+ bit ENSELTIMO 0x80
+ bit ENATNTARG 0x40
+ bit ENSCSIRST 0x20
+ bit ENPHASEMIS 0x10
+ bit ENBUSFREE 0x08
+ bit ENSCSIPERR 0x04
+ bit ENPHASECHG 0x02
+ bit ENREQINIT 0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+ address 0x012
+ access_mode RO
+}
+
+register SCSIBUSH {
+ address 0x013
+ access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus. They are counted up in the same
+ * manner as STCNT is counted down. SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+ address 0x014
+ size 4
+ access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+ address 0x018
+ access_mode RW
+ bit STAGE6 0x20
+ bit STAGE5 0x10
+ bit STAGE4 0x08
+ bit STAGE3 0x04
+ bit STAGE2 0x02
+ bit STAGE1 0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id. The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+ address 0x019
+ access_mode RW
+ mask SELID_MASK 0xf0
+ bit ONEBIT 0x08
+}
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection. In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+ address 0x01f
+ access_mode RW
+ bit DIAGLEDEN 0x80 /* Aic78X0 only */
+ bit DIAGLEDON 0x40 /* Aic78X0 only */
+ bit AUTOFLUSHDIS 0x20
+ bit SELBUSB 0x08
+ bit SELWIDE 0x02
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+ address 0x060
+ access_mode RW
+ bit PERRORDIS 0x80
+ bit PAUSEDIS 0x40
+ bit FAILDIS 0x20
+ bit FASTMODE 0x10
+ bit BRKADRINTEN 0x08
+ bit STEP 0x04
+ bit SEQRESET 0x02
+ bit LOADRAM 0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
+ * four bytes in sucessesion. The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+ address 0x061
+ access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+ address 0x062
+ access_mode RW
+}
+
+register SEQADDR1 {
+ address 0x063
+ access_mode RW
+ mask SEQADDR1_MASK 0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+ address 0x064
+ access_mode RW
+ accumulator
+}
+
+register SINDEX {
+ address 0x065
+ access_mode RW
+ sindex
+}
+
+register DINDEX {
+ address 0x066
+ access_mode RW
+}
+
+register ALLONES {
+ address 0x069
+ access_mode RO
+ allones
+}
+
+register ALLZEROS {
+ address 0x06a
+ access_mode RO
+ allzeros
+}
+
+register NONE {
+ address 0x06a
+ access_mode WO
+ none
+}
+
+register FLAGS {
+ address 0x06b
+ access_mode RO
+ bit ZERO 0x02
+ bit CARRY 0x01
+}
+
+register SINDIR {
+ address 0x06c
+ access_mode RO
+}
+
+register DINDIR {
+ address 0x06d
+ access_mode WO
+}
+
+register FUNCTION1 {
+ address 0x06e
+ access_mode RW
+}
+
+register STACK {
+ address 0x06f
+ access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+ address 0x084
+ access_mode RW
+ bit ACE 0x08
+ bit ENABLE 0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+ address 0x084
+ access_mode RW
+ bit CACHETHEN 0x80 /* Cache Threshold enable */
+ bit DPARCKEN 0x40 /* Data Parity Check Enable */
+ bit MPARCKEN 0x20 /* Memory Parity Check Enable */
+ bit EXTREQLCK 0x10 /* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+ address 0x085
+ access_mode RW
+ mask BOFF 0xf0
+ mask BON 0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+ address 0x086
+ access_mode RW
+ mask DFTHRSH 0xc0
+ mask STBOFF 0x38
+ mask STBON 0x07
+ mask DFTHRSH_100 0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+ address 0x087
+ access_mode RW
+ bit POWRDN 0x40
+ bit SWINT 0x10
+ bit IRQMS 0x08
+ bit PAUSE 0x04
+ bit INTEN 0x02
+ bit CHIPRST 0x01
+ bit CHIPRSTACK 0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+ address 0x088
+ size 4
+ access_mode RW
+}
+
+register HCNT {
+ address 0x08c
+ size 3
+ access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+ address 0x090
+ access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+ address 0x091
+ access_mode RW
+ bit BRKADRINT 0x08
+ bit SCSIINT 0x04
+ bit CMDCMPLT 0x02
+ bit SEQINT 0x01
+ mask BAD_PHASE SEQINT /* unknown scsi bus phase */
+ mask SEND_REJECT 0x10|SEQINT /* sending a message reject */
+ mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/
+ mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */
+ mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */
+ mask NO_MATCH_BUSY 0x50|SEQINT /* Couldn't find BUSY SCB */
+ mask REJECT_MSG 0x60|SEQINT /* Reject message received */
+ mask BAD_STATUS 0x70|SEQINT /* Bad status from target */
+ mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */
+ mask ABORT_CMDCMPLT 0x91 /*
+ * Command tagged for abort
+ * completed successfully.
+ */
+ mask AWAITING_MSG 0xa0|SEQINT /*
+ * Kernel requested to specify
+ * a message to this target
+ * (command was null), so tell
+ * it that it can fill the
+ * message buffer.
+ */
+ mask MSG_BUFFER_BUSY 0xc0|SEQINT /*
+ * Sequencer wants to use the
+ * message buffer, but it
+ * already contains a message
+ */
+ mask MSGIN_PHASEMIS 0xd0|SEQINT /*
+ * Target changed phase on us
+ * when we were expecting
+ * another msgin byte.
+ */
+ mask DATA_OVERRUN 0xe0|SEQINT /*
+ * Target attempted to write
+ * beyond the bounds of its
+ * command.
+ */
+
+ mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */
+ mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors. You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+ address 0x092
+ access_mode RO
+ bit PARERR 0x08
+ bit ILLOPCODE 0x04
+ bit ILLSADDR 0x02
+ bit ILLHADDR 0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+ address 0x092
+ access_mode WO
+ bit CLRBRKADRINT 0x08
+ bit CLRSCSIINT 0x04
+ bit CLRCMDINT 0x02
+ bit CLRSEQINT 0x01
+}
+
+register DFCNTRL {
+ address 0x093
+ access_mode RW
+ bit WIDEODD 0x40
+ bit SCSIEN 0x20
+ bit SDMAEN 0x10
+ bit SDMAENACK 0x10
+ bit HDMAEN 0x08
+ bit HDMAENACK 0x08
+ bit DIRECTION 0x04
+ bit FIFOFLUSH 0x02
+ bit FIFORESET 0x01
+}
+
+register DFSTATUS {
+ address 0x094
+ access_mode RO
+ bit DWORDEMP 0x20
+ bit MREQPEND 0x10
+ bit HDONE 0x08
+ bit DFTHRESH 0x04
+ bit FIFOFULL 0x02
+ bit FIFOEMP 0x01
+}
+
+register DFDAT {
+ address 0x099
+ access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+ address 0x09a
+ access_mode RW
+ bit SCBAUTO 0x80
+ mask SCBCNT_MASK 0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+ address 0x09b
+ access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT {
+ address 0x09c
+ access_mode RO
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+ address 0x09d
+ access_mode WO
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+ address 0x09e
+ access_mode RO
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+ address 0x0a0
+ SCB_CONTROL {
+ size 1
+ bit MK_MESSAGE 0x80
+ bit DISCENB 0x40
+ bit TAG_ENB 0x20
+ bit MUST_DMAUP_SCB 0x10
+ bit ABORT_SCB 0x08
+ bit DISCONNECTED 0x04
+ mask SCB_TAG_TYPE 0x03
+ }
+ SCB_TCL {
+ size 1
+ bit SELBUSB 0x08
+ mask TID 0xf0
+ mask LID 0x07
+ }
+ SCB_TARGET_STATUS {
+ size 1
+ }
+ SCB_SGCOUNT {
+ size 1
+ }
+ SCB_SGPTR {
+ size 4
+ }
+ SCB_RESID_SGCNT {
+ size 1
+ }
+ SCB_RESID_DCNT {
+ size 3
+ }
+ SCB_DATAPTR {
+ size 4
+ }
+ SCB_DATACNT {
+ size 3
+ }
+ SCB_LINKED_NEXT {
+ size 1
+ }
+ SCB_CMDPTR {
+ size 4
+ }
+ SCB_CMDLEN {
+ size 1
+ }
+ SCB_TAG {
+ size 1
+ }
+ SCB_NEXT {
+ size 1
+ }
+ SCB_PREV {
+ size 1
+ }
+ SCB_BUSYTARGETS {
+ size 4
+ }
+}
+
+const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+ address 0x0c0
+ access_mode RW
+ bit CS_2840 0x04
+ bit CK_2840 0x02
+ bit DO_2840 0x01
+}
+
+register STATUS_2840 {
+ address 0x0c1
+ access_mode RW
+ bit EEPROM_TF 0x80
+ mask BIOS_SEL 0x60
+ mask ADSEL 0x1e
+ bit DI_2840 0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+ address 0x086
+}
+
+register BRDCTL {
+ address 0x01d
+ bit BRDDAT7 0x80
+ bit BRDDAT6 0x40
+ bit BRDDAT5 0x20
+ bit BRDSTB 0x10
+ bit BRDCS 0x08
+ bit BRDRW 0x04
+ bit BRDCTL1 0x02
+ bit BRDCTL0 0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device. In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device. When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM. When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.
+ *
+ * After successful arbitration for the memory port, the SEECS bit of
+ * the SEECTL register is connected to the chip select. The SEECK,
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in
+ * lines respectively. The SEERDY bit of SEECTL is useful in that it
+ * gives us an 800 nsec timer. After a write to the SEECTL register,
+ * the SEERDY goes high 800 nsec later. The one exception to this is
+ * when we first request access to the memory port. The SEERDY goes
+ * high to signify that access has been granted and, for this case, has
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to
+ * read the serial EEPROM.
+ */
+register SEECTL {
+ address 0x01e
+ bit EXTARBACK 0x80
+ bit EXTARBREQ 0x40
+ bit SEEMS 0x20
+ bit SEERDY 0x10
+ bit SEECS 0x08
+ bit SEECK 0x04
+ bit SEEDO 0x02
+ bit SEEDI 0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, 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). The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space. This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+ address 0x020
+
+ /*
+ * 1 byte per target starting at this address for configuration values
+ */
+ TARG_SCRATCH {
+ size 16
+ }
+ ULTRA_ENB {
+ size 2
+ }
+ /*
+ * Bit vector of targets that have disconnection disabled.
+ */
+ DISC_DSB {
+ size 2
+ }
+ /*
+ * Length of pending message
+ */
+ MSG_LEN {
+ size 1
+ }
+ /* We reserve 8bytes to store outgoing messages */
+ MSG_OUT {
+ size 8
+ }
+ /* Parameters for DMA Logic */
+ DMAPARAMS {
+ size 1
+ bit WIDEODD 0x40
+ bit SCSIEN 0x20
+ bit SDMAEN 0x10
+ bit SDMAENACK 0x10
+ bit HDMAEN 0x08
+ bit HDMAENACK 0x08
+ bit DIRECTION 0x04
+ bit FIFOFLUSH 0x02
+ bit FIFORESET 0x01
+ }
+ /*
+ * Number of SCBs supported by
+ * this card.
+ */
+ SCBCOUNT {
+ size 1
+ }
+ /*
+ * Two's complement of SCBCOUNT
+ */
+ COMP_SCBCOUNT {
+ size 1
+ }
+ /*
+ * Mask of bits to test against
+ * when looking at the Queue Count
+ * registers. Works around a bug
+ * on aic7850 chips.
+ */
+ QCNTMASK {
+ size 1
+ }
+ SEQ_FLAGS {
+ size 1
+ bit RESELECTED 0x80
+ bit IDENTIFY_SEEN 0x40
+ bit TAGGED_SCB 0x20
+ bit DPHASE 0x10
+ bit PAGESCBS 0x04
+ bit WIDE_BUS 0x02
+ bit TWIN_BUS 0x01
+ }
+ /*
+ * Temporary storage for the
+ * target/channel/lun of a
+ * reconnecting target
+ */
+ SAVED_TCL {
+ size 1
+ }
+ SG_COUNT {
+ size 1
+ }
+ /* working value of SG pointer */
+ SG_NEXT {
+ size 4
+ }
+ /*
+ * head of list of SCBs awaiting
+ * selection
+ */
+ WAITING_SCBH {
+ size 1
+ }
+ SAVED_LINKPTR {
+ size 1
+ }
+ SAVED_SCBPTR {
+ size 1
+ }
+ /*
+ * The sequencer will stick the frist byte of any rejected message here
+ * so we can see what is getting thrown away.
+ */
+ REJBYTE {
+ size 1
+ }
+ /*
+ * The last bus phase as seen by the sequencer.
+ */
+ LASTPHASE {
+ size 1
+ bit CDI 0x80
+ bit IOI 0x40
+ bit MSGI 0x20
+ mask PHASE_MASK CDI|IOI|MSGI
+ mask P_DATAOUT 0x00
+ mask P_DATAIN IOI
+ mask P_COMMAND CDI
+ mask P_MESGOUT CDI|MSGI
+ mask P_STATUS CDI|IOI
+ mask P_MESGIN CDI|IOI|MSGI
+ mask P_BUSFREE 0x01
+ }
+ MSGIN_EXT_LEN {
+ size 1
+ }
+ MSGIN_EXT_OPCODE {
+ size 1
+ }
+ /*
+ * location 3, stores the last
+ * byte of an extended message if
+ * it passes the two bytes of space
+ * we allow now. This byte isn't
+ * used for anything, it just makes
+ * the code shorter for tossing
+ * extra bytes.
+ */
+ MSGIN_EXT_BYTES {
+ size 3
+ }
+ /*
+ * head of list of SCBs that are
+ * disconnected. Used for SCB
+ * paging.
+ */
+ DISCONNECTED_SCBH {
+ size 1
+ }
+ /*
+ * head of list of SCBs that are
+ * not in use. Used for SCB paging.
+ */
+ FREE_SCBH {
+ size 1
+ }
+ HSCB_ADDR {
+ size 4
+ }
+ CUR_SCBID {
+ size 1
+ }
+ ARG_1 {
+ size 1
+ mask SEND_MSG 0x80
+ mask SEND_SENSE 0x40
+ mask SEND_REJ 0x20
+ alias RETURN_1
+ }
+ /*
+ * These are reserved registers in the card's scratch ram. Some of
+ * the values are specified in the AHA2742 technical reference manual
+ * and are initialized by the BIOS at boot time.
+ */
+ SCSICONF {
+ address 0x05a
+ size 1
+ bit RESET_SCSI 0x40
+ }
+ HOSTCONF {
+ address 0x05d
+ size 1
+ }
+ HA_274_BIOSCTRL {
+ address 0x05f
+ size 1
+ mask BIOSMODE 0x30
+ mask BIOSDISABLED 0x30
+ bit CHANNEL_B_PRIMARY 0x08
+ }
+}
+
+const SCB_LIST_NULL 0xff
+
+
+/* WDTR Message values */
+const BUS_8_BIT 0x00
+const BUS_16_BIT 0x01
+const BUS_32_BIT 0x02
+const MAX_OFFSET_8BIT 0x0f
+const MAX_OFFSET_16BIT 0x08
--- /dev/null
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aic7xxx.seq,v 1.74 1997/06/27 19:38:42 gibbs Exp $
+ */
+
+#include <aic7xxx.reg>
+#include <scsi_message.h>
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration. The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time. This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection. The solution used here is to
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes,
+ * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued. The sequencer will
+ * automatically consume the entries.
+ */
+
+/*
+ * We assume that the kernel driver may reset us at any time, even in the
+ * middle of a DMA, so clear DFCNTRL too.
+ */
+reset:
+ clr SCSISIGO; /* De-assert BSY */
+ /* Always allow reselection */
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP;
+ call clear_target_state;
+poll_for_work:
+ test SSTAT0,SELDO jnz select;
+ test SSTAT0,SELDI jnz reselect;
+ test SCSISEQ, ENSELO jnz poll_for_work;
+.if ( TWIN_CHANNEL )
+ /*
+ * Twin channel devices cannot handle things like SELTO
+ * interrupts on the "background" channel. So, if we
+ * are selecting, keep polling the current channel util
+ * either a selection or reselection occurs.
+ */
+ xor SBLKCTL,SELBUSB; /* Toggle to the other bus */
+ test SSTAT0,SELDO jnz select;
+ test SSTAT0,SELDI jnz reselect;
+ test SCSISEQ, ENSELO jnz poll_for_work;
+ xor SBLKCTL,SELBUSB; /* Toggle back */
+.endif
+ cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+test_queue:
+ /* Has the driver posted any work for us? */
+ mov A, QCNTMASK;
+ test QINCNT,A jz poll_for_work;
+
+/*
+ * We have at least one queued SCB now and we don't have any
+ * SCBs in the list of SCBs awaiting selection. If we have
+ * any SCBs available for use, pull the tag from the QINFIFO
+ * and get to work on it.
+ */
+.if ( SCB_PAGING )
+ mov ALLZEROS call get_free_or_disc_scb;
+ cmp SINDEX, SCB_LIST_NULL je poll_for_work;
+.endif
+dequeue_scb:
+ mov CUR_SCBID,QINFIFO;
+.if !( SCB_PAGING )
+ /* In the non-paging case, the SCBID == hardware SCB index */
+ mov SCBPTR, CUR_SCBID;
+.endif
+dma_queued_scb:
+/*
+ * DMA the SCB from host ram into the current SCB location.
+ */
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov CUR_SCBID call dma_scb;
+
+/*
+ * See if there is not already an active SCB for this target. This code
+ * locks out on a per target basis instead of target/lun. Although this
+ * is not ideal for devices that have multiple luns active at the same
+ * time, it is faster than looping through all SCB's looking for active
+ * commands. We also don't have enough spare SCB space for us to store the
+ * SCBID of the currently busy transaction for each target/lun making it
+ * impossible to link up the SCBs.
+ */
+test_busy:
+ test SCB_CONTROL, TAG_ENB|ABORT_SCB jnz start_scb;
+ mvi SEQCTL, PAUSEDIS|FASTMODE;
+ mov SAVED_SCBPTR, SCBPTR;
+ mov SCB_TCL call index_untagged_scb;
+ mov ARG_1, SINDIR; /*
+ * ARG_1 should
+ * now have the SCB ID of
+ * any active, non-tagged,
+ * command for this target.
+ */
+ cmp ARG_1, SCB_LIST_NULL je make_busy;
+.if ( SCB_PAGING )
+ /*
+ * Put this SCB back onto the free list. It
+ * may be necessary to satisfy the search for
+ * the active SCB.
+ */
+ mov SCBPTR, SAVED_SCBPTR;
+ call add_scb_to_free_list;
+ /* Find the active SCB */
+ mov ALLZEROS call findSCB;
+ /*
+ * If we couldn't find it, tell the kernel. This should
+ * never happen.
+ */
+ cmp SINDEX, SCB_LIST_NULL jne paged_busy_link;
+ mvi INTSTAT, NO_MATCH_BUSY;
+paged_busy_link:
+ /* Link us in */
+ mov SCB_LINKED_NEXT, CUR_SCBID;
+ /* Put it back on the disconnected list */
+ call add_scb_to_disc_list;
+ mvi SEQCTL, FASTMODE;
+ jmp poll_for_work;
+.else
+simple_busy_link:
+ mov SCBPTR, ARG_1;
+ mov SCB_LINKED_NEXT, CUR_SCBID;
+ mvi SEQCTL, FASTMODE;
+ jmp poll_for_work;
+.endif
+make_busy:
+ mov DINDIR, CUR_SCBID;
+ mov SCBPTR, SAVED_SCBPTR;
+ mvi SEQCTL, FASTMODE;
+
+start_scb:
+ /*
+ * Place us on the waiting list in case our selection
+ * doesn't win during bus arbitration.
+ */
+ mov SCB_NEXT,WAITING_SCBH;
+ mov WAITING_SCBH, SCBPTR;
+start_waiting:
+ /*
+ * Pull the first entry off of the waiting SCB list
+ * We don't have to "test_busy" because only transactions that
+ * have passed that test can be in the WAITING_SCB list.
+ */
+ mov SCBPTR, WAITING_SCBH;
+ call start_selection;
+ jmp poll_for_work;
+
+start_selection:
+.if ( TWIN_CHANNEL )
+ and SINDEX,~SELBUSB,SBLKCTL;/* Clear the channel select bit */
+ and A,SELBUSB,SCB_TCL; /* Get new channel bit */
+ or SINDEX,A;
+ mov SBLKCTL,SINDEX; /* select channel */
+.endif
+initialize_scsiid:
+ and A, TID, SCB_TCL; /* Get target ID */
+ and SCSIID, OID; /* Clear old target */
+ or SCSIID, A;
+ mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+reselect:
+ clr MSG_LEN; /* Don't have anything in the mesg buffer */
+ mvi CLRSINT0, CLRSELDI;
+ /* XXX test for and handle ONE BIT condition */
+ and SAVED_TCL, SELID_MASK, SELID;
+ or SEQ_FLAGS,RESELECTED;
+ jmp select2;
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list. This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH. Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select:
+ /* Turn off the selection hardware */
+ mvi SCSISEQ, ENRSELI|ENAUTOATNP; /*
+ * ATN on parity errors
+ * for "in" phases
+ */
+ mvi CLRSINT0, CLRSELDO;
+ mov SCBPTR, WAITING_SCBH;
+ mov WAITING_SCBH,SCB_NEXT;
+ mov SAVED_TCL, SCB_TCL;
+/*
+ * 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.
+ *
+ * Messages are stored in scratch RAM starting with a length byte
+ * followed by the message itself.
+ */
+
+mk_identify:
+ and MSG_OUT,0x7,SCB_TCL; /* lun */
+ and A,DISCENB,SCB_CONTROL; /* mask off disconnect privledge */
+ or MSG_OUT,A; /* or in disconnect privledge */
+ or MSG_OUT,MSG_IDENTIFYFLAG;
+ mvi MSG_LEN, 1;
+
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+mk_tag:
+ test SCB_CONTROL,TAG_ENB jz mk_message;
+ and MSG_OUT[1],TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+ mov MSG_OUT[2],SCB_TAG;
+ add MSG_LEN,2; /* update message length */
+
+/*
+ * Interrupt the driver, and allow it to tweak the message buffer
+ * if it asks.
+ */
+mk_message:
+ test SCB_CONTROL,MK_MESSAGE jz select2;
+ mvi INTSTAT,AWAITING_MSG;
+
+select2:
+ mvi CLRSINT1,CLRBUSFREE;
+ or SIMODE1, ENBUSFREE; /*
+ * We aren't expecting a
+ * bus free, so interrupt
+ * the kernel driver if it
+ * happens.
+ */
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ */
+ or SXFRCTL0, CLRSTCNT|SPIOEN|CLRCHN;
+.if ( ULTRA )
+ultra:
+ mvi SINDEX, ULTRA_ENB+1;
+ test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */
+ dec SINDEX;
+ultra_2:
+ mov FUNCTION1,SAVED_TCL;
+ mov A,FUNCTION1;
+ test SINDIR, A jz ndx_dtr;
+ or SXFRCTL0, FAST20;
+.endif
+
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCRATCH.
+ */
+ndx_dtr:
+ shr A,4,SAVED_TCL;
+ test SBLKCTL,SELBUSB jz ndx_dtr_2;
+ or SAVED_TCL, SELBUSB; /* Add the channel bit while we're here */
+ or A,0x08; /* Channel B entries add 8 */
+ndx_dtr_2:
+ add SINDEX,TARG_SCRATCH,A;
+ mov SCSIRATE,SINDIR;
+
+
+/*
+ * 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.
+ *
+ */
+ITloop:
+ test SSTAT1,REQINIT jz ITloop;
+ test SSTAT1, SCSIPERR jnz ITloop;
+
+ and A,PHASE_MASK,SCSISIGI;
+ mov LASTPHASE,A;
+ mov SCSISIGO,A;
+
+ cmp ALLZEROS,A je p_dataout;
+ cmp A,P_DATAIN je p_datain;
+ cmp A,P_COMMAND je p_command;
+ cmp A,P_MESGOUT je p_mesgout;
+ cmp A,P_STATUS je p_status;
+ cmp A,P_MESGIN je p_mesgin;
+
+ mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */
+ jmp ITloop; /* Try reading the bus again. */
+
+await_busfree:
+ and SIMODE1, ~ENBUSFREE;
+ call clear_target_state;
+ mov NONE, SCSIDATL; /* Ack the last byte */
+ test SSTAT1,REQINIT|BUSFREE jz .;
+ test SSTAT1, BUSFREE jnz poll_for_work;
+ mvi INTSTAT, BAD_PHASE;
+
+clear_target_state:
+ clr DFCNTRL;
+ clr SCSIRATE; /*
+ * We don't know the target we will
+ * connect to, so default to narrow
+ * transfers to avoid parity problems.
+ */
+ and SXFRCTL0, ~FAST20;
+ mvi LASTPHASE, P_BUSFREE;
+ /* clear target specific flags */
+ and SEQ_FLAGS,~(RESELECTED|IDENTIFY_SEEN|TAGGED_SCB|DPHASE) ret;
+
+p_dataout:
+ mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET;
+ jmp data_phase_init;
+
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ */
+data_phase_reinit:
+ mvi DINDEX, STCNT;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ jmp data_phase_loop;
+
+p_datain:
+ mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+data_phase_init:
+ call assert; /*
+ * Ensure entering a data
+ * phase is okay - seen identify, etc.
+ */
+
+ test SEQ_FLAGS, DPHASE jnz data_phase_reinit;
+
+ /*
+ * Initialize the DMA address and counter from the SCB.
+ * Also set SG_COUNT and SG_NEXT in memory since we cannot
+ * modify the values in the SCB itself until we see a
+ * save data pointers message.
+ */
+ mvi DINDEX, HADDR;
+ mvi SCB_DATAPTR call bcopy_7;
+
+ call set_stcnt_from_hcnt;
+
+ mov SG_COUNT,SCB_SGCOUNT;
+
+ mvi DINDEX, SG_NEXT;
+ mvi SCB_SGPTR call bcopy_4;
+
+data_phase_loop:
+/* Guard against overruns */
+ test SG_COUNT, 0xff jnz data_phase_inbounds;
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+ or SXFRCTL1,BITBUCKET;
+ mvi HCNT[0], 0xff;
+ mvi HCNT[1], 0xff;
+ mvi HCNT[2], 0xff;
+ call set_stcnt_from_hcnt;
+
+data_phase_inbounds:
+/* If we are the last SG block, ensure wideodd is off. */
+ cmp SG_COUNT,0x01 jne data_phase_wideodd;
+ and DMAPARAMS, ~WIDEODD;
+data_phase_wideodd:
+ mov DMAPARAMS call dma;
+
+/* Go tell the host about any overruns */
+ test SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun. dma clears SINDEX in this case. */
+ test SINDEX,0xff jz data_phase_finish;
+
+/*
+ * Advance the scatter-gather pointers if needed
+ */
+sg_advance:
+ dec SG_COUNT; /* one less segment to go */
+
+ test SG_COUNT, 0xff jz data_phase_finish; /* Are we done? */
+
+ clr A; /* add sizeof(struct scatter) */
+ add SG_NEXT[0],SG_SIZEOF;
+ adc SG_NEXT[1],A;
+
+/*
+ * Load a struct scatter 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 all DMA's, assumes little-endian host data storage.
+ */
+sg_load:
+ mvi DINDEX, HADDR;
+ mvi SG_NEXT call bcopy_4;
+
+ mvi HCNT[0],SG_SIZEOF;
+ clr HCNT[1];
+ clr HCNT[2];
+
+ or DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+ call dma_finish;
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count. This assumes
+ * that the SG segments are of the form:
+ *
+ * struct ahc_dma_seg {
+ * u_int32_t addr; four bytes, little-endian order
+ * u_int32_t len; four bytes, little endian order
+ * };
+ */
+ mvi HADDR call dfdat_in_7;
+
+/* Load STCNT as well. It is a mirror of HCNT */
+ call set_stcnt_from_hcnt;
+ test SSTAT1,PHASEMIS jz data_phase_loop;
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+ mov SCB_RESID_DCNT[0],STCNT[0];
+ mov SCB_RESID_DCNT[1],STCNT[1];
+ mov SCB_RESID_DCNT[2],STCNT[2];
+ mov SCB_RESID_SGCNT, SG_COUNT;
+
+ /* We have seen a data phase */
+ or SEQ_FLAGS, DPHASE;
+
+ jmp ITloop;
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+ and SXFRCTL1, ~BITBUCKET;
+ mvi INTSTAT,DATA_OVERRUN;
+ jmp ITloop;
+
+/*
+ * Command phase. Set up the DMA registers and let 'er rip.
+ */
+p_command:
+ call assert;
+
+/*
+ * Load HADDR and HCNT.
+ */
+ mvi DINDEX, HADDR;
+ mvi SCB_CMDPTR call bcopy_5;
+ clr HCNT[1];
+ clr HCNT[2];
+
+ call set_stcnt_from_hcnt;
+
+ mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+ jmp ITloop;
+
+/*
+ * Status phase. Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+ call assert;
+
+ mov SCB_TARGET_STATUS, SCSIDATL;
+ jmp ITloop;
+
+/*
+ * Message out phase. If there is not an active message, but the target
+ * took us into this phase anyway, build a no-op message and send it.
+ */
+p_mesgout:
+ test MSG_LEN, 0xff jnz p_mesgout_start;
+ mvi MSG_NOOP call mk_mesg; /* build NOP message */
+p_mesgout_start:
+/*
+ * Set up automatic PIO transfer from MSG_OUT. Bit 3 in
+ * SXFRCTL0 (SPIOEN) is already on.
+ */
+ mvi SINDEX,MSG_OUT;
+ mov DINDEX,MSG_LEN;
+
+/*
+ * 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.
+ * ATN must be dropped *at least* 90ns before we ack the last byte, so
+ * the code is aranged to execute two instructions before the byte is
+ * transferred to give a good margin of safety
+ *
+ * Keep an eye out for a phase change, in case the target issues
+ * a MESSAGE REJECT.
+ */
+p_mesgout_loop:
+ test SSTAT1, REQINIT jz p_mesgout_loop;
+ test SSTAT1, SCSIPERR jnz p_mesgout_loop;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
+p_mesgout_testretry:
+ test DINDEX,0xff jnz p_mesgout_dropatn;
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+ jmp p_mesgout_start;
+/*
+ * 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_mesgout_dropatn:
+ cmp DINDEX,1 jne p_mesgout_outb; /* last byte? */
+ mvi CLRSINT1,CLRATNO; /* drop ATN */
+p_mesgout_outb:
+ dec DINDEX;
+ mov SCSIDATL,SINDIR;
+ jmp p_mesgout_loop;
+
+p_mesgout_done:
+ mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
+ clr MSG_LEN; /* no active msg */
+ jmp ITloop;
+
+/*
+ * Message in phase. Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+ mvi ACCUM call inb_first; /* read the 1st message byte */
+ mov REJBYTE,A; /* save it for the driver */
+
+ test A,MSG_IDENTIFYFLAG jnz mesgin_identify;
+ cmp A,MSG_DISCONNECT je mesgin_disconnect;
+ cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs;
+ cmp ALLZEROS,A je mesgin_complete;
+ cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs;
+ cmp A,MSG_EXTENDED je mesgin_extended;
+ cmp A,MSG_MESSAGE_REJECT je mesgin_reject;
+ cmp A,MSG_NOOP je mesgin_done;
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best. In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
+ */
+ mvi INTSTAT,SEND_REJECT; /* let driver know */
+
+ mvi MSG_MESSAGE_REJECT call mk_mesg;
+
+mesgin_done:
+ mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
+ jmp ITloop;
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt. Before doing so, check to see if there
+ * is a residual or the status byte is something other than NO_ERROR (0). In
+ * either of these conditions, we upload the SCB back to the host so it can
+ * process this information. In the case of a non zero status byte, we
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved. If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command and set
+ * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload
+ * the SCB, and process it as the next command by adding it to the waiting list.
+ * If the kernel driver does not wish to request sense, it need only clear
+ * RETURN_1, and the command is allowed to complete normally. We don't bother
+ * to post to the QOUTFIFO in the error cases since it would require extra
+ * work in the kernel driver to ensure that the entry was removed before the
+ * command complete code tried processing it.
+ */
+
+/*
+ * First check for residuals
+ */
+ test SCB_RESID_SGCNT,0xff jnz upload_scb;
+ test SCB_TARGET_STATUS,0xff jz status_ok; /* Good Status? */
+upload_scb:
+ mvi DMAPARAMS, FIFORESET;
+ mov SCB_TAG call dma_scb;
+check_status:
+ test SCB_TARGET_STATUS,0xff jz status_ok; /* Just a residual? */
+ mvi INTSTAT,BAD_STATUS; /* let driver know */
+ cmp RETURN_1, SEND_SENSE jne status_ok;
+ /* This SCB becomes the next to execute as it will retrieve sense */
+ mov SCB_LINKED_NEXT, SCB_TAG;
+ jmp dma_next_scb;
+
+status_ok:
+/* First, mark this target as free. */
+ test SCB_CONTROL,TAG_ENB jnz complete; /*
+ * Tagged commands
+ * don't busy the
+ * target.
+ */
+ mov SAVED_SCBPTR, SCBPTR;
+ mov SAVED_LINKPTR, SCB_LINKED_NEXT;
+ mov SCB_TCL call index_untagged_scb;
+ mov DINDIR, SAVED_LINKPTR;
+ mov SCBPTR, SAVED_SCBPTR;
+
+complete:
+ /* Post the SCB and issue an interrupt */
+ mov QOUTFIFO,SCB_TAG;
+ mvi INTSTAT,CMDCMPLT;
+ test SCB_CONTROL, ABORT_SCB jz dma_next_scb;
+ mvi INTSTAT, ABORT_CMDCMPLT;
+
+dma_next_scb:
+ cmp SCB_LINKED_NEXT, SCB_LIST_NULL je add_to_free_list;
+.if !( SCB_PAGING )
+ /* Only DMA on top of ourselves if we are the SCB to download */
+ mov A, SCB_LINKED_NEXT;
+ cmp SCB_TAG, A je dma_next_scb2;
+ call add_scb_to_free_list;
+ mov SCBPTR, A;
+ jmp add_to_waiting_list;
+.endif
+dma_next_scb2:
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov SCB_LINKED_NEXT call dma_scb;
+add_to_waiting_list:
+ mov SCB_NEXT,WAITING_SCBH;
+ mov WAITING_SCBH, SCBPTR;
+ /*
+ * Prepare our selection hardware before the busfree so we have a
+ * high probability of winning arbitration.
+ */
+ call start_selection;
+ jmp await_busfree;
+add_to_free_list:
+ call add_scb_to_free_list;
+ jmp await_busfree;
+
+/*
+ * Is it an extended message? Copy the message to our message buffer and
+ * notify the host. The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
+ */
+mesgin_extended:
+ mvi MSGIN_EXT_LEN call inb_next;
+ mov A, MSGIN_EXT_LEN;
+mesgin_extended_loop:
+ mov DINDEX call inb_next;
+ dec A;
+ cmp DINDEX, MSGIN_EXT_BYTES+3 jne mesgin_extended_loop_test;
+ dec DINDEX; /* dump by repeatedly filling the last byte */
+mesgin_extended_loop_test:
+ test A, 0xFF jnz mesgin_extended_loop;
+mesgin_extended_intr:
+ mvi INTSTAT,EXTENDED_MSG; /* let driver know */
+ cmp RETURN_1,SEND_REJ je rej_mesgin;
+ cmp RETURN_1,SEND_MSG jne mesgin_done;
+/* The kernel has setup a message to be sent */
+ or SCSISIGO,ATNO,LASTPHASE; /* turn on ATNO */
+ jmp mesgin_done;
+
+/*
+ * Is it a disconnect message? Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+ or SCB_CONTROL,DISCONNECTED;
+.if ( SCB_PAGING )
+ call add_scb_to_disc_list;
+.endif
+ jmp await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them. This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+mesgin_sdptrs:
+ test SEQ_FLAGS, DPHASE jz mesgin_done;
+ mov SCB_SGCOUNT,SG_COUNT;
+
+ /* The SCB SGPTR becomes the next one we'll download */
+ mvi DINDEX, SCB_SGPTR;
+ mvi SG_NEXT call bcopy_4;
+
+ /* The SCB DATAPTR0 becomes the current SHADDR */
+ mvi DINDEX, SCB_DATAPTR;
+ mvi SHADDR call bcopy_4;
+
+/*
+ * Use the residual number since STCNT is corrupted by any message transfer.
+ */
+ mvi SCB_RESID_DCNT call bcopy_3;
+
+ jmp mesgin_done;
+
+/*
+ * Restore pointers message? Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+ and SEQ_FLAGS, ~DPHASE; /*
+ * We'll reload them
+ * the next time through
+ * the dataphase.
+ */
+ jmp 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.
+ */
+mesgin_identify:
+ test A,0x78 jnz rej_mesgin; /*!DiscPriv|!LUNTAR|!Reserved*/
+ and A,0x07; /* lun in lower three bits */
+ or SAVED_TCL,A; /* SAVED_TCL should be complete now */
+ mov SAVED_TCL call index_untagged_scb;
+ mov ARG_1, SINDIR;
+.if ( SCB_PAGING )
+ cmp ARG_1,SCB_LIST_NULL jne use_findSCB;
+.else
+ cmp ARG_1,SCB_LIST_NULL je snoop_tag;
+ /* Directly index the SCB */
+ mov SCBPTR,ARG_1;
+ test SCB_CONTROL,DISCONNECTED jz not_found;
+ jmp setup_SCB;
+.endif
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB. With SCB paging, this requires using findSCB for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
+ */
+snoop_tag:
+ mov NONE,SCSIDATL; /* ACK Identify MSG */
+snoop_tag_loop:
+ test SSTAT1,REQINIT jz snoop_tag_loop;
+ test SSTAT1, SCSIPERR jnz snoop_tag_loop;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGIN jne not_found;
+ cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+ or SEQ_FLAGS, TAGGED_SCB;
+ mvi ARG_1 call inb_next; /* tag value */
+/*
+ * See if the tag is in range. The tag is < SCBCOUNT if we add
+ * the complement of SCBCOUNT to the incomming tag and there is
+ * no carry.
+ */
+ mov A,COMP_SCBCOUNT;
+ add SINDEX,A,ARG_1;
+ jc not_found;
+
+.if ! ( SCB_PAGING )
+index_by_tag:
+ mov SCBPTR,ARG_1;
+ mov A, SAVED_TCL;
+ cmp SCB_TCL,A jne not_found;
+ test SCB_CONTROL,TAG_ENB jz not_found;
+ test SCB_CONTROL,DISCONNECTED jz not_found;
+.else
+/*
+ * Ensure that the SCB the tag points to is for an SCB transaction
+ * to the reconnecting target.
+ */
+use_findSCB:
+ mov ALLZEROS call findSCB; /* Have to search */
+ cmp SINDEX, SCB_LIST_NULL je not_found;
+.endif
+setup_SCB:
+ and SCB_CONTROL,~DISCONNECTED;
+ or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */
+ jmp mesgin_done;
+
+not_found:
+ mvi INTSTAT, NO_MATCH;
+ mvi MSG_BUS_DEV_RESET call mk_mesg;
+ jmp mesgin_done;
+
+/*
+ * Message reject? Let the kernel driver handle this. If we have an
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+ mvi INTSTAT, REJECT_MSG;
+ jmp mesgin_done;
+
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * 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, PAUSEDIS|FASTMODE;
+ test MSG_LEN,0xff jz mk_mesg1; /* Should always succeed */
+
+ /*
+ * Hmmm. For some reason the mesg buffer is in use.
+ * Tell the driver. It should look at SINDEX to find
+ * out what we wanted to use the buffer for and resolve
+ * the conflict.
+ */
+ mvi SEQCTL,FASTMODE;
+ mvi INTSTAT,MSG_BUFFER_BUSY;
+
+mk_mesg1:
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+ mvi MSG_LEN,1; /* length = 1 */
+ mov MSG_OUT,SINDEX; /* 1-byte message */
+ mvi SEQCTL,FASTMODE ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * 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_next:
+ mov NONE,SCSIDATL; /*dummy read from latch to ACK*/
+inb_next_wait:
+ /*
+ * If there is a parity error, wait for the kernel to
+ * see the interrupt and prepare our message response
+ * before continuing.
+ */
+ test SSTAT1, REQINIT jz inb_next_wait;
+ test SSTAT1, SCSIPERR jnz inb_next_wait;
+ and LASTPHASE, PHASE_MASK, SCSISIGI;
+ cmp LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+ mov DINDEX,SINDEX;
+ mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/
+inb_last:
+ mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/
+
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+ mvi INTSTAT, MSGIN_PHASEMIS;
+ jmp ITloop;
+
+/*
+ * 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;
+dma_loop:
+ test SSTAT0,DMADONE jnz dma_dmadone;
+ test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */
+dma_phasemis:
+ test SSTAT0,SDONE jnz dma_checkfifo;
+ mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */
+
+/*
+ * 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.
+ */
+dma_checkfifo:
+ test DFCNTRL,DIRECTION jnz dma_fifoempty;
+dma_fifoflush:
+ test DFSTATUS,FIFOEMP jz dma_fifoflush;
+
+dma_fifoempty:
+ /* Don't clobber an inprogress host data transfer */
+ test DFSTATUS, MREQPEND jnz dma_fifoempty;
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are
+ * actually off first lest we get an ILLSADDR.
+ */
+dma_dmadone:
+ and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+ test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+return:
+ ret;
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
+assert:
+ test SEQ_FLAGS,RESELECTED jz return; /* reselected? */
+ test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */
+
+ mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */
+
+.if ( SCB_PAGING )
+/*
+ * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
+ * or by the SCBIDn ARG_1. The search begins at the SCB index passed in
+ * via SINDEX. If the SCB cannot be found, SINDEX will be SCB_LIST_NULL,
+ * otherwise, SCBPTR is set to the proper SCB.
+ */
+findSCB:
+ mov SCBPTR,SINDEX; /* switch to next SCB */
+ mov A, ARG_1; /* Tag passed in ARG_1 */
+ cmp SCB_TAG,A jne findSCB_loop;
+ test SCB_CONTROL,DISCONNECTED jnz foundSCB;/*should be disconnected*/
+findSCB_loop:
+ inc SINDEX;
+ mov A,SCBCOUNT;
+ cmp SINDEX,A jne findSCB;
+/*
+ * We didn't find it. If we're paging, pull an SCB and DMA down the
+ * one we want. If we aren't paging or the SCB we dma down has the
+ * abort flag set, return not found.
+ */
+ mov ALLZEROS call get_free_or_disc_scb;
+ mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+ mov ARG_1 call dma_scb;
+ test SCB_RESID_SGCNT, 0xff jz . + 2;
+ or SCB_CONTROL, MUST_DMAUP_SCB;
+ test SCB_CONTROL, ABORT_SCB jz return;
+find_error:
+ mvi SINDEX, SCB_LIST_NULL ret;
+foundSCB:
+ test SCB_CONTROL, ABORT_SCB jnz find_error;
+rem_scb_from_disc_list:
+/* Remove this SCB from the disconnection list */
+ cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev;
+ mov SAVED_LINKPTR, SCB_PREV;
+ mov SCBPTR, SCB_NEXT;
+ mov SCB_PREV, SAVED_LINKPTR;
+ mov SCBPTR, SINDEX;
+unlink_prev:
+ cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */
+ mov SAVED_LINKPTR, SCB_NEXT;
+ mov SCBPTR, SCB_PREV;
+ mov SCB_NEXT, SAVED_LINKPTR;
+ mov SCBPTR, SINDEX ret;
+rHead:
+ mov DISCONNECTED_SCBH,SCB_NEXT ret;
+.else
+ ret;
+.endif
+
+set_stcnt_from_hcnt:
+ mov STCNT[0], HCNT[0];
+ mov STCNT[1], HCNT[1];
+ mov STCNT[2], HCNT[2] ret;
+
+bcopy_7:
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR;
+bcopy_5:
+ mov DINDIR, SINDIR;
+bcopy_4:
+ mov DINDIR, SINDIR;
+bcopy_3:
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR;
+ mov DINDIR, SINDIR ret;
+
+dma_scb:
+ /*
+ * SCB index is in SINDEX. Determine the physical address in
+ * the host where this SCB is located and load HADDR with it.
+ */
+ shr DINDEX, 3, SINDEX;
+ shl A, 5, SINDEX;
+ add HADDR[0], A, HSCB_ADDR[0];
+ mov A, DINDEX;
+ adc HADDR[1], A, HSCB_ADDR[1];
+ clr A;
+ adc HADDR[2], A, HSCB_ADDR[2];
+ adc HADDR[3], A, HSCB_ADDR[3];
+ /* Setup Count */
+ mvi HCNT[0], 28;
+ clr HCNT[1];
+ clr HCNT[2];
+ mov DFCNTRL, DMAPARAMS;
+ test DMAPARAMS, DIRECTION jnz dma_scb_fromhost;
+ /* Fill it with the SCB data */
+copy_scb_tofifo:
+ mvi SINDEX, SCB_CONTROL;
+ add A, 28, SINDEX;
+copy_scb_tofifo_loop:
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ mov DFDAT,SINDIR;
+ cmp SINDEX, A jne copy_scb_tofifo_loop;
+ or DFCNTRL, HDMAEN|FIFOFLUSH;
+dma_scb_fromhost:
+ call dma_finish;
+ /* If we were putting the SCB, we are done */
+ test DMAPARAMS, DIRECTION jz return;
+ mvi SCB_CONTROL call dfdat_in_7;
+ call dfdat_in_7_continued;
+ call dfdat_in_7_continued;
+ jmp dfdat_in_7_continued;
+dfdat_in_7:
+ mov DINDEX,SINDEX;
+dfdat_in_7_continued:
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT;
+ mov DINDIR,DFDAT ret;
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+ test DFSTATUS,HDONE jz dma_finish;
+ /* Turn off DMA */
+ and DFCNTRL, ~HDMAEN;
+ test DFCNTRL, HDMAEN jnz .;
+ ret;
+
+index_untagged_scb:
+ mov DINDEX, SINDEX;
+ shr DINDEX, 4;
+ and DINDEX, 0x03; /* Bottom two bits of tid */
+ add DINDEX, SCB_BUSYTARGETS;
+ shr A, 6, SINDEX; /* Target ID divided by 4 */
+ test SINDEX, SELBUSB jz index_untagged_scb2;
+ add A, 2; /* Add 2 positions */
+index_untagged_scb2:
+ mov SCBPTR, A; /*
+ * Select the SCB with this
+ * target's information.
+ */
+ mov SINDEX, DINDEX ret;
+
+add_scb_to_free_list:
+ mov SCB_NEXT, FREE_SCBH;
+ mvi SCB_TAG, SCB_LIST_NULL;
+ mov FREE_SCBH, SCBPTR ret;
+
+.if ( SCB_PAGING )
+get_free_or_disc_scb:
+ cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+ cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+ mvi SINDEX, SCB_LIST_NULL ret;
+dequeue_disc_scb:
+ mov SCBPTR, DISCONNECTED_SCBH;
+/*
+ * If we have a residual, then we are in the middle of some I/O
+ * and we have to send this SCB back up to the kernel so that the
+ * saved data pointers and residual information isn't lost.
+ */
+ test SCB_CONTROL, MUST_DMAUP_SCB jz . + 3;
+ and SCB_CONTROL, ~MUST_DMAUP_SCB;
+ jmp dma_up_scb;
+ test SCB_RESID_SGCNT,0xff jnz dma_up_scb;
+ cmp SCB_LINKED_NEXT, SCB_LIST_NULL je unlink_disc_scb;
+dma_up_scb:
+ mvi DMAPARAMS, FIFORESET;
+ mov SCB_TAG call dma_scb;
+unlink_disc_scb:
+ /* jmp instead of call since we want to return anyway */
+ mov SCBPTR jmp rem_scb_from_disc_list;
+dequeue_free_scb:
+ mov SCBPTR, FREE_SCBH;
+ mov FREE_SCBH, SCB_NEXT ret;
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list. This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+ mvi SCB_PREV, SCB_LIST_NULL;
+ mov SCB_NEXT, DISCONNECTED_SCBH;
+ mov DISCONNECTED_SCBH, SCBPTR;
+ cmp SCB_NEXT,SCB_LIST_NULL je return;
+ mov SCBPTR,SCB_NEXT;
+ mov SCB_PREV,DISCONNECTED_SCBH;
+ mov SCBPTR,DISCONNECTED_SCBH ret;
+.endif
--- /dev/null
+/*
+ * SCSI messages definitions.
+ */
+
+/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */
+#define MSG_CMDCOMPLETE 0x00 /* M/M */
+#define MSG_EXTENDED 0x01 /* O/O */
+#define MSG_SAVEDATAPOINTER 0x02 /* O/O */
+#define MSG_RESTOREPOINTERS 0x03 /* O/O */
+#define MSG_DISCONNECT 0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */
+#define MSG_ABORT 0x06 /* O/M */
+#define MSG_MESSAGE_REJECT 0x07 /* M/M */
+#define MSG_NOOP 0x08 /* M/M */
+#define MSG_PARITY_ERROR 0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
+#define MSG_BUS_DEV_RESET 0x0c /* O/M */
+#define MSG_ABORT_TAG 0x0d /* O/O */
+#define MSG_CLEAR_QUEUE 0x0e /* O/O */
+#define MSG_INIT_RECOVERY 0x0f /* O/O */
+#define MSG_REL_RECOVERY 0x10 /* O/O */
+#define MSG_TERM_IO_PROC 0x11 /* O/O */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
+#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */
+#define MSG_ORDERED_Q_TAG 0x22 /* O/O */
+#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */
+
+/* Identify message */ /* M/M */
+#define MSG_IDENTIFYFLAG 0x80
+#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR 0x01
+#define MSG_EXT_SDTR_LEN 0x03
+
+#define MSG_EXT_WDTR 0x03
+#define MSG_EXT_WDTR_LEN 0x02
--- /dev/null
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: sequencer.h,v 1.2 1997/06/27 19:38:52 gibbs Exp $
+ */
+
+#if defined(__KERNEL__)
+typedef unsigned char u_int8_t;
+#endif
+
+struct ins_format1 {
+ u_int8_t immediate;
+ u_int8_t source;
+ u_int8_t destination;
+ u_int8_t opcode_ret;
+};
+
+struct ins_format2 {
+ u_int8_t shift_control;
+ u_int8_t source;
+ u_int8_t destination;
+ u_int8_t opcode_ret;
+#define RETURN_BIT 0x01
+};
+
+struct ins_format3 {
+ u_int8_t immediate;
+ u_int8_t source;
+ u_int8_t address;
+ u_int8_t opcode_addr;
+#define ADDR_HIGH_BIT 0x01
+};
+
+struct instruction {
+ union {
+ struct ins_format1 format1;
+ struct ins_format2 format2;
+ struct ins_format3 format3;
+ u_int8_t bytes[4];
+ } format;
+ u_int srcline;
+ struct symbol *patch_label;
+ struct {
+ struct instruction *stqe_next; /* next element */
+ } links;
+};
+
+#define AIC_OP_OR 0x0
+#define AIC_OP_AND 0x1
+#define AIC_OP_XOR 0x2
+#define AIC_OP_ADD 0x3
+#define AIC_OP_ADC 0x4
+#define AIC_OP_ROL 0x5
+
+#define AIC_OP_JMP 0x8
+#define AIC_OP_JC 0x9
+#define AIC_OP_JNC 0xa
+#define AIC_OP_CALL 0xb
+#define AIC_OP_JNE 0xc
+#define AIC_OP_JNZ 0xd
+#define AIC_OP_JE 0xe
+#define AIC_OP_JZ 0xf
+
+/* Pseudo Ops */
+#define AIC_OP_SHL 0x10
+#define AIC_OP_SHR 0x20
+#define AIC_OP_ROR 0x30
+++ /dev/null
-/*+M*************************************************************************
- * Adaptec AIC7xxx sequencer code assembler.
- *
- * Copyright (c) 1994 John Aycock
- * 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, 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; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *-M*************************************************************************/
-static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
-#endif
-#define MAX_ARGS 16
-static const char *cpp[] = {
- "/lib/cpp -P - -",
- "/usr/lib/cpp -P - -",
- "/usr/bin/cpp -P - -",
- "/usr/bin/gcc -E -P -",
- "/usr/bin/cc -E -P -"
-};
-
-#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
-
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
-
-void
-error(const char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
-
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
-{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
-
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
-
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
- }
-
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
- }
-}
-
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
-
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
-}
-
-void
-patch(sym_t *p, int location)
-{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
- p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
- int i;
- sym_t *p;
-
- for (p = head; p; p = p->next) {
-
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
-
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
- }
-
- if (debug)
- fputc('\n', stderr);
- }
- }
-}
-
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
-{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
-
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
-
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
- }
- return(NULL);
-}
-
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- const char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
- /*
- * Extensions (note also that mvi allows A)
- */
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- const char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
- }
-
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
-
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
-
- p = lookup(a[spec]);
-
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
-}
-
-int
-crack(char **a, int n)
-{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
-
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
- }
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- }
-
- return (1); /* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void
-assemble(FILE *ofile)
-{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
- }
-
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
- }
- }
-
- backpatch();
- output(ofile);
-
- if (debug)
- output(stderr);
-}
-
-int
-main(int argc, char **argv)
-{
- int c;
- int pid;
- int ifile;
- int status;
- FILE *ofile;
- char *ofilename;
- int fd[2];
-
- ofile = NULL;
- ofilename = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
- ofilename = optarg;
- if ((ofile = fopen(ofilename, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofilename) {
- ofilename = ADOTOUT;
- if ((ofile = fopen(ofilename, "w")) < 0) {
- perror(ofilename);
- exit(EXIT_FAILURE);
- }
- }
-
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
-
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- if (wait(&status) < 0) {
- perror("wait error");
- }
-
- if (status != 0) {
- unlink(ofilename);
- }
- exit(status);
- } else { /* Child */
- int i, arg_cnt, found;
- char *args[MAX_ARGS];
- char *buf;
-
- arg_cnt = 0;
- found = FALSE;
- for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
- char *bp;
-
- buf = strdup(cpp[i]);
-
- for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
- bp != NULL;
- bp = strtok(NULL, " \t\n"), arg_cnt++) {
- if (arg_cnt == 0) {
- if (access(bp, X_OK) == 0) {
- found = TRUE;
- }
- }
-
- args[arg_cnt] = bp;
- }
-
- if (!found) {
- free(buf);
- }
- }
- args[arg_cnt] = NULL;
-
- if (found) {
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
-
- if (execvp(args[0], args) < 0) {
- perror("execvp() error");
- exit(EXIT_FAILURE);
- }
- } else {
- fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- }
- return(EXIT_SUCCESS);
-}
*
* Dean W. Gehnert, deang@teleport.com, 05/01/96
*
- * $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
#define BLS buffer + len + size
struct Scsi_Host *HBAptr;
struct aic7xxx_host *p;
static u8 buff[512];
- int i;
+ int i;
+ int found = FALSE;
int size = 0;
int len = 0;
off_t begin = 0;
off_t pos = 0;
static char *bus_names[] = { "Single", "Twin", "Wide" };
- static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
+ static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
+ "AIC-787x", "AIC-788x" };
HBAptr = NULL;
- for (i = 0; i < NUMBER(aic7xxx_boards); i++)
+ for (i=0; i < NUMBER(aic7xxx_boards); i++)
{
if ((HBAptr = aic7xxx_boards[i]) != NULL)
{
break;
}
- while ((HBAptr->hostdata != NULL) &&
+ while ((HBAptr->hostdata != NULL) && !found &&
((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
{
if (HBAptr->host_no == hostno)
{
- break; break;
+ found = TRUE;
}
}
- HBAptr = NULL;
+ if (!found)
+ {
+ HBAptr = NULL;
+ }
+ else
+ {
+ break;
+ }
}
}
size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
- size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_H_VERSION));
+ size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
+#if 0
size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
+#endif
len += size; pos = begin + len; size = 0;
size += sprintf(BLS, "\n");
#ifdef AIC7XXX_CMDS_PER_LUN
size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n", AIC7XXX_CMDS_PER_LUN);
#endif
-#ifdef AIC7XXX_TWIN_SUPPORT
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Enabled\n");
-#else
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Disabled\n");
-#endif
#ifdef AIC7XXX_TAGGED_QUEUEING
size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Enabled\n");
#else
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " SCSI Adapter: %s\n", board_names[p->type]);
+ size += sprintf(BLS, " SCSI Adapter: %s\n",
+ board_names[p->chip_type]);
size += sprintf(BLS, " (%s chipset)\n",
- chip_names[p->chip_type]);
+ chip_names[p->chip_class]);
size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]);
size += sprintf(BLS, " Base IO: %#.4x\n", p->base);
+ size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase);
size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n",
- p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
+ p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
size += sprintf(BLS, " Interrupts: %d", p->isr_count);
- if (p->chip_type == AIC_777x)
+ if (p->chip_class == AIC_777x)
{
size += sprintf(BLS, " %s\n",
(p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
-/*+M*************************************************************************
- * Adaptec AIC7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * 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, 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; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
- *
- * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
- *-M*************************************************************************/
-
/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
+ * DO NOT EDIT - This file is automatically generated.
+ */
+
+#define SCSISEQ 0x00
+#define TEMODE 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRSELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
+
+#define SXFRCTL0 0x01
+#define DFON 0x80
+#define DFPEXP 0x40
+#define FAST20 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x08
+#define SCAMEN 0x04
+#define CLRCHN 0x02
+
+#define SXFRCTL1 0x02
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18
+#define ENSTIMER 0x04
+#define ACTNEGEN 0x02
+#define STPWEN 0x01
+
+#define SCSISIGO 0x03
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
+
+#define SCSISIGI 0x03
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
+#define SCSIRATE 0x04
+#define WIDEXFER 0x80
+#define SXFR 0x70
+#define SOFS 0x0f
+
+#define SCSIID 0x05
+#define OID 0x0f
+
+#define SCSIDATL 0x06
+
+#define SCSIDATH 0x07
+
+#define STCNT 0x08
+
+#define CLRSINT0 0x0b
+#define CLRSELDO 0x40
+#define CLRSELDI 0x20
+#define CLRSELINGO 0x10
+#define CLRSWRAP 0x08
+#define CLRSPIORDY 0x02
+
+#define SSTAT0 0x0b
+#define TARGET 0x80
+#define SELDO 0x40
+#define SELDI 0x20
+#define SELINGO 0x10
+#define SWRAP 0x08
+#define SDONE 0x04
+#define SPIORDY 0x02
+#define DMADONE 0x01
+
+#define CLRSINT1 0x0c
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
+
+#define SSTAT1 0x0c
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
+
+#define SSTAT2 0x0d
+#define OVERRUN 0x80
+#define SFCNT 0x1f
+
+#define SSTAT3 0x0e
+#define SCSICNT 0xf0
+#define OFFCNT 0x0f
+
+#define SCSITEST 0x0f
+#define RQAKCNT 0x04
+#define CNTRTEST 0x02
+#define CMODE 0x01
+
+#define SIMODE0 0x10
+#define ENSELDO 0x40
+#define ENSELDI 0x20
+#define ENSELINGO 0x10
+#define ENSWRAP 0x08
+#define ENSDONE 0x04
+#define ENSPIORDY 0x02
+#define ENDMADONE 0x01
+
+#define SIMODE1 0x11
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
+
+#define SCSIBUSL 0x12
+
+#define SCSIBUSH 0x13
+
+#define SHADDR 0x14
+
+#define SELTIMER 0x18
+#define STAGE6 0x20
+#define STAGE5 0x10
+#define STAGE4 0x08
+#define STAGE3 0x04
+#define STAGE2 0x02
+#define STAGE1 0x01
+
+#define SELID 0x19
+#define SELID_MASK 0xf0
+#define ONEBIT 0x08
+
+#define BRDCTL 0x1d
+#define BRDDAT7 0x80
+#define BRDDAT6 0x40
+#define BRDDAT5 0x20
+#define BRDSTB 0x10
+#define BRDCS 0x08
+#define BRDRW 0x04
+#define BRDCTL1 0x02
+#define BRDCTL0 0x01
+
+#define SEECTL 0x1e
+#define EXTARBACK 0x80
+#define EXTARBREQ 0x40
+#define SEEMS 0x20
+#define SEERDY 0x10
+#define SEECS 0x08
+#define SEECK 0x04
+#define SEEDO 0x02
+#define SEEDI 0x01
+
+#define SBLKCTL 0x1f
+#define DIAGLEDEN 0x80
+#define DIAGLEDON 0x40
+#define AUTOFLUSHDIS 0x20
+#define SELWIDE 0x02
+
+#define SRAM_BASE 0x20
+
+#define TARG_SCRATCH 0x20
+
+#define ULTRA_ENB 0x30
+
+#define DISC_DSB 0x32
+
+#define MSG_LEN 0x34
+
+#define MSG_OUT 0x35
+
+#define DMAPARAMS 0x3d
+#define WIDEODD 0x40
+#define SCSIEN 0x20
+#define SDMAENACK 0x10
+#define SDMAEN 0x10
+#define HDMAEN 0x08
+#define HDMAENACK 0x08
+#define DIRECTION 0x04
+#define FIFOFLUSH 0x02
+#define FIFORESET 0x01
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ 0x000
-#define TEMODEO 0x80
-#define ENSELO 0x40
-#define ENSELI 0x20
-#define ENRSELI 0x10
-#define ENAUTOATNO 0x08
-#define ENAUTOATNI 0x04
-#define ENAUTOATNP 0x02
-#define SCSIRSTO 0x01
+#define SCBCOUNT 0x3e
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL0 0x001
-#define DFON 0x80
-#define DFPEXP 0x40
-#define ULTRAEN 0x20
-#define CLRSTCNT 0x10
-#define SPIOEN 0x08
-#define SCAMEN 0x04
-#define CLRCHN 0x02
-/* UNUSED 0x01 */
+#define COMP_SCBCOUNT 0x3f
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL1 0x002
-#define BITBUCKET 0x80
-#define SWRAPEN 0x40
-#define ENSPCHK 0x20
-#define STIMESEL 0x18
-#define ENSTIMER 0x04
-#define ACTNEGEN 0x02
-#define STPWEN 0x01 /* Powered Termination */
+#define QCNTMASK 0x40
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI 0x003
-#define CDI 0x80
-#define IOI 0x40
-#define MSGI 0x20
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
+#define SEQ_FLAGS 0x41
+#define RESELECTED 0x80
+#define IDENTIFY_SEEN 0x40
+#define TAGGED_SCB 0x20
+#define DPHASE 0x10
+#define PAGESCBS 0x04
+#define WIDE_BUS 0x02
+#define TWIN_BUS 0x01
-/*
- * Possible phases in SCSISIGI
- */
-#define PHASE_MASK 0xe0
-#define P_DATAOUT 0x00
-#define P_DATAIN 0x40
-#define P_COMMAND 0x80
-#define P_MESGOUT 0xa0
-#define P_STATUS 0xc0
-#define P_MESGIN 0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus. Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO 0x003
-#define CDO 0x80
-#define IOO 0x40
-#define MSGO 0x20
-#define ATNO 0x10
-#define SELO 0x08
-#define BSYO 0x04
-#define REQO 0x02
-#define ACKO 0x01
-
-/*
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers. Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE 0x004
-#define WIDEXFER 0x80 /* Wide transfer control */
-#define SXFR 0x70 /* Sync transfer rate */
-#define SOFS 0x0f /* Sync offset */
+#define SAVED_TCL 0x42
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID 0x005
-#define TID 0xf0 /* Target ID mask */
-#define OID 0x0f /* Our ID mask */
+#define SG_COUNT 0x43
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode. SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL 0x006
-#define SCSIDATH 0x007
+#define SG_NEXT 0x44
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus. The counter is decremented only once
- * the data has been safely transfered. SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */
-#define STCNT 0x008
-#define STCNT0 0x008
-#define STCNT1 0x009
-#define STCNT2 0x00a
+#define WAITING_SCBH 0x48
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define CLRSINT0 0x00b
-#define CLRSELDO 0x40
-#define CLRSELDI 0x20
-#define CLRSELINGO 0x10
-#define CLRSWRAP 0x08
-/* UNUSED 0x04 */
-#define CLRSPIORDY 0x02
-/* UNUSED 0x01 */
+#define SAVED_LINKPTR 0x49
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0 0x00b
-#define TARGET 0x80 /* Board acting as target */
-#define SELDO 0x40 /* Selection Done */
-#define SELDI 0x20 /* Board has been selected */
-#define SELINGO 0x10 /* Selection In Progress */
-#define SWRAP 0x08 /* 24bit counter wrap */
-#define SDONE 0x04 /* STCNT = 0x000000 */
-#define SPIORDY 0x02 /* SCSI PIO Ready */
-#define DMADONE 0x01 /* DMA transfer completed */
+#define SAVED_SCBPTR 0x4a
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1 0x00c
-#define CLRSELTIMEO 0x80
-#define CLRATNO 0x40
-#define CLRSCSIRSTI 0x20
-/* UNUSED 0x10 */
-#define CLRBUSFREE 0x08
-#define CLRSCSIPERR 0x04
-#define CLRPHASECHG 0x02
-#define CLRREQINIT 0x01
+#define REJBYTE 0x4b
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1 0x00c
-#define SELTO 0x80
-#define ATNTARG 0x40
-#define SCSIRSTI 0x20
-#define PHASEMIS 0x10
-#define BUSFREE 0x08
-#define SCSIPERR 0x04
-#define PHASECHG 0x02
-#define REQINIT 0x01
+#define LASTPHASE 0x4c
+#define P_MESGIN 0xe0
+#define PHASE_MASK 0xe0
+#define P_STATUS 0xc0
+#define P_MESGOUT 0xa0
+#define P_COMMAND 0x80
+#define CDI 0x80
+#define IOI 0x40
+#define P_DATAIN 0x40
+#define MSGI 0x20
+#define P_BUSFREE 0x01
+#define P_DATAOUT 0x00
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define SIMODE1 0x011
-#define ENSELTIMO 0x80
-#define ENATNTARG 0x40
-#define ENSCSIRST 0x20
-#define ENPHASEMIS 0x10
-#define ENBUSFREE 0x08
-#define ENSCSIPERR 0x04
-#define ENPHASECHG 0x02
-#define ENREQINIT 0x01
+#define MSGIN_EXT_LEN 0x4d
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define SCSIBUSL 0x012
-#define SCSIBUSH 0x013
+#define MSGIN_EXT_OPCODE 0x4e
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus. They are counted up in the same
- * manner as STCNT is counted down. SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write ahead.
- */
-#define SHADDR 0x014
-#define SHADDR0 0x014
-#define SHADDR1 0x015
-#define SHADDR2 0x016
-#define SHADDR3 0x017
+#define MSGIN_EXT_BYTES 0x4f
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id. The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID 0x019
-#define SELID_MASK 0xf0
-#define ONEBIT 0x08
-/* UNUSED 0x07 */
+#define DISCONNECTED_SCBH 0x52
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection. In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL 0x01f
-#define DIAGLEDEN 0x80 /* Aic78X0 only */
-#define DIAGLEDON 0x40 /* Aic78X0 only */
-#define AUTOFLUSHDIS 0x20
-/* UNUSED 0x10 */
-#define SELBUS_MASK 0x0a
-#define SELBUSB 0x08
-/* UNUSED 0x04 */
-#define SELWIDE 0x02
-/* UNUSED 0x01 */
-#define SELNARROW 0x00
+#define FREE_SCBH 0x53
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL 0x060
-#define PERRORDIS 0x80
-#define PAUSEDIS 0x40
-#define FAILDIS 0x20
-#define FASTMODE 0x10
-#define BRKADRINTEN 0x08
-#define STEP 0x04
-#define SEQRESET 0x02
-#define LOADRAM 0x01
+#define HSCB_ADDR 0x54
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
- * four bytes in succession. The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM 0x061
+#define CUR_SCBID 0x58
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0 0x062
-#define SEQADDR1 0x063
-#define SEQADDR1_MASK 0x01
+#define ARG_1 0x59
+#define RETURN_1 0x59
+#define SEND_MSG 0x80
+#define SEND_SENSE 0x40
+#define SEND_REJ 0x20
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM 0x064
-
-#define SINDEX 0x065
-#define DINDEX 0x066
-#define ALLZEROS 0x06a
-#define NONE 0x06a
-#define SINDIR 0x06c
-#define DINDIR 0x06d
-#define FUNCTION1 0x06e
+#define SCSICONF 0x5a
+#define RESET_SCSI 0x40
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR 0x088
-#define HADDR0 0x088
-#define HADDR1 0x089
-#define HADDR2 0x08a
-#define HADDR3 0x08b
-
-#define HCNT 0x08c
-#define HCNT0 0x08c
-#define HCNT1 0x08d
-#define HCNT2 0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR 0x090
+#define HOSTCONF 0x5d
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL 0x084
-/* RSVD 0xf0 */
-#define ACE 0x08 /* Support for external processors */
-/* RSVD 0x06 */
-#define ENABLE 0x01
+#define HA_274_BIOSCTRL 0x5f
+#define BIOSMODE 0x30
+#define BIOSDISABLED 0x30
+#define CHANNEL_B_PRIMARY 0x08
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define DSCOMMAND 0x084
-#define CACHETHEN 0x80 /* Cache Threshold enable */
-#define DPARCKEN 0x40 /* Data Parity Check Enable */
-#define MPARCKEN 0x20 /* Memory Parity Check Enable */
-#define EXTREQLCK 0x10 /* External Request Lock */
+#define SEQCTL 0x60
+#define PERRORDIS 0x80
+#define PAUSEDIS 0x40
+#define FAILDIS 0x20
+#define FASTMODE 0x10
+#define BRKADRINTEN 0x08
+#define STEP 0x04
+#define SEQRESET 0x02
+#define LOADRAM 0x01
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME 0x085
-#define BOFF 0xf0
-#define BON 0x0f
+#define SEQRAM 0x61
-/*
- * Bus Speed (p. 3-45)
- */
-#define BUSSPD 0x086
-#define DFTHRSH 0xc0
-#define STBOFF 0x38
-#define STBON 0x07
-#define DFTHRSH_100 0xc0
+#define SEQADDR0 0x62
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL 0x087
-/* UNUSED 0x80 */
-#define POWRDN 0x40
-/* UNUSED 0x20 */
-#define SWINT 0x10
-#define IRQMS 0x08
-#define PAUSE 0x04
-#define INTEN 0x02
-#define CHIPRST 0x01
-#define CHIPRSTACK 0x01
+#define SEQADDR1 0x63
+#define SEQADDR1_MASK 0x01
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT 0x091
-#define SEQINT_MASK 0xf1 /* SEQINT Status Codes */
-#define BAD_PHASE 0x01 /* unknown scsi bus phase */
-#define SEND_REJECT 0x11 /* sending a message reject */
-#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/
-#define NO_MATCH 0x31 /* no cmd match for reconnect */
-#define SDTR_MSG 0x41 /* SDTR message received */
-#define WDTR_MSG 0x51 /* WDTR message received */
-#define REJECT_MSG 0x61 /* Reject message received */
-#define BAD_STATUS 0x71 /* Bad status from target */
-#define RESIDUAL 0x81 /* Residual byte count != 0 */
-#define ABORT_TAG 0x91 /* Sent an ABORT_TAG message */
-#define AWAITING_MSG 0xa1 /*
- * Kernel requested to specify
- * a message to this target
- * (command was null), so tell
- * it that it can fill the
- * message buffer.
- */
-#define IMMEDDONE 0xb1 /*
- * An immediate command has
- * completed
- */
-#define MSG_BUFFER_BUSY 0xc1 /*
- * Sequencer wants to use the
- * message buffer, but it
- * already contains a message
- */
-#define MSGIN_PHASEMIS 0xd1 /*
- * Target changed phase on us
- * when we were expecting
- * another msgin byte.
- */
-#define DATA_OVERRUN 0xe1 /*
- * Target attempted to write
- * beyond the bounds of its
- * command.
- */
-#define BRKADRINT 0x08
-#define SCSIINT 0x04
-#define CMDCMPLT 0x02
-#define SEQINT 0x01
-#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+#define ACCUM 0x64
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors. You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR 0x092
-/* UNUSED 0xf0 */
-#define PARERR 0x08
-#define ILLOPCODE 0x04
-#define ILLSADDR 0x02
-#define ILLHADDR 0x01
+#define SINDEX 0x65
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT 0x092
-#define CLRBRKADRINT 0x08
-#define CLRSCSIINT 0x04
-#define CLRCMDINT 0x02
-#define CLRSEQINT 0x01
-
-#define DFCNTRL 0x093
-#define WIDEODD 0x40
-#define SCSIEN 0x20
-#define SDMAEN 0x10
-#define SDMAENACK 0x10
-#define HDMAEN 0x08
-#define HDMAENACK 0x08
-#define DIRECTION 0x04
-#define FIFOFLUSH 0x02
-#define FIFORESET 0x01
-
-#define DFSTATUS 0x094
-#define HDONE 0x08
-#define FIFOEMP 0x01
-
-#define DFDAT 0x099
+#define DINDEX 0x66
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT 0x09a
-#define SCBAUTO 0x80
-#define SCBCNT_MASK 0x1f
+#define ALLONES 0x69
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the sequencer has yet to start)
- */
-#define QINFIFO 0x09b
+#define ALLZEROS 0x6a
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT 0x09c
+#define NONE 0x6a
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO 0x09d
+#define FLAGS 0x6b
+#define ZERO 0x02
+#define CARRY 0x01
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT 0x09e
+#define SINDIR 0x6c
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR respectively when starting this command.
- */
-#define SCBARRAY 0x0a0
-#define SCB_CONTROL 0x0a0
-#define NEEDWDTR 0x80
-#define DISCENB 0x40
-#define TAG_ENB 0x20
-#define NEEDSDTR 0x10
-#define DISCONNECTED 0x04
-#define SCB_TAG_TYPE 0x03
-#define SCB_TCL 0x0a1
-#define SCB_TARGET_STATUS 0x0a2
-#define SCB_SGCOUNT 0x0a3
-#define SCB_SGPTR 0x0a4
-#define SCB_SGPTR0 0x0a4
-#define SCB_SGPTR1 0x0a5
-#define SCB_SGPTR2 0x0a6
-#define SCB_SGPTR3 0x0a7
-#define SCB_RESID_SGCNT 0x0a8
-#define SCB_RESID_DCNT 0x0a9
-#define SCB_RESID_DCNT0 0x0a9
-#define SCB_RESID_DCNT1 0x0aa
-#define SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR 0x0ac
-#define SCB_DATAPTR0 0x0ac
-#define SCB_DATAPTR1 0x0ad
-#define SCB_DATAPTR2 0x0ae
-#define SCB_DATAPTR3 0x0af
-#define SCB_DATACNT 0x0b0
-#define SCB_DATACNT0 0x0b0
-#define SCB_DATACNT1 0x0b1
-#define SCB_DATACNT2 0x0b2
-/* UNUSED - QUAD PADDING 0x0b3 */
-#define SCB_CMDPTR 0x0b4
-#define SCB_CMDPTR0 0x0b4
-#define SCB_CMDPTR1 0x0b5
-#define SCB_CMDPTR2 0x0b6
-#define SCB_CMDPTR3 0x0b7
-#define SCB_CMDLEN 0x0b8
-#define SCB_TAG 0x0b9
-#define SCB_NEXT 0x0ba
-#define SCB_PREV 0x0bb
-
-#define SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define SEECTL_2840 0x0c0
-/* UNUSED 0xf8 */
-#define CS_2840 0x04
-#define CK_2840 0x02
-#define DO_2840 0x01
-
-#define STATUS_2840 0x0c1
-#define EEPROM_TF 0x80
-#define BIOS_SEL 0x60
-#define ADSEL 0x1e
-#define DI_2840 0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS 0x086
+#define DINDIR 0x6d
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device. In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device. When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM. When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.
- *
- * After successful arbitration for the memory port, the SEECS bit of
- * the SEECTL register is connected to the chip select. The SEECK,
- * SEEDO, and SEEDI are connected to the clock, data out, and data in
- * lines respectively. The SEERDY bit of SEECTL is useful in that it
- * gives us an 800 nsec timer. After a write to the SEECTL register,
- * the SEERDY goes high 800 nsec later. The one exception to this is
- * when we first request access to the memory port. The SEERDY goes
- * high to signify that access has been granted and, for this case, has
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to
- * read the serial EEPROM.
- */
-#define SEECTL 0x01e
-#define EXTARBACK 0x80
-#define EXTARBREQ 0x40
-#define SEEMS 0x20
-#define SEERDY 0x10
-#define SEECS 0x08
-#define SEECK 0x04
-#define SEEDO 0x02
-#define SEEDI 0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, 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). The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space. This should work regardless of
- * whether the bios has been installed.
- */
+#define FUNCTION1 0x6e
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH 0x020
+#define STACK 0x6f
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away. Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE 0x030
-#define REJBYTE_EXT 0x031
+#define BCTL 0x84
+#define ACE 0x08
+#define ENABLE 0x01
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define DISC_DSB 0x032
-#define DISC_DSB_A 0x032
-#define DISC_DSB_B 0x033
+#define DSCOMMAND 0x84
+#define CACHETHEN 0x80
+#define DPARCKEN 0x40
+#define MPARCKEN 0x20
+#define EXTREQLCK 0x10
-/*
- * Length of pending message
- */
-#define MSG_LEN 0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0 0x035
-#define COMP_MSG0 0xcb /* 2's complement of MSG0 */
-#define MSG1 0x036
-#define MSG2 0x037
-#define MSG3 0x038
-#define MSG4 0x039
-#define MSG5 0x03a
-#define MSG6 0x03b
-#define MSG7 0x03c
+#define BUSTIME 0x85
+#define BOFF 0xf0
+#define BON 0x0f
-/*
- * These are offsets into the card's scratch ram. Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE 0x03d
-#define ARG_1 0x03e
-#define MAXOFFSET 0x01
-#define RETURN_1 0x03f
-#define SEND_WDTR 0x80
-#define SEND_SDTR 0x60
-#define SEND_SENSE 0x40
-#define SEND_REJ 0x20
-#define SCB_PAGEDIN 0x10
-
-#define SIGSTATE 0x040
-
-#define DMAPARAMS 0x041 /* Parameters for DMA Logic */
-
-#define SG_COUNT 0x042
-#define SG_NEXT 0x043 /* working value of SG pointer */
-#define SG_NEXT0 0x043
-#define SG_NEXT1 0x044
-#define SG_NEXT2 0x045
-#define SG_NEXT3 0x046
-
-#define SCBCOUNT 0x047 /*
- * Number of SCBs supported by
- * this card.
- */
-#define COMP_SCBCOUNT 0x048 /*
- * Two's compliment of SCBCOUNT
- */
-#define QCNTMASK 0x049 /*
- * Mask of bits to test against
- * when looking at the Queue Count
- * registers. Works around a bug
- * on aic7850 chips.
- */
-#define FLAGS 0x04a
-#define SINGLE_BUS 0x00
-#define TWIN_BUS 0x01
-#define WIDE_BUS 0x02
-#define PAGESCBS 0x04
-#define DPHASE 0x10
-#define SELECTED 0x20
-#define IDENTIFY_SEEN 0x40
-#define RESELECTED 0x80
-
-#define SAVED_TCL 0x04b /*
- * Temporary storage for the
- * target/channel/lun of a
- * reconnecting target
- */
-#define ACTIVE_A 0x04c
-#define ACTIVE_B 0x04d
-#define WAITING_SCBH 0x04e /*
- * head of list of SCBs awaiting
- * selection
- */
-#define DISCONNECTED_SCBH 0x04f /*
- * head of list of SCBs that are
- * disconnected. Used for SCB
- * paging.
- */
-#define SCB_LIST_NULL 0xff
-
-#define SAVED_LINKPTR 0x050
-#define SAVED_SCBPTR 0x051
-#define ULTRA_ENB 0x052
-#define ULTRA_ENB_B 0x053
-
-#define SCSICONF 0x05a
-#define RESET_SCSI 0x40
-
-#define HOSTCONF 0x05d
-
-#define HA_274_BIOSCTRL 0x05f
-#define BIOSMODE 0x30
-#define BIOSDISABLED 0x30
-#define CHANNEL_B_PRIMARY 0x08
-
-/* Message codes */
-#define MSG_EXTENDED 0x01
-#define MSG_SDTR 0x01
-#define MSG_WDTR 0x03
-#define MSG_SDPTRS 0x02
-#define MSG_RDPTRS 0x03
-#define MSG_DISCONNECT 0x04
-#define MSG_INITIATOR_DET_ERROR 0x05
-#define MSG_ABORT 0x06
-#define MSG_REJECT 0x07
-#define MSG_NOP 0x08
-#define MSG_MSG_PARITY_ERROR 0x09
-#define MSG_BUS_DEVICE_RESET 0x0c
-#define MSG_ABORT_TAG 0x0d
-#define MSG_SIMPLE_TAG 0x20
-#define MSG_IDENTIFY 0x80
-
-/* WDTR Message values */
-#define BUS_8_BIT 0x00
-#define BUS_16_BIT 0x01
-#define BUS_32_BIT 0x02
-
-#define MAX_OFFSET_8BIT 0x0f
-#define MAX_OFFSET_16BIT 0x08
+#define BUSSPD 0x86
+#define DFTHRSH_100 0xc0
+#define DFTHRSH 0xc0
+#define STBOFF 0x38
+#define STBON 0x07
+
+#define DSPCISTATUS 0x86
+
+#define HCNTRL 0x87
+#define POWRDN 0x40
+#define SWINT 0x10
+#define IRQMS 0x08
+#define PAUSE 0x04
+#define INTEN 0x02
+#define CHIPRST 0x01
+#define CHIPRSTACK 0x01
+
+#define HADDR 0x88
+
+#define HCNT 0x8c
+
+#define SCBPTR 0x90
+
+#define INTSTAT 0x91
+#define SEQINT_MASK 0xf1
+#define DATA_OVERRUN 0xe1
+#define MSGIN_PHASEMIS 0xd1
+#define MSG_BUFFER_BUSY 0xc1
+#define AWAITING_MSG 0xa1
+#define ABORT_CMDCMPLT 0x91
+#define RESIDUAL 0x81
+#define BAD_STATUS 0x71
+#define REJECT_MSG 0x61
+#define NO_MATCH_BUSY 0x51
+#define EXTENDED_MSG 0x41
+#define NO_MATCH 0x31
+#define NO_IDENT 0x21
+#define SEND_REJECT 0x11
+#define INT_PEND 0x0f
+#define BRKADRINT 0x08
+#define SCSIINT 0x04
+#define CMDCMPLT 0x02
+#define BAD_PHASE 0x01
+#define SEQINT 0x01
+
+#define CLRINT 0x92
+#define CLRBRKADRINT 0x08
+#define CLRSCSIINT 0x04
+#define CLRCMDINT 0x02
+#define CLRSEQINT 0x01
+
+#define ERROR 0x92
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
+#define DFCNTRL 0x93
+
+#define DFSTATUS 0x94
+#define DWORDEMP 0x20
+#define MREQPEND 0x10
+#define HDONE 0x08
+#define DFTHRESH 0x04
+#define FIFOFULL 0x02
+#define FIFOEMP 0x01
+
+#define DFDAT 0x99
+
+#define SCBCNT 0x9a
+#define SCBAUTO 0x80
+#define SCBCNT_MASK 0x1f
+
+#define QINFIFO 0x9b
+
+#define QINCNT 0x9c
+
+#define QOUTFIFO 0x9d
+
+#define QOUTCNT 0x9e
+
+#define SCB_CONTROL 0xa0
+#define MK_MESSAGE 0x80
+#define DISCENB 0x40
+#define TAG_ENB 0x20
+#define MUST_DMAUP_SCB 0x10
+#define ABORT_SCB 0x08
+#define DISCONNECTED 0x04
+#define SCB_TAG_TYPE 0x03
+
+#define SCB_BASE 0xa0
+
+#define SCB_TCL 0xa1
+#define TID 0xf0
+#define SELBUSB 0x08
+#define LID 0x07
+
+#define SCB_TARGET_STATUS 0xa2
+
+#define SCB_SGCOUNT 0xa3
+
+#define SCB_SGPTR 0xa4
+
+#define SCB_RESID_SGCNT 0xa8
+
+#define SCB_RESID_DCNT 0xa9
+
+#define SCB_DATAPTR 0xac
+
+#define SCB_DATACNT 0xb0
+
+#define SCB_LINKED_NEXT 0xb3
+
+#define SCB_CMDPTR 0xb4
+
+#define SCB_CMDLEN 0xb8
+
+#define SCB_TAG 0xb9
+
+#define SCB_NEXT 0xba
+
+#define SCB_PREV 0xbb
+
+#define SCB_BUSYTARGETS 0xbc
+
+#define SEECTL_2840 0xc0
+#define CS_2840 0x04
+#define CK_2840 0x02
+#define DO_2840 0x01
+
+#define STATUS_2840 0xc1
+#define EEPROM_TF 0x80
+#define BIOS_SEL 0x60
+#define ADSEL 0x1e
+#define DI_2840 0x01
+
+
+#define BUS_8_BIT 0x00
+#define MAX_OFFSET_8BIT 0x0f
+#define BUS_16_BIT 0x01
+#define MAX_OFFSET_16BIT 0x08
+#define SCB_LIST_NULL 0xff
+#define SG_SIZEOF 0x08
+#define BUS_32_BIT 0x02
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/nvram.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
#endif
-#define RTC_READ(reg) \
- ({ unsigned char __val; \
- outb(reg,&tt_rtc.regsel); \
- __val = tt_rtc.data; \
- __val; \
- })
-
-#define RTC_WRITE(reg,val) \
- do { \
- outb(reg,&tt_rtc.regsel); \
- tt_rtc.data = (val); \
- } while(0)
-
-
int atari_scsi_detect (Scsi_Host_Template *host)
{
static int called = 0;
/* use 7 as default */
host->this_id = 7;
/* Test if a host id is set in the NVRam */
- if (ATARIHW_PRESENT(TT_CLK)) {
- unsigned char sum = 0, b;
- int i;
-
- /* Make checksum */
- for( i = 14; i < 62; ++i )
- sum += RTC_READ(i);
-
- if (/* NV-Ram checksum valid? */
- RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
- /* Arbitration enabled? (for TOS) */
- (b = RTC_READ( 30 )) & 0x80) {
+ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+ unsigned char b = nvram_read_byte( 14 );
+ /* Arbitration enabled? (for TOS) If yes, use configured host ID */
+ if (b & 0x80)
host->this_id = b & 7;
- }
}
}
* the nexus and tell the device to abort. However, we really
* cannot 'reconnect' per se, therefore we tell the upper layer
* the safest thing we can. This is, wait a bit, if nothing
- * happens, we are really hung so reset the bug.
+ * happens, we are really hung so reset the bus.
*/
return SCSI_ABORT_SNOOZE;
done_SC->request_bufflen,
esp->edev->my_bus);
} else {
- struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
#ifdef DEBUG_ESP_SG
printk("esp%d: unmapping sg ", esp->esp_id);
#endif
- mmu_release_scsi_sgl((struct mmu_sglist *) scl,
+ mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
done_SC->use_sg - 1,
esp->edev->my_bus);
#ifdef DEBUG_ESP_SG
if(sz > 0x1000000)
sz = 0x1000000;
} else {
- base = ((__u32)sp->SCp.ptr);
+ base = ((__u32)((unsigned long)sp->SCp.ptr));
base &= (0x1000000 - 1);
end = (base + sp->SCp.this_residual);
if(end > 0x1000000)
tmp |= DMA_ST_WRITE;
else
tmp &= ~(DMA_ST_WRITE);
- dregs->st_addr = ((__u32)SCptr->SCp.ptr);
+ dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
dregs->cond_reg = tmp;
} else {
esp_setcount(eregs, hmuch, 0);
- dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
+ dma_setup(dregs, esp->dma->revision,
+ ((__u32)((unsigned long)SCptr->SCp.ptr)),
hmuch, (thisphase == in_datain));
ESPDATA(("DMA|TI --> do_intr_end\n"));
esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
}
#else
+/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
#ifdef __sparc_v9__
-#error Dave you need to fix some things first...
+extern unsigned char ino_to_pil[];
+#define INO_TO_PIL(esp) (ino_to_pil[(esp)->irq])
+#else
+#define INO_TO_PIL(esp) ((esp)->irq & 0xf)
#endif
/* For SMP we only service one ESP on the list list at our IRQ level! */
/* Handle all ESP interrupts showing at this IRQ level. */
for_each_esp(esp) {
- if((esp->irq & 0xf) == irq) {
+ if(INO_TO_PIL(esp) == irq) {
if(DMA_IRQ_P(esp->dregs)) {
DMA_INTSOFF(esp->dregs);
#endif
#ifdef DEBUG
-#define DPRINTK(D) printk D;
+#define DPRINTK(D) (printk D)
#else
-#define DPRINTK(D)
+#define DPRINTK(D) ((void)0)
#endif
#define AUTOFS_SUPER_MAGIC 0x0187
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* Time before asking the daemon again */
+
/* Structures associated with the root directory hash */
#define AUTOFS_HASH_SIZE 67
}
static struct file_operations autofs_dir_operations = {
- NULL, /* lseek */
+ NULL, /* llseek */
NULL, /* read */
NULL, /* write */
autofs_dir_readdir, /* readdir */
- NULL, /* select */
+ NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* release */
- NULL /* fsync */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations autofs_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* read_page */
+ NULL, /* follow_link */
+ NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
unlock_super(s);
s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
if (!s->s_root) {
- s->s_dev = 0;
- kfree(sbi);
printk("autofs: get root inode failed\n");
+ kfree(sbi);
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+ printk("autofs: called with bogus options\n");
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
- printk("autofs: called with bogus options\n");
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+ printk("autofs: kernel does not match daemon version\n");
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
- printk("autofs: kernel does not match daemon version\n");
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
printk("autofs: could not open pipe file descriptor\n");
}
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
static struct file_operations autofs_root_operations = {
- NULL, /* lseek */
+ NULL, /* llseek */
NULL, /* read */
NULL, /* write */
autofs_root_readdir, /* readdir */
- NULL, /* select */
+ NULL, /* poll */
autofs_root_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* release */
- NULL /* fsync */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations autofs_root_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
static int autofs_root_readdir(struct inode *inode, struct file *filp,
{
struct inode * inode;
struct autofs_dir_ent *ent;
-
+
while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
int status = autofs_wait(sbi, &dentry->d_name);
/* Turn this into a real negative dentry? */
if (status == -ENOENT) {
- dentry->d_flags = 0;
- return 0;
+ dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
+ } else if (status) {
+ /* Return a negative dentry, but leave it "pending" */
+ return 1;
}
- if (status)
- return status;
}
+ /* Abuse this field as a pointer to the directory entry, used to
+ find the expire list pointers */
+ dentry->d_time = (unsigned long) ent;
+
if (!dentry->d_inode) {
inode = iget(sb, ent->ino);
- if (!inode)
- return -EACCES;
-
+ if (!inode) {
+ /* Failed, but leave pending for next time */
+ return 1;
+ }
dentry->d_inode = inode;
}
while (dentry == dentry->d_mounts)
schedule();
}
- dentry->d_flags = 0;
- return 0;
+
+ autofs_update_usage(&sbi->dirhash,ent);
+
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
}
{
struct autofs_sb_info *sbi;
struct inode * dir = dentry->d_parent->d_inode;
+ struct autofs_dir_ent *ent;
sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
- /* Incomplete dentry? */
- if (dentry->d_flags) {
+ /* Pending dentry */
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
if (autofs_oz_mode(sbi))
return 1;
- try_to_fill_dentry(dentry, dir->i_sb, sbi);
- return 1;
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
}
- /* Negative dentry.. Should we time these out? */
+ /* Negative dentry.. invalidate if "old" */
if (!dentry->d_inode)
- return 1;
+ return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
- /* We should update the usage stuff here.. */
+ /* Update the usage list */
+ ent = (struct autofs_dir_ent *) dentry->d_time;
+ autofs_update_usage(&sbi->dirhash,ent);
return 1;
}
* We need to do this before we release the directory semaphore.
*/
dentry->d_revalidate = autofs_revalidate;
- dentry->d_flags = 1;
+ dentry->d_flags |= DCACHE_AUTOFS_PENDING;
d_add(dentry, NULL);
up(&dir->i_sem);
autofs_revalidate(dentry);
down(&dir->i_sem);
+
return 0;
}
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
if (!bh)
return NULL;
bh->b_count++;
+ bh->b_lru_time = jiffies;
wait_on_buffer(bh);
if (bh->b_dev == dev &&
bh->b_blocknr == block &&
}
}
-/* Check if a buffer is OK to be reclaimed. */
-static inline int can_reclaim(struct buffer_head *bh, int size)
-{
- if (bh->b_count ||
- buffer_protected(bh) ||
- buffer_locked(bh))
- return 0;
-
- if (buffer_dirty(bh)) {
- refile_buffer(bh);
- return 0;
- }
-
- if (bh->b_size != size)
- return 0;
-
- return 1;
-}
-
-/* Find a candidate buffer to be reclaimed. */
-static struct buffer_head *find_candidate(struct buffer_head *list,
+/*
+ * Find a candidate buffer to be reclaimed.
+ * N.B. Must search the entire BUF_LOCKED list rather than terminating
+ * when the first locked buffer is found. Buffers are unlocked at
+ * completion of IO, and under some conditions there may be (many)
+ * unlocked buffers after the first locked one.
+ */
+static struct buffer_head *find_candidate(struct buffer_head *bh,
int *list_len, int size)
{
- struct buffer_head *bh;
-
- for (bh = list;
- bh && (*list_len) > 0;
- bh = bh->b_next_free, (*list_len)--) {
+ if (!bh)
+ goto no_candidate;
+
+ for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) {
if (size != bh->b_size) {
/* This provides a mechanism for freeing blocks
* of other sizes, this is necessary now that we
break;
continue;
}
-
- if (buffer_locked(bh) && bh->b_list == BUF_LOCKED) {
- /* Buffers are written in the order they are placed
- * on the locked list. If we encounter a locked
- * buffer here, this means that the rest of them
- * are also locked.
- */
- (*list_len) = 0;
- return NULL;
- }
-
- if (can_reclaim(bh,size))
- return bh;
+ else if (!bh->b_count &&
+ !buffer_locked(bh) &&
+ !buffer_protected(bh) &&
+ !buffer_dirty(bh))
+ return bh;
}
+no_candidate:
return NULL;
}
static void refill_freelist(int size)
{
- struct buffer_head * bh;
+ struct buffer_head * bh, * next;
struct buffer_head * candidate[BUF_DIRTY];
- unsigned int best_time, winner;
int buffers[BUF_DIRTY];
int i;
- int needed;
+ int needed, obtained=0;
refilled = 1;
- /* If there are too many dirty buffers, we wake up the update process
- * now so as to ensure that there are still clean buffers available
- * for user processes to use (and dirty).
- */
/* We are going to try to locate this much memory. */
needed = bdf_prm.b_un.nrefill * size;
- while ((nr_free_pages > min_free_pages*2) &&
- (needed > 0) &&
- grow_buffers(GFP_BUFFER, size))
- needed -= PAGE_SIZE;
+ while ((nr_free_pages > min_free_pages*2) &&
+ grow_buffers(GFP_BUFFER, size)) {
+ obtained += PAGE_SIZE;
+ if (obtained >= needed)
+ return;
+ }
+ /*
+ * Update the needed amount based on the number of potentially
+ * freeable buffers. We don't want to free more than one quarter
+ * of the available buffers.
+ */
+ i = (nr_buffers_type[BUF_CLEAN] + nr_buffers_type[BUF_LOCKED]) >> 2;
+ if (i < bdf_prm.b_un.nrefill) {
+ needed = i * size;
+ if (needed < PAGE_SIZE)
+ needed = PAGE_SIZE;
+ }
+
+ /*
+ * OK, we cannot grow the buffer cache, now try to get some
+ * from the lru list.
+ */
repeat:
- if(needed <= 0)
+ if (obtained >= needed)
return;
- /* OK, we cannot grow the buffer cache, now try to get some
- * from the lru list.
- *
+ /*
* First set the candidate pointers to usable buffers. This
- * should be quick nearly all of the time.
+ * should be quick nearly all of the time. N.B. There must be
+ * no blocking calls after setting up the candidate[] array!
*/
-
- for(i=0; i<BUF_DIRTY; i++) {
+ for (i = BUF_CLEAN; i<BUF_DIRTY; i++) {
buffers[i] = nr_buffers_type[i];
candidate[i] = find_candidate(lru_list[i], &buffers[i], size);
}
- /* Now see which candidate wins the election. */
-
- winner = best_time = UINT_MAX;
- for(i=0; i<BUF_DIRTY; i++) {
- if(!candidate[i])
- continue;
- if(candidate[i]->b_lru_time < best_time) {
- best_time = candidate[i]->b_lru_time;
- winner = i;
- }
- }
-
- /* If we have a winner, use it, and then get a new candidate from that list. */
- if(winner != UINT_MAX) {
- i = winner;
- while (needed>0 && (bh=candidate[i])) {
- candidate[i] = bh->b_next_free;
- if(candidate[i] == bh)
- candidate[i] = NULL; /* Got last one */
- remove_from_queues(bh);
- bh->b_dev = B_FREE;
- put_last_free(bh);
- needed -= bh->b_size;
- buffers[i]--;
- if(buffers[i] == 0)
- candidate[i] = NULL;
-
- if (candidate[i] && !can_reclaim(candidate[i],size))
- candidate[i] = find_candidate(candidate[i],
- &buffers[i], size);
+ /*
+ * Select the older of the available buffers until we reach our goal.
+ */
+ for (;;) {
+ i = BUF_CLEAN;
+ if (!candidate[BUF_CLEAN]) {
+ if (!candidate[BUF_LOCKED])
+ break;
+ i = BUF_LOCKED;
}
- goto repeat;
- }
+ else if (candidate[BUF_LOCKED] &&
+ (candidate[BUF_LOCKED]->b_lru_time <
+ candidate[BUF_CLEAN ]->b_lru_time))
+ i = BUF_LOCKED;
+ /*
+ * Free the selected buffer and get the next candidate.
+ */
+ bh = candidate[i];
+ next = bh->b_next_free;
+
+ obtained += bh->b_size;
+ remove_from_queues(bh);
+ put_last_free(bh);
+ if (obtained >= needed)
+ return;
+
+ if (--buffers[i] && bh != next)
+ candidate[i] = find_candidate(next, &buffers[i], size);
+ else
+ candidate[i] = NULL;
+ }
+
+ /*
+ * If we achieved at least half of our goal, return now.
+ */
+ if (obtained >= (needed >> 1))
+ return;
/* Too bad, that was not enough. Try a little harder to grow some. */
if (nr_free_pages > min_free_pages + 5) {
if (grow_buffers(GFP_BUFFER, size)) {
- needed -= PAGE_SIZE;
+ obtained += PAGE_SIZE;
goto repeat;
}
}
-
- /* And repeat until we find something good. */
+
+ /*
+ * Make one more attempt to allocate some buffers.
+ */
if (grow_buffers(GFP_ATOMIC, size))
- needed -= PAGE_SIZE;
- else
- wakeup_bdflush(1);
+ obtained += PAGE_SIZE;
+
+ /*
+ * If we got any buffers, or another task freed some,
+ * return now to let this task proceed.
+ */
+ if (obtained || free_list[BUFSIZE_INDEX(size)]) {
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: obtained %d of %d, free list=%d\n",
+obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL);
+#endif
+ return;
+ }
+
+ /*
+ * System is _very_ low on memory ... wake up bdflush and wait.
+ */
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: waking bdflush\n");
+#endif
+ wakeup_bdflush(1);
+ /*
+ * While we slept, other tasks may have needed buffers and entered
+ * refill_freelist. This could be a big problem ... reset the
+ * needed amount to the absolute minimum.
+ */
+ needed = size;
goto repeat;
}
* and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
*/
bh->b_count=1;
+ bh->b_list = BUF_CLEAN;
+ bh->b_lru_time = jiffies;
bh->b_flushtime=0;
bh->b_state=(1<<BH_Touched);
bh->b_dev=dev;
}
+/*
+ * Put a buffer into the appropriate list, without side-effects.
+ */
+static inline void file_buffer(struct buffer_head *bh, int list)
+{
+ remove_from_queues(bh);
+ bh->b_list = list;
+ insert_into_queues(bh);
+}
+
/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
dispose = BUF_LOCKED;
else
dispose = BUF_CLEAN;
- if(dispose == BUF_CLEAN)
- buf->b_lru_time = jiffies;
if(dispose != buf->b_list) {
- if(dispose == BUF_DIRTY)
- buf->b_lru_time = jiffies;
- remove_from_queues(buf);
- buf->b_list = dispose;
- insert_into_queues(buf);
- if (dispose == BUF_DIRTY) {
+ file_buffer(buf, dispose);
+ if(dispose == BUF_DIRTY) {
int too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
/* This buffer is dirty, maybe we need to start flushing.
printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
kdevname(dev));
- invalidate_inodes(dev);
+ if (invalidate_inodes(dev))
+ printk("VFS: busy inodes on changed media..\n");
+
invalidate_buffers(dev);
if (fops->revalidate)
}
}
if (last)
- fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
- 12 ? EOF_FAT12 : EOF_FAT16);
+ fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
else {
MSDOS_I(inode)->i_start = 0;
mark_inode_dirty(inode);
unlock_fat(sb);
return -ENOSPC;
}
- fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ?
- EOF_FAT12 : EOF_FAT16);
+ fat_access(sb,nr,EOF_FAT(sb));
if (MSDOS_SB(sb)->free_clusters != -1)
MSDOS_SB(sb)->free_clusters--;
unlock_fat(sb);
inode->i_state = 0;
}
-#define CAN_UNUSE(inode) \
- (((inode)->i_count == 0) && \
- ((inode)->i_nrpages == 0) && \
- (!(inode)->i_state))
+/*
+ * Dispose-list gets a local list, so it doesn't need to
+ * worry about list corruption.
+ */
+static void dispose_list(struct list_head * head)
+{
+ struct list_head *next;
+
+ next = head->next;
+ for (;;) {
+ struct list_head * tmp = next;
+ struct inode * inode;
+
+ next = next->next;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_list);
+ truncate_inode_pages(inode, 0);
+ list_del(&inode->i_list);
+ }
-static void invalidate_list(struct list_head *head, kdev_t dev)
+ /* Add them all to the unused list in one fell swoop */
+ spin_lock(&inode_lock);
+ list_splice(head, &inode_unused);
+ spin_unlock(&inode_lock);
+}
+
+static int invalidate_list(struct list_head *head, kdev_t dev, struct list_head * dispose)
{
struct list_head *next;
+ int busy = 0;
next = head->next;
for (;;) {
break;
inode = list_entry(tmp, struct inode, i_list);
if (inode->i_dev != dev)
- continue;
- if (!CAN_UNUSE(inode))
continue;
- list_del(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_hash);
- list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_unused);
+ if (!inode->i_count && !inode->i_state) {
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, dispose);
+ continue;
+ }
+ busy = 1;
}
+ return busy;
}
-void invalidate_inodes(kdev_t dev)
+/*
+ * This is a two-stage process. First we collect all
+ * offending inodes onto the throw-away list, and in
+ * the second stage we actually dispose of them. This
+ * is because we don't want to sleep while messing
+ * with the global lists..
+ */
+int invalidate_inodes(kdev_t dev)
{
+ int busy;
+ LIST_HEAD(throw_away);
+
spin_lock(&inode_lock);
- invalidate_list(&inode_in_use, dev);
- invalidate_list(&inode_dirty, dev);
+ busy = invalidate_list(&inode_in_use, dev, &throw_away);
+ busy |= invalidate_list(&inode_dirty, dev, &throw_away);
spin_unlock(&inode_lock);
+
+ dispose_list(&throw_away);
+
+ return busy;
}
/*
* Otherwise we just move the inode to be the first inode and expect to
* get back to the problem later..
*/
+#define CAN_UNUSE(inode) \
+ (((inode)->i_count == 0) && \
+ ((inode)->i_nrpages == 0) && \
+ (!(inode)->i_state))
+
static void try_to_free_inodes(void)
{
struct list_head * tmp;
return ((unsigned long *)schedule_frame)[12];
}
return pc;
- }
+ }
#elif defined(__mc68000__)
{
unsigned long fp, pc;
fp = *(unsigned long *) fp;
} while (count++ < 16);
}
+#elif defined(__powerpc__)
+ return (p->tss.wchan);
#endif
return 0;
}
eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__powerpc__)
+#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
+#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1])
#elif defined (__sparc_v9__)
# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc)
# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
-/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
+/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
#define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
-static int openpromfs_create (struct inode *, const char *, int, int,
- struct inode **);
+static int openpromfs_create (struct inode *, struct dentry *, int);
static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int openpromfs_lookup(struct inode *, const char *, int,
- struct inode **);
-static int openpromfs_unlink (struct inode *, const char *, int);
+static int openpromfs_lookup(struct inode *, struct dentry *dentry);
+static int openpromfs_unlink (struct inode *, struct dentry *dentry);
static long nodenum_read(struct inode *inode, struct file *file,
char *buf, unsigned long count)
return 0;
}
-static int openpromfs_lookup(struct inode * dir, const char * name, int len,
- struct inode ** result)
+static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
{
int ino = 0;
#define OPFSL_DIR 0
int type = 0;
char buffer[128];
char *p;
+ const char *name;
u32 n;
u16 dirnode;
+ unsigned int len;
int i;
struct inode *inode;
struct openpromfs_dev *d = NULL;
char buffer2[64];
- *result = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOTDIR;
- }
- *result = dir;
- if (!len) return 0;
- if (name [0] == '.') {
- if (len == 1)
- return 0;
- if (name [1] == '.' && len == 2) {
- if (dir->i_ino == PROC_OPENPROM) {
- inode = proc_get_inode (dir->i_sb,
- PROC_ROOT_INO,
- &proc_root);
- iput(dir);
- if (!inode)
- return -EINVAL;
- *result = inode;
- return 0;
- }
- ino = NODE2INO(NODE(dir->i_ino).parent);
- type = OPFSL_DIR;
- } else if (len == 5 && !strncmp (name + 1, "node", 4)) {
- ino = NODEP2INO(NODE(dir->i_ino).first_prop);
- type = OPFSL_NODENUM;
- }
+ inode = NULL;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
+ if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) {
+ ino = NODEP2INO(NODE(dir->i_ino).first_prop);
+ type = OPFSL_NODENUM;
}
if (!ino) {
u16 node = NODE(dir->i_ino).child;
ino = lookup_children (NODE(dir->i_ino).child, name, len);
if (ino)
type = OPFSL_DIR;
- else {
- iput(dir);
+ else
return -ENOENT;
- }
}
inode = proc_get_inode (dir->i_sb, ino, 0);
- iput(dir);
if (!inode)
return -EINVAL;
switch (type) {
inode->i_rdev = d->rdev;
break;
}
- *result = inode;
+ d_add(dentry, inode);
return 0;
}
return 0;
}
-static int openpromfs_create (struct inode *dir, const char *name, int len,
- int mode, struct inode **result)
+static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode)
{
char *p;
struct inode *inode;
- *result = NULL;
if (!dir)
return -ENOENT;
- if (len > 256) {
+ if (dentry->d_name.len > 256) {
iput (dir);
return -EINVAL;
}
iput (dir);
return -EIO;
}
- p = kmalloc (len + 1, GFP_KERNEL);
+ p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
if (!p) {
iput (dir);
return -ENOMEM;
}
- strncpy (p, name, len);
- p [len] = 0;
+ strncpy (p, dentry->d_name.name, dentry->d_name.len);
+ p [dentry->d_name.len] = 0;
alias_names [aliases_nodes++] = p;
inode = proc_get_inode (dir->i_sb,
NODEP2INO(NODE(dir->i_ino).first_prop)
if (inode->i_size < 0) inode->i_size = 0;
inode->u.generic_ip = (void *)(long)(((u16)aliases) |
(((u16)(aliases_nodes - 1)) << 16));
- *result = inode;
+ d_instantiate(dentry, inode);
return 0;
}
-static int openpromfs_unlink (struct inode *dir, const char *name, int len)
+static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
{
+ unsigned int len;
char *p;
+ const char *name;
int i;
- if (!dir)
- return -ENOENT;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
for (i = 0; i < aliases_nodes; i++)
if ((strlen (alias_names [i]) == len)
&& !strncmp (name, alias_names[i], len)) {
buffer [10 + len] = 0;
prom_feval (buffer);
}
- iput (dir);
+ d_delete(dentry);
return 0;
}
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
void (*proc_openprom_use)(struct inode *, int) = 0;
static struct openpromfs_dev *proc_openprom_devices = NULL;
static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
struct inode_operations *
proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, struct qstr *, struct inode **),
+ int (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***devices)
{
}
static int
-proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
{
request_module("openpromfs");
if (proc_openprom_inode_operations.lookup !=
proc_openprom_deflookup)
return proc_openprom_inode_operations.lookup
- (dir, str, result);
+ (dir, dentry);
return -ENOENT;
}
#endif
* Changed for 2.1.19 modules
* Jan 1997 Initial release
* Jun 1997 2.1.43+ changes
- * Jul 1997 proper page locking in readpage
+ * Proper page locking in readpage
* Changed to work with 2.1.45+ fs
- * Fixed follow_link
+ * Jul 1997 Fixed follow_link
+ * 2.1.47
+ * lookup shouldn't return -ENOENT
+ * from Horst von Brand:
+ * fail on wrong checksum
+ * double unlock_super was possible
+ * correct namelen for statfs
+ * spotted by Bill Hawes:
+ * readlink shouldn't iput()
*/
/* todo:
* - see Documentation/filesystems/romfs.txt
* - use malloced memory for file names?
+ * - quicklist routines from fs/namei.c, get_page is possibly not
+ * intended to be used now
* - considering write access...
* - network (tftp) files?
* - in the ancient times something leaked to made umounts
if (romfs_checksum(rsb, min(sz,512))) {
printk ("romfs: bad initial checksum on dev "
"%s.\n", kdevname(dev));
+ goto out;
}
s->s_magic = ROMFS_MAGIC;
s->s_op = &romfs_ops;
s->s_root = d_alloc_root(iget(s, sz), NULL);
- unlock_super(s);
-
if (!s->s_root)
goto outnobh;
+ unlock_super(s);
+
/* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */
if (0) {
out:
tmp.f_type = ROMFS_MAGIC;
tmp.f_bsize = ROMBSIZE;
tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
- /* XXX tmp.f_namelen = relevant? */
+ tmp.f_namelen = ROMFS_MAXFN;
return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
}
const char *name; /* got from dentry */
int len;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- res = -EBADF;
+ res = -EBADF;
+ if (!dir || !S_ISDIR(dir->i_mode))
goto out;
- }
+ res = 0; /* instead of ENOENT */
offset = dir->i_ino & ROMFH_MASK;
- if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
- res = -ENOENT;
+ if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
- }
maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
offset = ntohl(ri.spec) & ROMFH_MASK;
for(;;) {
if (!offset || offset >= maxoff
- || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
- res = -ENOENT;
+ || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
- }
/* try to match the first 16 bytes of name */
fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = ntohl(ri.spec) & ROMFH_MASK;
- res = -EACCES;
- if ((inode = iget(dir->i_sb, offset))!=NULL) {
- res = 0;
+ if ((inode = iget(dir->i_sb, offset))==NULL) {
+ res = -EACCES;
+ } else {
d_add(dentry, inode);
}
copy_to_user(buffer, buf, mylen);
out:
- iput(inode);
return mylen;
}
printk("romfs: read error for inode 0x%x\n", ino);
return;
}
+ /* XXX: do romfs_checksum here too (with name) */
+
nextfh = ntohl(ri.next);
if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
break;
d_umount(sb->s_root);
sb->s_root = NULL;
+ /* Forget any inodes */
+ invalidate_inodes(dev);
+
if (sb->s_op) {
if (sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_namei.c,v 1.8 1997/07/17 02:24:14 davem Exp $
+ * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $
*
*/
break;
}
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("lfragno 0x%lx direct d 0x%x d_ino %u d_reclen %u d_namlen %u d_name `%s'\n",
- lfragno, (unsigned int)d, ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), ufs_swab16(d->d_namlen), d->d_name);
+ printk("lfragno 0x%lx direct d 0x%x d_ino %u "
+ "d_reclen %u d_namlen %u d_name `%s'\n",
+ lfragno, (unsigned int)((unsigned long)d),
+ ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
+ ufs_swab16(d->d_namlen), d->d_name);
}
if ((ufs_swab16(d->d_namlen) == len) &&
/* XXX - don't use strncmp() - see ext2fs */
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
#define INIT_KBD
+#define SYSRQ_KEY 0x54
+
#endif /* __KERNEL__ */
#endif /* __ASMalpha_KEYBOARD_H */
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
#endif /* __KERNEL__ */
} while (0)
+extern const char lk_lockmsg[];
+
/* Locking the kernel */
extern __inline__ void lock_kernel(void)
{
if (local_irq_count[cpu]) {
__label__ l1;
-l1: printk("lock from interrupt context at %p\n", &&l1);
+l1: printk(lk_lockmsg, &&l1);
}
if (cpu == global_irq_holder) {
__label__ l2;
#define SER_AMIGA 105 /* Amiga built-in serial port */
#define SER_IOEXT 106 /* Amiga GVP IO-Extender (16c552) */
#define SER_MFC_III 107 /* Amiga BSC Multiface Card III (MC68681) */
-
+#define SER_WHIPPET 108 /* Amiga Hisoft Whippet PCMCIA (16c550B) */
struct serial_struct {
int type;
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: byteorder.h,v 1.5 1997/06/25 19:10:18 ralf Exp $
+ * $Id: byteorder.h,v 1.6 1997/07/20 15:15:01 ralf Exp $
*/
#ifndef __ASM_MIPS_BYTEORDER_H
#define __ASM_MIPS_BYTEORDER_H
#if defined (__MIPSEB__)
#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
#endif
#ifndef __BIG_ENDIAN_BITFIELD
#define __constant_htonl(x) (x)
#define __constant_htons(x) (x)
+#elif defined (__MIPSEL__)
+
+#ifndef __LITTLE_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#endif
+
+#ifndef __LITTLE_ENDIAN_BITFIELD
+#define __LITTLE_ENDIAN_BITFIELD
+#endif
+
+#define __constant_ntohl(x) __swap32(x)
+#define __constant_ntohs(x) __swap16(x)
+#define __constant_htonl(x) __swap32(x)
+#define __constant_htons(x) __swap16(x)
+
+#endif /* defined(__MIPSEL_) */
+
#ifdef __KERNEL__
+#if defined (__MIPSEB__)
+
/*
* In-kernel byte order macros to handle stuff like
* byte-order-dependent filesystems etc.
#define cpu_to_be16(x) (x)
#define be16_to_cpu(x) (x)
-#endif /* __KERNEL__ */
-
#elif defined (__MIPSEL__)
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN
-#endif
-
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#define __constant_ntohl(x) __swap32(x)
-#define __constant_ntohs(x) __swap16(x)
-#define __constant_htonl(x) __swap32(x)
-#define __constant_htons(x) __swap16(x)
-
-#ifdef __KERNEL__
-
/*
* In-kernel byte order macros to handle stuff like
* byte-order-dependent filesystems etc.
#define cpu_to_be16(x) __swap16((x))
#define be16_to_cpu(x) __swap16((x))
-#endif /* __KERNEL__ */
-
#else
#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
#endif
#define be16_to_cpus(x) cpu_to_be16s(x)
#define be32_to_cpus(x) cpu_to_be32s(x)
-#ifdef __KERNEL__
+#endif /* __KERNEL__ */
+
extern unsigned long int ntohl(unsigned long int __x);
extern unsigned short int ntohs(unsigned short int __x);
extern unsigned short int htons(unsigned short int __x);
{
return __constant_htons(__x);
}
-#endif /* __KERNEL__ */
#endif /* __ASM_MIPS_BYTEORDER_H */
#define TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */
#define TIOCTTYGSTRUCT 0x5487 /* For debugging only */
+#define TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCSERCONFIG 0x5488
#define TIOCSERGWILD 0x5489
#define JAZZ_SERIAL2_IRQ 4
#define JAZZ_PARALLEL_IRQ 5
#define JAZZ_FLOPPY_IRQ 6 /* needs to be consistent with floppy driver! */
-
+#define JAZZ_SCSI_INTERRUPT 12
/*
* JAZZ DMA Channels
#define VDMA_PAGESIZE 4096
#define VDMA_PGTBL_ENTRIES 4096
#define VDMA_PGTBL_SIZE (sizeof(VDMA_PGTBL_ENTRY) * VDMA_PGTBL_ENTRIES)
-#define VDMA_PAGE_EMPTY 0
+#define VDMA_PAGE_EMPTY 0xff000000
/*
* Macros to get page no. and offset of a given address
#define SWP_OFFSET(entry) ((entry) >> 15)
#define SWP_ENTRY(type,offset) (((type) << 8) | ((offset) << 15))
+#define module_map vmalloc
+#define module_unmap vfree
+
/* TLB operations. */
extern inline void tlb_probe(void)
{
#define save_and_cli(x) __save_and_cli(x)
#define restore_flags(x) __restore_flags(x)
-#define sync_mem() \
-__asm__ __volatile__( \
- ".set\tnoreorder\n\t" \
- "sync\n\t" \
- ".set\treorder" \
- : /* no output */ \
- : /* no input */ \
+#define mb() \
+__asm__ __volatile__( \
+ "# prevent instructions being moved around\n\t" \
+ ".set\tnoreorder\n\t" \
+ ".set\treorder" \
+ : /* no output */ \
+ : /* no input */ \
: "memory")
#if !defined (__LANGUAGE_ASSEMBLY__)
#define __NR_query_module (__NR_Linux + 187)
#define __NR_poll (__NR_Linux + 188)
#define __NR_nfsservctl (__NR_Linux + 189)
+#define __NR_setresgid (__NR_Linux + 190)
+#define __NR_getresgid (__NR_Linux + 191)
/*
* Offset of the last Linux flavoured syscall
*/
-#define __NR_Linux_syscalls 189
+#define __NR_Linux_syscalls 191
#ifndef __LANGUAGE_ASSEMBLY__
#ifndef _ASM_PPC_ATOMIC_H_
#define _ASM_PPC_ATOMIC_H_
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT(i) { (i) }
+#endif
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ((v)->counter)
-#define atomic_set(v) (((v)->counter) = i)
+#define atomic_set(v,i) (((v)->counter) = (i))
-#define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
-#define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
+extern void atomic_add(int a, atomic_t *v);
+extern void atomic_sub(int a, atomic_t *v);
+extern void atomic_inc(atomic_t *v);
+extern int atomic_inc_return(atomic_t *v);
+extern void atomic_dec(atomic_t *v);
+extern int atomic_dec_return(atomic_t *v);
+extern int atomic_dec_and_test(atomic_t *v);
-#define atomic_inc(v) atomic_add(1,(v))
-#define atomic_dec(v) atomic_sub(1,(v))
-#endif
+extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
+extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
+
+#if 0 /* for now */
+extern __inline__ void atomic_add(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ add %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+}
+
+extern __inline__ void atomic_sub(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ subf %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+}
+
+extern __inline__ int atomic_sub_and_test(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ subf %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+
+ return t == 0;
+}
+
+extern __inline__ void atomic_inc(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+}
+
+extern __inline__ void atomic_dec(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+}
+
+extern __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+
+ return t == 0;
+}
+#endif /* 0 */
+#endif /* _ASM_PPC_ATOMIC_H_ */
#include <asm/system.h>
#include <asm/byteorder.h>
+#include <linux/kernel.h> /* for printk */
#define BIT(n) 1<<(n&0x1F)
typedef unsigned long BITFIELD;
-/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. powerpc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+/*
+ * These are ifdef'd out here because using : "cc" as a constraing
+ * results in errors from gcc. -- Cort
*/
-extern __inline__ int set_bit(int nr, void * add)
+#if 0
+extern __inline__ int set_bit(int nr, void * addr)
{
- BITFIELD *addr = add;
- long mask,oldbit;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- oldbit = (mask & *addr) != 0;
- *addr |= mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return oldbit;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("set_bit(%lx, %p)\n", nr, addr);
+
+ __asm__ __volatile__(
+ "1:lwarx %0,0,%3 \n\t"
+ "or %1,%0,%2 \n\t"
+ "stwcx. %1,0,%3 \n\t"
+ "bne 1b \n\t"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc" */);
+
+n return (old & mask) != 0;
}
-extern __inline__ int change_bit(int nr, void *add)
+extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
{
- BITFIELD *addr = add;
- int mask, retval;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- retval = (mask & *addr) != 0;
- *addr ^= mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return retval;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("clear_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
}
-extern __inline__ int clear_bit(int nr, void *add)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
{
- BITFIELD *addr = add;
- int mask, retval;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- retval = (mask & *addr) != 0;
- *addr &= ~mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("change_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
+}
#endif
- return retval;
+
+extern __inline__ int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
}
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+
#define _EXT2_HAVE_ASM_BITOPS_
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)
* This file is included by 'init/main.c'
*/
-void
-check_bugs(void)
-{
-}
+extern void
+check_bugs(void);
#ifndef _PPC_BYTEORDER_H
#define _PPC_BYTEORDER_H
+#include <asm/types.h>
+
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN
#endif
#define __htonl(x) ntohl(x)
#define __htons(x) ntohs(x)
+
+#define __constant_ntohs(x) ntohs(x)
+#define __constant_ntohl(x) ntohl(x)
#define __constant_htonl(x) ntohl(x)
#define __constant_htons(x) ntohs(x)
#ifdef __KERNEL__
+/*
+ * 16 and 32 bit little-endian loads and stores.
+ */
+extern inline unsigned ld_le16(volatile unsigned short *addr)
+{
+ unsigned val;
-/* Convert from CPU byte order, to specified byte order. */
-extern __inline__ __u16 cpu_to_le16(__u16 value)
+ asm volatile("lhbrx %0,0,%1" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+extern inline void st_le16(volatile unsigned short *addr, unsigned val)
+{
+ asm volatile("sthbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned ld_le32(volatile unsigned *addr)
+{
+ unsigned val;
+
+ asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+extern inline void st_le32(volatile unsigned *addr, unsigned val)
{
- return (value >> 8) | (value << 8);
+ asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
}
+
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+ return ld_le16(&value);
+}
extern __inline__ __u32 cpu_to_le32(__u32 value)
{
- return((value>>24) | ((value>>8)&0xff00) |
- ((value<<8)&0xff0000) | (value<<24));
+ return ld_le32(&value);
}
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
/* The same, but returns converted value from the location pointer by addr. */
extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
{
- return cpu_to_le16(*addr);
+ return ld_le16(addr);
}
extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
{
- return cpu_to_le32(*addr);
+ return ld_le32(addr);
}
extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
{
- return cpu_to_be16(*addr);
+ return *addr;
}
extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
{
- return cpu_to_be32(*addr);
+ return *addr;
}
/* The same, but do the conversion in situ, ie. put the value back to addr. */
extern __inline__ void cpu_to_le16s(__u16 *addr)
{
- *addr = cpu_to_le16(*addr);
+ st_le16(addr,*addr);
}
extern __inline__ void cpu_to_le32s(__u32 *addr)
{
- *addr = cpu_to_le32(*addr);
+ st_le32(addr,*addr);
}
#define cpu_to_be16s(x) do { } while (0)
#define be16_to_cpus(x) cpu_to_be16s(x)
#define be32_to_cpus(x) cpu_to_be32s(x)
+
#endif /* __KERNEL__ */
#endif /* !(_PPC_BYTEORDER_H) */
+
+
+
+
+
+
#define __ARCH_PPC_CACHE_H
/* bytes per L1 cache line */
-#define L1_CACHE_BYTES 32 /* a guess */
+/* a guess */ /* a correct one -- Cort */
+#define L1_CACHE_BYTES 32
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
*/
#define csum_partial_copy_fromuser csum_partial_copy
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ *
+ * right now - it just calls csum_partial_copy()
+ * -- Cort
+ */
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ int *dst_err_ptr=NULL;
+ return csum_partial_copy( src, dst, len, sum);
+}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
#ifndef _PPC_CURRENT_H
#define _PPC_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel. For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()]) /* Current on this processor */
+#include <linux/config.h>
+
+extern struct task_struct *current_set[1];
+
+register struct task_struct *current asm("r2");
#endif /* !(_PPC_CURRENT_H) */
#ifndef _PPC_DELAY_H
#define _PPC_DELAY_H
+/*
+ * Copyright 1996, Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
-extern __inline__ void __delay(unsigned long );
-extern __inline__ void __udelay(unsigned long );
-
+extern __inline__ void __delay(unsigned int loops)
+{
+ if (loops != 0)
+ __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+ "r" (loops) : "ctr");
+}
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+extern __inline__ void udelay(unsigned long usecs)
{
- return (a*b)/c;
+ unsigned long loops;
+
+ /* compute (usecs * 2^32 / 10^6) * loops_per_sec / 2^32 */
+ usecs *= 0x10c6; /* 2^32 / 10^6 */
+ __asm__("mulhwu %0,%1,%2" : "=r" (loops) :
+ "r" (usecs), "r" (loops_per_sec));
+ __delay(loops);
}
#endif /* defined(_PPC_DELAY_H) */
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/* $Id: dma.h,v 1.3 1997/03/16 06:20:39 cort Exp $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
* and John Boyd, Nov. 1992.
*/
+#include <linux/config.h>
+
/*
* Note: Adapted for PowerPC by Gary Thomas
* Modified by Cort Dougan <cort@cs.nmt.edu>
*
+ * None of this really applies for Power Macintoshes. There is
+ * basically just enough here to get kernel/dma.c to compile.
+ *
* There may be some comments or restrictions made here which are
- * not valid for the PowerPC (PreP) platform. Take what you read
+ * not valid for the PReP platform. Take what you read
* with a grain of salt.
*/
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
+#ifdef CONFIG_PREP
#include <asm/io.h> /* need byte IO */
/* These are in kernel/dma.c: */
extern void free_dma(unsigned int dmanr); /* release it again */
+#endif /* CONFIG_PREP */
#endif /* _ASM_DMA_H */
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
+#define _LAST_ERRNO 515
+
#endif
--- /dev/null
+#ifndef __ASM_HARDIRQ_H
+#define __ASM_HARDIRQ_H
+
+extern unsigned int local_irq_count[NR_CPUS];
+#define in_interrupt() (local_irq_count[smp_processor_id()] != 0)
+
+#ifndef __SMP__
+
+#define hardirq_trylock(cpu) (local_irq_count[cpu] == 0)
+#define hardirq_endlock(cpu) do { } while (0)
+
+#define hardirq_enter(cpu) (local_irq_count[cpu]++)
+#define hardirq_exit(cpu) (local_irq_count[cpu]--)
+
+#define synchronize_irq() do { } while (0)
+
+#else
+
+#error Somebody should do SMP support for PPC...
+
+#endif /* __SMP__ */
+
+#endif /* __ASM_HARDIRQ_H */
/*
- * linux/include/asm-i386/ide.h
+ * linux/include/asm-ppc/ide.h
*
* Copyright (C) 1994-1996 Linus Torvalds & authors
*/
#ifdef __KERNEL__
-typedef unsigned short ide_ioreg_t;
+#include <linux/config.h>
#ifndef MAX_HWIFS
#define MAX_HWIFS 4
#define ide_sti() sti()
+#ifdef CONFIG_PREP
+
+typedef unsigned short ide_ioreg_t;
+
static __inline__ int ide_default_irq(ide_ioreg_t base)
{
switch (base) {
- case 0x1f0: return 14;
- case 0x170: return 15;
+ case 0x1f0: return 13;
+ case 0x170: return 13;
case 0x1e8: return 11;
case 0x168: return 10;
default:
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *device, void *dev_id)
-{
- return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
- free_irq(irq, dev_id);
-}
+} select_t;
static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
{
release_region(from, extent);
}
-/*
- * The following are not needed for the non-m68k ports
- */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+#define ide_fix_driveid(id) do {} while (0)
+
+#endif
+
+#ifdef CONFIG_PMAC
+
+#include <asm/io.h> /* so we can redefine insw/outsw */
+
+typedef unsigned long ide_ioreg_t;
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+ return 0;
+}
+
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+ return index;
+}
+
+extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit7 : 1; /* always 1 */
+ unsigned lba : 1; /* using LBA instead of CHS */
+ unsigned bit5 : 1; /* always 1 */
+ unsigned unit : 1; /* drive select number, 0/1 */
+ unsigned head : 4; /* always zeros here */
+ } b;
+} select_t;
+
+#undef SUPPORT_SLOW_DATA_PORTS
+#define SUPPORT_SLOW_DATA_PORTS 0
+#undef SUPPORT_VLB_SYNC
+#define SUPPORT_VLB_SYNC 0
+
+static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
{
- return(1);
+ return 0;
}
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
{
}
-static __inline__ void ide_release_lock (int *ide_lock)
+static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
{
}
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+#undef insw
+#undef outsw
+#define insw(port, buf, ns) ide_insw((port), (buf), (ns))
+#define outsw(port, buf, ns) ide_outsw((port), (buf), (ns))
+
+void ide_insw(ide_ioreg_t port, void *buf, int ns);
+void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+
+#define ide_fix_driveid(id) do { \
+ int nh; \
+ unsigned short *p = (unsigned short *) id; \
+ for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p) \
+ *p = (*p << 8) + (*p >> 8); \
+} while (0)
+
+#endif
+
+static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *device, void *dev_id)
{
+ return request_irq(irq, handler, flags, device, dev_id);
+}
+
+static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
+{
+ free_irq(irq, dev_id);
}
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(base, irq) (1)
+#define ide_release_lock(lock) do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
+
#endif /* __KERNEL__ */
#endif /* __ASMPPC_IDE_H */
#ifndef _PPC_INIT_H
#define _PPC_INIT_H
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define __init
+#define __init
#define __initdata
-#define __initfunc(__arginit) __arginit
-/* For assembly routines */
+#define __initfunc(x) x
+/*
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+ __arginit __init; \
+ __arginit
+*/
+ /* For assembly routines */
#define __INIT
#define __FINIT
#define __INITDATA
-
+/*
+#define __INIT .section ".text.init",#alloc,#execinstr
+#define __FINIT .previous
+#define __INITDATA .section ".data.init",#alloc,#write
+*/
#endif
#ifndef _PPC_IO_H
#define _PPC_IO_H
+#include <linux/config.h>
#include <asm/page.h>
+#include <asm/byteorder.h>
+#ifdef CONFIG_PREP
/* from the Carolina Technical Spec -- Cort */
#define IBM_ACORN 0x82A
#define SIO_CONFIG_RA 0x398
#define IBM_L2_INVALIDATE 0x814
#define IBM_SYS_CTL 0x81c
-
-
-/* Define the particulars of outb/outw/outl "instructions" */
#define SLOW_DOWN_IO
#ifndef PCI_DRAM_OFFSET
#define PCI_DRAM_OFFSET 0x80000000
#endif
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+void outsl(int port, long *ptr, int len);
+
+__inline__ unsigned char outb(unsigned char val, int port);
+__inline__ unsigned short outw(unsigned short val, int port);
+__inline__ unsigned long outl(unsigned long val, int port);
+__inline__ unsigned char inb(int port);
+__inline__ unsigned short inw(int port);
+__inline__ unsigned long inl(int port);
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
+/*
+ * Read and write the non-volatile RAM.
+ */
+extern int nvram_readb(int addr);
+extern void nvram_writeb(int addr, int val);
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+#define inb(port) in_8((unsigned char *)(port))
+#define outb(val, port) out_8((unsigned char *)(port), (val))
+#define inw(port) in_le16((unsigned short *)(port))
+#define outw(val, port) out_le16((unsigned short *)(port), (val))
+#define inl(port) in_le32((unsigned long *)(port))
+#define outl(val, port) out_le32((unsigned long *)(port), (val))
+
+#define inb_p(port) in_8((unsigned char *)(port))
+#define outb_p(val, port) out_8((unsigned char *)(port), (val))
+#define inw_p(port) in_le16((unsigned short *)(port))
+#define outw_p(val, port) out_le16((unsigned short *)(port), (val))
+#define inl_p(port) in_le32(((unsigned long *)port))
+#define outl_p(val, port) out_le32((unsigned long *)(port), (val))
+
+#define insw(port, buf, ns) _insw((unsigned short *)(port), (buf), (ns))
+#define outsw(port, buf, ns) _outsw((unsigned short *)(port), (buf), (ns))
+#define insl(port, buf, nl) _insl((unsigned long *)(port), (buf), (nl))
+#define outsl(port, buf, nl) _outsl((unsigned long *)(port), (buf), (nl))
+#endif /* CONFIG_PMAC */
/*
* The PCI bus is inherently Little-Endian. The PowerPC is being
if (address == 0) return 0;
return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
}
-/* #define virt_to_bus(a) ((unsigned long)(((char *)a==(char *) 0) ? ((char *)0) \
- : ((char *)((long)a - KERNELBASE + PCI_DRAM_OFFSET))))
-#define bus_to_virt(a) ((void *) (((char *)a==(char *)0) ? ((char *)0) \
- : ((char *)((long)a - PCI_DRAM_OFFSET + KERNELBASE))))
-*/
-
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+/*
+ * Map in an area of physical address space, for accessing
+ * I/O devices etc.
+ */
+extern void *ioremap(unsigned long address, unsigned long size);
/*
* Change virtual addresses to physical addresses and vv.
return (void *) address;
}
-/* from arch/ppc/kernel/port_io.c
- * -- Cort
+#define _IO_BASE ((unsigned long)0x80000000)
+
+/*
+ * These are much more useful le/be io functions from Paul
+ * than leXX_to_cpu() style functions since the ppc has
+ * load/store byte reverse instructions
+ * -- Cort
*/
-unsigned char inb(int port);
-unsigned short inw(int port);
-unsigned long inl(int port);
-unsigned char outb(unsigned char val,int port);
-unsigned short outw(unsigned short val,int port);
-unsigned long outl(unsigned long val,int port);
-void outsl(int port, long *ptr, int len);
-static inline unsigned char inb_p(int port) {return (inb(port)); }
-static inline unsigned short inw_p(int port) {return (inw(port)); }
-static inline unsigned long inl_p(int port) {return (inl(port)); }
+/*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+ * completed before any further ones are issued.
+ */
+extern inline void eieio(void)
+{
+ asm volatile ("eieio" : :);
+}
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+ int ret;
+
+ ret = ld_le16(addr);
+ eieio();
+ return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+ st_le16(addr, val);
+ eieio();
+}
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
-static inline unsigned char outb_p(unsigned char val,int port) { return (outb(val,port)); }
-static inline unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-static inline unsigned long outl_p(unsigned long val,int port) { return (outl(val,port)); }
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+ unsigned ret;
+ ret = ld_le32(addr);
+ eieio();
+ return ret;
+}
+extern inline int in_be32(volatile unsigned *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+ st_le32(addr, val);
+ eieio();
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
#endif
#define TIOCGETD 0x5424
#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */
-#define TIOCSBRK 0x5427 /* BSD compatibility */
-#define TIOCCBRK 0x5428 /* BSD compatibility */
+#define TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
+#include <linux/config.h>
+
+#ifdef CONFIG_PMAC
#define NR_IRQS 32
+#else
+#define NR_IRQS 16
+#endif
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
* linux/include/asm-ppc/keyboard.h
*
* Created 3 Nov 1996 by Geert Uytterhoeven
+ * Modified for Power Macintosh by Paul Mackerras
*/
/*
- * This file contains the ppc architecture specific keyboard definitions
+ * This file contains the ppc architecture specific keyboard definitions -
+ * like the intel pc for prep systems, different for power macs.
*/
#ifndef __ASMPPC_KEYBOARD_H
#ifdef __KERNEL__
+#include <linux/config.h>
+
+#ifdef CONFIG_MAC_KEYBOARD
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern int mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+
+#define kbd_setkeycode mackbd_setkeycode
+#define kbd_getkeycode mackbd_getkeycode
+#define kbd_pretranslate mackbd_pretranslate
+#define kbd_translate mackbd_translate
+#define kbd_unexpected_up mackbd_unexpected_up
+#define kbd_leds mackbd_leds
+#define kbd_init_hw mackbd_init_hw
+
+#else /* CONFIG_MAC_KEYBOARD */
+
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
#define kbd_init_hw pckbd_init_hw
#define INIT_KBD
+#endif /* CONFIG_MAC_KEYBOARD */
#endif /* __KERNEL__ */
+++ /dev/null
-/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
- * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
- * derived from Data Sheet, Copyright Motorola 1984 (!).
- * It was written to be part of the Linux operating system.
- */
-/* permission is hereby granted to copy, modify and redistribute this code
- * in terms of the GNU Library General Public License, Version 2 or later,
- * at your option.
- */
-
-#ifndef _MC146818RTC_H
-#define _MC146818RTC_H
-#include <asm/io.h>
-
-#ifndef MCRTC_PORT
-#define MCRTC_PORT(x) (0x70 + (x))
-#define MCRTC_ALWAYS_BCD 1
-#endif
-
-#define CMOS_MCRTC_READ(addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-inb_p(MCRTC_PORT(1)); \
-})
-#define CMOS_MCRTC_WRITE(val, addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-outb_p((val),MCRTC_PORT(1)); \
-})
-
-/**********************************************************************
- * register summary
- **********************************************************************/
-#define MCRTC_SECONDS 0
-#define MCRTC_SECONDS_ALARM 1
-#define MCRTC_MINUTES 2
-#define MCRTC_MINUTES_ALARM 3
-#define MCRTC_HOURS 4
-#define MCRTC_HOURS_ALARM 5
-/* RTC_*_alarm is always true if 2 MSBs are set */
-# define MCRTC_ALARM_DONT_CARE 0xC0
-
-#define MCRTC_DAY_OF_WEEK 6
-#define MCRTC_DAY_OF_MONTH 7
-#define MCRTC_MONTH 8
-#define MCRTC_YEAR 9
-
-/* control registers - Moto names
- */
-#define MCRTC_REG_A 10
-#define MCRTC_REG_B 11
-#define MCRTC_REG_C 12
-#define MCRTC_REG_D 13
-
-/**********************************************************************
- * register details
- **********************************************************************/
-#define MCRTC_FREQ_SELECT MCRTC_REG_A
-
-/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
- * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
- * totalling to a max high interval of 2.228 ms.
- */
-# define MCRTC_UIP 0x80
-# define MCRTC_DIV_CTL 0x70
- /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
-# define MCRTC_REF_CLCK_4MHZ 0x00
-# define MCRTC_REF_CLCK_1MHZ 0x10
-# define MCRTC_REF_CLCK_32KHZ 0x20
- /* 2 values for divider stage reset, others for "testing purposes only" */
-# define MCRTC_DIV_RESET1 0x60
-# define MCRTC_DIV_RESET2 0x70
- /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
-# define MCRTC_RATE_SELECT 0x0F
-
-/**********************************************************************/
-#define MCRTC_CONTROL MCRTC_REG_B
-# define MCRTC_SET 0x80 /* disable updates for clock setting */
-# define MCRTC_PIE 0x40 /* periodic interrupt enable */
-# define MCRTC_AIE 0x20 /* alarm interrupt enable */
-# define MCRTC_UIE 0x10 /* update-finished interrupt enable */
-# define MCRTC_SQWE 0x08 /* enable square-wave output */
-# define MCRTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
-# define MCRTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
-# define MCRTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
-
-/**********************************************************************/
-#define MCRTC_INTR_FLAGS MCRTC_REG_C
-/* caution - cleared by read */
-# define MCRTC_IRQF 0x80 /* any of the following 3 is active */
-# define MCRTC_PF 0x40
-# define MCRTC_AF 0x20
-# define MCRTC_UF 0x10
-
-/**********************************************************************/
-#define MCRTC_VALID MCRTC_REG_D
-# define MCRTC_VRT 0x80 /* valid RAM and time */
-/**********************************************************************/
-
-/* example: !(CMOS_READ(MCRTC_CONTROL) & MCRTC_DM_BINARY)
- * determines if the following two #defines are needed
- */
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
-#endif /* _MC146818RTC_H */
/* Segment Register */
typedef struct _SEGREG
- {
- unsigned long t:1; /* Normal or I/O type */
- unsigned long ks:1; /* Supervisor 'key' (normally 0) */
- unsigned long kp:1; /* User 'key' (normally 1) */
- unsigned long n:1; /* No-execute */
- unsigned long :4; /* Unused */
- unsigned long vsid:24; /* Virtual Segment Identifier */
- } SEGREG;
+{
+ unsigned long t:1; /* Normal or I/O type */
+ unsigned long ks:1; /* Supervisor 'key' (normally 0) */
+ unsigned long kp:1; /* User 'key' (normally 1) */
+ unsigned long n:1; /* No-execute */
+ unsigned long :4; /* Unused */
+ unsigned long vsid:24; /* Virtual Segment Identifier */
+} SEGREG;
/* Block Address Translation (BAT) Registers */
+typedef struct _P601_BATU
+{
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :8; /* unused */
+ unsigned long w:1;
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+ unsigned long pp:2; /* Page access protections */
+} P601_BATU;
+
typedef struct _BATU /* Upper part of BAT */
- {
- unsigned long bepi:15; /* Effective page index (virtual address) */
- unsigned long :4; /* Unused */
- unsigned long bl:11; /* Block size mask */
- unsigned long vs:1; /* Supervisor valid */
- unsigned long vp:1; /* User valid */
- } BATU;
+{
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :4; /* Unused */
+ unsigned long bl:11; /* Block size mask */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+} BATU;
+
+typedef struct _P601_BATL
+{
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long v:1; /* valid/invalid */
+ unsigned long bl:6; /* Block size mask */
+} P601_BATL;
typedef struct _BATL /* Lower part of BAT */
- {
- unsigned long brpn:15; /* Real page index (physical address) */
- unsigned long :10; /* Unused */
- unsigned long w:1; /* Write-thru cache */
- unsigned long i:1; /* Cache inhibit */
- unsigned long m:1; /* Memory coherence */
- unsigned long g:1; /* Guarded (MBZ) */
- unsigned long :1; /* Unused */
- unsigned long pp:2; /* Page access protections */
- } BATL;
+{
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long w:1; /* Write-thru cache */
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded (MBZ) */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page access protections */
+} BATL;
typedef struct _BAT
- {
- BATU batu; /* Upper register */
- BATL batl; /* Lower register */
- } BAT;
+{
+ BATU batu; /* Upper register */
+ BATL batl; /* Lower register */
+} BAT;
+
+typedef struct _P601_BAT
+{
+ P601_BATU batu; /* Upper register */
+ P601_BATL batl; /* Lower register */
+} P601_BAT;
/* Block size masks */
#define BL_128K 0x000
pte **pmap; /* Two-level page-map structure */
} MMU_context;
-#if 0
-BAT ibat[4]; /* Instruction BAT images */
-BAT dbat[4]; /* Data BAT images */
-PTE *hash_table; /* Hardware hashed page table */
-int hash_table_size;
-int hash_table_mask;
-unsigned long sdr; /* Hardware image of SDR */
-#endif
-
/* Used to set up SDR register */
#define HASH_TABLE_SIZE_64K 0x00010000
#define HASH_TABLE_SIZE_128K 0x00020000
#define HASH_TABLE_MASK_2M 0x01F
#define HASH_TABLE_MASK_4M 0x03F
-extern inline int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
-
#endif
#ifndef __PPC_MMU_CONTEXT_H
#define __PPC_MMU_CONTEXT_H
+/* the way contexts are handled on the ppc they are vsid's and
+ don't need any special treatment right now.
+ perhaps I can defer flushing the tlb by keeping a list of
+ zombie vsid/context's and handling that through destroy_context
+ later -- Cort
+ */
+
+#define NO_CONTEXT 0
+#define LAST_CONTEXT 0xfffff
+
+extern int next_mmu_context;
+extern void mmu_context_overflow(void);
+extern void set_context(int context);
+
/*
- * get a new mmu context.. PowerPC's don't know about contexts [yet]
+ * Allocating context numbers this way tends to spread out
+ * the entries in the hash table better than a simple linear
+ * allocation.
*/
-#define get_mmu_context(x) do { } while (0)
+#define MUNGE_CONTEXT(n) (((n) * 897) & LAST_CONTEXT)
-#define init_new_context(mm) do { } while(0)
-#define destroy_context(mm) do { } while(0)
+/*
+ * Get a new mmu context for task tsk if necessary.
+ */
+#define get_mmu_context(tsk) \
+do { \
+ struct mm_struct *mm = (tsk)->mm; \
+ if (mm->context == NO_CONTEXT) { \
+ int i; \
+ if (next_mmu_context == LAST_CONTEXT) \
+ mmu_context_overflow(); \
+ mm->context = MUNGE_CONTEXT(++next_mmu_context);\
+ if ( tsk == current ) \
+ set_context(mm->context); \
+ } \
+} while (0)
-#endif
+/*
+ * Set up the context for a new address space.
+ */
+#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+
+/*
+ * We're finished using the context for an address space.
+ */
+#define destroy_context(mm) do { } while (0)
+/*
+ * compute the vsid from the context and segment
+ * segments > 7 are kernel segments and their
+ * vsid is the segment -- Cort
+ */
+#define VSID_FROM_CONTEXT(segment,context) \
+ ((segment < 8) ? ((segment) | (context)<<4) : (segment))
+
+#endif
--- /dev/null
+/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
+ * linux/include/asm-i386/namei.h
+ *
+ * Included from linux/fs/namei.c
+ */
+
+#ifndef __I386_NAMEI_H
+#define __I386_NAMEI_H
+
+/* These dummy routines maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define translate_namei(pathname, base, follow_links, res_inode) \
+ do { } while (0)
+
+#define translate_open_namei(pathname, flag, mode, res_inode, base) \
+ do { } while (0)
+
+#endif /* __I386_NAMEI_H */
#define NVRAM_AS1 0x75
#define NVRAM_DATA 0x77
+
/* RTC Offsets */
#define RTC_SECONDS 0x1FF9
#define RTC_DAY_OF_MONTH 0x1FFD
#define RTC_MONTH 0x1FFE
#define RTC_YEAR 0x1FFF
+#define RTC_CONTROLA 0x1FF8
+#define RTC_CONTROLB 0x1FF9
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
#ifndef _PPC_PAGE_H
#define _PPC_PAGE_H
+#include <linux/config.h>
+
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
+/* This handles the memory map.. */
+
+/*
+ * these virtual mappings for prep and pmac
+ * on the prep machine the io areas are at different physical locations
+ * than their virtual address. On the pmac the io areas
+ * are mapped 1-1 virtual/physical.
+ * -- Cort
+ */
+#ifdef CONFIG_PREP
+#define KERNELBASE 0x90000000
+#endif
+#ifdef CONFIG_PMAC
+#define KERNELBASE 0xc0000000
+#endif
+#define PAGE_OFFSET KERNELBASE
+
+
+#ifndef __ASSEMBLY__
#ifdef __KERNEL__
#define STRICT_MM_TYPECHECKS
#endif
+
+/* align addr on a size boundry - adjust address up if needed -- Cort */
+#define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
+
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* This handles the memory map.. */
-
-#define KERNELBASE 0x90000000
-#define PAGE_OFFSET KERNELBASE
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
#define MAP_PAGE_RESERVED (1<<15)
+extern __inline__ unsigned long get_prezerod_page(void);
#endif /* __KERNEL__ */
-
+#endif /* __ASSEMBLY__ */
#endif /* _PPC_PAGE_H */
-/* * Last edited: Nov 7 23:44 1995 (cort) */
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
+#include <linux/config.h>
#include <asm/page.h>
#include <asm/mmu.h>
-inline void flush_tlb(void);
-inline void flush_tlb_all(void);
-inline void flush_tlb_mm(struct mm_struct *mm);
-inline void flush_tlb_page(struct vm_area_struct *vma, long vmaddr);
-inline void flush_tlb_range(struct mm_struct *mm, long start, long end);
-inline void flush_page_to_ram(unsigned long);
-inline void really_flush_cache_all(void);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void flush_tlb(void);
+
+/* Caches aren't brain-dead on the ppc. */
+#define flush_cache_all()
+#define flush_cache_mm(mm)
+#define flush_cache_range(mm, start, end)
+#define flush_cache_page(vma, vmaddr)
+/*
+ * For the page specified, write modified lines in the data cache
+ * out to memory, and invalidate lines in the instruction cache.
+ */
+extern void flush_page_to_ram(unsigned long);
-/* only called from asm in head.S, so why bother? */
-/*void MMU_init(void);*/
+extern unsigned long va_to_phys(unsigned long address);
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
+/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
#define PMD_SHIFT 22
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/*
- * entries per page directory level: the i386 is two-level, so
- * we don't really have any PMD directory physically.
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
*/
#define PTRS_PER_PTE 1024
#define PTRS_PER_PMD 1
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
-/* this must be a decent size since the ppc bat's can map only certain sizes
- but these can be different from the physical ram size configured.
- bat mapping must map at least physical ram size and vmalloc start addr
- must beging AFTER the area mapped by the bat.
- 32 works for now, but may need to be changed with larger differences.
- offset = next greatest bat mapping to ramsize - ramsize
- (ie would be 0 if batmapping = ramsize)
- -- Cort 10/6/96
- */
-#define VMALLOC_OFFSET (32*1024*1024)
+#define VMALLOC_OFFSET (0x2000000) /* 32M */
#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_COW 0x200 /* implemented in software (one of the AVL bits) */
-#define _PAGE_NO_CACHE 0x400
+/*
+ * Bits in a linux-style PTE. These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */
+#define _PAGE_USER 0x002 /* matches one of the PP bits */
+#define _PAGE_RW 0x004 /* software: user write access allowed */
+#define _PAGE_GUARDED 0x008
+#define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */
+#define _PAGE_DIRTY 0x080 /* C: page changed */
+#define _PAGE_ACCESSED 0x100 /* R: page referenced */
+#define _PAGE_HWWRITE 0x200 /* software: _PAGE_RW & _PAGE_DIRTY */
-#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+ _PAGE_ACCESSED)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_NO_CACHE __pgprot(_PAGE_NO_CACHE | _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+ _PAGE_HWWRITE | _PAGE_ACCESSED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
+ _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
/*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis. So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
*/
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
#define __S110 PAGE_SHARED
#define __S111 PAGE_SHARED
-/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
-#if 0
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-#endif
-
/*
* BAD_PAGETABLE is used when we need a bogus page-table, while
* BAD_PAGE is used for a bogus page.
extern unsigned long empty_zero_page[1024];
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE ((unsigned long) empty_zero_page)
/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR (8*sizeof(unsigned long))
+#define BITS_PER_PTR (8*sizeof(unsigned long))
/* to align the pointer to a pointer address */
-#define PTR_MASK (~(sizeof(void*)-1))
+#define PTR_MASK (~(sizeof(void*)-1))
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* sizeof(void*) == 1<<SIZEOF_PTR_LOG2 */
/* 64-bit machines, beware! SRB. */
-#define SIZEOF_PTR_LOG2 2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+#define SIZEOF_PTR_LOG2 2
/* to set the page-dir */
/* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
- (tsk)->tss.pg_tables = (unsigned long *)(pgdir); \
- if ((tsk) == current) \
- { \
-/*_printk("Change page tables = %x\n", pgdir);*/ \
- } \
-} while (0)
-
-/* comes from include/linux/mm.h now -- Cort */
-/*extern void *high_memory;*/
+#define SET_PAGE_DIR(tsk,pgdir) ({ \
+ ((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
+})
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
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; }
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
-extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
+extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != 0; }
+extern inline int pmd_present(pmd_t pmd) { return (pmd_val(pmd) & PAGE_MASK) != 0; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp) { }
+
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded
extern inline int pgd_present(pgd_t pgd) { return 1; }
extern inline void pgd_clear(pgd_t * pgdp) { }
-
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-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_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; 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_ACCESSED; 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_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_USER; 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_ACCESSED; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte) { pte_val(pte) |= _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.
- */
+extern inline int pte_uncache(pte_t pte) { return pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline int pte_cache(pte_t pte) { return pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+extern inline pte_t pte_rdprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkold(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+extern inline pte_t pte_mkread(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_RW;
+ if (pte_val(pte) & _PAGE_DIRTY)
+ pte_val(pte) |= _PAGE_HWWRITE;
+ return pte;
+}
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_DIRTY;
+ if (pte_val(pte) & _PAGE_RW)
+ pte_val(pte) |= _PAGE_HWWRITE;
+ return pte;
+}
+extern inline pte_t pte_mkyoung(pte_t pte) {
+ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#if 1
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#else
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+ unsigned long val = pte_val(pteval);
+ extern void xmon(void *);
+
+ if ((val & _PAGE_PRESENT) && ((val < 0x111000 || (val & 0x800)
+ || ((val & _PAGE_HWWRITE) && (~val & (_PAGE_RW|_PAGE_DIRTY)))) {
+ printk("bad pte val %lx ptr=%p\n", val, pteptr);
+ xmon(0);
+ }
+ *pteptr = pteval;
+}
+#endif
-static pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
{ pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
-/*#define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })*/
extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+{ pte_t pte; pte_val(pte) = __pa(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; }
+{ return (pte_val(pte) & PAGE_MASK) + KERNELBASE; }
extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd) & PAGE_MASK; }
+{ return pmd_val(pmd); }
/* to find an entry in a kernel page-table-directory */
/*
* 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.
+ * used to allocate a kernel page table, but are actually identical
+ * to the xxx() versions.
*/
extern inline void pte_free_kernel(pte_t * pte)
{
free_page((unsigned long) pte);
}
+
extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
{
address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (page) {
-/* pmd_set(pmd,page);*/
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+ pmd_val(*pmd) = (unsigned long) page;
return page + address;
}
-/* pmd_set(pmd, BAD_PAGETABLE);*/
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (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_set(pmd, (pte_t *) BAD_PAGETABLE); */
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
return (pte_t *) pmd_page(*pmd) + address;
pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (page) {
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+ pmd_val(*pmd) = (unsigned long) page;
return page + address;
}
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (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;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
return (pte_t *) pmd_page(*pmd) + address;
extern pgd_t swapper_pg_dir[1024];
/*
- * Software maintained MMU tables may have changed -- update the
- * hardware [aka cache]
+ * Page tables may have changed. We don't need to do anything here
+ * as entries are faulted into the hash table by the low-level
+ * data/instruction access exception handlers.
*/
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
- unsigned long address, pte_t _pte);
+#define update_mmu_cache(vma,address,pte) while(0){}
#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
#define SWP_OFFSET(entry) ((entry) >> 8)
#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
-#define module_map vmalloc
-#define module_unmap vfree
+
#endif /* _PPC_PAGE_H */
--- /dev/null
+#ifndef __i386_POLL_H
+#define __i386_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN 0x0001
+#define POLLPRI 0x0002
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+#define POLLHUP 0x0010
+#define POLLNVAL 0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#define POLLWRNORM 0x0100
+#define POLLWRBAND 0x0200
+#define POLLMSG 0x0400
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+#endif
+++ /dev/null
-/*
- * PowerPC machine specifics
- */
-
-#ifndef _PPC_MACHINE_H_
-#define _PPC_MACHINE_H_
-
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
-
-/* Bit encodings for Machine State Register (MSR) */
-#define MSR_POW (1<<18) /* Enable Power Management */
-#define MSR_TGPR (1<<17) /* TLB Update registers in use */
-#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */
-#define MSR_EE (1<<15) /* External Interrupt enable */
-#define MSR_PR (1<<14) /* Supervisor/User privilege */
-#define MSR_FP (1<<13) /* Floating Point enable */
-#define MSR_ME (1<<12) /* Machine Check enable */
-#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */
-#define MSR_SE (1<<10) /* Single Step */
-#define MSR_BE (1<<9) /* Branch Trace */
-#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */
-#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */
-#define MSR_IR (1<<5) /* Instruction MMU enable */
-#define MSR_DR (1<<4) /* Data MMU enable */
-#define MSR_RI (1<<1) /* Recoverable Exception */
-#define MSR_LE (1<<0) /* Little-Endian enable */
-
-#define MSR_ MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
-#define MSR_USER MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
-
-/* Bit encodings for Hardware Implementation Register (HID0) */
-#define HID0_EMCP (1<<31) /* Enable Machine Check pin */
-#define HID0_EBA (1<<29) /* Enable Bus Address Parity */
-#define HID0_EBD (1<<28) /* Enable Bus Data Parity */
-#define HID0_SBCLK (1<<27)
-#define HID0_EICE (1<<26)
-#define HID0_ECLK (1<<25)
-#define HID0_PAR (1<<24)
-#define HID0_DOZE (1<<23)
-#define HID0_NAP (1<<22)
-#define HID0_SLEEP (1<<21)
-#define HID0_DPM (1<<20)
-#define HID0_ICE (1<<15) /* Instruction Cache Enable */
-#define HID0_DCE (1<<14) /* Data Cache Enable */
-#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */
-#define HID0_DLOCK (1<<12) /* Data Cache Lock */
-#define HID0_ICFI (1<<11) /* Instruction Cache Flash Invalidate */
-#define HID0_DCI (1<<10) /* Data Cache Invalidate */
-#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
-#define HID0_BHTE (1<<2) /* Branch History Table Enable */
-
-/* fpscr settings */
-#define FPSCR_FX (1<<31)
-#define FPSCR_FEX (1<<30)
-#endif
#ifndef __ASM_PPC_PROCESSOR_H
#define __ASM_PPC_PROCESSOR_H
-/*
- * PowerPC machine specifics
- */
+#include <linux/config.h>
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
/* Bit encodings for Machine State Register (MSR) */
#define MSR_POW (1<<18) /* Enable Power Management */
#define MSR_RI (1<<1) /* Recoverable Exception */
#define MSR_LE (1<<0) /* Little-Endian enable */
-#define MSR_ MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_ MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_KERNEL MSR_|MSR_IR|MSR_DR
#define MSR_USER MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
/* Bit encodings for Hardware Implementation Register (HID0) */
#define HID0_DCI (1<<10) /* Data Cache Invalidate */
#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
#define HID0_BHTE (1<<2) /* Branch History Table Enable */
-
/* fpscr settings */
#define FPSCR_FX (1<<31)
#define FPSCR_FEX (1<<30)
-
-
#ifndef __ASSEMBLY__
/*
* PowerPC machine specifics
*/
extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
-
/*
* Bus types
*/
#define wp_works_ok 1
#define wp_works_ok__is_a_macro /* for versions in ksyms.c */
-/*
- * User space process size: 2GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- *
- * "this is gonna have to change to 1gig for the sparc" - David S. Miller
- */
#define TASK_SIZE (0x80000000UL)
-
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
struct thread_struct
{
- unsigned long ksp; /* Kernel stack pointer */
- unsigned long *pg_tables; /* MMU information */
- unsigned long segs[16]; /* MMU Segment registers */
- unsigned long last_pc; /* PC when last entered system */
- unsigned long user_stack; /* [User] Stack when entered kernel */
- double fpr[32]; /* Complete floating point set */
- unsigned long wchan; /* Event task is sleeping on */
- unsigned long *regs; /* Pointer to saved register state */
- unsigned long fp_used; /* number of quantums fp was used */
- unsigned long fs; /* for get_fs() validation */
- unsigned long expc; /* exception handler addr (see fault.c) */
- unsigned long excount; /* exception handler count */
+ unsigned long ksp; /* Kernel stack pointer */
+ unsigned long *pg_tables; /* MMU information */
+#ifdef CONFIG_PMAC
+ unsigned long last_pc; /* PC when last entered system */
+ unsigned long user_stack; /* [User] Stack when entered kernel */
+#endif
+ unsigned long fpscr_pad; /* (so we can save fpscr with stfd) */
+ unsigned long fpscr; /* fp status reg */
+ double fpr[32]; /* Complete floating point set */
+ unsigned long fp_used;
+ unsigned long wchan; /* Event task is sleeping on */
+ struct pt_regs *regs; /* Pointer to saved register state */
+ unsigned long fs; /* for get_fs() validation */
+ signed long last_syscall;
+ unsigned long pad[2]; /* pad to 16-byte boundry */
};
+/* Points to the thread_struct of the thread (if any) which
+ currently owns the FPU. */
+#define fpu_tss (&(last_task_used_math->tss))
+
+#ifdef CONFIG_PMAC
+#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
+#endif
+#ifdef CONFIG_PREP
+#define LAZY_TSS_FPR_INIT 0,0,{0},
+#endif
#define INIT_TSS { \
- sizeof(init_kernel_stack) + (long) &init_kernel_stack,\
- (long *)swapper_pg_dir, {0}, \
- 0, 0, {0}, \
- 0, 0, 0, \
- KERNEL_DS, 0, 0 \
+ sizeof(init_stack) + (long) &init_stack, /* ksp */ \
+ (long *)swapper_pg_dir, /* pg_tables */ \
+ LAZY_TSS_FPR_INIT \
+ 0, /*fp_used*/ 0, /*wchan*/ \
+ sizeof(init_stack) + (long)&init_stack - \
+ sizeof(struct pt_regs), /* regs */ \
+ KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
}
-#define INIT_MMAP { &init_mm, 0, 0x40000000, \
- PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-/* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
+ PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
/*
* Return saved PC of a blocked thread. For now, this is the "user" PC
*/
static inline unsigned long thread_saved_pc(struct thread_struct *t)
{
- return (t->last_pc);
+ return (t->regs) ? t->regs->nip : 0;
+ /*return (t->last_pc);*/
}
-#define _PROC_Motorola 0
-#define _PROC_IBM 1
-#define _PROC_Be 2
-
-int _Processor;
+extern int _machine;
+#define _MACH_Motorola 0
+#define _MACH_IBM 1
+#define _MACH_Be 2
+#define _MACH_Pmac 3
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define free_task_struct(p) kfree(p)
-
-#ifdef KERNEL_STACK_BUFFER
-/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
-#define alloc_kernel_stack() \
- (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
-#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
-#else
-#define alloc_kernel_stack() get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-#endif
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p) free_pages((unsigned long)(p),1)
-#endif /* ASSEMBLY*/
+/* in process.c - for early bootup debug -- Cort */
+int ll_printk(const char *, ...);
+void ll_puts(const char *);
-#endif
+#endif /* ndef ASSEMBLY*/
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
+
+#endif /* __ASM_PPC_PROCESSOR_H */
#define _PPC_PTRACE_H
/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- * Note: the "_overhead" and "_underhead" spaces are stack locations
- * used by called routines. Because of the way the PowerPC ABI
- * specifies the function prologue/epilogue, registers can be
- * saved in stack locations which are below the current stack
- * pointer (_underhead). If an interrupt occurs during this
- * [albeit] small time interval, registers which were saved on
- * the stack could be trashed by the interrupt save code. The
- * "_underhead" leaves a hole just in case this happens. It also
- * wastes 80 bytes of stack if it doesn't! Similarly, the called
- * routine stores some information "above" the stack pointer before
- * if gets adjusted. This is covered by the "_overhead" field
- * and [thankfully] is not totally wasted.
+ * this should only contain volatile regs
+ * since we can keep non-volatile in the tss
+ * should set this up when only volatiles are saved
+ * by intr code.
*
+ * I can't find any reference to the above comment (from Gary Thomas)
+ * about _underhead/_overhead in the sys V abi for the ppc
+ * dated july 25, 1994.
+ *
+ * the stack must be kept to a size that is a multiple of 16
+ * so this includes the stack frame overhead
+ * -- Cort.
+ */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't. To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
*/
+#define STACK_FRAME_OVERHEAD 16
+#define STACK_UNDERHEAD 64
+#ifndef __ASSEMBLY__
struct pt_regs {
- unsigned long _overhead[14]; /* Callee's SP,LR,params */
- unsigned long gpr[32];
- unsigned long nip;
- unsigned long msr;
- unsigned long ctr;
- unsigned long link;
- unsigned long ccr;
- unsigned long xer;
- unsigned long dar; /* Fault registers */
- unsigned long dsisr;
- unsigned long srr1;
- unsigned long srr0;
- unsigned long hash1, hash2;
- unsigned long imiss, dmiss;
- unsigned long icmp, dcmp;
- unsigned long orig_gpr3; /* Used for restarting system calls */
- unsigned long result; /* Result of a system call */
- double fpcsr;
- unsigned long trap; /* Reason for being here */
- unsigned long marker; /* Should have DEADDEAD */
- /*unsigned long _underhead[20]; *//* Callee's register save area */
- unsigned long edx; /* for binfmt_elf.c which wants edx */
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long ccr;
+ unsigned long xer;
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+#if 0
+ unsigned long srr1;
+ unsigned long srr0;
+ unsigned long hash1, hash2;
+ unsigned long imiss, dmiss;
+ unsigned long icmp, dcmp;
+#endif
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long result; /* Result of a system call */
+ unsigned long trap; /* Reason for being here */
+ unsigned long marker; /* Should have DEADDEAD */
};
+
#define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) ((regs)->msr & 0x4000)
#ifdef KERNEL
extern void show_regs(struct pt_regs *);
#endif
+/* should include and generate these in ppc_defs.h -- Cort */
/* Offsets used by 'ptrace' system call interface */
/* Note: these should correspond to gpr[x] */
#define PT_R0 0
#define PT_CCR 38
#define PT_FPR0 48
+#endif /* __ASSEMBLY__ */
-#endif
+#endif /* _PPC_PTRACE_H */
#ifndef _PPC_SEMAPHORE_H
#define _PPC_SEMAPHORE_H
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas and Paul Mackerras
+ */
+
#include <asm/atomic.h>
struct semaphore {
atomic_t count;
- atomic_t waiting;
+ atomic_t waking;
struct wait_queue * wait;
};
#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
extern void __down(struct semaphore * sem);
+extern int __down_interruptible(struct semaphore * sem);
extern void __up(struct semaphore * sem);
-extern void atomic_add(int c, int *v);
-extern void atomic_sub(int c, int *v);
+#define sema_init(sem, val) atomic_set(&((sem)->count), (val))
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * i.e. load with reservation and store conditional on the ppc.
+ */
-#define sema_init(sem, val) atomic_set(&((sem)->count), val)
+static inline void wake_one_more(struct semaphore * sem)
+{
+ atomic_inc(&sem->waking);
+}
static inline int waking_non_zero(struct semaphore *sem)
{
- unsigned long flags;
- int ret = 0;
+ int ret, tmp;
+
+ __asm__ __volatile__(
+ "1: lwarx %1,0,%2\n"
+ " cmpwi 0,%1,0\n"
+ " addi %1,%1,-1\n"
+ " ble- 2f\n"
+ " stwcx. %1,0,%2\n"
+ " bne- 1b\n"
+ " mr %0,%1\n"
+ "2:"
+ : "=r" (ret), "=r" (tmp)
+ : "r" (&sem->waking), "0" (0)
+ : "cr0", "memory");
- save_flags(flags);
- cli();
- if (atomic_read(&sem->waking) > 0) {
- atomic_dec(&sem->waking);
- ret = 1;
- }
- restore_flags(flags);
return ret;
}
extern inline void down(struct semaphore * sem)
{
- for (;;)
- {
- atomic_dec_return(&sem->count);
- if ( sem->count >= 0)
- break;
- __down(sem);
- }
+ if (atomic_dec_return(&sem->count) < 0)
+ __down(sem);
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+ if (atomic_dec_return(&sem->count) < 0)
+ ret = __down_interruptible(sem);
+ return ret;
}
extern inline void up(struct semaphore * sem)
{
- atomic_inc_return(&sem->count);
- if ( sem->count <= 0)
- __up(sem);
+ if (atomic_inc_return(&sem->count) <= 0)
+ __up(sem);
}
#endif /* !(_PPC_SEMAPHORE_H) */
};
extern struct cpuinfo_PPC cpu_data[NR_CPUS];
-
+#endif /* __ASSEMBLY__ */
#endif /* !(__SMP__) */
--- /dev/null
+#ifndef __PPC_SMPLOCK_H
+#define __PPC_SMPLOCK_H
+
+#ifndef __SMP__
+
+#define lock_kernel() do { } while (0)
+#define unlock_kernel() do { } while (0)
+#define release_kernel_lock(task, cpu, depth) ((depth) = 1)
+#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
+
+#else
+
+#error need to defined lock_kernel and unlock_kernel, etc.
+
+#endif /* __SMP__ */
+#endif /* __PPC_SMPLOCK_H */
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 14 */
+/* To add :#define SO_REUSEPORT 15 */
#define SO_RCVLOWAT 16
#define SO_SNDLOWAT 17
#define SO_RCVTIMEO 18
#define SO_SNDTIMEO 19
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION 20
-#define SO_SECURITY_ENCRYPTION_TRANSPORT 21
-#define SO_SECURITY_ENCRYPTION_NETWORK 22
+#define SO_PASSCRED 20
+#define SO_PEERCRED 21
#endif /* _ASM_SOCKET_H */
--- /dev/null
+/*
+ * Software interrupts..
+ */
+
+#ifndef __ASM_SOFTIRQ_H
+#define __ASM_SOFTIRQ_H
+
+#include <asm/atomic.h>
+#include <asm/hardirq.h>
+
+#define get_active_bhs() (bh_mask & bh_active)
+#define clear_active_bhs(x) atomic_clear_mask((x),&bh_active)
+
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+ bh_base[nr] = routine;
+ bh_mask_count[nr] = 0;
+ bh_mask |= 1 << nr;
+}
+
+extern inline void remove_bh(int nr)
+{
+ bh_base[nr] = NULL;
+ bh_mask &= ~(1 << nr);
+}
+
+extern inline void mark_bh(int nr)
+{
+ set_bit(nr, &bh_active);
+}
+
+/*
+ * These use a mask count to correctly handle
+ * nested disable/enable calls
+ */
+extern inline void disable_bh(int nr)
+{
+ bh_mask &= ~(1 << nr);
+ bh_mask_count[nr]++;
+}
+
+extern inline void enable_bh(int nr)
+{
+ if (!--bh_mask_count[nr])
+ bh_mask |= 1 << nr;
+}
+
+#ifndef __SMP__
+
+/*
+ * The locking mechanism for base handlers, to prevent re-entrancy,
+ * is entirely private to an implementation, it should not be
+ * referenced at all outside of this file.
+ */
+
+extern int __ppc_bh_counter;
+
+extern inline void start_bh_atomic(void)
+{
+ __ppc_bh_counter++;
+ barrier();
+}
+
+extern inline void end_bh_atomic(void)
+{
+ barrier();
+ __ppc_bh_counter--;
+}
+
+/* These are for the irq's testing the lock */
+#define softirq_trylock() (__ppc_bh_counter? 0: ((__ppc_bh_counter=1),1))
+#define softirq_endlock() (__ppc_bh_counter = 0)
+
+#else
+#error Nein, wir haben noch kein SMP
+#endif
+
+#endif
--- /dev/null
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#ifndef __SMP__
+
+typedef struct { int blah; } spinlock_t;
+#define SPIN_LOCK_UNLOCKED { }
+
+#define spin_lock_init(lock) do { } while(0)
+#define spin_lock(lock) do { } while(0)
+#define spin_trylock(lock) do { } while(0)
+#define spin_unlock(lock) do { } while(0)
+#define spin_lock_irq(lock) cli()
+#define spin_unlock_irq(lock) sti()
+
+#define spin_lock_irqsave(lock, flags) \
+ do { save_flags(flags); cli(); } while (0)
+#define spin_unlock_irqrestore(lock, flags) \
+ restore_flags(flags)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct { int fred; } rwlock_t;
+#define RW_LOCK_UNLOCKED { }
+
+#define read_lock(lock) do { } while(0)
+#define read_unlock(lock) do { } while(0)
+#define write_lock(lock) do { } while(0)
+#define write_unlock(lock) do { } while(0)
+#define read_lock_irq(lock) cli()
+#define read_unlock_irq(lock) sti()
+#define write_lock_irq(lock) cli()
+#define write_unlock_irq(lock) sti()
+
+#define read_lock_irqsave(lock, flags) \
+ do { save_flags(flags); cli(); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+ restore_flags(flags)
+#define write_lock_irqsave(lock, flags) \
+ do { save_flags(flags); cli(); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+ restore_flags(flags)
+
+#else
+
+/* Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+typedef struct {
+ volatile unsigned int lock;
+ unsigned long previous;
+} spinlock_t;
+
+#define SPIN_LOCK_UNLOCKED { 0, 0 }
+
+#define spin_unlock(lock) ((lock)->lock = 0)
+
+static inline void spin_lock(spinlock_t * lock)
+{
+ int stuck = 10000000;
+ int tmp, val;
+ __label__ l1;
+
+l1: __asm__ __volatile__(
+ " mtctr %2\n"
+ "1: lwarx %0,0,%3\n"
+ " andi. %1,%0,1\n\t"
+ " ori %0,%0,1\n\t"
+ " bne- 2f\n\t"
+ " stwcx. %0,0,%3\n\t"
+ "2: bdnzf- 2,1b"
+ : "=r" (tmp), "=r" (val)
+ : "r" (stuck), "r" (lock)
+ : "ctr");
+ if (!val) {
+ printk("spinlock stuck at %p (%lx)\n", &&l1, lock->previous);
+ } else
+ lock->previous = (unsigned long) &&l1;
+}
+
+#define spin_trylock(lock) (!set_bit(0,(lock)))
+
+#define spin_lock_irq(lock) \
+ do { __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irq(lock) \
+ do { spin_unlock(lock); __sti(); } while (0)
+
+#define spin_lock_irqsave(lock, flags) \
+ do { __save_flags(flags); __cli(); spin_lock(lock); } while (0)
+
+#define spin_unlock_irqrestore(lock, flags) \
+ do { spin_unlock(lock); __restore_flags(flags); } while (0)
+
+#endif /* SMP */
+#endif /* __ASM_SPINLOCK_H */
#ifndef _PPC_STRING_H_
#define _PPC_STRING_H_
-
-
-/*
- * keep things happy, the compile became unhappy since memset is
- * in include/linux/string.h and lib/string.c with different prototypes
- * -- Cort
- */
-#if 1
-#define __HAVE_ARCH_MEMSET
-extern __inline__ void * memset(void * s,int c,__kernel_size_t count)
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRNCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCHR
+/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
+extern inline void * memchr(const void * cs,int c,size_t count)
{
- char *xs = (char *) s;
-
- while (count--)
- *xs++ = c;
-
- return s;
+ unsigned long i = 0;
+ while ( count != i )
+ {
+ if ( (char)c == *(char *)(cs + i) )
+ return (void *)(cs + i);
+ i--;
+ }
+ return NULL;
}
#endif
-#define bzero(addr,size) memset((addr),(int)(0),(size))
-
-
-#endif
#ifndef __PPC_SYSTEM_H
#define __PPC_SYSTEM_H
-#if 0
-#define mb() \
-__asm__ __volatile__("mb": : :"memory")
-#endif
-#define mb() __asm__ __volatile__ ("" : : :"memory")
+#include <linux/delay.h>
+
+#define mb() __asm__ __volatile__ ("sync" : : : "memory")
+
+#define __save_flags(flags) ({\
+ __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
+/* using Paul's in misc.S now -- Cort */
+extern void __restore_flags(unsigned long flags);
+/*
+ #define __sti() _soft_sti(void)
+ #define __cli() _soft_cli(void)
+ */
+extern void __sti(void);
+extern void __cli(void);
-extern void __save_flags(long *flags);
-extern void __restore_flags(long flags);
-extern void sti(void);
-extern void cli(void);
+extern void _hard_sti(void);
+extern void _hard_cli(void);
+extern void _soft_sti(void);
+extern void _soft_cli(void);
extern int _disable_interrupts(void);
extern void _enable_interrupts(int);
-/*extern void memcpy(void *, void *, int);*/
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern void find_scsi_boot(void);
+extern int sd_find_target(void *, int);
+extern int _get_PVR(void);
+extern void via_cuda_init(void);
+extern void read_rtc_time(void);
+extern void pmac_find_display(void);
+extern void giveup_fpu(void);
+extern void store_cache_range(unsigned long, unsigned long);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
struct task_struct;
extern void switch_to(struct task_struct *prev, struct task_struct *next);
-#define save_flags(flags) __save_flags(&(flags))
-#define restore_flags(flags) __restore_flags(flags)
+struct thread_struct;
+extern void _switch(struct thread_struct *prev, struct thread_struct *next,
+ unsigned long context);
+
+struct pt_regs;
+extern int do_signal(unsigned long oldmask, struct pt_regs *regs);
+extern void dump_regs(struct pt_regs *);
+
+#ifndef __SMP__
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(flags) __save_flags(flags)
+#define restore_flags(flags) __restore_flags(flags)
+
+#else
+#error need global cli/sti etc. defined for SMP
+#endif
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
-#if 0 /* This is how it's done on Alpha - maybe later. */
/*
* termios type and macro definitions. Be careful about adding stuff
* to this file since it's used in GNU libc and there are strict rules
};
/* c_cc characters */
-#define VEOF 0
-#define VEOL 1
-#define VEOL2 2
-#define VERASE 3
-#define VWERASE 4
-#define VKILL 5
-#define VREPRINT 6
-#define VSWTC 7
-#define VINTR 8
-#define VQUIT 9
-#define VSUSP 10
-#define VSTART 12
-#define VSTOP 13
-#define VLNEXT 14
-#define VDISCARD 15
-#define VMIN 16
-#define VTIME 17
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VMIN 5
+#define VEOL 6
+#define VTIME 7
+#define VEOL2 8
+#define VSWTC 9
+
+#define VWERASE 10
+#define VREPRINT 11
+#define VSUSP 12
+#define VSTART 13
+#define VSTOP 14
+#define VLNEXT 15
+#define VDISCARD 16
/* c_iflag bits */
#define IGNBRK 0000001
#define ICRNL 0000400
#define IXON 0001000
#define IXOFF 0002000
-#if !defined(KERNEL) || defined(__USE_BSD)
+#if defined(__KERNEL__) || defined(__USE_BSD)
/* POSIX.1 doesn't want these... */
# define IXANY 0004000
# define IUCLC 0010000
#define XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
/* c_cflag bit meaning */
-#define CBAUD 0000017
+#define CBAUD 0000377
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
-#endif
#endif /* _PPC_TERMBITS_H */
unsigned char c_cc[NCC]; /* control characters */
};
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_cc[NCCS]; /* control characters */
- cc_t c_line; /* line discipline (== c_cc[19]) */
- int c_ispeed; /* input speed */
- int c_ospeed; /* output speed */
-};
-
/* c_cc characters */
#define _VINTR 0
#define _VQUIT 1
#define _VEOL2 8
#define _VSWTC 9
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VMIN 5
-#define VEOL 6
-#define VTIME 7
-#define VEOL2 8
-#define VSWTC 9
-
-#define VWERASE 10
-#define VREPRINT 11
-#define VSUSP 12
-#define VSTART 13
-#define VSTOP 14
-#define VLNEXT 15
-#define VDISCARD 16
-
-
#ifdef __KERNEL__
-/* 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\001\000"
-*/
-
/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
#endif
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IXON 0001000
-#define IXOFF 0002000
-#define IXANY 0004000
-#define IUCLC 0010000
-#define IMAXBEL 0020000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define ONLCR 0000002
-#define OLCUC 0000004
-
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-
-#define OFILL 00000100
-#define OFDEL 00000200
-#define NLDLY 00001400
-#define NL0 00000000
-#define NL1 00000400
-#define NL2 00001000
-#define NL3 00001400
-#define TABDLY 00006000
-#define TAB0 00000000
-#define TAB1 00002000
-#define TAB2 00004000
-#define TAB3 00006000
-#define CRDLY 00030000
-#define CR0 00000000
-#define CR1 00010000
-#define CR2 00020000
-#define CR3 00030000
-#define FFDLY 00040000
-#define FF0 00000000
-#define FF1 00040000
-#define BSDLY 00100000
-#define BS0 00000000
-#define BS1 00100000
-#define VTDLY 00200000
-#define VT0 00000000
-#define VT1 00200000
-#define XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
-
-/* c_cflag bit meaning */
-#define CBAUD 0000377
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000020
-#define B57600 00020
-#define B115200 00021
-#define B230400 00022
-#define B460800 00023
-
-#define CSIZE 00001400
-#define CS5 00000000
-#define CS6 00000400
-#define CS7 00001000
-#define CS8 00001400
-
-#define CSTOPB 00002000
-#define CREAD 00004000
-#define PARENB 00010000
-#define PARODD 00020000
-#define HUPCL 00040000
-
-#define CLOCAL 00100000
-#define CRTSCTS 020000000000 /* flow control */
-
-/* c_lflag bits */
-#define ISIG 0x00000080
-#define ICANON 0x00000100
-#define XCASE 0x00004000
-#define ECHO 0x00000008
-#define ECHOE 0x00000002
-#define ECHOK 0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL 0x00000040
-#define ECHOPRT 0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-
/* modem lines */
#define TIOCM_LE 0x001
#define TIOCM_DTR 0x002
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
/* line disciplines */
#define N_TTY 0
#define N_SLIP 1
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+ unsigned short __tmp; \
+ get_user(__tmp,&(termio)->x); \
+ (termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
+}
+
#define user_termio_to_kernel_termios(termios, termio) \
-do { \
- unsigned short tmp; \
- get_user(tmp, &(termio)->c_iflag); \
- (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
- get_user(tmp, &(termio)->c_oflag); \
- (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
- get_user(tmp, &(termio)->c_cflag); \
- (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
- get_user(tmp, &(termio)->c_lflag); \
- (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
- get_user((termios)->c_line, &(termio)->c_line); \
- get_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
- get_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
- get_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
- get_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
- get_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
- get_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
- get_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
- get_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
- get_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
- get_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-} while(0)
+({ \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
/*
* Translate a "termios" structure into a "termio". Ugh.
- *
- * Note the "fun" _VMIN overloading.
*/
#define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
put_user((termios)->c_iflag, &(termio)->c_iflag); \
put_user((termios)->c_oflag, &(termio)->c_oflag); \
put_user((termios)->c_cflag, &(termio)->c_cflag); \
put_user((termios)->c_lflag, &(termio)->c_lflag); \
put_user((termios)->c_line, &(termio)->c_line); \
- put_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
- put_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
- put_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
- put_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
- put_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
- put_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
- put_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
- put_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
- if (1/*!((termios)->c_lflag & ICANON)*/) { \
- put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
- put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
- } \
-} while(0)
+ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
+#ifndef _PPC_UACCESS_H
+#define _PPC_UACCESS_H
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/errno.h>
-#define KERNEL_DS (0)
-#define USER_DS (1)
-
#define VERIFY_READ 0
#define VERIFY_WRITE 1
-#define get_fs() (current->tss.fs)
-#define get_ds() (KERNEL_DS)
-#define set_fs(val) ( current->tss.fs = (val))
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS (0)
+#define USER_DS (1)
+
+#define get_fs() (current->tss.fs)
+#define get_ds() (KERNEL_DS)
+#define set_fs(val) (current->tss.fs = (val))
#define __user_ok(addr,size) (((size) <= 0x80000000)&&((addr) <= 0x80000000-(size)))
-#define __kernel_ok (get_fs() == KERNEL_DS)
+#define __kernel_ok (get_fs() == KERNEL_DS)
#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+ unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
*
- * As the powerpc uses the same address space for kernel and user
- * data, we can just do these as direct assignments. (Of course, the
- * exception handling means that it's no longer "just"...)
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
*
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
+ * As we use the same address space for kernel and user data on the
+ * PowerPC, we can just do these as direct assignments. (Of course, the
+ * exception handling means that it's no longer "just"...)
*/
+#define get_user(x,ptr) \
+ __get_user_check((x),(ptr),sizeof(*(ptr)))
+#define put_user(x,ptr) \
+ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+ __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
/*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the programmer has to do the
- * checks by hand with "access_ok()")
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
*/
-#define put_user(x,ptr) ({ \
-unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
-#define get_user(x,ptr) ({ \
-unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err; \
+ __put_user_size((x),(ptr),(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_check(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
+ __put_user_size((x),__pu_addr,(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __put_user_asm(x,ptr,retval,"stb"); break; \
+ case 2: __put_user_asm(x,ptr,retval,"sth"); break; \
+ case 4: __put_user_asm(x,ptr,retval,"stw"); break; \
+ default: __put_user_bad(); \
+ } \
+} while (0)
-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
struct __large_struct { unsigned long buf[100]; };
-#define __m(x) ((struct __large_struct *)(x))
-
-#define __put_user_check(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
-
-#define __put_user_nocheck(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} __pu_ret; })
-
-extern int __put_user_bad(void);
-
-#define __get_user_check(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __gu_val = __get_user_8(__gu_val,addr); break; \
-case 2: __gu_val = __get_user_16(__gu_val,addr); break; \
-case 4: __gu_val = __get_user_32(__gu_val,addr); break; \
-default: __get_user_bad(); break; \
-} } (x) = (type) __gu_val; __gu_ret; })
-
-#define __get_user_nocheck(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-switch (size) { \
-case 1: __gu_val =__get_user_8(__gu_val,addr); break; \
-case 2: __gu_val =__get_user_16(__gu_val,addr); break; \
-case 4: __gu_val =__get_user_32(__gu_val,addr); break; \
-default: __gu_val = __get_user_bad(); break; \
-} (x) = (type) __gu_val; __gu_ret; })
-
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" %1,0(%2)\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r"(err) \
+ : "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err = -EFAULT, __gu_val = 0; \
+ const __typeof__(*(ptr)) *__gu_addr = (ptr); \
+ if (access_ok(VERIFY_READ,__gu_addr,size)) \
+ __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __get_user_asm(x,ptr,retval,"lbz"); break; \
+ case 2: __get_user_asm(x,ptr,retval,"lhz"); break; \
+ case 4: __get_user_asm(x,ptr,retval,"lwz"); break; \
+ default: (x) = __get_user_bad(); \
+ } \
+} while (0)
+
+#define __get_user_asm(x, addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" %1,0(%2)\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " li %1,0\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r"(err), "=r"(x) \
+ : "b"(addr), "i"(-EFAULT), "0"(err))
/* more complex routines */
-extern int __copy_tofrom_user(unsigned long to, unsigned long from, int size);
-
-#define copy_to_user(to,from,n) ({ \
-unsigned long __copy_to = (unsigned long) (to); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_tofrom_user(__copy_to, (unsigned long) (from), __copy_size); \
-} \
-__copy_res; })
-
-#define copy_from_user(to,from,n) ({ \
-unsigned long __copy_from = (unsigned long) (from); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_tofrom_user((unsigned long) (to), __copy_from, __copy_size); \
-} \
-__copy_res; })
-
-extern int __clear_user(unsigned long addr, int size);
-
-#define clear_user(addr,n) ({ \
-unsigned long __clear_addr = (unsigned long) (addr); \
-int __clear_size = (int) (n); \
-int __clear_res = -EFAULT; \
-if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
-__clear_res = __clear_user(__clear_addr, __clear_size); \
-} \
-__clear_res; })
-
-extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
-
-#define strncpy_from_user(dest,src,count) ({ \
-unsigned long __sfu_src = (unsigned long) (src); \
-int __sfu_count = (int) (count); \
-long __sfu_res = -EFAULT; \
-if(__access_ok(__sfu_src, __sfu_count)) { \
-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
-} __sfu_res; })
+extern int __copy_tofrom_user(void *to, const void *from, unsigned long size);
+
+extern inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ return __copy_tofrom_user(to, from, n);
+ return n? -EFAULT: 0;
+}
+
+extern inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ return __copy_tofrom_user(to, from, n);
+ return n? -EFAULT: 0;
+}
+
+#define __copy_from_user(to, from, size) \
+ __copy_tofrom_user((to), (from), (size))
+#define __copy_to_user(to, from, size) \
+ __copy_tofrom_user((to), (from), (size))
+
+extern unsigned long __clear_user(void *addr, unsigned long size);
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+ if (access_ok(VERIFY_WRITE, addr, size))
+ return __clear_user(addr, size);
+ return size? -EFAULT: 0;
+}
+
+extern int __strncpy_from_user(char *dst, const char *src, long count);
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ if (access_ok(VERIFY_READ, src, 1))
+ return __strncpy_from_user(dst, src, count);
+ return -EFAULT;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+
+extern long strlen_user(const char *);
#endif /* __ASSEMBLY__ */
-#endif /* _ASM_UACCESS_H */
+#endif /* _PPC_UACCESS_H */
-/* * Last edited: Nov 17 16:28 1995 (cort) */
#ifndef _ASM_PPC_UNISTD_H_
#define _ASM_PPC_UNISTD_H_
-#define _NR(n) #n
-#define _lisc(n) "li 0," _NR(n)
-
/*
* This file contains the system call numbers.
*/
#define __NR_mremap 163
#define __NR_setresuid 164
#define __NR_getresuid 165
-#define __NR_nfsservctl 166
+#define __NR_query_module 166
+#define __NR_poll 167
+#define __NR_nfsservctl 168
+
+#define __NR(n) #n
+#define __do_syscall(n) \
+ asm volatile ("li 0,%0\n\
+ sc\n\
+ bns 1f\n\
+ mr 0,3\n\
+ lis 3,errno@ha\n\
+ stw 0,errno@l(3)\n\
+ li 3,-1\n\
+1:" : : "i" (n) : "r0", "r3")
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
type name(void) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5) \
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
+{ __do_syscall(__NR_##name); }
#ifdef __KERNEL_SYSCALLS__
/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
+ * Forking from kernel space will result in NO COPY ON WRITE (!!!),
+ * until an execve is executed. This is no problem, but for the stack.
+ * This is handled by not letting main() use the stack at all after
+ * fork(). On the PowerPC, this means we can only call leaf functions.
*/
-
-#if 0
/*
- This is the mechanism for creating a new kernel thread.
- For the time being it only behaves the same as clone().
- It should be changed very soon to work properly and cleanly. This
- gets us going for now, though.
-
- some versions of gcc hate this -- complains about constraints being
- incorrect. not sure why so it's in arch/ppc/kernel/misc.S now.
- -- Cort
+ * Create a new kernel thread.
*/
-static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- long retval;
- __asm__ (
- "li 0, 120 \n\t" /* __NR_clone */
- "li 3, %5 \n\t" /* load flags as arg to clone */
- /*"mr 1,7 \n\t"*/ /* save kernel stack */
- "sc \n\t" /* syscall */
- /*"cmp 0,1,7 \n\t"*/ /* if kernel stack changes -- child */
- "cmpi 0,3,0 \n\t"
- "bne 1f \n\t" /* return if parent */
- /* this is in child */
- "li 3, %3 \n\t" /* child -- load args and call fn */
- "mtlr %4 \n\t"
- "blrl \n\t"
- "li 0, %2 \n\t" /* exit after child exits */
- "li 3, 0 \n\t"
- "sc \n\t"
- /* parent */
- "1: \n\t"
- :"=3" (retval)
- :"i" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "r" (fn), "g" (CLONE_VM|flags)
- :"cc", "1", "0", "3", "7", "31", "memory" );
- return retval;
-}
-#else
extern long __kernel_thread(unsigned long, int (*)(void *), void *);
static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
return __kernel_thread(flags | CLONE_VM, fn, arg);
}
-#endif
-#define __NR__exit __NR_exit
-static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */
-static inline _syscall0(int,fork) /* needs to be inline */
-static inline _syscall0(int,pause) /* needs to be inline */
-static inline _syscall1(int,setup,int,magic) /* called in init before execve */
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static /*inline*/ _syscall1(int,dup,int,fd)
-static /*inline*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static /*inline*/ _syscall3(int,open,const char *,file,int,flag,int,mode)
-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)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+/*
+ * System call prototypes.
+ */
+int idle(void);
+int setup(int);
+int sync(void);
+pid_t setsid(void);
+int write(int, const char *, off_t);
+int dup(int);
+int execve(const char *, char **, char **);
+int open(const char *, int, int);
+int close(int);
+pid_t waitpid(pid_t, int *, int);
-/* called from init before execve -- need to be inline? -- Cort */
static inline pid_t wait(int * wait_stat)
{
return waitpid(-1,wait_stat,0);
}
-#endif
+#endif /* __KERNEL_SYSCALLS__ */
#endif /* _ASM_PPC_UNISTD_H_ */
-
-
};
#define FBIOGTYPE _IOR('F', 0, struct fbtype)
-/* Used by FBIOPUTCMAP */
struct fbcmap {
int index; /* first element (0 origin) */
int count;
#define FBIO_WID_PUT _IOW('F', 32, struct fb_wid_list)
#define FBIO_WID_GET _IOWR('F', 33, struct fb_wid_list)
+/* Creator ioctls */
+#define FFB_IOCTL ('F'<<8)
+#define FFB_SYS_INFO (FFB_IOCTL|80)
+#define FFB_CLUTREAD (FFB_IOCTL|81)
+#define FFB_CLUTPOST (FFB_IOCTL|82)
+#define FFB_SETDIAGMODE (FFB_IOCTL|83)
+#define FFB_GETMONITORID (FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE (FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE (FFB_IOCTL|86)
+#define FFB_SETSERVER (FFB_IOCTL|87)
+#define FFB_SETOVCTL (FFB_IOCTL|88)
+#define FFB_GETOVCTL (FFB_IOCTL|89)
+#define FFB_GETSAXNUM (FFB_IOCTL|90)
+#define FFB_FBDEBUG (FFB_IOCTL|91)
+
/* Cg14 ioctls */
#define MDI_IOCTL ('M'<<8)
#define MDI_RESET (MDI_IOCTL|1)
*/
#define MDI_CLEAR_XLUT (MDI_IOCTL|9)
-/* leo ioctls */
-struct leo_clut_alloc {
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
__u32 clutid; /* Set on return */
__u32 flag;
__u32 index;
};
-struct leo_clut {
-#define LEO_CLUT_WAIT 0x00000001 /* Not yet implemented */
+struct fb_clut {
+#define FB_CLUT_WAIT 0x00000001 /* Not yet implemented */
__u32 flag;
__u32 clutid;
__u32 offset;
char * green;
char * blue;
};
-#define LEO_CLUTALLOC _IOWR('L', 53, struct leo_clut_alloc)
-#define LEO_CLUTFREE _IOW('L', 54, struct leo_clut_alloc)
-#define LEO_CLUTREAD _IOW('L', 55, struct leo_clut)
-#define LEO_CLUTPOST _IOW('L', 56, struct leo_clut)
+
+struct fb_clut32 {
+ __u32 flag;
+ __u32 clutid;
+ __u32 offset;
+ __u32 count;
+ __u32 red;
+ __u32 green;
+ __u32 blue;
+};
+
+#define LEO_CLUTALLOC _IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE _IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD _IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST _IOW('L', 56, struct fb_clut)
#define LEO_SETGAMMA _IOW('L', 68, int) /* Not yet implemented */
#define LEO_GETGAMMA _IOR('L', 69, int) /* Not yet implemented */
#ifndef _SPARC_SMP_H
#define _SPARC_SMP_H
+#include <asm/head.h>
+
#ifndef __ASSEMBLY__
/* PROM provided per-processor information we need
* to start them all up.
-/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $
+/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
* oplib.h: Describes the interface and available routines in the
* Linux Prom library.
*
/* 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);
+extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
/* Stop the CPU with the passed device tree node. */
extern int prom_stopcpu(int cpunode);
-/* $Id: pgtable.h,v 1.49 1997/06/30 09:24:12 jj Exp $
+/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
/* Cache and TLB flush operations. */
-#define flush_cache_all() \
-do { unsigned long va; \
- flushw_all(); \
- for(va = 0; \
- va<(PAGE_SIZE<<1); \
- va += 32) \
-spitfire_put_icache_tag(va,0x0);\
-} while(0)
-
+/* These are the same regardless of whether this is an SMP kernel or not. */
#define flush_cache_mm(mm) do { } while(0)
#define flush_cache_range(mm, start, end) do { } while(0)
#define flush_cache_page(vma, page) do { } while(0)
/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page) do { } while (0)
+#define flush_page_to_ram(page) do { } while (0)
-extern void flush_tlb_all(void);
+extern void __flush_cache_all(void);
+extern void __flush_tlb_all(void);
extern void __flush_tlb_mm(unsigned long context);
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+ unsigned long end);
+extern void __flush_tlb_page(unsigned long context, unsigned long page);
+
+#ifndef __SMP__
+
+#define flush_cache_all() __flush_cache_all()
+#define flush_tlb_all() __flush_tlb_all()
+
extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT)
__flush_tlb_mm(mm->context & 0x1fff);
}
-extern void __flush_tlb_range(unsigned long context, unsigned long start,
- unsigned long end);
extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
__flush_tlb_range(mm->context & 0x1fff, start, end);
}
-extern void __flush_tlb_page(unsigned long context, unsigned long page);
extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
struct mm_struct *mm = vma->vm_mm;
__flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
}
+#else /* __SMP__ */
+
+extern void smp_flush_cache_all(void);
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+
+#define flush_cache_all() smp_flush_cache_all()
+#define flush_tlb_all() smp_flush_tlb_all()
+
+extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
+{
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_mm(mm);
+}
+
+extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_range(mm, start, end);
+}
+
+extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_page(vma, page);
+}
+
+#endif
+
extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
{ return __pte(__pa(page) | pgprot_val(pgprot)); }
#define wake_one_more(sem) atomic_inc(&sem->waking);
-extern __inline__ int waking_non_zero(struct semaphore *sem)
-{
- unsigned long flags;
- int ret = 0;
-
- save_flags(flags);
- cli();
- if (atomic_read(&sem->waking) > 0) {
- atomic_dec(&sem->waking);
- ret = 1;
- }
- restore_flags(flags);
- return ret;
-}
+#define waking_non_zero(sem) \
+({ unsigned long flags; \
+ int ret = 0; \
+ save_and_cli(flags); \
+ if (atomic_read(&sem->waking) > 0) { \
+ atomic_dec(&sem->waking); \
+ ret = 1; \
+ } \
+ restore_flags(flags); \
+ ret; \
+})
extern __inline__ void down(struct semaphore * sem)
{
};
extern int linux_num_cpus; /* number of CPUs probed */
-extern struct prom_cpuinfo linux_cpus[NCPUS];
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
#endif /* !(__ASSEMBLY__) */
extern struct cpuinfo_sparc cpu_data[NR_CPUS];
-typedef __volatile__ unsigned char klock_t;
-extern klock_t kernel_flag;
+struct klock_info {
+ unsigned char kernel_flag;
+ unsigned char akp;
+};
+
+extern struct klock_info klock_info;
#define KLOCK_HELD 0xff
#define KLOCK_CLEAR 0x00
extern int smp_found_cpus;
extern unsigned char boot_cpu_id;
-extern unsigned int cpu_present_map;
+extern unsigned long cpu_present_map;
extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
extern __volatile__ unsigned long kernel_counter;
extern __volatile__ unsigned char active_kernel_processor;
extern void smp_callin(void);
extern void smp_boot_cpus(void);
extern void smp_store_cpu_info(int id);
-extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4, unsigned long arg5);
-
-extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
-extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
-{ smp_cross_call(func, arg1, 0, 0, 0, 0); }
-extern __inline__ void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
-{ smp_cross_call(func, arg1, arg2, 0, 0, 0); }
-extern __inline__ void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3)
-{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); }
-extern __inline__ void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); }
-extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4, unsigned long arg5)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); }
extern __volatile__ int cpu_number_map[NR_CPUS];
extern __volatile__ int cpu_logical_map[NR_CPUS];
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
{
- int cpuid;
+ unsigned long upaconfig;
- /* Get MID from UPA Config register, and use that. */
- __asm__ __volatile__("
- ldxa [%g0] %1, %0
- srlx %0, 17, %0
- and %0, 0x1f, %0
- " : "=r" cpuid
- : "i" (ASI_UPA_CONFIG));
-
- return cpuid;
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (upaconfig)
+ : "i" (ASI_UPA_CONFIG));
+ return ((upaconfig >> 17) & 0x1f);
}
+#define smp_processor_id() (current->processor)
extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
#endif /* !(__ASSEMBLY__) */
#define MBOX_IDLECPU2 0xFD
#define MBOX_STOPCPU2 0xFE
-
-#define NO_PROC_ID 0xFF
-
#define PROC_CHANGE_PENALTY 20
#define SMP_FROM_INT 1
#endif /* !(__SMP__) */
+#define NO_PROC_ID 0xFF
+
#endif /* !(_SPARC64_SMP_H) */
#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
#else
-#error SMP on sparc64 not supported yet
+
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth) \
+do { \
+ if((depth = (task)->lock_depth) != 0) { \
+ __cli(); \
+ (task)->lock_depth = 0; \
+ klock_info.akp = NO_PROC_ID; \
+ klock_info.kernel_flag = 0; \
+ } \
+ release_irqlock(cpu); \
+ __sti(); \
+} while(0)
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+#define reacquire_kernel_lock(task, cpu, depth) \
+do { \
+ if(depth) { \
+ register struct klock_info *klip asm("g1"); \
+ klip = &klock_info; \
+ __asm__ __volatile__("mov %%o7, %%g5\n\t" \
+ "call ___lock_reacquire_kernel\n\t" \
+ " mov %1, %%g2" \
+ : /* No outputs. */ \
+ : "r" (klip), "r" (depth) \
+ : "g2", "g3", "g5", "g7", "memory", "cc"); \
+ } \
+} while(0)
+
+/* The following acquire and release the master kernel global lock,
+ * the idea is that the usage of this mechanmism becomes less and less
+ * as time goes on, to the point where they are no longer needed at all
+ * and can thus disappear.
+ */
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+extern __inline__ void lock_kernel(void)
+{
+ register struct klock_info *klip asm("g1");
+ klip = &klock_info;
+ __asm__ __volatile__("
+ mov %%o7, %%g5
+ call ___lock_kernel
+ ld [%%g6 + %0], %%g2
+" : : "i" (AOFF_task_lock_depth), "r" (klip)
+ : "g2", "g3", "g5", "g7", "memory", "cc");
+}
+
+/* Release kernel global lock. */
+extern __inline__ void unlock_kernel(void)
+{
+ register struct klock_info *klip asm("g1");
+ klip = &klock_info;
+ __asm__ __volatile__("
+ mov %%o7, %%g5
+ call ___unlock_kernel
+ ld [%%g6 + %0], %%g2
+" : : "i" (AOFF_task_lock_depth), "r" (klip)
+ : "g2", "g3", "g5", "memory", "cc");
+}
+
#endif /* (__SMP__) */
#endif /* !(__SPARC64_SMPLOCK_H) */
#include <asm/spinlock.h>
+extern spinlock_t global_bh_lock;
+
#define init_bh(nr, routine) \
do { unsigned long flags; \
int ent = nr; \
#define softirq_trylock() \
({ \
int ret = 1; \
- if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \
- atomic_dec(&__sparc_bh_counter); \
+ if(atomic_add_return(1, &__sparc64_bh_counter) != 1) { \
+ atomic_dec(&__sparc64_bh_counter); \
ret = 0; \
} \
ret; \
})
-#define softirq_endlock() atomic_dec(&__sparc_bh_counter)
+#define softirq_endlock() atomic_dec(&__sparc64_bh_counter)
#define clear_active_bhs(mask) \
do { unsigned long flags; \
spin_lock_irqsave(&global_bh_lock, flags); \
/* All of these locking primitives are expected to work properly
* even in an RMO memory model, which currently is what the kernel
* runs in.
+ *
+ * There is another issue. Because we play games to save cycles
+ * in the non-contention case, we need to be extra careful about
+ * branch targets into the "spinning" code. They live in their
+ * own section, but the newer V9 branches have a shorter range
+ * than the traditional 32-bit sparc branch variants. The rule
+ * is that the branches that go into and out of the spinner sections
+ * must be pre-V9 branches.
*/
typedef unsigned char spinlock_t;
{
__asm__ __volatile__("
1: ldstub [%0], %%g2
- brnz,a,pn %%g2, 2f
- ldub [%0], %%g2
- membar #LoadLoad | #LoadStore
+ brz,pt %%g2, 2f
+ membar #LoadLoad | #LoadStore
+ b,a %%xcc, 3f
+2:
.text 2
-2: brnz,a,pt 2b
+3: ldub [%0], %%g2
+4: brnz,a,pt %%g2, 4b
ldub [%0], %%g2
- b,a,pt %%xcc, 1b
+ b,a 1b
.previous
" : /* no outputs */
: "r" (lock)
{
__asm__ __volatile__("
wrpr %%g0, 15, %%pil
- ldstub [%0], %%g2
- brnz,a,pn %%g2, 2f
- ldub [%0], %%g2
- membar #LoadLoad | #LoadStore
+1: ldstub [%0], %%g2
+ brz,pt %%g2, 2f
+ membar #LoadLoad | #LoadStore
+ b,a 3f
+2:
.text 2
-2: brnz,a,pt 2b
+3: ldub [%0], %%g2
+4: brnz,a,pt %%g2, 4b
ldub [%0], %%g2
- b,a,pt %%xcc, 1b
+ b,a 1b
.previous
" : /* no outputs */
: "r" (lock)
do { register spinlock_t *lp asm("g1"); \
lp = lock; \
__asm__ __volatile__( \
- " rdpr %%pil, %0\n\t" \
- " wrpr %%g0, 15, %%pil\n\t" \
- "1: ldstub [%1], %%g2\n\t" \
- " brnz,a,pnt %%g2, 2f\n\t" \
- " ldub [%1], %%g2\n\t" \
- " membar #LoadLoad | #LoadStore\n\t" \
- " .text 2\n\t" \
- "2: brnz,a,pt %%g2, 2b\n\t" \
- " ldub [%1], %%g2\n\t" \
- " b,a,pt %%xcc, 1b\n\t" \
+ "\n rdpr %%pil, %0\n" \
+ " wrpr %%g0, 15, %%pil\n" \
+ "1: ldstub [%1], %%g2\n" \
+ " brz,pt %%g2, 2f\n" \
+ " membar #LoadLoad | #LoadStore\n" \
+ " b,a 3f\n" \
+ "2:\n" \
+ " .text 2\n" \
+ "3: ldub [%1], %%g2\n" \
+ "4: brnz,a,pt %%g2, 4b\n" \
+ " ldub [%1], %%g2\n" \
+ " b,a 1b\n" \
" .previous\n" \
- : "=r" (flags) \
+ : "=&r" (flags) \
: "r" (lp) \
: "g2", "memory"); \
} while(0)
{
__asm__ __volatile__("
ldx [%0], %%g2
-1:
- brlz,pn %%g2, 2f
-4: add %%g2, 1, %%g3
- casx [%0], %%g2, %%g3
+1: brgez,pt %%g2, 4f
+ add %%g2, 1, %%g3
+ b,a 2f
+4: casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
- ldx [%0],%%g2
+ ldx [%0], %%g2
membar #LoadLoad | #LoadStore
.text 2
2: ldx [%0], %%g2
-3: brlz,pt %%g2, 3b
+3: brlz,a,pt %%g2, 3b
ldx [%0], %%g2
- b,a,pt %%xcc, 4b
+ b 4b
+ add %%g2, 1, %%g3
.previous
" : /* no outputs */
: "r" (rw)
__asm__ __volatile__("
membar #StoreStore | #LoadStore
ldx [%0], %%g2
-1:
- sub %%g2, 1, %%g3
+1: sub %%g2, 1, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
{
__asm__ __volatile__("
sethi %%uhi(0x8000000000000000), %%g5
- ldx [%0] %%g2
+ ldx [%0], %%g2
sllx %%g5, 32, %%g5
-1:
- brlz,pn %%g2, 5f
-4: or %%g2, %%g5, %%g3
- casx [%0], %%g2, %%g3
+1: brgez,pt %%g2, 4f
+ or %%g2, %%g5, %%g3
+ b,a 5f
+4: casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
ldx [%0], %%g2
andncc %%g3, %%g5, %%g0
- bne,a,pn %%xcc, 3f
- ldx [%0], %%g2
- membar #LoadLoad | #LoadStore
+ be,pt %%xcc, 2f
+ membar #LoadLoad | #LoadStore
+ b,a 7f
+2:
.text 2
-3:
- andn %%g2, %%g5, %%g3
+7: ldx [%0], %%g2
+3: andn %%g2, %%g5, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 3b
ldx [%0], %%g2
membar #LoadLoad | #LoadStore
5: ldx [%0], %%g2
-6: brlz,pt %%g2, 6b
+6: brlz,a,pt %%g2, 6b
ldx [%0], %%g2
- b,a,pt %%xcc, 4b
+ b 4b
+ or %%g2, %%g5, %%g3
+ .previous
" : /* no outputs */
: "r" (rw)
: "g2", "g3", "g5", "memory", "cc");
sethi %%uhi(0x8000000000000000), %%g5
ldx [%0], %%g2
sllx %%g5, 32, %%g5
-1:
- andn %%g2, %%g5, %%g3
+1: andn %%g2, %%g5, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
-/* $Id: system.h,v 1.26 1997/06/28 10:04:03 davem Exp $ */
+/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
#define restore_flags(x) __restore_flags(x)
#define save_and_cli(x) __save_and_cli(x)
#else
-#error SMP not supported on sparc64
+
+#ifndef __ASSEMBLY__
+extern unsigned char global_irq_holder;
+#endif
+
+#define save_flags(x) \
+do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+ ((getipl() != 0) ? 2 : 0))); } while(0)
+
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
+
+#ifndef __ASSEMBLY__
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+#endif
+
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define restore_flags(flags) __global_restore_flags(flags)
+
#endif
#define mb() __asm__ __volatile__ ("stbar" : : : "memory")
* when modifying this code inspect output of sched.s very
* carefully to make sure things still work. -DaveM
*/
-#define switch_to(prev, next) \
-do { \
- __label__ switch_continue; \
- register unsigned long task_pc asm("o7"); \
- (prev)->tss.kregs->fprs = 0; \
- task_pc = ((unsigned long) &&switch_continue) - 0x8; \
- __asm__ __volatile__( \
- "rdpr %%pstate, %%g2\n\t" \
- "wrpr %%g2, 0x3, %%pstate\n\t" \
- "flushw\n\t" \
-/*XXX*/ "wr %%g0, 0, %%fprs\n\t" \
- "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
- "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
- "rdpr %%wstate, %%o5\n\t" \
- "stx %%o6, [%%g6 + %3]\n\t" \
- "stx %%o5, [%%g6 + %2]\n\t" \
- "rdpr %%cwp, %%o5\n\t" \
- "stx %%o7, [%%g6 + %4]\n\t" \
- "st %%o5, [%%g6 + %5]\n\t" \
- "mov %0, %%g6\n\t" \
- "ld [%0 + %5], %%g1\n\t" \
- "wrpr %%g1, %%cwp\n\t" \
- "ldx [%%g6 + %2], %%o5\n\t" \
- "ldx [%%g6 + %3], %%o6\n\t" \
- "ldx [%%g6 + %4], %%o7\n\t" \
- "mov %%g6, %0\n\t" \
- "wrpr %%o5, 0x0, %%wstate\n\t" \
- "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
- "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
- "wrpr %%g0, 0x96, %%pstate\n\t" \
- "jmpl %%o7 + 0x8, %%g0\n\t" \
- " mov %0, %%g6\n\t" \
- : /* No outputs */ \
- : "r" (next), "r" (task_pc), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \
- : "cc", "g1", "g2", "g3", "g5", "g7", \
- "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
- "i0", "i1", "i2", "i3", "i4", "i5", \
- "o0", "o1", "o2", "o3", "o4", "o5"); \
+#define switch_to(prev, next) \
+do { __label__ switch_continue; \
+ register unsigned long task_pc asm("o7"); \
+ (prev)->tss.kregs->fprs = 0; \
+ task_pc = ((unsigned long) &&switch_continue) - 0x8; \
+ (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id()); \
+ __asm__ __volatile__( \
+ "rdpr %%pstate, %%g2\n\t" \
+ "wrpr %%g2, 0x3, %%pstate\n\t" \
+ "flushw\n\t" \
+/*XXX*/ "wr %%g0, 0, %%fprs\n\t" \
+ "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
+ "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
+ "rdpr %%wstate, %%o5\n\t" \
+ "stx %%o6, [%%g6 + %3]\n\t" \
+ "stx %%o5, [%%g6 + %2]\n\t" \
+ "rdpr %%cwp, %%o5\n\t" \
+ "stx %%o7, [%%g6 + %4]\n\t" \
+ "st %%o5, [%%g6 + %5]\n\t" \
+ "mov %0, %%g6\n\t" \
+ "ld [%0 + %5], %%g1\n\t" \
+ "wrpr %%g1, %%cwp\n\t" \
+ "ldx [%%g6 + %2], %%o5\n\t" \
+ "ldx [%%g6 + %3], %%o6\n\t" \
+ "ldx [%%g6 + %4], %%o7\n\t" \
+ "mov %%g6, %0\n\t" \
+ "wrpr %%o5, 0x0, %%wstate\n\t" \
+ "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
+ "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
+ "wrpr %%g0, 0x96, %%pstate\n\t" \
+ "jmpl %%o7 + 0x8, %%g0\n\t" \
+ " mov %0, %%g6\n\t" \
+ : /* No outputs */ \
+ : "r" (next), "r" (task_pc), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \
+ : "cc", "g1", "g2", "g3", "g5", "g7", \
+ "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
+ "i0", "i1", "i2", "i3", "i4", "i5", \
+ "o0", "o1", "o2", "o3", "o4", "o5"); \
switch_continue: } while(0)
/* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
--- /dev/null
+/* $Id: timer.h,v 1.1 1997/07/23 10:38:00 davem Exp $
+ * timer.h: System timer definitions for sun5.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_TIMER_H
+#define _SPARC64_TIMER_H
+
+/* How timers work:
+ *
+ * On uniprocessors we just use counter zero for the system wide
+ * ticker, this performs thread scheduling, clock book keeping,
+ * and runs timer based events. Previously we used the Ultra
+ * %tick interrupt for this purpose.
+ *
+ * On multiprocessors we pick one cpu as the master level 10 tick
+ * processor. Here this counter zero tick handles clock book
+ * keeping and timer events only. Each Ultra has it's level
+ * 14 %tick interrupt set to fire off as well, even the master
+ * tick cpu runs this locally. This ticker performs thread
+ * scheduling, system/user tick counting for the current thread,
+ * and also profiling if enabled.
+ */
+
+/* Two timers, traditionally steered to PIL's 10 and 14 respectively.
+ * But since INO packets are used on sun5, we could use any PIL level
+ * we like, however for now we use the normal ones.
+ *
+ * The 'reg' and 'interrupts' properties for these live in nodes named
+ * 'counter-timer'. The first of three 'reg' properties describe where
+ * the sun5_timer registers are. The other two I have no idea. (XXX)
+ */
+struct sun5_timer {
+ u64 count0;
+ u64 limit0;
+ u64 count1;
+ u64 limit1;
+};
+
+#define SUN5_LIMIT_ENABLE 0x80000000
+#define SUN5_LIMIT_TOZERO 0x40000000
+#define SUN5_LIMIT_ZRESTART 0x20000000
+#define SUN5_LIMIT_CMASK 0x1fffffff
+
+/* Given a HZ value, set the limit register to so that the timer IRQ
+ * gets delivered that often.
+ */
+#define SUN5_HZ_TO_LIMIT(__hz) (1000000/(__hz))
+
+#endif /* _SPARC64_TIMER_H */
int (*d_revalidate)(struct dentry *);
};
+/* d_flags entries */
+#define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */
+
/*
* d_drop() unhashes the entry from the parent
* dentry hashes, so that it won't be found through
}
extern int check_disk_change(kdev_t dev);
-extern void invalidate_inodes(kdev_t dev);
+extern int invalidate_inodes(kdev_t dev);
extern void invalidate_inode_pages(struct inode *);
extern void invalidate_buffers(kdev_t dev);
extern int floppy_is_wp(int minor);
#define PC110PAD_MINOR 9
#define RTC_MINOR 135
#define SUN_OPENPROM_MINOR 139
+#define NVRAM_MINOR 144
#define MISC_DYNAMIC_MINOR 255
extern int misc_init(void);
unsigned long offset;
struct page *next_hash;
atomic_t count;
+ unsigned int age;
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
- unsigned dirty:16,
- age:8;
struct wait_queue *wait;
struct page **pprev_hash;
struct buffer_head * buffers;
#define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
-#ifdef CONFIG_ATARI
-#define EOF_FAT12 0xFFF /* Atari GEMDOS fs uses a different EOF */
-#define EOF_FAT16 0xFFFF
-#else
#define EOF_FAT12 0xFF8 /* standard EOF */
#define EOF_FAT16 0xFFF8
-#endif
+#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 16 ? 0xFFF8 : 0xFF8)
/*
* Inode flags
isvfat:1, /* 0=no vfat long filename support, 1=vfat support */
unicode_xlate:1, /* create escape sequences for unhandled Unicode */
posixfs:1, /* Allow names like makefile and Makefile to coexist */
- numtail:1; /* Does first alias have a numeric '~1' type tail? */
+ numtail:1, /* Does first alias have a numeric '~1' type tail? */
+ atari:1; /* Use Atari GEMDOS variation of MS-DOS fs */
};
--- /dev/null
+#ifndef _LINUX_NVRAM_H
+#define _LINUX_NVRAM_H
+
+#include <linux/ioctl.h>
+
+/* /dev/nvram ioctls */
+#define NVRAM_INIT _IO('p', 0x40) /* initialize NVRAM and set checksum */
+#define NVRAM_SETCKS _IO('p', 0x41) /* recalculate checksum */
+
+#ifdef __KERNEL__
+extern unsigned char nvram_read_byte( int i );
+extern void nvram_write_byte( unsigned char c, int i );
+extern int nvram_check_checksum( void );
+extern void nvram_set_checksum( void );
+extern int nvram_init( void );
+#endif
+
+#endif /* _LINUX_NVRAM_H */
};
extern struct inode_operations *
proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, struct qstr *, struct inode **),
+ int (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***);
extern void proc_openprom_deregister(void);
#define get_video_num_columns(dummy) video_num_columns
#define get_video_num_lines(dummy) video_num_lines
#define get_video_size_row(dummy) video_size_row
+#endif
+
extern unsigned long video_num_columns;
extern unsigned long video_num_lines;
extern unsigned long video_size_row;
-#endif
-
extern unsigned char video_type;
extern unsigned long video_mem_base;
extern unsigned long video_mem_term;
/* how to access screen memory */
-#include <linux/config.h>
-
#if defined(CONFIG_TGA_CONSOLE)
extern int tga_blitc(unsigned int, unsigned long);
static inline void scr_writew(unsigned short val, unsigned short * addr)
{
+#ifdef __powerpc__
+ st_le16(addr, val);
+#else
if ((long) addr < 0)
*addr = val;
else
writew(val, (unsigned long) addr);
+#endif /* !__powerpc__ */
}
static inline unsigned short scr_readw(unsigned short * addr)
{
+#ifdef __powerpc__
+ return ld_le16(addr);
+#else
if ((long) addr < 0)
return *addr;
return readw((unsigned long) addr);
+#endif /* !__powerpc__ */
}
#endif /* CONFIG_TGA_CONSOLE */
/* -*- linux-c -*-
*
- * $Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ * $Id: sysrq.h,v 1.3 1997/07/17 11:54:33 mj Exp $
*
* Linux Magic System Request Key Hacks
*
#include <linux/config.h>
+struct pt_regs;
+struct kbd_struct;
+struct tty_struct;
+
+/* Generic SysRq interface -- you may call it from any device driver, supplying
+ * ASCII code of the key, pointer to registers and kbd/tty structs (if they
+ * are available -- else NULL's).
+ */
+
+void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+
+/* Deferred actions */
+
extern int emergency_sync_scheduled;
#define EMERG_SYNC 1
#define EMERG_REMOUNT 2
-extern void do_emergency_sync(void);
+void do_emergency_sync(void);
#ifdef CONFIG_MAGIC_SYSRQ
#define CHECK_EMERGENCY_SYNC \
return str;
}
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
}
continue;
+ case 'I': /* IPv4 / IPv6 printout */
+ {
+ __u8 *ip4;
+ char sbuf[6];
+ if (qualifier == 'l') {
+ __u16 *ip6 = va_arg(args, __u16 *);
+ i = 6;
+ for ( ; i > 0; --i, ++ip6)
+ if (*ip6 != 0)
+ break;
+ if (i < 6)
+ *str++ = ':';
+ for ( ; i > 0; --i, ++ip6) {
+ sprintf(sbuf,":%04x",(int)(*ip6));
+ s = sbuf;
+ while (*s)
+ *str++ = *s++;
+ }
+ *str++ = ':';
+ ip4 = (__u8*) ip6;
+ } else {
+ ip4 = va_arg(args, __u8 *);
+ }
+ for (i = 0; i < 4; ++i, ++ip4) {
+ if (i == 3)
+ sprintf(sbuf,"%d", 0xFF & (*ip4));
+ else
+ sprintf(sbuf,"%d.", 0xFF & (*ip4));
+ s = sbuf;
+ while (*s)
+ *str++ = *s++;
+ }
+ }
+ continue;
+
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
inode->i_nrpages--;
if ((*p = page->next) != NULL)
(*p)->prev = page->prev;
- page->dirty = 0;
page->next = NULL;
page->prev = NULL;
remove_page_from_hash_queue(page);
inode->i_nrpages--;
if ((*p = page->next) != NULL)
(*p)->prev = page->prev;
- page->dirty = 0;
page->next = NULL;
page->prev = NULL;
remove_page_from_hash_queue(page);
*/
#include <linux/simp.h>
+#include <linux/tasks.h>
#include <linux/smp.h>
#include <linux/mm.h>
#include <asm/spinlock.h>
simp->usable_list = hdr;
}
-
/* current x86 memcpy() is horribly moving around registers for nothing,
* is doing unnecessary work if the size is dividable by a power-of-two,
* and it clobbers way too many registers.
because a single frame in the data stream has been lost). Given a
mathematician with some queue theory you can show this allows you to
lose one frame per window full of data without measurable speed loss.
+[done]
4. RFC1323. These are the extensions for very fast nets.
RFC1323 will be useful for Linux talking to systems over 100Mb/sec
ethernet and over ATM as it allows large windows and protects from some
potential high speed TCP problems.
+[In progress]
6. Delayed ack. This is mostly supported but not actually set up and
used yet. Basically ack frames are held back 1/10th of a second in the hope
that two acks can be merged into one or for interactive use the ack can
piggyback on the next character typed (great improvement on 2400 baud
modems). Johannes Stille did some work on this about 0.99.13 but it never
-got merged in. [Pedro Roque]
+got merged in. [Pedro Roque] [Done, but needs fixing]
7. One on my tempting project list. Add an extra (unofficial - but so
is SLIP6) SLIP mode that does packet data compression [maybe use the code
a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
Mike McLagan][Fritz Elfert is doing the isdn4linux kit].
-11. IP over SCSI.
+11. IP over SCSI. [worked on]
14. Bidirectional PLIP. Also PLIP for the newer style parallel ports.
bp[14] |= AX25_EBIT;
bp[14] |= AX25_SSSID_SPARE;
+ skb_pull(skb, AX25_KISS_HEADER_LEN);
+
if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb, FREE_WRITE);
unsigned char *bp;
int len;
- skb_pull(skb, 1); /* skip KISS command */
-
len = digi->ndigi * AX25_ADDR_LEN;
if (skb_headroom(skb) < len) {
struct device *dev;
- size = sprintf(buffer, "Inter-| Receive | Transmit\n"
- " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier\n");
+ size = sprintf(buffer,
+ "Inter-| Receive | Transmit\n"
+ " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier\n");
pos+=size;
len+=size;
* This was very pretty but didn't work when a socket is destroyed
* at the wrong moment (eg a syn recv socket getting a reset), or
* a memory timer destroy. Instead of playing with timers we just
- * concede defeat and cli().
+ * concede defeat and do a start_bh_atomic().
*/
SOCKHASH_LOCK();
sp = pro->sklist_next;
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
+ * Version: $Id: tcp.c,v 1.67 1997/07/20 12:46:07 freitag Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Eric Schenk : Fix fast close down bug with
* shutdown() followed by close().
*
- * To Fix:
- * Fast path the code. Two things here - fix the window calculation
- * so it doesn't iterate over the queue, also spot packets with no funny
- * options arriving in order and process directly.
- *
- * Rewrite output state machine to use a single queue.
- * Speed up input assembly algorithm.
- * RFC1323 - PAWS and window scaling.[Required for IPv6]
- * User settable/learned rtt/max window/mtu
- *
- * Change the fundamental structure to a single send queue maintained
- * by TCP (removing the bogus ip stuff [thus fixing mtu drops on
- * active routes too]). Cut the queue off in tcp_retransmit/
- * tcp_transmit.
- * Change the receive queue to assemble as it goes. This lets us
- * dispose of most of tcp_sequence, half of tcp_ack and chunks of
- * tcp_data/tcp_read as well as the window shrink crud.
- * Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
- * tcp_queue_skb seem obvious routines to extract.
- *
* 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
* for violations and the like. tcp.c is just too big... If I say something
* "does?" or "doesn't?", it means I'm not sure, and will have to hash it out
* with Alan. -- MS 950903
+ * [Note: Most of the TCP code has been rewriten/redesigned since this
+ * RFC1122 check. It is probably not correct anymore. It should be redone
+ * before 2.2. -AK]
*
* Use of PSH (4.2.2.2)
* MAY aggregate data sent without the PSH flag. (does)
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.51 1997/07/04 23:35:02 freitag Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.52 1997/07/23 15:19:10 freitag Exp $
*
* IPv4 specific functions
*
/* Check for syn retransmission */
flg = *(((u32 *)skb->h.th) + 3);
- flg &= __constant_htonl(0x002f0000);
+ flg &= __constant_htonl(0x001f0000);
if ((flg == __constant_htonl(0x00020000)) &&
(!after(skb->seq, req->rcv_isn))) {
/* retransmited syn
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
+ * $Id: route.c,v 1.13 1997/07/19 11:11:35 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
arg->len += sprintf(arg->buffer + arg->len,
" %08lx %08x %08x %08lx %8s\n",
- rt->rt6i_metric, rt->rt6i_use,
- rt->rt6i_ref, rt->rt6i_flags,
+ rt->rt6i_metric, atomic_read(&rt->rt6i_use),
+ atomic_read(&rt->rt6i_ref), rt->rt6i_flags,
rt->rt6i_dev ? rt->rt6i_dev->name : "");
}
}
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.33 1997/06/06 20:38:10 freitag Exp $
+ * $Id: tcp_ipv6.c,v 1.35 1997/07/23 15:18:04 freitag Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
{
struct tcp_opt tp;
struct open_request *req;
- __u16 req_mss;
/* If the socket is dead, don't accept the connection. */
if (sk->dead) {
/* Check for syn retransmission */
flg = *(((u32 *)skb->h.th) + 3);
- flg &= __constant_htonl(0x002f0000);
+ flg &= __constant_htonl(0x001f0000);
if ((flg == __constant_htonl(0x00020000)) &&
(!after(skb->seq, req->rcv_isn))) {