conv=text (Carriage return, line feed) is replaced with newline.
conv=auto Chooses, file by file, conv=binary or conv=text (by guessing)
-There is one mount option unique to HPFS.
+There are mount options unique to HPFS.
case=lower Convert file names to lower case. [default]
case=asis Return file names as is, in mixed case.
+ nocheck Proceed even if "Improperly stopped flag is set"
+
Case is not significant in filename matching, like real HPFS.
VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 47
+SUBLEVEL = 48
ARCH = i386
oldconfig: symlinks
$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
-xconfig: symlinks scripts/kconfig.tk
- wish -f scripts/kconfig.tk
-
-scripts/kconfig.tk:
+xconfig: symlinks
$(MAKE) -C scripts kconfig.tk
+ wish -f scripts/kconfig.tk
config: symlinks
$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
envval, sizeof(envval));
if (nbytes > 0) {
envval[nbytes] = '\0';
- strcpy((char*)ZERO_PGE, envval);
+ strcpy((char*)ZERO_PAGE, envval);
}
printk(" Ok\nNow booting the kernel\n");
#
# CONFIG_BLK_DEV_HD is not set
CONFIG_BLK_DEV_IDE=y
-# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDEATAPI is not set
# CONFIG_BLK_DEV_TRITON is not set
# CONFIG_BLK_DEV_XD is not set
# Networking options
#
# CONFIG_FIREWALL is not set
+# CONFIG_NET_ALIAS is not set
CONFIG_INET=y
# CONFIG_IP_FORWARD is not set
# CONFIG_IP_MULTICAST is not set
# CONFIG_MS_BUSMOUSE is not set
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
#
# Sound
pcibios_write_config_byte(dev->bus->number, dev->devfn,
PCI_INTERRUPT_LINE, dev->irq);
#endif
+ /*
+ * if its a VGA, enable its BIOS ROM at C0000
+ */
+ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+ pcibios_write_config_dword(dev->bus->number, dev->devfn,
+ PCI_ROM_ADDRESS,
+ 0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+ }
}
if (ide_base) {
enable_ide(ide_base);
if (pirq < 0) {
continue;
}
+ /*
+ * if its a VGA, enable its BIOS ROM at C0000
+ */
+ if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) {
+ pcibios_write_config_dword(dev->bus->number, dev->devfn,
+ PCI_ROM_ADDRESS,
+ 0x000c0000 | PCI_ROM_ADDRESS_ENABLE);
+ }
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
continue; /* for now, displays get no IRQ */
}
/* must set the PCI IRQs to level triggered */
/* assume they are all >= 8 */
level_bits |= (1 << (dev->irq - 8));
- outb(level_bits, 0x4d1);
#if PCI_MODIFY
/* tell the device: */
PCI_INTERRUPT_LINE, dev->irq);
#endif
}
+ /* now, set any level-triggered IRQs */
+ if (level_bits)
+ outb(level_bits, 0x4d1);
+
#if PCI_MODIFY
{
#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/hwrpb.h>
#include <asm/dma.h>
* initialized, we need to copy things out into a more permanent
* place.
*/
-#define PARAM ZERO_PGE
+#define PARAM ZERO_PAGE
#define COMMAND_LINE ((char*)(PARAM + 0x0000))
#define COMMAND_LINE_SIZE 256
#include <asm/pgtable.h>
extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void tbi(unsigned long type, unsigned long arg);
-#define tbisi(x) tbi(1,(x))
-#define tbisd(x) tbi(2,(x))
-#define tbis(x) tbi(3,(x))
/*
* This routine handles page faults. It determines the address,
return pte_mkdirty(mk_pte((unsigned long) EMPTY_PGE, PAGE_SHARED));
}
-unsigned long __zero_page(void)
-{
- memset((void *) ZERO_PGE, 0, PAGE_SIZE);
- return (unsigned long) ZERO_PGE;
-}
-
void show_mem(void)
{
int i,free = 0,total = 0,reserved = 0;
/* unmap the console stuff: we don't need it, and we don't want it */
/* Also set up the real kernel PCB while we're at it.. */
- memset((void *) ZERO_PGE, 0, PAGE_SIZE);
+ memset((void *) ZERO_PAGE, 0, PAGE_SIZE);
memset(swapper_pg_dir, 0, PAGE_SIZE);
newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL);
HEAD = head.o
SYSTEM = $(TOPDIR)/vmlinux
-OBJECTS = $(HEAD) inflate.o unzip.o misc.o
+OBJECTS = $(HEAD) misc.o
CFLAGS = -O2 -DSTDC_HEADERS
--- /dev/null
+#
+# linux/arch/i386/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+OBJECTS = misc.o
+
+CFLAGS = -g -O2 -DSTDC_HEADERS -DSTANDALONE_DEBUG -Wall
+
+test-gzip: piggy.o $(OBJECTS)
+ $(CC) -g -o test-gzip $(OBJECTS) piggy.o
+
+clean:
+ $(RM) inflate.o misc.o test-gzip
+
+inflate.o: inflate.c gzip.h
+
+misc.o: misc.c gzip.h
+
+
+++ /dev/null
-/* crypt.h (dummy version) -- do not perform encryption
- * Hardly worth copyrighting :-)
- */
-
-#ifdef CRYPT
-# undef CRYPT /* dummy version */
-#endif
-
-#define RAND_HEAD_LEN 12 /* length of encryption random header */
-
-#define zencode
-#define zdecode
+++ /dev/null
-/* gzip.h -- common declarations for all gzip modules
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if defined(__STDC__) || defined(PROTO)
-# define OF(args) args
-#else
-# define OF(args) ()
-#endif
-
-#ifdef __STDC__
- typedef void *voidp;
-#else
- typedef char *voidp;
-#endif
-
-/* I don't like nested includes, but the string functions are used too often */
-#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
-# include <string.h>
-# define memzero(s, n) memset ((s), 0, (n))
-#else
-# include <strings.h>
-# define strchr index
-# define strrchr rindex
-# define memcpy(d, s, n) bcopy((s), (d), (n))
-# define memcmp(s1, s2, n) bcmp((s1), (s2), (n))
-# define memzero(s, n) bzero((s), (n))
-#endif
-
-#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
-# include <memory.h>
-#endif
-
-#ifndef RETSIGTYPE
-# define RETSIGTYPE void
-#endif
-
-#define local static
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-/* Return codes from gzip */
-#define OK 0
-#define ERROR 1
-#define WARNING 2
-
-/* Compression methods (see algorithm.doc) */
-#define STORED 0
-#define COMPRESSED 1
-#define PACKED 2
-/* methods 3 to 7 reserved */
-#define DEFLATED 8
-extern int method; /* compression method */
-
-/* To save memory for 16 bit systems, some arrays are overlayed between
- * the various modules:
- * deflate: prev+head window d_buf l_buf outbuf
- * unlzw: tab_prefix tab_suffix stack inbuf outbuf
- * inflate: window inbuf
- * unpack: window inbuf
- * For compression, input is done in window[]. For decompression, output
- * is done in window except for unlzw.
- */
-
-#ifndef INBUFSIZ
-# define INBUFSIZ 0x8000 /* input buffer size */
-#endif
-#define INBUF_EXTRA 64 /* required by unlzw() */
-
-#ifndef OUTBUFSIZ
-# define OUTBUFSIZ 16384 /* output buffer size */
-#endif
-#define OUTBUF_EXTRA 2048 /* required by unlzw() */
-
-#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
-
-#ifdef DYN_ALLOC
-# define EXTERN(type, array) extern type * near array
-# define DECLARE(type, array, size) type * near array
-# define ALLOC(type, array, size) { \
- array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
- if (array == NULL) error("insufficient memory"); \
- }
-# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
-#else
-# define EXTERN(type, array) extern type array[]
-# define DECLARE(type, array, size) type array[size]
-# define ALLOC(type, array, size)
-# define FREE(array)
-#endif
-
-EXTERN(uch, inbuf); /* input buffer */
-EXTERN(uch, outbuf); /* output buffer */
-EXTERN(ush, d_buf); /* buffer for distances, see trees.c */
-EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */
-#define tab_suffix window
-#ifndef MAXSEG_64K
-# define tab_prefix prev /* hash link (see deflate.c) */
-# define head (prev+WSIZE) /* hash head (see deflate.c) */
- EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */
-#else
-# define tab_prefix0 prev
-# define head tab_prefix1
- EXTERN(ush, tab_prefix0); /* prefix for even codes */
- EXTERN(ush, tab_prefix1); /* prefix for odd codes */
-#endif
-
-extern unsigned insize; /* valid bytes in inbuf */
-extern unsigned inptr; /* index of next byte to be processed in inbuf */
-extern unsigned outcnt; /* bytes in output buffer */
-
-extern long bytes_in; /* number of input bytes */
-extern long bytes_out; /* number of output bytes */
-extern long overhead; /* number of bytes in gzip header */
-
-#define isize bytes_in
-/* for compatibility with old zip sources (to be cleaned) */
-
-extern int ifd; /* input file descriptor */
-extern int ofd; /* output file descriptor */
-extern char ifname[]; /* input filename or "stdin" */
-extern char ofname[]; /* output filename or "stdout" */
-
-extern ulg time_stamp; /* original time stamp (modification time) */
-extern long ifile_size; /* input file size, -1 for devices (debug only) */
-
-extern int exit_code; /* program exit code */
-
-typedef int file_t; /* Do not use stdio */
-#define NO_FILE (-1) /* in memory compression */
-
-
-#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */
-#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
-#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */
-#define PACK_MAGIC "\037\036" /* Magic header for packed files */
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-/* internal file attribute */
-#define UNKNOWN (-1)
-#define BINARY 0
-#define ASCII 1
-
-#ifndef WSIZE
-# define WSIZE 0x8000 /* window size--must be a power of two, and */
-#endif /* at least 32K for zip's deflate method */
-
-#define MIN_MATCH 3
-#define MAX_MATCH 258
-/* The minimum and maximum match lengths */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST (WSIZE-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-extern int decrypt; /* flag to turn on decryption */
-extern int save_orig_name; /* set if original name must be saved */
-extern int verbose; /* be verbose (-v) */
-extern int level; /* compression level */
-extern int test; /* check .z file integrity */
-extern int to_stdout; /* output to stdout (-c) */
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* put_byte is used for the compressed output, put_char for the
- * uncompressed output. However unlzw() uses window for its
- * suffix table instead of its output buffer, so it does not use put_char.
- * (to be cleaned up).
- */
-#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
- flush_outbuf();}
-#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
- flush_window();}
-
-/* Output a 16 bit value, lsb first */
-#define put_short(w) \
-{ if (outcnt < OUTBUFSIZ-2) { \
- outbuf[outcnt++] = (uch) ((w) & 0xff); \
- outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
- } else { \
- put_byte((uch)((w) & 0xff)); \
- put_byte((uch)((ush)(w) >> 8)); \
- } \
-}
-
-/* Output a 32 bit value to the bit stream, lsb first */
-#define put_long(n) { \
- put_short((n) & 0xffff); \
- put_short(((ulg)(n)) >> 16); \
-}
-
-#define seekable() 0 /* force sequential output */
-#define translate_eol 0 /* no option -a yet */
-
-#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */
-
-/* Macros for getting two-byte and four-byte header values */
-#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
-#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
-
-/* Diagnostic functions */
-#ifdef DEBUG
-# define Assert(cond,msg) {if(!(cond)) error(msg);}
-# define Trace(x) fprintf x
-# define Tracev(x) {if (verbose) fprintf x ;}
-# define Tracevv(x) {if (verbose>1) fprintf x ;}
-# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-# define Assert(cond,msg)
-# define Trace(x)
-# define Tracev(x)
-# define Tracevv(x)
-# define Tracec(c,x)
-# define Tracecv(c,x)
-#endif
-
- /* in zip.c: */
-extern void zip OF((int in, int out));
-extern int file_read OF((char *buf, unsigned size));
-
- /* in unzip.c */
-extern void unzip OF((int in, int out));
-extern int check_zipfile OF((int in));
-
- /* in unpack.c */
-extern void unpack OF((int in, int out));
-
- /* in gzip.c */
-RETSIGTYPE abort_gzip OF((void));
-
- /* in deflate.c */
-void lm_init OF((int pack_level, ush *flags));
-ulg deflate OF((void));
-
- /* in trees.c */
-void ct_init OF((ush *attr, int *method));
-int ct_tally OF((int dist, int lc));
-ulg flush_block OF((char *buf, ulg stored_len, int eof));
-
- /* in bits.c */
-void bi_init OF((file_t zipfile));
-void send_bits OF((int value, int length));
-unsigned bi_reverse OF((unsigned value, int length));
-void bi_windup OF((void));
-void copy_block OF((char *buf, unsigned len, int header));
-extern int (*read_buf) OF((char *buf, unsigned size));
-
- /* in util.c: */
-extern ulg updcrc OF((uch *s, unsigned n));
-extern void clear_bufs OF((void));
-extern int fill_inbuf OF((void));
-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 *add_envopt OF((int *argcp, char ***argvp, char *env));
-extern void error OF((char *m));
-extern void warn OF((char *a, char *b));
-extern void read_error OF((void));
-extern void write_error OF((void));
-extern void display_ratio OF((long num, long den));
-extern voidp xmalloc OF((unsigned int size));
-
- /* in inflate.c */
-extern int inflate OF((void));
+++ /dev/null
-#define DEBG(x)
-#define DEBG1(x)
-/* inflate.c -- Not copyrighted 1992 by Mark Adler
- version c10p1, 10 January 1993 */
-
-/*
- * Adapted for booting Linux by Hannu Savolainen 1993
- * based on gzip-1.0.3
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#define slide window
-
-#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
-# include <sys/types.h>
-# include <stdlib.h>
-#endif
-
-struct huft {
- uch e; /* number of extra bits or operation */
- uch b; /* number of bits in this code or subcode */
- union {
- ush n; /* literal, length base, or distance base */
- struct huft *t; /* pointer to next level of table */
- } v;
-};
-
-
-/* Function prototypes */
-int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
- struct huft **, int *));
-int huft_free OF((struct huft *));
-int inflate_codes OF((struct huft *, struct huft *, int, int));
-int inflate_stored OF((void));
-int inflate_fixed OF((void));
-int inflate_dynamic OF((void));
-int inflate_block OF((int *));
-int inflate OF((void));
-
-
-#define wp outcnt
-#define flush_output(w) (wp=(w),flush_window())
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static unsigned border[] = { /* Order of the bit length code lengths */
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
- 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
- /* note: see note #13 above about the 258 in this list. */
-static ush cplext[] = { /* Extra bits for literal codes 257..285 */
- 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
-static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
- 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
- 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
- 8193, 12289, 16385, 24577};
-static ush cpdext[] = { /* Extra bits for distance codes */
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
- 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
- 12, 12, 13, 13};
-
-
-ulg bb; /* bit buffer */
-unsigned bk; /* bits in bit buffer */
-
-ush mask_bits[] = {
- 0x0000,
- 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
- 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-#ifdef CRYPT
- uch cc;
-# define NEXTBYTE() \
- (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
-#else
-# define NEXTBYTE() (uch)get_byte()
-#endif
-#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
-#define DUMPBITS(n) {b>>=(n);k-=(n);}
-
-int lbits = 9; /* bits in base literal/length lookup table */
-int dbits = 6; /* bits in base distance lookup table */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-#define BMAX 16 /* maximum bit length of any code (16 for explode) */
-#define N_MAX 288 /* maximum number of codes in any set */
-
-
-unsigned hufts; /* track memory usage */
-
-
-int huft_build(b, n, s, d, e, t, m)
-unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
-unsigned n; /* number of codes (assumed <= N_MAX) */
-unsigned s; /* number of simple-valued codes (0..s-1) */
-ush *d; /* list of base values for non-simple codes */
-ush *e; /* list of extra bits for non-simple codes */
-struct huft **t; /* result: starting table */
-int *m; /* maximum lookup bits, returns actual */
-/* Given a list of code lengths and a maximum table size, make a set of
- tables to decode that set of codes. Return zero on success, one if
- the given code set is incomplete (the tables are still built in this
- case), two if the input is invalid (all zero length codes or an
- oversubscribed set of lengths), and three if not enough memory. */
-{
- unsigned a; /* counter for codes of length k */
- unsigned c[BMAX+1]; /* bit length count table */
- unsigned f; /* i repeats in table every f entries */
- int g; /* maximum code length */
- int h; /* table level */
- register unsigned i; /* counter, current code */
- register unsigned j; /* counter */
- register int k; /* number of bits in current code */
- int l; /* bits per table (returned in m) */
- register unsigned *p; /* pointer into c[], b[], or v[] */
- register struct huft *q; /* points to current table */
- struct huft r; /* table entry for structure assignment */
- struct huft *u[BMAX]; /* table stack */
- unsigned v[N_MAX]; /* values in order of bit length */
- register int w; /* bits before this table == (l * h) */
- unsigned x[BMAX+1]; /* bit offsets, then code stack */
- unsigned *xp; /* pointer into x */
- int y; /* number of dummy codes added */
- unsigned z; /* number of entries in current table */
-
-DEBG("huft1 ");
-
- /* Generate counts for each bit length */
- memzero(c, sizeof(c));
- p = b; i = n;
- do {
- c[*p++]++; /* assume all entries <= BMAX */
- } while (--i);
- if (c[0] == n) /* null input--all zero length codes */
- {
- *t = (struct huft *)NULL;
- *m = 0;
- return 0;
- }
-
-DEBG("huft2 ");
-
- /* Find minimum and maximum length, bound *m by those */
- l = *m;
- for (j = 1; j <= BMAX; j++)
- if (c[j])
- break;
- k = j; /* minimum code length */
- if ((unsigned)l < j)
- l = j;
- for (i = BMAX; i; i--)
- if (c[i])
- break;
- g = i; /* maximum code length */
- if ((unsigned)l > i)
- l = i;
- *m = l;
-
-DEBG("huft3 ");
-
- /* Adjust last length count to fill out codes, if needed */
- for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= c[j]) < 0)
- return 2; /* bad input: more codes than bits */
- if ((y -= c[i]) < 0)
- return 2;
- c[i] += y;
-
-DEBG("huft4 ");
-
- /* Generate starting offsets into the value table for each length */
- x[1] = j = 0;
- p = c + 1; xp = x + 2;
- while (--i) { /* note that i == g from above */
- *xp++ = (j += *p++);
- }
-
-DEBG("huft5 ");
-
- /* Make a table of values in order of bit lengths */
- p = b; i = 0;
- do {
- if ((j = *p++) != 0)
- v[x[j]++] = i;
- } while (++i < n);
-
-DEBG("h6 ");
-
- /* Generate the Huffman codes and for each, make the table entries */
- x[0] = i = 0; /* first Huffman code is zero */
- p = v; /* grab values in bit order */
- h = -1; /* no tables yet--level -1 */
- w = -l; /* bits decoded == (l * h) */
- u[0] = (struct huft *)NULL; /* just to keep compilers happy */
- q = (struct huft *)NULL; /* ditto */
- z = 0; /* ditto */
-DEBG("h6a ");
-
- /* go through the bit lengths (k already is bits in shortest code) */
- for (; k <= g; k++)
- {
-DEBG("h6b ");
- a = c[k];
- while (a--)
- {
-DEBG("h6b1 ");
- /* here i is the Huffman code of length k bits for value *p */
- /* make tables up to required level */
- while (k > w + l)
- {
-DEBG1("1 ");
- h++;
- w += l; /* previous table always l bits */
-
- /* compute minimum size table less than or equal to l bits */
- z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
- if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
- { /* too few codes for k-w bit table */
-DEBG1("2 ");
- f -= a + 1; /* deduct codes from patterns left */
- xp = c + k;
- while (++j < z) /* try smaller tables up to z bits */
- {
- if ((f <<= 1) <= *++xp)
- break; /* enough codes to use up j bits */
- f -= *xp; /* else deduct codes from patterns */
- }
- }
-DEBG1("3 ");
- z = 1 << j; /* table entries for j-bit table */
-
- /* allocate and link in new table */
- q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
-DEBG1("4 ");
- hufts += z + 1; /* track memory usage */
- *t = q + 1; /* link to list for huft_free() */
- *(t = &(q->v.t)) = (struct huft *)NULL;
- u[h] = ++q; /* table starts after link */
-
-DEBG1("5 ");
- /* connect to last table, if there is one */
- if (h)
- {
- x[h] = i; /* save pattern for backing up */
- r.b = (uch)l; /* bits to dump before this table */
- r.e = (uch)(16 + j); /* bits in this table */
- r.v.t = q; /* pointer to this table */
- j = i >> (w - l); /* (get around Turbo C bug) */
- u[h-1][j] = r; /* connect to last table */
- }
-DEBG1("6 ");
- }
-DEBG("h6c ");
-
- /* set up table entry in r */
- r.b = (uch)(k - w);
- if (p >= v + n)
- r.e = 99; /* out of values--invalid code */
- else if (*p < s)
- {
- r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
- r.v.n = *p++; /* simple code is just the value */
- }
- else
- {
- r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
- r.v.n = d[*p++ - s];
- }
-DEBG("h6d ");
-
- /* fill code-like entries with r */
- f = 1 << (k - w);
- for (j = i >> w; j < z; j += f)
- q[j] = r;
-
- /* backwards increment the k-bit code i */
- for (j = 1 << (k - 1); i & j; j >>= 1)
- i ^= j;
- i ^= j;
-
- /* backup over finished tables */
- while ((i & ((1 << w) - 1)) != x[h])
- {
- h--; /* don't need to update q */
- w -= l;
- }
-DEBG("h6e ");
- }
-DEBG("h6f ");
- }
-
-DEBG("huft7 ");
-
- /* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
-}
-
-
-
-int huft_free(t)
-struct huft *t; /* table to free */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
- list of the tables it made, with the links in a dummy first entry of
- each table. */
-{
- register struct huft *p, *q;
-
-
- /* Go through linked list, freeing from the malloced (t[-1]) address. */
- p = t;
- while (p != (struct huft *)NULL)
- {
- q = (--p)->v.t;
- free(p);
- p = q;
- }
- return 0;
-}
-
-
-int inflate_codes(tl, td, bl, bd)
-struct huft *tl, *td; /* literal/length and distance decoder tables */
-int bl, bd; /* number of bits decoded by tl[] and td[] */
-/* inflate (decompress) the codes in a deflated (compressed) block.
- Return an error code or zero if it all goes ok. */
-{
- register unsigned e; /* table entry flag/number of extra bits */
- unsigned n, d; /* length and index for copy */
- unsigned w; /* current window position */
- struct huft *t; /* pointer to table entry */
- unsigned ml, md; /* masks for bl and bd bits */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-
- /* make local copies of globals */
- b = bb; /* initialize bit buffer */
- k = bk;
- w = wp; /* initialize window position */
-
- /* inflate the coded data */
- ml = mask_bits[bl]; /* precompute masks for speed */
- md = mask_bits[bd];
- for (;;) /* do until end of block */
- {
- NEEDBITS((unsigned)bl)
- if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
- do {
- if (e == 99)
- return 1;
- DUMPBITS(t->b)
- e -= 16;
- NEEDBITS(e)
- } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
- DUMPBITS(t->b)
- if (e == 16) /* then it's a literal */
- {
- slide[w++] = (uch)t->v.n;
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- }
- else /* it's an EOB or a length */
- {
- /* exit if end of block */
- if (e == 15)
- break;
-
- /* get length of block to copy */
- NEEDBITS(e)
- n = t->v.n + ((unsigned)b & mask_bits[e]);
- DUMPBITS(e);
-
- /* decode distance of block to copy */
- NEEDBITS((unsigned)bd)
- if ((e = (t = td + ((unsigned)b & md))->e) > 16)
- do {
- if (e == 99)
- return 1;
- DUMPBITS(t->b)
- e -= 16;
- NEEDBITS(e)
- } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
- DUMPBITS(t->b)
- NEEDBITS(e)
- d = w - t->v.n - ((unsigned)b & mask_bits[e]);
- DUMPBITS(e)
-
- /* do the copy */
- do {
- n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
- if (w - d >= e) /* (this test assumes unsigned comparison) */
- {
- memcpy(slide + w, slide + d, e);
- w += e;
- d += e;
- }
- else /* do it slow to avoid memcpy() overlap */
-#endif /* !NOMEMCPY */
- do {
- slide[w++] = slide[d++];
- } while (--e);
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- } while (n);
- }
- }
-
-
- /* restore the globals from the locals */
- wp = w; /* restore global window pointer */
- bb = b; /* restore global bit buffer */
- bk = k;
-
- /* done */
- return 0;
-}
-
-
-
-int inflate_stored()
-/* "decompress" an inflated type 0 (stored) block. */
-{
- unsigned n; /* number of bytes in block */
- unsigned w; /* current window position */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-DEBG("<stor");
-
- /* make local copies of globals */
- b = bb; /* initialize bit buffer */
- k = bk;
- w = wp; /* initialize window position */
-
-
- /* go to byte boundary */
- n = k & 7;
- DUMPBITS(n);
-
-
- /* get the length and its complement */
- NEEDBITS(16)
- n = ((unsigned)b & 0xffff);
- DUMPBITS(16)
- NEEDBITS(16)
- if (n != (unsigned)((~b) & 0xffff))
- return 1; /* error in compressed data */
- DUMPBITS(16)
-
-
- /* read and output the compressed data */
- while (n--)
- {
- NEEDBITS(8)
- slide[w++] = (uch)b;
- if (w == WSIZE)
- {
- flush_output(w);
- w = 0;
- }
- DUMPBITS(8)
- }
-
-
- /* restore the globals from the locals */
- wp = w; /* restore global window pointer */
- bb = b; /* restore global bit buffer */
- bk = k;
-
- DEBG(">");
- return 0;
-}
-
-
-
-int inflate_fixed()
-/* decompress an inflated type 1 (fixed Huffman codes) block. We should
- either replace this with a custom decoder, or at least precompute the
- Huffman tables. */
-{
- int i; /* temporary variable */
- struct huft *tl; /* literal/length code table */
- struct huft *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned l[288]; /* length list for huft_build */
-
-DEBG("<fix");
-
- /* set up literal table */
- for (i = 0; i < 144; i++)
- l[i] = 8;
- for (; i < 256; i++)
- l[i] = 9;
- for (; i < 280; i++)
- l[i] = 7;
- for (; i < 288; i++) /* make a complete, but wrong code set */
- l[i] = 8;
- bl = 7;
- if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
- return i;
-
-
- /* set up distance table */
- for (i = 0; i < 30; i++) /* make an incomplete code set */
- l[i] = 5;
- bd = 5;
- if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
- {
- huft_free(tl);
-
- DEBG(">");
- return i;
- }
-
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
- return 0;
-}
-
-
-
-int inflate_dynamic()
-/* decompress an inflated type 2 (dynamic Huffman codes) block. */
-{
- int i; /* temporary variables */
- unsigned j;
- unsigned l; /* last length */
- unsigned m; /* mask for bit lengths table */
- unsigned n; /* number of lengths to get */
- struct huft *tl; /* literal/length code table */
- struct huft *td; /* distance code table */
- int bl; /* lookup bits for tl */
- int bd; /* lookup bits for td */
- unsigned nb; /* number of bit length codes */
- unsigned nl; /* number of literal/length codes */
- unsigned nd; /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
- unsigned ll[288+32]; /* literal/length and distance code lengths */
-#else
- unsigned ll[286+30]; /* literal/length and distance code lengths */
-#endif
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
-DEBG("<dyn");
-
- /* make local bit buffer */
- b = bb;
- k = bk;
-
-
- /* read in table lengths */
- NEEDBITS(5)
- nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
- DUMPBITS(5)
- NEEDBITS(5)
- nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
- DUMPBITS(5)
- NEEDBITS(4)
- nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
- DUMPBITS(4)
-#ifdef PKZIP_BUG_WORKAROUND
- if (nl > 288 || nd > 32)
-#else
- if (nl > 286 || nd > 30)
-#endif
- return 1; /* bad lengths */
-
-DEBG("dyn1 ");
-
- /* read in bit-length-code lengths */
- for (j = 0; j < nb; j++)
- {
- NEEDBITS(3)
- ll[border[j]] = (unsigned)b & 7;
- DUMPBITS(3)
- }
- for (; j < 19; j++)
- ll[border[j]] = 0;
-
-DEBG("dyn2 ");
-
- /* build decoding table for trees--single level, 7 bit lookup */
- bl = 7;
- if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
- {
- if (i == 1)
- huft_free(tl);
- return i; /* incomplete code set */
- }
-
-DEBG("dyn3 ");
-
- /* read in literal and distance code lengths */
- n = nl + nd;
- m = mask_bits[bl];
- i = l = 0;
- while ((unsigned)i < n)
- {
- NEEDBITS((unsigned)bl)
- j = (td = tl + ((unsigned)b & m))->b;
- DUMPBITS(j)
- j = td->v.n;
- if (j < 16) /* length of code in bits (0..15) */
- ll[i++] = l = j; /* save last length in l */
- else if (j == 16) /* repeat last length 3 to 6 times */
- {
- NEEDBITS(2)
- j = 3 + ((unsigned)b & 3);
- DUMPBITS(2)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = l;
- }
- else if (j == 17) /* 3 to 10 zero length codes */
- {
- NEEDBITS(3)
- j = 3 + ((unsigned)b & 7);
- DUMPBITS(3)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- else /* j == 18: 11 to 138 zero length codes */
- {
- NEEDBITS(7)
- j = 11 + ((unsigned)b & 0x7f);
- DUMPBITS(7)
- if ((unsigned)i + j > n)
- return 1;
- while (j--)
- ll[i++] = 0;
- l = 0;
- }
- }
-
-DEBG("dyn4 ");
-
- /* free decoding table for trees */
- huft_free(tl);
-
-DEBG("dyn5 ");
-
- /* restore the global bit buffer */
- bb = b;
- bk = k;
-
-DEBG("dyn5a ");
-
- /* build the decoding tables for literal/length and distance codes */
- bl = lbits;
- if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
- {
-DEBG("dyn5b ");
- if (i == 1) {
- error(" incomplete literal tree\n");
- huft_free(tl);
- }
- return i; /* incomplete code set */
- }
-DEBG("dyn5c ");
- bd = dbits;
- if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
- {
-DEBG("dyn5d ");
- if (i == 1) {
- error(" incomplete distance tree\n");
-#ifdef PKZIP_BUG_WORKAROUND
- i = 0;
- }
-#else
- huft_free(td);
- }
- huft_free(tl);
- return i; /* incomplete code set */
-#endif
- }
-
-DEBG("dyn6 ");
-
- /* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
-
-DEBG("dyn7 ");
-
- /* free the decoding tables, return */
- huft_free(tl);
- huft_free(td);
-
- DEBG(">");
- return 0;
-}
-
-
-
-int inflate_block(e)
-int *e; /* last block flag */
-/* decompress an inflated block */
-{
- unsigned t; /* block type */
- register ulg b; /* bit buffer */
- register unsigned k; /* number of bits in bit buffer */
-
- DEBG("<blk");
-
- /* make local bit buffer */
- b = bb;
- k = bk;
-
-
- /* read in last block bit */
- NEEDBITS(1)
- *e = (int)b & 1;
- DUMPBITS(1)
-
-
- /* read in block type */
- NEEDBITS(2)
- t = (unsigned)b & 3;
- DUMPBITS(2)
-
-
- /* restore the global bit buffer */
- bb = b;
- bk = k;
-
- /* inflate that block type */
- if (t == 2)
- return inflate_dynamic();
- if (t == 0)
- return inflate_stored();
- if (t == 1)
- return inflate_fixed();
-
- DEBG(">");
-
- /* bad block type */
- return 2;
-}
-
-
-
-int inflate()
-/* decompress an inflated entry */
-{
- int e; /* last block flag */
- int r; /* result code */
- unsigned h; /* maximum struct huft's malloc'ed */
-
-
- /* initialize window, bit buffer */
- wp = 0;
- bk = 0;
- bb = 0;
-
-
- /* decompress until the last block */
- h = 0;
- do {
- hufts = 0;
- if ((r = inflate_block(&e)) != 0)
- return r;
- if (hufts > h)
- h = hufts;
- } while (!e);
-
- /* Undo too much lookahead. The next read will be byte aligned so we
- * can discard unused bits in the last meaningful byte.
- */
- while (bk >= 8) {
- bk -= 8;
- inptr--;
- }
-
- /* flush out slide */
- flush_output(wp);
-
-
- /* return success */
-#ifdef DEBUG
- fprintf(stderr, "<%u> ", h);
-#endif /* DEBUG */
- return 0;
-}
+++ /dev/null
-/* lzw.h -- define the lzw functions.
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if !defined(OF) && defined(lint)
-# include "gzip.h"
-#endif
-
-#ifndef BITS
-# define BITS 16
-#endif
-#define INIT_BITS 9 /* Initial number of bits per code */
-
-#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */
-
-#define BIT_MASK 0x1f /* Mask for 'number of compression bits' */
-/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
- * It's a pity that old uncompress does not check bit 0x20. That makes
- * extension of the format actually undesirable because old compress
- * would just crash on the new format instead of giving a meaningful
- * error message. It does check the number of bits, but it's more
- * helpful to say "unsupported format, get a new version" than
- * "can only handle 16 bits".
- */
-
-#define BLOCK_MODE 0x80
-/* Block compression: if table is full and compression rate is dropping,
- * clear the dictionary.
- */
-
-#define LZW_RESERVED 0x60 /* reserved bits */
-
-#define CLEAR 256 /* flush the dictionary */
-#define FIRST (CLEAR+1) /* first free entry */
-
-extern int maxbits; /* max bits per code for LZW */
-extern int block_mode; /* block compress mode -C compatible with 2.0 */
-
-extern void lzw OF((int in, int out));
-extern void unlzw OF((int in, int out));
* puts by Nick Holloway 1993, better puts by Martin Mares 1995
*/
-#include "gzip.h"
-#include "lzw.h"
+#include <string.h>
#include <asm/segment.h>
#include <asm/io.h>
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+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 */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+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 **);
+
/*
* These are set up by the setup-routine at boot-time:
*/
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
-#define EOF -1
-
-DECLARE(uch, inbuf, INBUFSIZ);
-DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
-DECLARE(uch, window, WSIZE);
-
-unsigned outcnt;
-unsigned insize;
-unsigned inptr;
-
extern char input_data[];
extern int input_len;
-int input_ptr;
-
-int method, exit_code, part_nb, last_member;
-int test = 0;
-int force = 0;
-int verbose = 1;
-long bytes_in, bytes_out;
-
-char *output_data;
-unsigned long output_ptr;
-
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#ifndef STANDALONE_DEBUG
+static void puts(const char *);
+
extern int end;
-long free_mem_ptr = (long)&end;
-
-int to_stdout = 0;
-int hard_math = 0;
+static long free_mem_ptr = (long)&end;
-void (*work)(int inf, int outf);
-void makecrc(void);
+static char *vidmem = (char *)0xb8000;
+static int vidport;
+static int lines, cols;
-local int get_method(int);
+#include "../../../../lib/inflate.c"
-char *vidmem = (char *)0xb8000;
-int vidport;
-int lines, cols;
-
-static void puts(const char *);
-
-void *malloc(int size)
+static void *malloc(int size)
{
void *p;
if (size <0) error("Malloc error\n");
if (free_mem_ptr <= 0) error("Memory error\n");
- while(1) {
free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
p = (void *)free_mem_ptr;
free_mem_ptr += size;
- /*
- * The part of the compressed kernel which has already been expanded
- * is no longer needed. Therefore we can reuse it for malloc.
- * With bigger kernels, this is necessary.
- */
-
- if (free_mem_ptr < (long)&end) {
- if (free_mem_ptr > (long)&input_data[input_ptr])
- error("\nOut of memory\n");
-
- return p;
- }
- if (free_mem_ptr < 0x90000)
+ if (free_mem_ptr >= 0x90000)
+ error("\nOut of memory\n");
+
return p;
- puts("large kernel, low 1M tight...");
- free_mem_ptr = (long)input_data;
- }
}
-void free(void *where)
+static void free(void *where)
{ /* Don't care */
}
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
static void scroll()
{
int i;
for (i=0;i<__n;i++) d[i] = s[i];
}
-
-extern ulg crc_32_tab[]; /* crc table, defined below */
-
-/* ===========================================================================
- * Run a set of bytes through the crc shift register. If s is a NULL
- * pointer, then initialize the crc shift register contents instead.
- * Return the current crc in either case.
- */
-ulg updcrc(s, n)
- uch *s; /* pointer to bytes to pump through */
- unsigned n; /* number of bytes in s[] */
-{
- register ulg c; /* temporary variable */
-
- static ulg crc = (ulg)0xffffffffL; /* shift register contents */
-
- if (s == NULL) {
- c = 0xffffffffL;
- } else {
- c = crc;
- while (n--) {
- c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
- }
- }
- crc = c;
- return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */
-}
-
-/* ===========================================================================
- * Clear input and output buffers
- */
-void clear_bufs()
-{
- outcnt = 0;
- insize = inptr = 0;
- bytes_in = bytes_out = 0L;
-}
+#endif
/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
-int fill_inbuf()
+static int fill_inbuf()
{
- int len, i;
-
- /* Read as much as possible */
- insize = 0;
- do {
- len = INBUFSIZ-insize;
- if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
- if (len == 0 || len == EOF) break;
-
- for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
- insize += len;
- input_ptr += len;
- } while (insize < INBUFSIZ);
-
- if (insize == 0) {
- error("unable to fill buffer\n");
- }
- bytes_in += (ulg)insize;
- inptr = 1;
- return inbuf[0];
+ if (insize != 0) {
+ error("ran out of input data\n");
+ }
+
+ inbuf = input_data;
+ insize = input_len;
+ 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.)
*/
-void flush_window()
+static void flush_window()
{
- if (outcnt == 0) return;
- updcrc(window, outcnt);
-
- memcpy(&output_data[output_ptr], (char *)window, outcnt);
-
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
bytes_out += (ulg)outcnt;
output_ptr += (ulg)outcnt;
outcnt = 0;
}
-/*
- * Code to compute the CRC-32 table. Borrowed from
- * gzip-1.0.3/makecrc.c.
- */
-
-ulg crc_32_tab[256];
-
-void
-makecrc(void)
-{
-/* Not copyrighted 1990 Mark Adler */
-
- unsigned long c; /* crc shift register */
- unsigned long e; /* polynomial exclusive-or pattern */
- int i; /* counter for all possible eight bit values */
- int k; /* byte being shifted into crc apparatus */
-
- /* terms of polynomial defining this crc (except x^32): */
- static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
- /* Make exclusive-or pattern from polynomial */
- e = 0;
- for (i = 0; i < sizeof(p)/sizeof(int); i++)
- e |= 1L << (31 - p[i]);
-
- crc_32_tab[0] = 0;
-
- for (i = 1; i < 256; i++)
- {
- c = 0;
- for (k = i | 256; k != 1; k >>= 1)
- {
- c = c & 1 ? (c >> 1) ^ e : c >> 1;
- if (k & 1)
- c ^= e;
- }
- crc_32_tab[i] = c;
- }
-}
-
-void error(char *x)
+static void error(char *x)
{
puts("\n\n");
puts(x);
short b;
} stack_start = { & user_stack [STACK_SIZE] , KERNEL_DS };
+#ifdef STANDALONE_DEBUG
+
+static void gzip_mark(void **ptr)
+{
+}
+
+static void gzip_release(void **ptr)
+{
+}
+
+char output_buffer[1024 * 800];
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ output_data = output_buffer;
+
+ makecrc();
+ puts("Uncompressing Linux...");
+ gunzip();
+ puts("done.\n");
+ return 0;
+}
+
+#else
+
void decompress_kernel()
{
if (SCREEN_INFO.orig_video_mode == 7) {
if (EXT_MEM_K < 1024) error("<2M of mem\n");
output_data = (char *)0x100000; /* Points to 1M */
- output_ptr = 0;
-
- exit_code = 0;
- test = 0;
- input_ptr = 0;
- part_nb = 0;
-
- clear_bufs();
makecrc();
-
puts("Uncompressing Linux...");
+ gunzip();
+ puts("done.\nNow booting the kernel\n");
+}
+#endif
- method = get_method(0);
-
- work(0, 0);
- puts("done.\n");
- puts("Now booting the kernel\n");
-}
-
-/* ========================================================================
- * Check the magic number of the input file and update ofname if an
- * original name was given and to_stdout is not set.
- * Return the compression method, -1 for error, -2 for warning.
- * Set inptr to the offset of the next byte to be processed.
- * This function may be called repeatedly for an input file consisting
- * of several contiguous gzip'ed members.
- * IN assertions: there is at least one remaining compressed member.
- * If the member is a zip file, it must be the only one.
- */
-local int get_method(in)
- int in; /* input file descriptor */
-{
- uch flags;
- char magic[2]; /* magic header */
-
- magic[0] = (char)get_byte();
- magic[1] = (char)get_byte();
-
- method = -1; /* unknown yet */
- part_nb++; /* number of parts in gzip file */
- last_member = 0;
- /* assume multiple members in gzip file except for record oriented I/O */
-
- if (memcmp(magic, GZIP_MAGIC, 2) == 0
- || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
-
- work = unzip;
- method = (int)get_byte();
- flags = (uch)get_byte();
- if ((flags & ENCRYPTED) != 0)
- error("Input is encrypted\n");
- if ((flags & CONTINUATION) != 0)
- error("Multi part input\n");
- if ((flags & RESERVED) != 0) {
- error("Input has invalid flags\n");
- exit_code = ERROR;
- if (force <= 1) return -1;
- }
- (ulg)get_byte(); /* Get timestamp */
- ((ulg)get_byte()) << 8;
- ((ulg)get_byte()) << 16;
- ((ulg)get_byte()) << 24;
-
- (void)get_byte(); /* Ignore extra flags for the moment */
- (void)get_byte(); /* Ignore OS type for the moment */
-
- if ((flags & EXTRA_FIELD) != 0) {
- unsigned len = (unsigned)get_byte();
- len |= ((unsigned)get_byte())<<8;
- while (len--) (void)get_byte();
- }
- /* Get original file name if it was truncated */
- if ((flags & ORIG_NAME) != 0) {
- if (to_stdout || part_nb > 1) {
- /* Discard the old name */
- while (get_byte() != 0) /* null */ ;
- } else {
- } /* to_stdout */
- } /* orig_name */
-
- /* Discard file comment if any */
- if ((flags & COMMENT) != 0) {
- while (get_byte() != 0) /* null */ ;
- }
- } else
- error("unknown compression method");
- return method;
-}
+++ /dev/null
-/* unzip.c -- decompress files in gzip or pkzip format.
- * Copyright (C) 1992-1993 Jean-loup Gailly
- *
- * Adapted for Linux booting by Hannu Savolainen 1993
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- *
- * The code in this file is derived from the file funzip.c written
- * and put in the public domain by Mark Adler.
- */
-
-/*
- This version can extract files in gzip or pkzip format.
- For the latter, only the first entry is extracted, and it has to be
- either deflated or stored.
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#include "crypt.h"
-
-#include <stdio.h>
-
-/* PKZIP header definitions */
-#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */
-#define LOCFLG 6 /* offset of bit flag */
-#define CRPFLG 1 /* bit for encrypted entry */
-#define EXTFLG 8 /* bit for extended local header */
-#define LOCHOW 8 /* offset of compression method */
-#define LOCTIM 10 /* file mod time (for decryption) */
-#define LOCCRC 14 /* offset of crc */
-#define LOCSIZ 18 /* offset of compressed size */
-#define LOCLEN 22 /* offset of uncompressed length */
-#define LOCFIL 26 /* offset of file name field length */
-#define LOCEXT 28 /* offset of extra field length */
-#define LOCHDR 30 /* size of local header, including sig */
-#define EXTHDR 16 /* size of extended local header, inc sig */
-
-
-/* Globals */
-
-int decrypt; /* flag to turn on decryption */
-char *key; /* not used--needed to link crypt.c */
-int pkzip = 0; /* set for a pkzip file */
-int extended = 0; /* set if extended local header */
-
-/* ===========================================================================
- * Check zip file and advance inptr to the start of the compressed data.
- * Get ofname from the local header if necessary.
- */
-int check_zipfile(in)
- int in; /* input file descriptors */
-{
- uch *h = inbuf + inptr; /* first local header */
-
- /* ifd = in; */
-
- /* Check validity of local header, and skip name and extra fields */
- inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
-
- if (inptr > insize || LG(h) != LOCSIG) {
- error("input not a zip");
- }
- method = h[LOCHOW];
- if (method != STORED && method != DEFLATED) {
- error("first entry not deflated or stored--can't extract");
- }
-
- /* If entry encrypted, decrypt and validate encryption header */
- if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
- error("encrypted file\n");
- exit_code = ERROR;
- return -1;
- }
-
- /* Save flags for unzip() */
- extended = (h[LOCFLG] & EXTFLG) != 0;
- pkzip = 1;
-
- /* Get ofname and time stamp from local header (to be done) */
- return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out. This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- * the compressed data, from offsets inptr to insize-1 included.
- * The magic header has already been checked. The output buffer is cleared.
- */
-void unzip(in, out)
- int in, out; /* input and output file descriptors */
-{
- ulg orig_crc = 0; /* original crc */
- ulg orig_len = 0; /* original uncompressed length */
- int n;
- uch buf[EXTHDR]; /* extended local header */
-
- /* ifd = in;
- ofd = out; */
-
- updcrc(NULL, 0); /* initialize crc */
-
- if (pkzip && !extended) { /* crc and length at the end otherwise */
- orig_crc = LG(inbuf + LOCCRC);
- orig_len = LG(inbuf + LOCLEN);
- }
-
- /* Decompress */
- if (method == DEFLATED) {
-
- int res = inflate();
-
- if (res == 3) {
- error("out of memory");
- } else if (res != 0) {
- error("invalid compressed format");
- }
-
- } else if (pkzip && method == STORED) {
-
- register ulg n = LG(inbuf + LOCLEN);
-
- if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
-
- error("length mismatch");
- }
- while (n--) {
- uch c = (uch)get_byte();
-#ifdef CRYPT
- if (decrypt) zdecode(c);
-#endif
- if (!test) put_char(c);
- }
- } else {
- error("internal error, invalid method");
- }
-
- /* Get the crc and original length */
- if (!pkzip) {
- /* crc32 (see algorithm.doc)
- * uncompressed input size modulo 2^32
- */
- for (n = 0; n < 8; n++) {
- buf[n] = (uch)get_byte(); /* may cause an error if EOF */
- }
- orig_crc = LG(buf);
- orig_len = LG(buf+4);
-
- } else if (extended) { /* If extended header, check it */
- /* signature - 4bytes: 0x50 0x4b 0x07 0x08
- * CRC-32 value
- * compressed size 4-bytes
- * uncompressed size 4-bytes
- */
- for (n = 0; n < EXTHDR; n++) {
- buf[n] = (uch)get_byte(); /* may cause an error if EOF */
- }
- orig_crc = LG(buf+4);
- orig_len = LG(buf+12);
- }
-
- /* Validate decompression */
- if (orig_crc != updcrc(outbuf, 0)) {
- error("crc error");
- }
- if (orig_len != bytes_out) {
- error("length error");
- }
-
- /* Check if there are more entries in a pkzip file */
- if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
- error("zip file has more than one entry");
- }
- extended = pkzip = 0; /* for next file */
-}
#endif
unsigned char aux_device_present;
-extern int ramdisk_size;
+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 */
extern int root_mountflags;
extern int _etext, _edata, _end;
#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_SIZE (*(unsigned short *) (PARAM+0x1F8))
+#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
#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, };
void setup_arch(char **cmdline_p,
aux_device_present = AUX_DEVICE_INFO;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= PAGE_MASK;
- ramdisk_size = RAMDISK_SIZE;
+ 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);
#ifdef CONFIG_MAX_16M
if (memory_end > 16*1024*1024)
memory_end = 16*1024*1024;
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1994, 1995 by Waldorf Electronics,
-# written by Ralf Baechle
+# Copyright (C) 1994, 1995 by Ralf Baechle
#
-AS = mips-linux-as
-#ASFLAGS = -mips3 -mcpu=r4000
-LD = mips-linux-ld
-LINKFLAGS = -Ttext 0xa0000000
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+prefix = mipsel-
+oformat = a.out-mips-little-linux
+else
+prefix = mips-
+oformat = a.out-mips-big-linux
+endif
+
+ifdef CONFIG_EXTRA_ELF_COMPILER
+prefix := $(prefix)linuxelf-
+else
+prefix := $(prefix)linux-
+endif
+
+AS = $(prefix)as
+LD = $(prefix)ld
+LINKFLAGS = -N -Ttext 0x80000000
+#LINKFLAGS = -oformat=$(oformat) -N -Ttext 0x80000000
#HOSTCC = gcc
-#
-# KERNELBASE is quite useless, but I need it to work
-# around a hardware bug in my Wreckstation board. Other people
-# would burn that @#!%# thing...
-#
-CC = mips-linux-gcc -V 2.5.8 -D__KERNEL__ -I$(TOPDIR)/include
+CC = $(prefix)gcc -D__KERNEL__ -I$(TOPDIR)/include
CPP = $(CC) -E $(CFLAGS)
-AR = mips-linux-ar
-RANLIB = mips-linux-ranlib
-STRIP = mips-linux-strip
+AR = $(prefix)ar
+RANLIB = $(prefix)ranlib
+OBJCOPY = $(prefix)objcopy
+OBJDUMP = $(prefix)objdump
+STRIP = $(prefix)strip
+NM = $(prefix)nm
-CFLAGS := $(CFLAGS) #-pipe
+#
+# The new ELF GCC uses -G0 -mabicalls -fpic as default. We don't need PIC
+# code in the kernel since it only slows down the whole thing. For the
+# old GCC these options are just the defaults. At some point we might
+# make use of global pointer optimizations.
+#
+ifdef CONFIG_ELF_KERNEL
+CFLAGS := $(CFLAGS) -G0 -mno-abicalls -fno-pic
+LINKFLAGS += -T arch/mips/ld.script
+endif
-CFLAGS := $(CFLAGS) -DKERNELBASE=0xa0000000
+ifdef CONFIG_REMOTE_DEBUG
+CFLAGS := $(CFLAGS) -g
+endif
-ifdef CONFIG_R4X00
-CFLAGS := $(CFLAGS) -Wa,-mips3 -mcpu=r4000 -D__R4000__
+ifdef CONFIG_CPU_R3000
+CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1
+#ASFLAGS := $(ASFLAGS) -mcpu=r3000 -mips1
+endif
+ifdef CONFIG_CPU_R6000
+CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2
+#ASFLAGS := $(ASFLAGS) -mcpu=r6000 -mips2
+endif
+ifdef CONFIG_CPU_R4X00
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4400 -mips2
+#ASFLAGS := $(ASFLAGS) -mcpu=r4400 -mips2
endif
+ifdef CONFIG_CPU_R4600
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r4600 -mips2
+#ASFLAGS := $(ASFLAGS) -mcpu=r4600 -mips2
+endif
+ifdef CONFIG_CPU_R8000
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2
+#ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2
+endif
+ifdef CONFIG_CPU_R10000
+CFLAGS := $(CFLAGS) -D__R4000__ -mcpu=r8000 -mips2
+#ASFLAGS := $(ASFLAGS) -mcpu=r8000 -mips2
+endif
+
+CFLAGS := $(CFLAGS) -pipe
HEAD := arch/mips/kernel/head.o
-SUBDIRS := $(SUBDIRS) arch/mips/kernel arch/mips/mm
+SUBDIRS := $(SUBDIRS) arch/mips/kernel arch/mips/mm arch/mips/lib
ARCHIVES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(ARCHIVES)
+LIBS := arch/mips/lib/lib.a $(LIBS) arch/mips/lib/lib.a
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
archclean:
@$(MAKEBOOT) clean
+ $(MAKE) -C arch/$(ARCH)/kernel clean
archdep:
@$(MAKEBOOT) dep
# License. See the file "COPYING" in the main directory of this archive
# for more details.
#
-# Copyright (C) 1995 by Waldorf Electronics,
-# written by Ralf Baechle
+# Copyright (C) 1995 by Ralf Baechle
#
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = milo.o a.out.o
+
+#
+# Drop some uninteresting sections in the kernel.
+# This is only relevant for ELF kernels but doesn't hurt a.out
+#
+DROP_SECTIONS = .reginfo .mdebug
+
+#
+# The new options of binutils 2.6 help to shrink object files alot.
+# This is especially usefull for booting from floppy. Though we
+# don't yet require everyone to have binutils 2.6 installed.
+#
+OBJDUMP_VERSION = $(word 4,$(shell $(OBJDUMP) --version))
+ifneq ($(OBJDUMP_VERSION),2.5.2)
+KEEP = kernel_entry boot_info screen_info _end
+STRIP_FLAGS = $(addprefix --keep-symbol=,$(KEEP))
+else
+STRIP_FLAGS = --discard-all
+endif
+
#
# Fake compressed boot
#
+ifdef CONFIG_ELF_KERNEL
+zImage: $(CONFIGURE) $(TOPDIR)/vmlinux
+ cp $(TOPDIR)/vmlinux zImage.tmp
+ $(STRIP) $(addprefix --remove-section=,$(DROP_SECTIONS)) \
+ --strip-symbol=blurb zImage.tmp
+ $(LD) -oformat=$(oformat) -N -e except_vec0 -Ttext=0x80000000 \
+ -o zImage zImage.tmp
+ rm -f zImage.tmp
+ $(STRIP) $(STRIP_FLAGS) zImage
+else
zImage: $(CONFIGURE) $(TOPDIR)/vmlinux
- ln -fs $(TOPDIR)/vmlinux zImage
+ cp $(TOPDIR)/vmlinux $@
+ $(STRIP) $(STRIP_FLAGS) $@
+endif
zdisk: zImage
- mcopy -n $(TOPDIR)/vmlinux a:vmlinux
+ mcopy -n zImage a:vmlinux
dep:
+ $(CPP) -M *.[cS] > .depend
clean:
- rm -f zImage
+ rm -f zImage zImage.tmp
+
+dummy:
+
+include $(TOPDIR)/Rules.make
# For a description of the syntax of this configuration file,
# see the Configure script.
#
-
+mainmenu_name "Linux Kernel Configuration"
+
+mainmenu_option next_comment
comment 'Machine setup'
-bool 'Support for Deskstation Tyne' CONFIG_DESKSTATION_TYNE y
-bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61 y
-bool 'Support for DECstation' CONFIG_DECSTATION n
-
-bool 'Generate code for R4x00' CONFIG_R4X00 y
-
-comment 'General setup'
-
-bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
-bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 y
-if [ "$CONFIG_ST506" = "y" ]; then
- comment 'Please see block/drivers/README.ide for help/info on IDE drives'
- bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y
- if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
- bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
- else
- bool ' Use new IDE driver for primary/secondary i/f' CONFIG_BLK_DEV_IDE n
- fi
- if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then
- bool ' Include support for IDE CDROM (ATAPI)' CONFIG_BLK_DEV_IDECD n
- fi
-fi
-
-bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
-bool 'Networking support' CONFIG_NET y
-bool 'System V IPC' CONFIG_SYSVIPC n
-bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n
+bool 'Support for Acer PICA 1 chipset' CONFIG_ACER_PICA_61
+bool 'Support for DECstation' CONFIG_DECSTATION
+bool 'Support for Deskstation RPC44' CONFIG_DESKSTATION_RPC44
+bool 'Support for Deskstation Tyne' CONFIG_DESKSTATION_TYNE
+bool 'Support for Mips Magnum 3000' CONFIG_MIPS_MAGNUM_3000
+bool 'Support for Mips Magnum 4000' CONFIG_MIPS_MAGNUM_4000
+bool 'Support for Olivetty M700' CONFIG_OLIVETTI_M700
+if [ "$CONFIG_ACER_PICA_61" = "y" -o \
+ "$CONFIG_MIPS_MAGNUM_4000" = "y" -o \
+ "$CONFIG_OLIVETTI_M700" = "y" ]; then
+ define_bool CONFIG_MIPS_JAZZ y
+fi
+
+choice 'CPU type' \
+ "R3000 CONFIG_CPU_R3000 \
+ R6000 CONFIG_CPU_R6000 \
+ R4x00 CONFIG_CPU_R4X00 \
+ R4600 CONFIG_CPU_R4600 \
+ R8000 CONFIG_CPU_R8000 \
+ R10000 CONFIG_CPU_R10000" R4x00
+if [ "$CONFIG_CPU_R3000" = "y" -o \
+ "$CONFIG_CPU_R6000" = "y" -o \
+ "$CONFIG_CPU_R4X00" = "y" -o \
+ "$CONFIG_CPU_R4600" = "y" -o \
+ "$CONFIG_CPU_R8000" = "y" ]; then
+ define_bool CONFIG_TLB_SHUTDOWN y
+fi
+
+define_bool CONFIG_BINFMT_ELF y
+bool 'Compile the kernel into the ELF object format' CONFIG_ELF_KERNEL
+if [ "$CONFIG_ELF_KERNEL" = "y" ]; then
+ bool 'Is your ELF compiler an extra compiler' CONFIG_EXTRA_ELF_COMPILER
+fi
+bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
+bool 'Networking support' CONFIG_NET
+#bool 'PCI bios support' CONFIG_PCI
+#if [ "$CONFIG_PCI" = "y" ]; then
+# bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE
+#fi
+bool 'System V IPC' CONFIG_SYSVIPC
+
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+
+source drivers/block/Config.in
if [ "$CONFIG_NET" = "y" ]; then
-comment 'Networking options'
-bool 'TCP/IP networking' CONFIG_INET y
-if [ "$CONFIG_INET" "=" "y" ]; then
-bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD y
-bool 'IP multicasting (ALPHA)' CONFIG_IP_MULTICAST n
-bool 'IP firewalling' CONFIG_IP_FIREWALL n
-bool 'IP accounting' CONFIG_IP_ACCT n
-comment '(it is safe to leave these untouched)'
-bool 'PC/TCP compatibility mode' CONFIG_INET_PCTCP n
-bool 'Reverse ARP' CONFIG_INET_RARP n
-bool 'Assume subnets are local' CONFIG_INET_SNARL y
-bool 'Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
-fi
-bool 'The IPX protocol' CONFIG_IPX n
-#bool 'Amateur Radio AX.25 Level 2' CONFIG_AX25 n
+ source net/Config.in
fi
+mainmenu_option next_comment
comment 'SCSI support'
-bool 'SCSI support?' CONFIG_SCSI n
-
-if [ "$CONFIG_SCSI" = "n" ]; then
-
-comment 'Skipping SCSI configuration options...'
+tristate 'SCSI support' CONFIG_SCSI
-else
-
-comment 'SCSI support type (disk, tape, CDrom)'
-
-bool 'SCSI disk support' CONFIG_BLK_DEV_SD y
-bool 'SCSI tape support' CONFIG_CHR_DEV_ST y
-bool 'SCSI CDROM support' CONFIG_BLK_DEV_SR y
-bool 'SCSI generic support' CONFIG_CHR_DEV_SG y
-
-comment 'SCSI low-level drivers'
-
-bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
-bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA y
-bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
-bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
-bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
-bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
-if [ "$CONFIG_PCI" = "y" ]; then
- bool 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx n
-fi
-bool 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 n
-bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 n
-bool 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC n
-bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
-bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
-bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
-bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
-#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
-#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
+if [ "$CONFIG_SCSI" != "n" ]; then
+ source drivers/scsi/Config.in
fi
-
if [ "$CONFIG_NET" = "y" ]; then
+ mainmenu_option next_comment
+ comment 'Network device support'
-comment 'Network device support'
-
-bool 'Network device support?' CONFIG_NETDEVICES n
-if [ "$CONFIG_NETDEVICES" = "n" ]; then
-
-comment 'Skipping network driver configuration options...'
-
-else
-bool 'Dummy net driver support' CONFIG_DUMMY n
-bool 'SLIP (serial line) support' CONFIG_SLIP n
-if [ "$CONFIG_SLIP" = "y" ]; then
- bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED y
-# bool ' SLIP debugging on' SL_DUMP y
-fi
-bool 'PPP (point-to-point) support' CONFIG_PPP n
-bool 'PLIP (parallel port) support' CONFIG_PLIP n
-bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
-bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
-bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC y
-if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
- bool 'WD80*3 support' CONFIG_WD80x3 y
- bool 'SMC Ultra support' CONFIG_ULTRA n
-fi
-bool 'AMD LANCE and PCnet (AT1500 and NE2100) support' CONFIG_LANCE n
-bool '3COM cards' CONFIG_NET_VENDOR_3COM y
-if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
- bool '3c501 support' CONFIG_EL1 n
- bool '3c503 support' CONFIG_EL2 n
- if [ "$CONFIG_NET_ALPHA" = "y" ]; then
- bool '3c505 support' CONFIG_ELPLUS n
- bool '3c507 support' CONFIG_EL16 n
- fi
- bool '3c509/3c579 support' CONFIG_EL3 n
-fi
-bool 'Other ISA cards' CONFIG_NET_ISA n
-if [ "$CONFIG_NET_ISA" = "y" ]; then
- bool 'Cabletron E21xx support' CONFIG_E2100 n
- bool 'DEPCA support' CONFIG_DEPCA n
- bool 'EtherWorks 3 support' CONFIG_EWRK3 n
- if [ "$CONFIG_NET_ALPHA" = "y" ]; then
- bool 'Arcnet support' CONFIG_ARCNET n
- bool 'AT1700 support' CONFIG_AT1700 n
-# bool 'EtherExpressPro support' CONFIG_EEXPRESS_PRO n
- bool 'EtherExpress support' CONFIG_EEXPRESS n
- bool 'NI5210 support' CONFIG_NI52 n
- bool 'NI6510 support' CONFIG_NI65 n
- fi
- bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
- bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
- bool 'NE2000/NE1000 support' CONFIG_NE2000 y
- bool 'SK_G16 support' CONFIG_SK_G16 n
-fi
-bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA n
-if [ "$CONFIG_NET_EISA" = "y" ]; then
- if [ "$CONFIG_NET_ALPHA" = "y" ]; then
- bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
- fi
- bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
-# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
-# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
-# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
- bool 'Zenith Z-Note support' CONFIG_ZNET y
-fi
-bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
-if [ "$CONFIG_NET_POCKET" = "y" ]; then
- bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n
- bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
- bool 'D-Link DE620 pocket adaptor support' CONFIG_DE620 n
-# bool 'Silicom pocket adaptor support' CONFIG_SILICOM_PEA n
-# bool 'WaveLAN PCMCIA support' CONFIG_WaveLAN n
-# bool '3 Com 3c589 PCMCIA support' CONFIG_3C589 n
-fi
-fi
-fi
-
-comment 'CD-ROM drivers'
-
-bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n
-bool 'Mitsumi CDROM driver support' CONFIG_MCD n
-bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n
-if [ "$CONFIG_SBPCD" = "y" ]; then
- bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n
- if [ "$CONFIG_SBPCD2" = "y" ]; then
- bool 'Matsushita/Panasonic third CDROM controller support' CONFIG_SBPCD3 n
- if [ "$CONFIG_SBPCD3" = "y" ]; then
- bool 'Matsushita/Panasonic fourth CDROM controller support' CONFIG_SBPCD4 n
- fi
+ bool 'Network device support' CONFIG_NETDEVICES
+ if [ "$CONFIG_NETDEVICES" = "y" ]; then
+ source drivers/net/Config.in
fi
fi
-comment 'Filesystems'
-
-bool 'Standard (minix) fs support' CONFIG_MINIX_FS y
-bool 'Extended fs support' CONFIG_EXT_FS n
-bool 'Second extended fs support' CONFIG_EXT2_FS n
-bool 'xiafs filesystem support' CONFIG_XIA_FS n
-bool 'msdos fs support' CONFIG_MSDOS_FS n
-if [ "$CONFIG_MSDOS_FS" = "y" ]; then
-bool 'umsdos: Unix like fs on top of std MSDOS FAT fs' CONFIG_UMSDOS_FS n
-fi
-bool '/proc filesystem support' CONFIG_PROC_FS n
-if [ "$CONFIG_INET" = "y" ]; then
-bool 'NFS filesystem support' CONFIG_NFS_FS y
-fi
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
- bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
-else
- bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
-fi
-bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n
-bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
-
-comment 'character devices'
+mainmenu_option next_comment
+comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-bool 'Cyclades async mux support' CONFIG_CYCLADES n
-bool 'Parallel printer support' CONFIG_PRINTER n
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
-bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
-if [ "$CONFIG_PSMOUSE" = "y" ]; then
-bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n
+bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
+if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+ source drivers/cdrom/Config.in
fi
-bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
-bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
-
-bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
-if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
-bool 'Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF n
-if [ "$CONFIG_QIC02_DYNCONF" != "y" ]; then
-comment '>>> Edit configuration parameters in ./include/linux/tpqic02.h!'
+source fs/Config.in
-else
-
-comment '>>> Setting runtime QIC-02 configuration is done with qic02conf'
-comment '>>> Which is available from ftp://ftp.funet.fi/pub/OS/Linux/BETA/QIC-02/'
-
-fi
-fi
-
-bool 'QIC-117 tape support' CONFIG_FTAPE n
-if [ "$CONFIG_FTAPE" = "y" ]; then
-int ' number of ftape buffers' NR_FTAPE_BUFFERS 3
-fi
+source drivers/char/Config.in
+bool 'Standard serial device support' CONFIG_SERIAL n
+mainmenu_option next_comment
comment 'Sound'
-bool 'Sound card support' CONFIG_SOUND n
+tristate 'Sound card support' CONFIG_SOUND
+if [ "$CONFIG_SOUND" != "n" ]; then
+ source drivers/sound/Config.in
+fi
+mainmenu_option next_comment
comment 'Kernel hacking'
-#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
-bool 'Kernel profiling support' CONFIG_PROFILE n
+#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
-if [ "$CONFIG_SCSI" = "y" ]; then
-bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
-fi
--- /dev/null
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Machine setup
+#
+CONFIG_ACER_PICA_61=y
+# CONFIG_DECSTATION is not set
+# CONFIG_DESKSTATION_RPC44 is not set
+# CONFIG_DESKSTATION_TYNE is not set
+# CONFIG_MIPS_MAGNUM_3000 is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_OLIVETTI_M700 is not set
+CONFIG_MIPS_JAZZ=y
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_R6000 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_R4600 is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+CONFIG_TLB_SHUTDOWN=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_ELF_KERNEL is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_NET is not set
+# CONFIG_SYSVIPC is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODVERSIONS is not set
+
+#
+# block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_ST506 is not set
+# CONFIG_BLK_DEV_XD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_MINIX_FS is not set
+# CONFIG_EXT_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_XIA_FS is not set
+# CONFIG_MSDOS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_SMB_FS is not set
+
+#
+# character devices
+#
+# CONFIG_CYCLADES is not set
+# CONFIG_STALDRV is not set
+# CONFIG_PRINTER is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_PSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_APM is not set
+# CONFIG_SERIAL is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PROFILE is not set
#
-# Makefile for the linux kernel.
+# Makefile for the Linux/MIPS kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-# Note 2! The CFLAGS definitions are now in the main makefile...
.S.s:
- $(CPP) $(CFLAGS) -D__ASSEMBLY__ -traditional $< -o $*.s
+ $(CPP) $(CFLAGS) $< -o $*.s
.S.o:
- $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+ $(CC) $(CFLAGS) -c $< -o $*.o
+all: kernel.o head.o
EXTRA_ASFLAGS = -mips3 -mcpu=r4000
-OBJS = process.o signal.o entry.o traps.o irq.o ptrace.o cache.o resume.o \
- ioport.o setup.o bios32.o tynedma.o
+O_TARGET := kernel.o
+O_OBJS := process.o signal.o entry.o traps.o irq.o ptrace.o vm86.o ioport.o \
+ setup.o syscall.o sysmips.o time.o bios32.o ipc.o
-all: kernel.o head.o
+#
+# Kernel debugging
+#
+ifdef CONFIG_REMOTE_DEBUG
+OBJS += gdb-low.o gdb-stub.o
+endif
+
+#
+# Board specific code
+#
+ifdef CONFIG_MIPS_JAZZ
+O_OBJS += jazzdma.o jazz-c.o
+endif
+
+ifdef CONFIG_ACER_PICA_61
+O_OBJS += pica.o
+endif
+
+ifdef CONFIG_DESKSTATION_TYNE
+O_OBJS += tyne.o tyne-c.o
+endif
-cache.o: cache.s
+ifdef CONFIG_MIPS_MAGNUM_4000
+O_OBJS += magnum4000.o
+endif
-cache.s: cache.S $(TOPDIR)/include/asm/mipsconfig.h \
- $(TOPDIR)/include/asm/regdef.h $(TOPDIR)/include/asm/segment.h
+#
+# CPU model specific code
+#
+ifdef CONFIG_CPU_R2000
+O_OBJS += r3000.o
+endif
-entry.o: entry.s
+ifdef CONFIG_CPU_R3000
+O_OBJS += r3000.o
+endif
-entry.s: entry.S $(TOPDIR)/include/linux/sys.h \
- $(TOPDIR)/include/linux/autoconf.h $(TOPDIR)/include/asm/segment.h \
- $(TOPDIR)/include/asm/mipsregs.h $(TOPDIR)/include/asm/mipsconfig.h \
- $(TOPDIR)/include/asm/page.h $(TOPDIR)/include/asm/stackframe.h \
- $(TOPDIR)/include/asm/regdef.h $(TOPDIR)/include/asm/processor.h
+ifdef CONFIG_CPU_R4X00
+O_OBJS += r4xx0.o
+endif
+
+ifdef CONFIG_CPU_R4600
+O_OBJS += r4xx0.o
+endif
+
+ifdef CONFIG_CPU_R6000
+ exit 1 # no detailed informations about CPU yet.
+endif
+
+ifdef CONFIG_CPU_R8000
+ exit 1 # no detailed informations about CPU yet.
+endif
+
+ifdef CONFIG_CPU_R10000
+O_OBJS += r4xx0.o
+endif
+
+#
+# Since we add the same object files to O_OBJS for different configurations.
+# O_OBJS might contain duplicate files. We correct this by filtering out
+# duplicate files. Just to avoid users having to know about all the
+# compatibility stuff between various boards and boards.
+#
+O_OBJS := $(sort $(O_OBJS))
+
+all: kernel.o head.o
-head.o: head.s
+entry.o: entry.S
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
+head.o: head.S
-resume.o: resume.s
+magnum4000.o: magnum4000.S
-resume.s: resume.S $(TOPDIR)/include/asm/regdef.h \
- $(TOPDIR)/include/asm/processor.h $(TOPDIR)/include/asm/mipsregs.h \
- $(TOPDIR)/include/asm/mipsconfig.h
+pica.o: pica.S
-tlb.o: tlb.s
+r4xx0.o: r4xx0.S
-tlb.s: tlb.S $(TOPDIR)/include/asm/regdef.h $(TOPDIR)/include/asm/mipsregs.h \
- $(TOPDIR)/include/asm/bootinfo.h
+tyne.o: tyne.S
-kernel.o: $(OBJS)
- $(LD) -r -o kernel.o $(OBJS)
- sync
+clean:
include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * arch/mips/kernel/cache.S
- *
- * Copyright (C) 1994, 1995 Waldorf Electronics
- * Written by Ralf Baechle
- *
- * Flush instruction/data caches
- *
- * Parameters: a0 - starting address to flush
- * a1 - size of area to be flushed
- * a2 - which caches to be flushed
- *
- * FIXME: - ignores parameters
- * - doesn't know about second level caches
- * - only knows how to handle the R4600
- */
-
-#include <asm/mipsconfig.h>
-#include <asm/regdef.h>
-#include <asm/segment.h>
-
-#define PAGE_SIZE 0x1000
-
-#define CACHELINES 512 /* number of cachelines */
-
- .set noreorder
- .globl _sys_cacheflush
- .text
-_sys_cacheflush:
- /*
- * Writeback/invalidate the data cache
- */
- li t0,KSEG0
- li t1,CACHELINES
-1: cache 1,0(t0)
- cache 1,32(t0)
- cache 1,64(t0)
- cache 1,96(t0)
- cache 1,128(t0)
- cache 1,160(t0)
- cache 1,192(t0)
- cache 1,224(t0)
- cache 1,256(t0)
- cache 1,288(t0)
- cache 1,320(t0)
- cache 1,352(t0)
- cache 1,384(t0)
- cache 1,416(t0)
- cache 1,448(t0)
- cache 1,480(t0)
- subu t1,t1,1
- bnez t1,1b
- addiu t0,t0,512 # delay slot
-
- /*
- * Flush the instruction cache
- */
- lui t0,0x8000
- li t1,CACHELINES
-1: cache 0,0(t0)
- cache 0,32(t0)
- cache 0,64(t0)
- cache 0,96(t0)
- cache 0,128(t0)
- cache 0,160(t0)
- cache 0,192(t0)
- cache 0,224(t0)
- cache 0,256(t0)
- cache 0,288(t0)
- cache 0,320(t0)
- cache 0,352(t0)
- cache 0,384(t0)
- cache 0,416(t0)
- cache 0,448(t0)
- cache 0,480(t0)
- subu t1,t1,1
- bnez t1,1b
- addiu t0,t0,512 # delay slot
-
- j ra
- nop
/*
- * arch/mips/kernel/entry.S
+ * Low level exception handling
*
- * Copyright (C) 1994, 1995 Waldorf Electronics
- * written by Ralf Baechle
+ * 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.
+ *
+ * Copyright (C) 1994, 1995 by Ralf Baechle
*/
/*
* entry.S contains the system-call and fault low-level handling routines.
* This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
+ * and faults that can result in a task-switch. The ISA dependend TLB
+ * code is in arch/mips/kernel/<cputype>.S
*/
-
#include <linux/sys.h>
-#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/errno.h>
#include <asm/segment.h>
#include <asm/mipsregs.h>
#include <asm/mipsconfig.h>
#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/stackframe.h>
-#include <asm/regdef.h>
#include <asm/processor.h>
+#include <asm/unistd.h>
/*
* These are offsets into the task-struct.
signal = 12
blocked = 16
flags = 20
-errno = 24 #/* MIPS OK */
-exec_domain = 60 #/* ??? */
-
-ENOSYS = 38
+errno = 24
+exec_domain = 60
- .globl ret_from_sys_call
- .globl _sys_call_table
+#ifdef __SMP__
+#error "Fix this for SMP"
+#else
+#define current current_set
+#endif
+/*
+ * Heia ... The %lo, %hi and %HI stuff is too strong for the ELF assembler
+ * and the ABI to cope with ...
+ */
.text
.set noreorder
.align 4
handle_bottom_half:
- /*
- * If your assembler breaks on the next line it's
- * time to update!
- */
- lui s0,%hi(_intr_count)
- lw s1,%lo(_intr_count)(s0)
- mfc0 s3,CP0_STATUS # Enable IRQs
+ lui s0,%hi(intr_count)
+ lw s1,%lo(intr_count)(s0)
+ mfc0 s3,CP0_STATUS # Enable IRQs
addiu s2,s1,1
- sw s2,%lo(_intr_count)(s0)
+ sw s2,%lo(intr_count)(s0)
ori t0,s3,0x1f
- xori t0,t0,0x1e
- jal _do_bottom_half
- mtc0 t0,CP0_STATUS # delay slot
- mtc0 s3,CP0_STATUS # Restore old IRQ state
- j 9f
- sw s1,%lo(_intr_count)(s0) # delay slot
-
- .set reorder
-reschedule:
- la ra,ret_from_sys_call
- j _schedule
- nop
-
- .align 5
- .globl _handle_sys
-_handle_sys:
- .set noreorder
- .set noat
- SAVE_ALL
- .set at
- STI
- /*
- * Compute return address. For now we assume that syscalls never
- * appear in branch delay slots. For the Linux/MIPS standard
- * libraries this assumption is always try.
- */
- lw t3,FR_EPC(sp)
- lw s1,FR_REG2(sp)
- li t0,-ENOSYS
- addiu t3,t3,4
- sw t3,FR_EPC(sp)
- li t2,NR_syscalls
- bge s1,t2,ret_from_sys_call
- sw t0,FR_REG2(sp) # delay slot
- sll s1,s1,2
- lw s1,_sys_call_table(s1)
- lw s0,_current
-
- beqz s1,ret_from_sys_call
- lw t0,flags(s0)
- sll t0,t0,2 # PF_TRACESYS
- bltz t0,1f
- sw zero,errno(s0) # delay slot
-
- lw a0,FR_REG4(sp)
- lw a1,FR_REG5(sp)
- lw a2,FR_REG6(sp)
- lw a3,FR_REG7(sp)
- lw t0,FR_REG3(sp)
- jalr s1 # do the real work
- sw t0,16(sp) # delay slot
-
- lw t0,errno(s0)
- sw v0,FR_REG2(sp) # save the return value
- subu t0,zero,t0 # t0 = -t0
- beqz t0,ret_from_sys_call
- nop
- /*
- * Fixme: should set error flag
- */
- j ret_from_sys_call
- sw t0,FR_REG2(sp) # delay slot
-
- .align 4
-1: jal _syscall_trace
- nop # delay slot
-
- lw a0,FR_REG4(sp)
- lw a1,FR_REG5(sp)
- lw a2,FR_REG6(sp)
- lw a3,FR_REG7(sp)
- lw t0,FR_REG3(sp)
- jalr s1 # do the real work
- sw t0,16(sp) # delay slot
+ xori t0,0x1e
+ jal do_bottom_half
+ mtc0 t0,CP0_STATUS # delay slot
+ mtc0 s3,CP0_STATUS # Restore old IRQ state
+ b 9f
+ sw s1,%lo(intr_count)(s0) # delay slot
- lw t0,errno(s0)
- sw v0,FR_REG2(sp) # save the return value
- subu t0,zero,t0
- beqz t0,1f
+reschedule: jal schedule
nop # delay slot
- sw t1,FR_REG2(sp)
- /*
- * Fixme: should set error flag
- */
-1: jal _syscall_trace
- nop
+EXPORT(ret_from_sys_call)
+ lw t0,intr_count # bottom half
+ bnez t0,return
- .align 4
-ret_from_sys_call:
- lw t0,_intr_count # bottom half
- bnez t0,2f
-9:
- lw t0,_bh_mask # delay slot
- lw t1,_bh_active # unused delay slot
+9: lw t0,bh_mask # delay slot
+ lw t1,bh_active # unused delay slot
and t0,t1
bnez t0,handle_bottom_half
- lw t0,FR_STATUS(sp) # returning to supervisor ?
+ lw t0,FR_STATUS(sp) # returning to kernel mode?
andi t1,t0,0x10
- beqz t1,2f
+ beqz t1,return # -> yes
mfc0 t0,CP0_STATUS # delay slot
- lw t1,_need_resched
+ lw t1,need_resched
ori t0,0x1f # enable irqs
xori t0,0x1e
bnez t1,reschedule
mtc0 t0,CP0_STATUS # delay slot
- lw s0,_current
- lw t0,_task
- lw t1,state(s0) # state
- beq s0,t0,2f # task[0] cannot have signals
- lw t0,counter(s0) # counter
- bnez t1,reschedule # state == 0 ?
+ lw s0,current
+ lw t0,task
lw a0,blocked(s0)
+ beq s0,t0,return # task[0] cannot have signals
# save blocked in a0 for
# signal handling
- beqz t0,reschedule # counter == 0 ?
lw t0,signal(s0)
nor t1,zero,a0
and t1,t0,t1
- beqz t1,skip_signal_return
+ beqz t1,return
nop
- jal _do_signal
+ jal do_signal
move a1,sp # delay slot
-skip_signal_return:
- .set noreorder
.set noat
-2:
-return: RESTORE_ALL
+EXPORT(return) RESTORE_ALL
+ ERET
.set at
-#ifdef CONFIG_DESKSTATION_TYNE
/*
- * Deskstation Tyne interrupt handler
- */
- .text
- .set noreorder
- .set noat
- .globl _deskstation_tyne_handle_int
- .align 5
-_deskstation_tyne_handle_int:
- SAVE_ALL
- .set at
- CLI
- lui s0,%hi(PORT_BASE)
- li t1,0x0f
- sb t1,%lo(PORT_BASE+0x20)(s0) # poll command
- lb t1,%lo(PORT_BASE+0x20)(s0) # read result
- li s1,1
- bgtz t1,Lpoll_second
- andi t1,t1,7
- /*
- * Acknowledge first pic
- */
- lb t2,%lo(PORT_BASE+0x21)(s0)
- lui s4,%hi(_cache_21)
- lb t0,%lo(_cache_21)(s4)
- sllv s1,s1,t1
- or t0,t0,s1
- sb t0,%lo(_cache_21)(s4)
- sb t0,%lo(PORT_BASE+0x21)(s0)
- lui s3,%hi(_intr_count)
- lw t0,%lo(_intr_count)(s3)
- li t2,0x20
- sb t2,%lo(PORT_BASE+0x20)(s0)
- /*
- * Now call the real handler
- */
- la t3,_IRQ_vectors
- sll t2,t1,2
- addu t3,t3,t2
- lw t3,(t3)
- addiu t0,t0,1
- jalr t3
- sw t0,%lo(_intr_count)(s3) # delay slot
- lw t0,%lo(_intr_count)(s3)
- /*
- * Unblock first pic
- */
- lbu t1,%lo(PORT_BASE+0x21)(s0)
- lb t1,%lo(_cache_21)(s4)
- subu t0,t0,1
- sw t0,%lo(_intr_count)(s3)
- nor s1,zero,s1
- and t1,t1,s1
- sb t1,%lo(_cache_21)(s4)
- jr v0
- sb t1,%lo(PORT_BASE+0x21)(s0) # delay slot
-
- .align 5
-Lpoll_second: li t1,0x0f
- sb t1,%lo(PORT_BASE+0xa0)(s0) # poll command
- lb t1,%lo(PORT_BASE+0xa0)(s0) # read result
- lui s4,%hi(_cache_A1)
- bgtz t1,Lspurious_interrupt
- andi t1,t1,7
- /*
- * Acknowledge second pic
- */
- lbu t2,%lo(PORT_BASE+0xa1)(s0)
- lb t3,%lo(_cache_A1)(s4)
- sllv s1,s1,t1
- or t3,t3,s1
- sb t3,%lo(_cache_A1)(s4)
- sb t3,%lo(PORT_BASE+0xa1)(s0)
- li t3,0x20
- sb t3,%lo(PORT_BASE+0xa0)(s0)
- lui s3,%hi(_intr_count)
- lw t0,%lo(_intr_count)(s3)
- sb t3,%lo(PORT_BASE+0x20)(s0)
- /*
- * Now call the real handler
- */
- la t0,_IRQ_vectors
- sll t2,t1,2
- addu t0,t0,t2
- lw t0,32(t0)
- addiu t0,t0,1
- jalr t0
- sw t0,%lo(_intr_count)(s3) # delay slot
- lw t0,%lo(_intr_count)(s3)
- /*
- * Unblock second pic
- */
- lb t1,%lo(PORT_BASE+0xa1)(s0)
- lb t1,%lo(_cache_A1)(s4)
- subu t0,t0,1
- lw t0,%lo(_intr_count)(s3)
- nor s1,zero,s1
- and t1,t1,s1
- sb t1,%lo(_cache_A1)(s4)
- jr v0
- sb t1,%lo(PORT_BASE+0xa1)(s0) # delay slot
-
- .align 5
-Lspurious_interrupt:
- /*
- * Nothing happened... (whistle)
- */
- lui t1,%hi(_spurious_count)
- lw t0,%lo(_spurious_count)(t1)
- la v0,return
- addiu t0,t0,1
- jr ra
- sw t0,%lo(_spurious_count)(t1)
-#endif /* CONFIG_DESKSTATION_TYNE */
-
-#ifdef CONFIG_ACER_PICA_61
-/*
- * Acer PICA interrupt handler dummy
+ * Beware: interrupt, fast_interrupt and bad_interrupt have unusal
+ * calling conventions to speedup the mess.
+ *
+ * t1 - interrupt number
+ * s2 - destroyed
+ * return values:
+ * v0 - return routine
*/
- .set noreorder
- .set noat
- .globl _acer_pica_61_handle_int
- .align 5
-_acer_pica_61_handle_int:
- la a0,acer_text
- jal _panic
- nop
-1: b 1b
- nop
-acer_text: .asciz "Interrupt handler for Acer PICA not written yet"
- .align 2
-#endif /* CONFIG_ACER_PICA_61 */
-
.text
- .set noreorder
.set at
- .globl _interrupt
.align 5
-_interrupt: move s2,ra
- mfc0 t0,CP0_STATUS
- ori t0,t0,0x1f
- xori t0,t0,0x1e
+NESTED(interrupt, FR_SIZE, sp)
+ move s2,ra
+ mfc0 t0,CP0_STATUS # enable IRQs
+ ori t0,0x1f
+ xori t0,0x1e
mtc0 t0,CP0_STATUS
move a0,t1
- jal _do_IRQ
+ jal do_IRQ
move a1,sp # delay slot
- mfc0 t0,CP0_STATUS
- ori t0,t0,1
- xori t0,t0,1
+ mfc0 t0,CP0_STATUS # disable IRQs
+ ori t0,1
+ xori t0,1
la v0,ret_from_sys_call
jr s2
mtc0 t0,CP0_STATUS # delay slot
+ END(interrupt)
- .globl _fast_interrupt
.align 5
-_fast_interrupt:
+NESTED(fast_interrupt, FR_SIZE, sp)
move s2,ra
move a0,t1
- jal _do_fast_IRQ
+ jal do_fast_IRQ
move a1,sp # delay slot
- la v0,return
+ lui v0,%hi(return)
jr s2
- nop # delay slot
+ addiu v0,%lo(return) # delay slot
+ END(fast_interrupt)
- .globl _bad_interrupt
-_bad_interrupt:
+LEAF(bad_interrupt)
/*
* Don't return & unblock the pic
*/
j return
nop
+ END(bad_interrupt)
- .globl _handle_tlbl
- .align 5
-_handle_tlbl:
+/*
+ * do_syscall calls the function in a1 with upto 7 arguments. If over
+ * four arguments are being requested, the additional arguments will
+ * be copied from the user stack pointed to by a0->reg29.
+ * Note that this routine relies on the GNU assemblers weak instruction
+ * scheduling abilities to generate the best possible code for all MIPS CPUs.
+ *
+ * a0 (struct pt_regs *) pointer to user registers
+ * a1 (syscall_t) pointer to syscall to do
+ * a2 (int) number of arguments to syscall
+ */
.set noreorder
- .set noat
- /*
- * Check whether this is a refill or an invalid exception
- *
- * NOTE: Some MIPS manuals say that the R4x00 sets the
- * BadVAddr only when EXL == 0. This is wrong - BadVaddr
- * is being set for all Reload, Invalid and Modified
- * exceptions.
- */
- mfc0 k0,CP0_BADVADDR
- mfc0 k1,CP0_ENTRYHI
- ori k0,k0,0x1fff
- xori k0,k0,0x1fff
- andi k1,k1,0xff
- or k0,k0,k1
- mfc0 k1,CP0_ENTRYHI
- mtc0 k0,CP0_ENTRYHI
- nop # for R4[04]00 pipeline
- nop
- nop
- tlbp
- nop # for R4[04]00 pipeline
- nop
- mfc0 k0,CP0_INDEX
- srl k0,k0,31
- beqz k0,invalid_tlbl
- mtc0 k1,CP0_ENTRYHI # delay slot
- /*
- * Not in tlb -> nested refill exception
- * Load the missing entry and return. This is the most
- * efficient way to regain the faulting address.
- */
- dmfc0 k1,CP0_CONTEXT
- dsra k1,k1,1
- lwu k0,(k1) # Never causes another exception
- lwu k1,4(k1)
- dsrl k0,k0,6 # Convert to EntryLo format
- dsrl k1,k1,6 # Convert to EntryLo format
- dmtc0 k0,CP0_ENTRYLO0
- dmtc0 k1,CP0_ENTRYLO1
- nop # for R4[04]00 pipeline
- tlbwr
- eret
-
- /*
- * Handle invalid exception
- *
- * There are two possible causes for an invalid (tlbl)
- * exception:
- * 1) pages that have the present bit set but the valid bit
- * unset.
- * 2) pages that don't exist
- * Case one needs fast handling, therefore don't save
- * registers yet.
- *
- * k0 now contains the bad virtual address.
- */
-invalid_tlbl:
- /*
- * Remove entry so we don't need to care later
- */
- mfc0 k0,CP0_INDEX
- lui k1,0x0008
- or k0,k0,k1
- dsll k0,k0,13
- dmtc0 k0,CP0_ENTRYHI
- dmtc0 zero,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- /*
- * Test whether present bit in entry is set
- */
- dmfc0 k0,CP0_BADVADDR
- tlbwi # delayed, for R4[04]00 pipeline
- srl k0,k0,10
- lui k1,%HI(TLBMAP)
- addu k0,k0,k1
- ori k0,k0,3
- xori k0,k0,3
- lw k1,(k0)
- andi k1,k1,_PAGE_PRESENT
- beqz k1,nopage_tlbl
- /*
- * Present bit is set -> set valid and accessed bits
- */
- lw k1,(k0) # delay slot
- ori k1,k1,_PAGE_ACCESSED
- sw k1,(k0)
- eret
-
- /*
- * Page doesn't exist. Lots of work which is less important
- * for speed needs to be done, so hand it all over to the
- * kernel memory management routines.
- */
-nopage_tlbl:
- SAVE_ALL
- .set at
- STI
- /*
- * Create a Intel-style errorcode
- * Bit 0: P Present
- * 0 == Page not in memory
- * 1 == privilege violation
- * Bit 1: R/W Read/Write
- * 0 == ReadAccess
- * 1 == WriteAccess
- * Bit 2: U/S User/Supervisor
- * 0 == User mode
- * 1 == Kernel mode
- *
- * a0 (struct pt_regs *) regs
- * a1 (unsigned long) error_code
- */
- lw a1,FR_STATUS(sp)
- move a0,sp
- srl a1,a1,4
- andi a1,a1,1
- jal _do_page_fault
- xori a1,a1,1 # delay slot
- j ret_from_sys_call
- nop # delay slot
-
.text
- .globl _handle_tlbs
- .align 5
-_handle_tlbs:
- .set noreorder
- .set noat
- /*
- * It is impossible that is a nested reload exception.
- * Therefore this must be a invalid exception.
- * Two possible cases:
- * 1) Page not used yet
- * 2) Page doesn't exist yet. Let the kernel handle the trouble.
- *
- * Test whether present bit in entry is set
- */
- dmfc0 k0,CP0_BADVADDR
- srl k0,k0,10
- lui k1,%HI(TLBMAP)
- addu k0,k0,k1
- ori k0,k0,3
- xori k0,k0,3
- lw k1,(k0)
- andi k1,k1,(_PAGE_PRESENT|_PAGE_RW)
- beqz k1,nopage_tlbs
- /*
- * Present and writable bits set -> set accessed and dirty bits.
- */
- lw k1,(k0) # delay slot
- ori k1,k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
- sw k1,(k0)
- /*
- * Now reload the entry into the tlb
- */
- ori k0,k0,0x1000
- xori k0,k0,0x1000
- lw k1,4(k0)
- lw k0,(k0)
- srl k0,k0,6
- srl k1,k1,6
- dmtc0 k0,CP0_ENTRYLO0
- dmtc0 k1,CP0_ENTRYLO1
- tlbwi
- eret
-
- /*
- * Page doesn't exist. Lots of work which is less important
- * for speed needs to be done, so hand it all over to the
- * kernel memory management routines.
- */
-nopage_tlbs:
-nowrite_mod:
- /*
- * Remove entry so we don't need to care later
- */
- mfc0 k0,CP0_INDEX
- lui k1,0x0008
- or k0,k0,k1
- dsll k0,k0,13
- dmtc0 k0,CP0_ENTRYHI
- dmtc0 zero,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- tlbwi
- SAVE_ALL
- .set at
- STI
- /*
- * Create a Intel-style errorcode
- * Bit 0: P Present
- * 0 == Page not in memory
- * 1 == privilege violation
- * Bit 1: R/W Read/Write
- * 0 == ReadAccess
- * 1 == WriteAccess
- * Bit 2: U/S User/Supervisor
- * 0 == User mode
- * 1 == Kernel mode
- *
- * a0 (struct pt_regs *) regs
- * a1 (unsigned long) error_code
- */
- lw a1,FR_STATUS(sp)
- move a0,sp
- srl a1,a1,4
- andi a1,a1,1
- jal _do_page_fault
- xori a1,a1,3 # branch delay slot
- j ret_from_sys_call
- nop # branch delay slot
-
- .globl _handle_mod
- .align 5
-_handle_mod:
- .set noreorder
- .set noat
- /*
- * Two possible cases:
- * 1) Page is rw but not dirty -> set dirty and return
- * 2) Page is not rw -> call C handler
- */
- dmfc0 k0,CP0_BADVADDR
- srl k0,k0,10
- lui k1,%HI(TLBMAP)
- addu k0,k0,k1
- ori k0,k0,3
- xori k0,k0,3
- lw k1,(k0)
- andi k1,k1,_PAGE_RW
- beqz k1,nopage_tlbs
- /*
- * Present and writable bits set -> set accessed and dirty bits.
- */
- lw k1,(k0) # delay slot
- ori k1,k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
- sw k1,(k0)
- /*
- * Now reload the entry into the tlb
- */
- ori k0,k0,0x1000
- xori k0,k0,0x1000
- lw k1,4(k0)
- lw k0,(k0)
- srl k0,k0,6
- srl k1,k1,6
- dmtc0 k0,CP0_ENTRYLO0
- dmtc0 k1,CP0_ENTRYLO1
- tlbwi
- eret
-
- .globl _handle_adel
- .align 5
-_handle_adel:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_adel
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_ades
- .align 5
-_handle_ades:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_ades
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_ibe
- .align 5
-_handle_ibe:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_ibe
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_dbe
- .align 5
-_handle_dbe:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_dbe
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_ov
- .align 5
-_handle_ov:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_ov
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_fpe
- .align 5
-_handle_fpe:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_fpe
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_bp
- .align 5
-_handle_bp:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_bp
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_tr
- .align 5
-_handle_tr:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_tr
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_ri
- .align 5
-_handle_ri:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_ri
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_cpu
- .align 5
-_handle_cpu:
+NESTED(do_syscalls, 32, sp)
+ subu sp,32
+ sw ra,28(sp)
+ sll a2,a2,PTRLOG
+ lw t0,dst(a2)
+ move t2,a1
+ jalr t0
+ lw t0,FR_REG29(a0) # get old user stack pointer
+
+ .set reorder # for sake of R3000
+7: lw t1,24(t0) # parameter #7 from usp
+ sw t1,24(t0)
+6: lw t1,20(t0) # parameter #6 from usp
+ sw t1,20(t0)
+5: lw t1,16(t0) # parameter #5 from usp
+ sw t1,16(t0)
.set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_cpu
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_vcei
- .align 5
-_handle_vcei:
+4: lw a3,FR_REG7(a0) # 4 args
+3: lw a2,FR_REG6(a0) # 3 args
+2: lw a1,FR_REG5(a0) # 2 args
+1: jalr t2 # 1 args
+ lw a0,FR_REG4(a0) # delay slot
+ .set reorder
+ lw ra,28(sp)
+ addiu sp,32
+ jr ra
+0: jalr t2 # 0 args, just pass a0
+ lw ra,28(sp)
+ addiu sp,32
+ jr ra
+ END(do_syscalls)
.set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_vcei
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
- .globl _handle_vced
- .align 5
-_handle_vced:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_vced
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
+ .rdata
+ .align PTRLOG
+dst: PTR 0b, 1b, 2b, 3b, 4b, 5b, 6b, 7b
- .globl _handle_watch
- .align 5
-_handle_watch:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_watch
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
-
- .globl _handle_reserved
- .align 5
-_handle_reserved:
- .set noreorder
- .set noat
- SAVE_ALL
- STI
- li t0,-1
- sw t0,FR_ORIG_REG2(sp)
- jal _do_reserved
- move a0,sp # delay slot
- j ret_from_sys_call
- nop # delay slot
+/*
+ * Build a default exception handler for the exceptions that don't need
+ * special handlers. If you didn't know yet - I *like* playing games with
+ * the C preprocessor ...
+ */
+#define __BUILD_silent(exception)
+#define __BUILD_verbose(exception) \
+ la a1,8f; \
+ TEXT (#exception); \
+ lw a2,FR_EPC(sp); \
+ PRINT("Got %s at %08x.\n")
+#define __BUILD_count(exception) \
+ .set reorder; \
+ lw t0,exception_count_##exception; \
+ addiu t0,1; \
+ sw t0,exception_count_##exception; \
+ .set noreorder; \
+ .data; \
+EXPORT(exception_count_##exception); \
+ .word 0; \
+ .text;
+#define BUILD_HANDLER(exception,verbose) \
+ .text; \
+ .align 5; \
+ NESTED(handle_##exception, FR_SIZE, sp); \
+ .set noat; \
+ SAVE_ALL; \
+ STI; \
+ .set at; \
+ __BUILD_##verbose(exception); \
+ li t0,-1; /* not a sys call */ \
+ sw t0,FR_ORIG_REG2(sp); \
+ jal do_##exception; \
+ move a0,sp; /* delay slot */ \
+ j ret_from_sys_call; \
+ nop; /* delay slot */ \
+ END(handle_##exception)
+
+ BUILD_HANDLER(adel,verbose) /* #4 */
+ BUILD_HANDLER(ades,verbose) /* #5 */
+ BUILD_HANDLER(ibe,verbose) /* #6 */
+ BUILD_HANDLER(dbe,verbose) /* #7 */
+ BUILD_HANDLER(sys,silent) /* #8 */
+ BUILD_HANDLER(bp,verbose) /* #9 */
+ BUILD_HANDLER(ri,verbose) /* #10 */
+ BUILD_HANDLER(cpu,silent) /* #11 */
+ BUILD_HANDLER(ov,verbose) /* #12 */
+ BUILD_HANDLER(tr,verbose) /* #13 */
+ BUILD_HANDLER(vcei,verbose) /* #14 */
+ BUILD_HANDLER(fpe,verbose) /* #15 */
+ BUILD_HANDLER(watch,verbose) /* #23 */
+ BUILD_HANDLER(vced,verbose) /* #31 */
+ BUILD_HANDLER(reserved,verbose) /* others */
/*
* Exception handler table with 32 entries.
* This might be extended to handle software exceptions
*/
.bss
- .globl _exception_handlers
- .align 2
-_exception_handlers:
- .fill 32,4,0
+ .align PTRLOG
+EXPORT(exception_handlers)
+ .fill 32,PTRSIZE,0
+
+/*
+ * Interrupt handler table with 16 entries.
+ */
+EXPORT(IRQ_vectors)
+ .fill 16,PTRSIZE,0
/*
* Table of syscalls
*/
.data
-_sys_call_table:
- .word _sys_setup /* 0 */
- .word _sys_exit
- .word _sys_fork
- .word _sys_read
- .word _sys_write
- .word _sys_open /* 5 */
- .word _sys_close
- .word _sys_waitpid
- .word _sys_creat
- .word _sys_link
- .word _sys_unlink /* 10 */
- .word _sys_execve
- .word _sys_chdir
- .word _sys_time
- .word _sys_mknod
- .word _sys_chmod /* 15 */
- .word _sys_chown
- .word _sys_break
- .word _sys_stat
- .word _sys_lseek
- .word _sys_getpid /* 20 */
- .word _sys_mount
- .word _sys_umount
- .word _sys_setuid
- .word _sys_getuid
- .word _sys_stime /* 25 */
- .word _sys_ptrace
- .word _sys_alarm
- .word _sys_fstat
- .word _sys_pause
- .word _sys_utime /* 30 */
- .word _sys_stty
- .word _sys_gtty
- .word _sys_access
- .word _sys_nice
- .word _sys_ftime /* 35 */
- .word _sys_sync
- .word _sys_kill
- .word _sys_rename
- .word _sys_mkdir
- .word _sys_rmdir /* 40 */
- .word _sys_dup
- .word _sys_pipe
- .word _sys_times
- .word _sys_prof
- .word _sys_brk /* 45 */
- .word _sys_setgid
- .word _sys_getgid
- .word _sys_signal
- .word _sys_geteuid
- .word _sys_getegid /* 50 */
- .word _sys_acct
- .word _sys_phys
- .word _sys_lock
- .word _sys_ioctl
- .word _sys_fcntl /* 55 */
- .word _sys_mpx
- .word _sys_setpgid
- .word _sys_ulimit
- .word _sys_olduname
- .word _sys_umask /* 60 */
- .word _sys_chroot
- .word _sys_ustat
- .word _sys_dup2
- .word _sys_getppid
- .word _sys_getpgrp /* 65 */
- .word _sys_setsid
- .word _sys_sigaction
- .word _sys_sgetmask
- .word _sys_ssetmask
- .word _sys_setreuid /* 70 */
- .word _sys_setregid
- .word _sys_sigsuspend
- .word _sys_sigpending
- .word _sys_sethostname
- .word _sys_setrlimit /* 75 */
- .word _sys_getrlimit
- .word _sys_getrusage
- .word _sys_gettimeofday
- .word _sys_settimeofday
- .word _sys_getgroups /* 80 */
- .word _sys_setgroups
- .word _sys_select
- .word _sys_symlink
- .word _sys_lstat
- .word _sys_readlink /* 85 */
- .word _sys_uselib
- .word _sys_swapon
- .word _sys_reboot
- .word _sys_readdir
- .word _sys_mmap /* 90 */
- .word _sys_munmap
- .word _sys_truncate
- .word _sys_ftruncate
- .word _sys_fchmod
- .word _sys_fchown /* 95 */
- .word _sys_getpriority
- .word _sys_setpriority
- .word _sys_profil
- .word _sys_statfs
- .word _sys_fstatfs /* 100 */
- .word _sys_ioperm
- .word _sys_socketcall
- .word _sys_syslog
- .word _sys_setitimer
- .word _sys_getitimer /* 105 */
- .word _sys_newstat
- .word _sys_newlstat
- .word _sys_newfstat
- .word _sys_uname
- .word _sys_iopl /* 110 */
- .word _sys_vhangup
- .word _sys_idle
- .word 0 #_sys_vm86
- .word _sys_wait4
- .word _sys_swapoff /* 115 */
- .word _sys_sysinfo
- .word _sys_ipc
- .word _sys_fsync
- .word _sys_sigreturn
- .word _sys_clone /* 120 */
- .word _sys_setdomainname
- .word _sys_newuname
- .word 0 #_sys_modify_ldt
- .word _sys_adjtimex
- .word _sys_mprotect /* 125 */
- .word _sys_sigprocmask
- .word _sys_create_module
- .word _sys_init_module
- .word _sys_delete_module
- .word _sys_get_kernel_syms /* 130 */
- .word _sys_quotactl
- .word _sys_getpgid
- .word _sys_fchdir
- .word _sys_bdflush
- .word _sys_sysfs /* 135 */
- .word _sys_personality
- .word 0 /* for afs_syscall */
- .word _sys_setfsuid
- .word _sys_setfsgid
- .word _sys_llseek /* 140 */
- .space (NR_syscalls-140)*4
+ .align PTRLOG
+EXPORT(sys_call_table)
+ /*
+ * Reserved space for all the SVR4, SVR, BSD43 and POSIX
+ * flavoured syscalls.
+ */
+ .space (__NR_Linux)*PTRSIZE
- .bss
- .globl _IRQ_vectors
-_IRQ_vectors: .fill 16,4,0
+ /*
+ * Linux flavoured syscalls.
+ */
+#define SYS(call, narg) PTR call
+#include "syscalls.h"
+/*
+ * Number of arguments of each syscall
+ */
+EXPORT(sys_narg_table)
+ /*
+ * Reserved space for all the SVR4, SVR, BSD43 and POSIX
+ * flavoured syscalls.
+ */
+ .space (__NR_Linux)
+
+ /*
+ * Linux flavoured syscalls.
+ */
+#undef SYS
+#define SYS(call, narg) .byte narg
+#include "syscalls.h"
--- /dev/null
+/*
+ * arch/mips/kernel/gdb-low.S
+ *
+ * gdb-low.S contains the low-level trap handler for the GDB stub.
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+
+#include <linux/sys.h>
+
+#include <asm/asm.h>
+#include <asm/segment.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/stackframe.h>
+#include <asm/gdb-stub.h>
+
+/*
+ * The low level trap handler
+ */
+ .align 5
+ NESTED(trap_low, GDB_FR_SIZE, sp)
+ .set noat
+ .set noreorder
+
+ mfc0 k0,CP0_STATUS
+ sll k0,3 /* extract cu0 bit */
+ bltz k0,1f
+ move k1,sp
+
+ /*
+ * Called from user mode, new stack
+ */
+ lui k1,%hi(kernelsp)
+ lw k1,%lo(kernelsp)(k1)
+1: move k0,sp
+ subu sp,k1,GDB_FR_SIZE
+ sw k0,GDB_FR_REG29(sp)
+ sw v0,GDB_FR_REG2(sp)
+
+/*
+ * first save the CP0 and special registers
+ */
+
+ mfc0 v0,CP0_STATUS
+ sw v0,GDB_FR_STATUS(sp)
+ mfc0 v0,CP0_CAUSE
+ sw v0,GDB_FR_CAUSE(sp)
+ mfc0 v0,CP0_EPC
+ sw v0,GDB_FR_EPC(sp)
+ mfc0 v0,CP0_BADVADDR
+ sw v0,GDB_FR_BADVADDR(sp)
+ mfhi v0
+ sw v0,GDB_FR_HI(sp)
+ mflo v0
+ sw v0,GDB_FR_LO(sp)
+
+/*
+ * Now the integer registers
+ */
+
+ sw zero,GDB_FR_REG0(sp) /* I know... */
+ sw $1,GDB_FR_REG1(sp)
+ /* v0 already saved */
+ sw v1,GDB_FR_REG3(sp)
+ sw a0,GDB_FR_REG4(sp)
+ sw a1,GDB_FR_REG5(sp)
+ sw a2,GDB_FR_REG6(sp)
+ sw a3,GDB_FR_REG7(sp)
+ sw t0,GDB_FR_REG8(sp)
+ sw t1,GDB_FR_REG9(sp)
+ sw t2,GDB_FR_REG10(sp)
+ sw t3,GDB_FR_REG11(sp)
+ sw t4,GDB_FR_REG12(sp)
+ sw t5,GDB_FR_REG13(sp)
+ sw t6,GDB_FR_REG14(sp)
+ sw t7,GDB_FR_REG15(sp)
+ sw s0,GDB_FR_REG16(sp)
+ sw s1,GDB_FR_REG17(sp)
+ sw s2,GDB_FR_REG18(sp)
+ sw s3,GDB_FR_REG19(sp)
+ sw s4,GDB_FR_REG20(sp)
+ sw s5,GDB_FR_REG21(sp)
+ sw s6,GDB_FR_REG22(sp)
+ sw s7,GDB_FR_REG23(sp)
+ sw t8,GDB_FR_REG24(sp)
+ sw t9,GDB_FR_REG25(sp)
+ sw k0,GDB_FR_REG26(sp)
+ sw k1,GDB_FR_REG27(sp)
+ sw gp,GDB_FR_REG28(sp)
+ /* sp already saved */
+ sw fp,GDB_FR_REG30(sp)
+ sw ra,GDB_FR_REG31(sp)
+
+ STI /* disable interrupts */
+
+/*
+ * Followed by the floating point registers
+ */
+ mfc0 v0,CP0_STATUS /* check if the FPU is enabled */
+ srl v0,v0,16
+ andi v0,v0,(ST0_CU1 >> 16)
+ beqz v0,2f /* disabled, skip */
+ nop
+
+ swc1 $0,GDB_FR_FPR0(sp)
+ swc1 $1,GDB_FR_FPR1(sp)
+ swc1 $2,GDB_FR_FPR2(sp)
+ swc1 $3,GDB_FR_FPR3(sp)
+ swc1 $4,GDB_FR_FPR4(sp)
+ swc1 $5,GDB_FR_FPR5(sp)
+ swc1 $6,GDB_FR_FPR6(sp)
+ swc1 $7,GDB_FR_FPR7(sp)
+ swc1 $8,GDB_FR_FPR8(sp)
+ swc1 $9,GDB_FR_FPR9(sp)
+ swc1 $10,GDB_FR_FPR10(sp)
+ swc1 $11,GDB_FR_FPR11(sp)
+ swc1 $12,GDB_FR_FPR12(sp)
+ swc1 $13,GDB_FR_FPR13(sp)
+ swc1 $14,GDB_FR_FPR14(sp)
+ swc1 $15,GDB_FR_FPR15(sp)
+ swc1 $16,GDB_FR_FPR16(sp)
+ swc1 $17,GDB_FR_FPR17(sp)
+ swc1 $18,GDB_FR_FPR18(sp)
+ swc1 $19,GDB_FR_FPR19(sp)
+ swc1 $20,GDB_FR_FPR20(sp)
+ swc1 $21,GDB_FR_FPR21(sp)
+ swc1 $22,GDB_FR_FPR22(sp)
+ swc1 $23,GDB_FR_FPR23(sp)
+ swc1 $24,GDB_FR_FPR24(sp)
+ swc1 $25,GDB_FR_FPR25(sp)
+ swc1 $26,GDB_FR_FPR26(sp)
+ swc1 $27,GDB_FR_FPR27(sp)
+ swc1 $28,GDB_FR_FPR28(sp)
+ swc1 $29,GDB_FR_FPR29(sp)
+ swc1 $30,GDB_FR_FPR30(sp)
+ swc1 $31,GDB_FR_FPR31(sp)
+
+/*
+ * FPU control registers
+ */
+
+ mfc1 v0,CP1_STATUS
+ sw v0,GDB_FR_FSR(sp)
+ mfc1 v0,CP1_REVISION
+ sw v0,GDB_FR_FIR(sp)
+
+/*
+ * current stack frame ptr
+ */
+
+2: sw sp,GDB_FR_FRP(sp)
+
+/*
+ * CP0 registers (R4000/R4400 unused registers skipped)
+ */
+
+ mfc0 v0,CP0_INDEX
+ sw v0,GDB_FR_CP0_INDEX(sp)
+ mfc0 v0,CP0_RANDOM
+ sw v0,GDB_FR_CP0_RANDOM(sp)
+ mfc0 v0,CP0_ENTRYLO0
+ sw v0,GDB_FR_CP0_ENTRYLO0(sp)
+ mfc0 v0,CP0_ENTRYLO1
+ sw v0,GDB_FR_CP0_ENTRYLO1(sp)
+ mfc0 v0,CP0_PAGEMASK
+ sw v0,GDB_FR_CP0_PAGEMASK(sp)
+ mfc0 v0,CP0_WIRED
+ sw v0,GDB_FR_CP0_WIRED(sp)
+ mfc0 v0,CP0_ENTRYHI
+ sw v0,GDB_FR_CP0_ENTRYHI(sp)
+ mfc0 v0,CP0_PRID
+ sw v0,GDB_FR_CP0_PRID(sp)
+
+ .set at
+
+/*
+ * continue with the higher level handler
+ */
+
+ move a0,sp
+ jal handle_exception
+ nop
+
+/*
+ * restore all writable registers, in reverse order
+ */
+
+ .set noat
+
+ lw v0,GDB_FR_CP0_ENTRYHI(sp)
+ lw v1,GDB_FR_CP0_WIRED(sp)
+ mtc0 v0,CP0_ENTRYHI
+ mtc0 v1,CP0_WIRED
+ lw v0,GDB_FR_CP0_PAGEMASK(sp)
+ lw v1,GDB_FR_CP0_ENTRYLO1(sp)
+ mtc0 v0,CP0_PAGEMASK
+ mtc0 v1,CP0_ENTRYLO1
+ lw v0,GDB_FR_CP0_ENTRYLO0(sp)
+ lw v1,GDB_FR_CP0_INDEX(sp)
+ mtc0 v0,CP0_ENTRYLO0
+ mtc0 v1,CP0_INDEX
+
+/*
+ * Next, the floating point registers
+ */
+ mfc0 v0,CP0_STATUS /* check if the FPU is enabled */
+ srl v0,v0,16
+ andi v0,v0,(ST0_CU1 >> 16)
+ beqz v0,3f /* disabled, skip */
+ nop
+
+ lwc1 $31,GDB_FR_FPR31(sp)
+ lwc1 $30,GDB_FR_FPR30(sp)
+ lwc1 $29,GDB_FR_FPR29(sp)
+ lwc1 $28,GDB_FR_FPR28(sp)
+ lwc1 $27,GDB_FR_FPR27(sp)
+ lwc1 $26,GDB_FR_FPR26(sp)
+ lwc1 $25,GDB_FR_FPR25(sp)
+ lwc1 $24,GDB_FR_FPR24(sp)
+ lwc1 $23,GDB_FR_FPR23(sp)
+ lwc1 $22,GDB_FR_FPR22(sp)
+ lwc1 $21,GDB_FR_FPR21(sp)
+ lwc1 $20,GDB_FR_FPR20(sp)
+ lwc1 $19,GDB_FR_FPR19(sp)
+ lwc1 $18,GDB_FR_FPR18(sp)
+ lwc1 $17,GDB_FR_FPR17(sp)
+ lwc1 $16,GDB_FR_FPR16(sp)
+ lwc1 $15,GDB_FR_FPR15(sp)
+ lwc1 $14,GDB_FR_FPR14(sp)
+ lwc1 $13,GDB_FR_FPR13(sp)
+ lwc1 $12,GDB_FR_FPR12(sp)
+ lwc1 $11,GDB_FR_FPR11(sp)
+ lwc1 $10,GDB_FR_FPR10(sp)
+ lwc1 $9,GDB_FR_FPR9(sp)
+ lwc1 $8,GDB_FR_FPR8(sp)
+ lwc1 $7,GDB_FR_FPR7(sp)
+ lwc1 $6,GDB_FR_FPR6(sp)
+ lwc1 $5,GDB_FR_FPR5(sp)
+ lwc1 $4,GDB_FR_FPR4(sp)
+ lwc1 $3,GDB_FR_FPR3(sp)
+ lwc1 $2,GDB_FR_FPR2(sp)
+ lwc1 $1,GDB_FR_FPR1(sp)
+ lwc1 $0,GDB_FR_FPR0(sp)
+
+/*
+ * Now the CP0 and integer registers
+ */
+
+3: mfc0 t0,CP0_STATUS
+ ori t0,0x1f
+ xori t0,0x1f
+ mtc0 t0,CP0_STATUS
+
+ lw v0,GDB_FR_STATUS(sp)
+ lw v1,GDB_FR_EPC(sp)
+ mtc0 v0,CP0_STATUS
+ mtc0 v1,CP0_EPC
+ lw v0,GDB_FR_HI(sp)
+ lw v1,GDB_FR_LO(sp)
+ mthi v0
+ mtlo v0
+ lw ra,GDB_FR_REG31(sp)
+ lw fp,GDB_FR_REG30(sp)
+ lw gp,GDB_FR_REG28(sp)
+ lw k1,GDB_FR_REG27(sp)
+ lw k0,GDB_FR_REG26(sp)
+ lw t9,GDB_FR_REG25(sp)
+ lw t8,GDB_FR_REG24(sp)
+ lw s7,GDB_FR_REG23(sp)
+ lw s6,GDB_FR_REG22(sp)
+ lw s5,GDB_FR_REG21(sp)
+ lw s4,GDB_FR_REG20(sp)
+ lw s3,GDB_FR_REG19(sp)
+ lw s2,GDB_FR_REG18(sp)
+ lw s1,GDB_FR_REG17(sp)
+ lw s0,GDB_FR_REG16(sp)
+ lw t7,GDB_FR_REG15(sp)
+ lw t6,GDB_FR_REG14(sp)
+ lw t5,GDB_FR_REG13(sp)
+ lw t4,GDB_FR_REG12(sp)
+ lw t3,GDB_FR_REG11(sp)
+ lw t2,GDB_FR_REG10(sp)
+ lw t1,GDB_FR_REG9(sp)
+ lw t0,GDB_FR_REG8(sp)
+ lw a3,GDB_FR_REG7(sp)
+ lw a2,GDB_FR_REG6(sp)
+ lw a1,GDB_FR_REG5(sp)
+ lw a0,GDB_FR_REG4(sp)
+ lw v1,GDB_FR_REG3(sp)
+ lw v0,GDB_FR_REG2(sp)
+ lw $1,GDB_FR_REG1(sp)
+ lw sp,GDB_FR_REG29(sp) /* Deallocate stack */
+
+ ERET
+ .set at
+ .set reorder
+ END(trap_low)
+
+/* end of file gdb-low.S */
--- /dev/null
+/*
+ * arch/mips/kernel/gdb-stub.c
+ *
+ * Originally written by Glenn Engel, Lake Stevens Instrument Division
+ *
+ * Contributed by HP Systems
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
+ * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+
+/*
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a BREAK instruction.
+ *
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * G set the value of the CPU registers OK or ENN
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
+ * baud rate
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/segment.h>
+#include <asm/cachectl.h>
+#include <asm/system.h>
+#include <asm/gdb-stub.h>
+
+/*
+ * external low-level support routines
+ */
+
+extern int putDebugChar(char c); /* write a single character */
+extern char getDebugChar(void); /* read and return a single char */
+extern void fltr_set_mem_err(void);
+extern void trap_low(void);
+
+/*
+ * breakpoint and test functions
+ */
+extern void breakpoint(void);
+extern void breakinst(void);
+extern void adel(void);
+
+/*
+ * local prototypes
+ */
+
+static void getpacket(char *buffer);
+static void putpacket(char *buffer);
+static void set_mem_fault_trap(int enable);
+static int computeSignal(int tt);
+static int hex(unsigned char ch);
+static int hexToInt(char **ptr, int *intValue);
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
+void handle_exception(struct gdb_regs *regs);
+static void show_gdbregs(struct gdb_regs *regs);
+
+/*
+ * BUFMAX defines the maximum number of characters in inbound/outbound buffers
+ * at least NUMREGBYTES*2 are needed for register packets
+ */
+#define BUFMAX 2048
+
+static char input_buffer[BUFMAX];
+static char output_buffer[BUFMAX];
+static int initialized = 0; /* !0 means we've been initialized */
+static const char hexchars[]="0123456789abcdef";
+
+
+/*
+ * Convert ch from a hex digit to an int
+ */
+static int hex(unsigned char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return ch-'a'+10;
+ if (ch >= '0' && ch <= '9')
+ return ch-'0';
+ if (ch >= 'A' && ch <= 'F')
+ return ch-'A'+10;
+ return -1;
+}
+
+/*
+ * scan for the sequence $<data>#<checksum>
+ */
+static void getpacket(char *buffer)
+{
+ unsigned char checksum;
+ unsigned char xmitcsum;
+ int i;
+ int count;
+ unsigned char ch;
+
+ do {
+ /*
+ * wait around for the start character,
+ * ignore all other characters
+ */
+ while ((ch = (getDebugChar() & 0x7f)) != '$') ;
+
+ checksum = 0;
+ xmitcsum = -1;
+ count = 0;
+
+ /*
+ * now, read until a # or end of buffer is found
+ */
+ while (count < BUFMAX) {
+ ch = getDebugChar() & 0x7f;
+ if (ch == '#')
+ break;
+ checksum = checksum + ch;
+ buffer[count] = ch;
+ count = count + 1;
+ }
+
+ if (count >= BUFMAX)
+ continue;
+
+ buffer[count] = 0;
+
+ if (ch == '#') {
+ xmitcsum = hex(getDebugChar() & 0x7f) << 4;
+ xmitcsum |= hex(getDebugChar() & 0x7f);
+
+ if (checksum != xmitcsum)
+ putDebugChar('-'); /* failed checksum */
+ else {
+ putDebugChar('+'); /* successful transfer */
+
+ /*
+ * if a sequence char is present,
+ * reply the sequence ID
+ */
+ if (buffer[2] == ':') {
+ putDebugChar(buffer[0]);
+ putDebugChar(buffer[1]);
+
+ /*
+ * remove sequence chars from buffer
+ */
+ count = strlen(buffer);
+ for (i=3; i <= count; i++)
+ buffer[i-3] = buffer[i];
+ }
+ }
+ }
+ }
+ while (checksum != xmitcsum);
+}
+
+/*
+ * send the packet in buffer.
+ */
+static void putpacket(char *buffer)
+{
+ unsigned char checksum;
+ int count;
+ unsigned char ch;
+
+ /*
+ * $<packet info>#<checksum>.
+ */
+
+ do {
+ putDebugChar('$');
+ checksum = 0;
+ count = 0;
+
+ while ((ch = buffer[count]) != 0) {
+ if (!(putDebugChar(ch)))
+ return;
+ checksum += ch;
+ count += 1;
+ }
+
+ putDebugChar('#');
+ putDebugChar(hexchars[checksum >> 4]);
+ putDebugChar(hexchars[checksum & 0xf]);
+
+ }
+ while ((getDebugChar() & 0x7f) != '+');
+}
+
+
+/*
+ * Indicate to caller of mem2hex or hex2mem that there
+ * has been an error.
+ */
+static volatile int mem_err = 0;
+
+/*
+ * Convert the memory pointed to by mem into hex, placing result in buf.
+ * Return a pointer to the last char put in buf (null), in case of mem fault,
+ * return 0.
+ * If MAY_FAULT is non-zero, then we will handle memory faults by returning
+ * a 0, else treat a fault like any other fault in the stub.
+ */
+static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
+{
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ while (count-- > 0) {
+ ch = *(mem++);
+ if (mem_err)
+ return 0;
+ *buf++ = hexchars[ch >> 4];
+ *buf++ = hexchars[ch & 0xf];
+ }
+
+ *buf = 0;
+
+/* set_mem_fault_trap(0); */
+
+ return buf;
+}
+
+/*
+ * convert the hex array pointed to by buf into binary to be placed in mem
+ * return a pointer to the character AFTER the last byte written
+ */
+static char *hex2mem(char *buf, char *mem, int count, int may_fault)
+{
+ int i;
+ unsigned char ch;
+
+/* set_mem_fault_trap(may_fault); */
+
+ for (i=0; i<count; i++)
+ {
+ ch = hex(*buf++) << 4;
+ ch |= hex(*buf++);
+ *(mem++) = ch;
+ if (mem_err)
+ return 0;
+ }
+
+/* set_mem_fault_trap(0); */
+
+ return mem;
+}
+
+/*
+ * This table contains the mapping between SPARC hardware trap types, and
+ * signals, which are primarily what GDB understands. It also indicates
+ * which hardware traps we need to commandeer when initializing the stub.
+ */
+static struct hard_trap_info
+{
+ unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */
+ unsigned char signo; /* Signal that we map this trap into */
+} hard_trap_info[] = {
+ { 4, SIGBUS }, /* address error (load) */
+ { 5, SIGBUS }, /* address error (store) */
+ { 6, SIGBUS }, /* instruction bus error */
+ { 7, SIGBUS }, /* data bus error */
+ { 9, SIGTRAP }, /* break */
+ { 10, SIGILL }, /* reserved instruction */
+/* { 11, SIGILL }, */ /* cpu unusable */
+ { 12, SIGFPE }, /* overflow */
+ { 13, SIGTRAP }, /* trap */
+ { 14, SIGSEGV }, /* virtual instruction cache coherency */
+ { 15, SIGFPE }, /* floating point exception */
+ { 23, SIGSEGV }, /* watch */
+ { 31, SIGSEGV }, /* virtual data cache coherency */
+ { 0, 0} /* Must be last */
+};
+
+
+/*
+ * Set up exception handlers for tracing and breakpoints
+ */
+void set_debug_traps(void)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ set_except_vector(ht->tt, trap_low);
+
+ /*
+ * In case GDB is started before us, ack any packets
+ * (presumably "$?#xx") sitting there.
+ */
+
+ putDebugChar ('+');
+ initialized = 1;
+
+ breakpoint();
+}
+
+
+/*
+ * Trap handler for memory errors. This just sets mem_err to be non-zero. It
+ * assumes that %l1 is non-zero. This should be safe, as it is doubtful that
+ * 0 would ever contain code that could mem fault. This routine will skip
+ * past the faulting instruction after setting mem_err.
+ */
+extern void fltr_set_mem_err(void)
+{
+ /* FIXME: Needs to be written... */
+}
+
+
+static void set_mem_fault_trap(int enable)
+{
+ mem_err = 0;
+
+#if 0
+ if (enable)
+ exceptionHandler(9, fltr_set_mem_err);
+ else
+ exceptionHandler(9, trap_low);
+#endif
+}
+
+/*
+ * Convert the MIPS hardware trap type code to a unix signal number.
+ */
+static int computeSignal(int tt)
+{
+ struct hard_trap_info *ht;
+
+ for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
+ if (ht->tt == tt)
+ return ht->signo;
+
+ return SIGHUP; /* default for things we don't know about */
+}
+
+/*
+ * While we find nice hex chars, build an int.
+ * Return number of chars processed.
+ */
+static int hexToInt(char **ptr, int *intValue)
+{
+ int numChars = 0;
+ int hexValue;
+
+ *intValue = 0;
+
+ while (**ptr)
+ {
+ hexValue = hex(**ptr);
+ if (hexValue < 0)
+ break;
+
+ *intValue = (*intValue << 4) | hexValue;
+ numChars ++;
+
+ (*ptr)++;
+ }
+
+ return (numChars);
+}
+
+/*
+ * This function does all command procesing for interfacing to gdb. It
+ * returns 1 if you should skip the instruction at the trap address, 0
+ * otherwise.
+ */
+void handle_exception (struct gdb_regs *regs)
+{
+ int trap; /* Trap type */
+ int sigval;
+ int addr;
+ int length;
+ char *ptr;
+ unsigned long *stack;
+
+#if 0
+ printk("in handle_exception()\n");
+ show_gdbregs(regs);
+#endif
+
+ /*
+ * First check trap type. If this is CPU_UNUSABLE and CPU_ID is 1,
+ * the simply switch the FPU on and return since this is no error
+ * condition. kernel/traps.c does the same.
+ * FIXME: This doesn't work yet, so we don't catch CPU_UNUSABLE
+ * traps for now.
+ */
+ trap = (regs->cp0_cause & 0x7c) >> 2;
+/* printk("trap=%d\n",trap); */
+ if (trap == 11) {
+ if (((regs->cp0_cause >> CAUSEB_CE) & 3) == 1) {
+ regs->cp0_status |= ST0_CU1;
+ return;
+ }
+ }
+
+ /*
+ * If we're in breakpoint() increment the PC
+ */
+ if (trap == 9 && regs->cp0_epc == (unsigned long)breakinst)
+ regs->cp0_epc += 4;
+
+ stack = (long *)regs->reg29; /* stack ptr */
+ sigval = computeSignal(trap);
+
+ /*
+ * reply to host that an exception has occurred
+ */
+ ptr = output_buffer;
+
+ /*
+ * Send trap type (converted to signal)
+ */
+ *ptr++ = 'T';
+ *ptr++ = hexchars[sigval >> 4];
+ *ptr++ = hexchars[sigval & 0xf];
+
+ /*
+ * Send Error PC
+ */
+ *ptr++ = hexchars[REG_EPC >> 4];
+ *ptr++ = hexchars[REG_EPC & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)®s->cp0_epc, ptr, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send frame pointer
+ */
+ *ptr++ = hexchars[REG_FP >> 4];
+ *ptr++ = hexchars[REG_FP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)®s->reg30, ptr, 4, 0);
+ *ptr++ = ';';
+
+ /*
+ * Send stack pointer
+ */
+ *ptr++ = hexchars[REG_SP >> 4];
+ *ptr++ = hexchars[REG_SP & 0xf];
+ *ptr++ = ':';
+ ptr = mem2hex((char *)®s->reg29, ptr, 4, 0);
+ *ptr++ = ';';
+
+ *ptr++ = 0;
+ putpacket(output_buffer); /* send it off... */
+
+ /*
+ * Wait for input from remote GDB
+ */
+ while (1) {
+ output_buffer[0] = 0;
+ getpacket(input_buffer);
+
+ switch (input_buffer[0])
+ {
+ case '?':
+ output_buffer[0] = 'S';
+ output_buffer[1] = hexchars[sigval >> 4];
+ output_buffer[2] = hexchars[sigval & 0xf];
+ output_buffer[3] = 0;
+ break;
+
+ case 'd':
+ /* toggle debug flag */
+ break;
+
+ /*
+ * Return the value of the CPU registers
+ */
+ case 'g':
+ ptr = output_buffer;
+ ptr = mem2hex((char *)®s->reg0, ptr, 32*4, 0); /* r0...r31 */
+ ptr = mem2hex((char *)®s->cp0_status, ptr, 6*4, 0); /* cp0 */
+ ptr = mem2hex((char *)®s->fpr0, ptr, 32*4, 0); /* f0...31 */
+ ptr = mem2hex((char *)®s->cp1_fsr, ptr, 2*4, 0); /* cp1 */
+ ptr = mem2hex((char *)®s->frame_ptr, ptr, 2*4, 0); /* frp */
+ ptr = mem2hex((char *)®s->cp0_index, ptr, 16*4, 0); /* cp0 */
+ break;
+
+ /*
+ * set the value of the CPU registers - return OK
+ * FIXME: Needs to be written
+ */
+ case 'G':
+ {
+#if 0
+ unsigned long *newsp, psr;
+
+ ptr = &input_buffer[1];
+ hex2mem(ptr, (char *)registers, 16 * 4, 0); /* G & O regs */
+
+ /*
+ * See if the stack pointer has moved. If so, then copy the
+ * saved locals and ins to the new location.
+ */
+
+ newsp = (unsigned long *)registers[SP];
+ if (sp != newsp)
+ sp = memcpy(newsp, sp, 16 * 4);
+
+#endif
+ strcpy(output_buffer,"OK");
+ }
+ break;
+
+ /*
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA
+ */
+ case 'm':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)) {
+ if (mem2hex((char *)addr, output_buffer, length, 1))
+ break;
+ strcpy (output_buffer, "E03");
+ } else
+ strcpy(output_buffer,"E01");
+ break;
+
+ /*
+ * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
+ */
+ case 'M':
+ ptr = &input_buffer[1];
+
+ if (hexToInt(&ptr, &addr)
+ && *ptr++ == ','
+ && hexToInt(&ptr, &length)
+ && *ptr++ == ':') {
+ if (hex2mem(ptr, (char *)addr, length, 1))
+ strcpy(output_buffer, "OK");
+ else
+ strcpy(output_buffer, "E03");
+ }
+ else
+ strcpy(output_buffer, "E02");
+ break;
+
+ /*
+ * cAA..AA Continue at address AA..AA(optional)
+ */
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+
+ ptr = &input_buffer[1];
+ if (hexToInt(&ptr, &addr))
+ regs->cp0_epc = addr;
+
+ /*
+ * Need to flush the instruction cache here, as we may
+ * have deposited a breakpoint, and the icache probably
+ * has no way of knowing that a data ref to some location
+ * may have changed something that is in the instruction
+ * cache.
+ * NB: We flush both caches, just to be sure...
+ */
+
+ sys_cacheflush((void *)KSEG0,KSEG1-KSEG0,BCACHE);
+ return;
+ /* NOTREACHED */
+ break;
+
+
+ /*
+ * kill the program
+ */
+ case 'k' :
+ break; /* do nothing */
+
+
+ /*
+ * Reset the whole machine (FIXME: system dependent)
+ */
+ case 'r':
+ break;
+
+
+ /*
+ * Step to next instruction
+ * FIXME: Needs to be written
+ */
+ case 's':
+ strcpy (output_buffer, "S01");
+ break;
+
+ /*
+ * Set baud rate (bBB)
+ * FIXME: Needs to be written
+ */
+ case 'b':
+ {
+#if 0
+ int baudrate;
+ extern void set_timer_3();
+
+ ptr = &input_buffer[1];
+ if (!hexToInt(&ptr, &baudrate))
+ {
+ strcpy(output_buffer,"B01");
+ break;
+ }
+
+ /* Convert baud rate to uart clock divider */
+
+ switch (baudrate)
+ {
+ case 38400:
+ baudrate = 16;
+ break;
+ case 19200:
+ baudrate = 33;
+ break;
+ case 9600:
+ baudrate = 65;
+ break;
+ default:
+ baudrate = 0;
+ strcpy(output_buffer,"B02");
+ goto x1;
+ }
+
+ if (baudrate) {
+ putpacket("OK"); /* Ack before changing speed */
+ set_timer_3(baudrate); /* Set it */
+ }
+#endif
+ }
+ break;
+
+ } /* switch */
+
+ /*
+ * reply to the request
+ */
+
+ putpacket(output_buffer);
+
+ } /* while */
+}
+
+/*
+ * This function will generate a breakpoint exception. It is used at the
+ * beginning of a program to sync up with a debugger and can be used
+ * otherwise as a quick means to stop program execution and "break" into
+ * the debugger.
+ */
+void breakpoint(void)
+{
+ if (!initialized)
+ return;
+
+ __asm__ __volatile__("
+ .globl breakinst
+ .set noreorder
+ nop
+breakinst: break
+ nop
+ .set reorder
+ ");
+}
+
+void adel(void)
+{
+ __asm__ __volatile__("
+ .globl adel
+ la $8,0x80000001
+ lw $9,0($8)
+ ");
+}
+
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+void show_gdbregs(struct gdb_regs * regs)
+{
+ /*
+ * Saved main processor registers
+ */
+ printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg0, regs->reg1, regs->reg2, regs->reg3,
+ regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+ printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+ regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+ printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+ regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+ printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg24, regs->reg25, regs->reg26, regs->reg27,
+ regs->reg28, regs->reg29, regs->reg30, regs->reg31);
+
+ /*
+ * Saved cp0 registers
+ */
+ printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
+ regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
/*
- * mips/head.S
+ * arch/mips/kernel/head.S
*
- * Copyright (C) 1994 Waldorf Electronics
+ * Copyright (C) 1994, 1995 Waldorf Electronics
* Written by Ralf Baechle and Andreas Busse
*
* Head.S contains the MIPS exception handler and startup code.
*/
-
-#undef DEBUGPICA /* undef this if you have a different system */
-
#include <linux/tasks.h>
+#include <asm/asm.h>
#include <asm/segment.h>
#include <asm/cachectl.h>
#include <asm/mipsregs.h>
#include <asm/mipsconfig.h>
#include <asm/stackframe.h>
-#include <asm/regdef.h>
#include <asm/bootinfo.h>
-#include <asm/segment.h>
#define PAGE_SIZE 0x1000
-/*
- * For now we can't enable write caching. This would cause trouble
- * with the page aliases used by the memory management.
- * The page table's aliases even have to be uncachable, but that
- * doesn't hurt much anyway.
- */
-#define PAGE_TABLE 0x0580 /* uncachable */
-#define PAGE_SHARED 0x0580 /* cachable, writethrough, no write allocate */
+#define MODE_GLOBAL 0x0001 /* shared for all processes */
#define MODE_ALIAS 0x0016 /* uncachable */
- .globl _empty_bad_page
- .globl _empty_bad_page_table
- .globl _pg0
- .globl _empty_zero_page
- .globl _swapper_pg_dir
-
.text
- .globl _kernelbase
-_kernelbase:
-
+ .set mips3
/*
* This is space for the interrupt handlers.
* They are located at virtual address KSEG[01] (physical 0x0)
*/
.set noreorder
.set noat
-except_vec0:
-#if KERNELBASE == KSEG1
- la k0,1f
- jr k0
- nop
-1:
-#endif
+ LEAF(except_vec0)
dmfc0 k1,CP0_CONTEXT
- dsra k1,k1,1
+ dsra k1,1
lwu k0,(k1) # May cause another exception
lwu k1,4(k1)
- dsrl k0,k0,6 # Convert to EntryLo format
- dsrl k1,k1,6 # Convert to EntryLo format
+ dsrl k0,6 # Convert to EntryLo format
+ dsrl k1,6 # Convert to EntryLo format
dmtc0 k0,CP0_ENTRYLO0
dmtc0 k1,CP0_ENTRYLO1
+ nop # Needed for R4[04]00 pipeline
tlbwr
+ nop # Needed for R4[04]00 pipeline
+ nop
+ nop
+ eret
+ /*
+ * Workaround for R4000 bug. For explanation see MIPS
+ * docs. Note that this that obscure that it wont almost
+ * never happen. Well, but Mips writes about it's bugs.
+ */
+ nop
eret
+ END(except_vec0)
/*
* XTLB refill, EXL == 0
* Should never be reached
*/
.org except_vec0+0x80
-except_vec1:
-#if KERNELBASE == KSEG1
- la k0,1f
- jr k0
- nop
-1:
-#endif
- la a0,xtlb_text
- jal _panic
- nop
+ LEAF(except_vec1)
+ PANIC("XTLB Refill exception.\n")
1: j 1b
nop
-xtlb_text: .asciz "XTLB Refill exception.\n"
+ END(except_vec1)
/*
* Cache Error
*/
.org except_vec1+0x80
-except_vec2:
-#if KERNELBASE == KSEG1
- la k0,1f
- jr k0
- nop
-1:
-#endif
+ LEAF(except_vec2)
/*
- * Should never be reached
+ * Famous last words: unreached
*/
- la a0,xtlb_text
- jal _panic
- nop
+ mfc0 a1,CP0_ERROREPC
+ PRINT("Cache error exception: c0_errorepc == %08x\n")
1: j 1b
nop
-cache_text: .asciz "Cache error exception\n"
+ END(except_vec2)
/*
* General exception vector.
*/
.org except_vec2+0x80
-except_vec3: /*
+ NESTED(except_vec3, 0, sp)
+ .set noat
+ /*
* Register saving is delayed as long as we don't know
* which registers really need to be saved.
*/
-#if KERNELBASE == KSEG1
- la k0,1f
- jr k0
- nop
-1:
-#endif
- .set noat
mfc0 k1,CP0_CAUSE
- la k0,_exception_handlers
+ la k0,exception_handlers
/*
* Next lines assumes that the used CPU type has max.
* 32 different types of exceptions. We might use this
* to implement software exceptions in the future.
*/
- andi k1,k1,0x7c
- addu k0,k0,k1
+ andi k1,0x7c
+ addu k0,k1
lw k0,(k0)
- FILL_LDS
+ NOP
jr k0
nop
+ END(except_vec3)
+ .set at
/******************************************************************************/
* Kernel entry
*/
.set noreorder
- .set at
-kernel_entry:
- jal refill
- nop
+ NESTED(kernel_entry, 16, sp)
+ /*
+ * The followin two symbols are used for kernel profiling.
+ */
+ EXPORT(stext)
+ EXPORT(_stext)
+#ifdef CONF_DISABLE_KSEG0_CACHING
+ /*
+ * Disable all caching for KSEG0. This option is usefull
+ * when cache trouble with drivers is suspected
+ */
+ mfc0 t0,CP0_CONFIG
+ ori t0,7
+ xori t0,5
+ mtc0 t0,CP0_CONFIG
+#endif
/*
* Clear BSS first so that there are no surprises...
*/
- la t0,__edata
- la t1,__end
+ la t0,_edata
+ la t1,_end
sw zero,(t0)
-1: addiu t0,t0,4
+1: addiu t0,4
bnel t0,t1,1b
sw zero,(t0)
-#ifdef DEBUGPICA
- la t0,_boot_info
- lw t0,OFFSET_BOOTINFO_VRAM_BASE(t0)
- li t1,0x0f00 + '3'
- sh t1,4(t0)
-#endif
-
- .set noreorder
- jal _tlbflush
- mtc0 zero,CP0_WIRED
- /*
- * Spread some mines...
- */
- la t0,_end
- la t1,0x003ffffc
- la t2,KERNELBASE
- or t1,t2
- li t2,0xdeadbeef
-1: sw t2,(t0)
- bne t0,t1,1b
- addiu t0,t0,4
/*
- * Initialize memory management, map lowest 4MB
+ * Initialize low level part of memory management
+ * First flush the TLB to make shure that we don't get a
+ * TLB shutdown during wire_mappings.
*/
- .set reorder
- jal setup_paging
-#if KERNELBASE == KSEG0
- jal _sys_cacheflush
-#endif
+ jal tlbflush
+ mtc0 zero,CP0_WIRED # delay slot
+ jal wire_mappings
+ nop
-#ifdef DEBUGPICA
- la t0,_boot_info
- lw t0,OFFSET_BOOTINFO_VRAM_BASE(t0)
- li t1,0x0f00 + '4'
- sh t1,6(t0)
-#endif
/*
* Stack for kernel and init
*/
- la sp,_init_user_stack+PAGE_SIZE-24
- sw sp,_kernelsp
+ la sp,init_user_stack+PAGE_SIZE-24
+ la t0,init_kernel_stack+PAGE_SIZE
+ sw t0,kernelsp
-1: jal _start_kernel
+ /*
+ * Disable coprocessors; set ST0_CU0 to indicate that
+ * we're running on the kernel stack
+ */
+ mfc0 t0,CP0_STATUS
+ li t1,~(ST0_CU1|ST0_CU2|ST0_CU3)
+ and t0,t1
+ li t1,ST0_CU0
+ or t0,ST0_CU0
+ mtc0 t0,CP0_STATUS
+
+1: jal start_kernel
+ nop # delay slot
/*
* Main should never return here, but
* just in case, we know what happens.
*/
- j 1b
+ b 1b
+ nop # delay slot
+ END(kernel_entry)
/*
- * Setup_paging
- *
- * Wire mappings for page_tables.
- * The page tables are set up, identity-mapping
- * the first 4MB. The rest are initialized later.
+ * wire_mappings - used to map hardware registers
*/
- .set noreorder
-setup_paging:
+ LEAF(wire_mappings)
/*
- * get base address of map0 table for the
+ * Get base address of map0 table for the
* the board we're running on
*/
- la t0,_boot_info
+ la t0,boot_info
lw t1,OFFSET_BOOTINFO_MACHTYPE(t0)
- sll t1,t1,2 # machtype used as index
la t0,map0table
- addu t0,t0,t1
+ sll t1,PTRLOG # machtype used as index
+ addu t0,t1
lw t0,(t0) # get base address
/*
addiu t3,t1,1 # wire one additional entry
beqz t1,2f # null, exit
mtc0 t3,CP0_WIRED # delay slot
- addiu t0,t0,8
+ addiu t0,8
1: lw t4,24(t0) # PageMask
ld t5,0(t0) # entryHi
ld t6,8(t0) # entryLo0
ld t7,16(t0) # entryLo1
- addiu t2,t2,1 # increment ctr
+ addiu t2,1 # increment ctr
mtc0 t2,CP0_INDEX # set TLB entry
mtc0 t4,CP0_PAGEMASK
dmtc0 t5,CP0_ENTRYHI
dmtc0 t6,CP0_ENTRYLO0
dmtc0 t7,CP0_ENTRYLO1
- tlbwi
+ addiu t0,32
bne t1,t2,1b # next TLB entry
- addiu t0,t0,32 # delay slot
+ tlbwi # delay slot
/*
* We use only 4k pages. Therefore the PageMask register
2: li t0,PM_4K
mtc0 t0,CP0_PAGEMASK
- la t1,_swapper_pg_dir # swapper_pg_dir is at 0x1000
- la t2,_swapper_pg_dir+(PAGE_SIZE-4)
-1: sw zero,(t1)
- bne t1,t2,1b
- addiu t1,t1,4 # delay slot
-
- /*
- * Setup invalid_pg_table and
- * clear page table for the first 4MB
- */
- la t0,_pg0 # swapper_pg_dir is at 0x1000
- la t1,_pg0+PAGE_SIZE
- li t2,KERNELBASE
- addu t0,t2
- addu t1,t2
-1: sw zero,(t0)
- addiu t0,t0,4
- bne t0,t1,1b
- addiu t2,t2,4 # delay slot
-
- /*
- * Identity-map the kernel in low 4MB memory for ease
- * of transition. Unlike the Intel version the kernel
- * code/data is automagically being mapped by kseg0.
- */
- la t0,_pg0+PAGE_TABLE # set valid bit/user r/w
- sw t0,_swapper_pg_dir
-
- li t0,PAGE_SHARED # set valid bit/user r/w
- la t1,_pg0
- la t2,_pg0+PAGE_SIZE
- li t3,KERNELBASE
- addu t1,t3
- addu t2,t3
-1: sw t0,(t1)
- addiu t1,t1,4
- bne t1,t2,1b
- addiu t0,t0,PAGE_SIZE # delay slot
-
/*
* Now map the pagetables
*/
mtc0 zero,CP0_INDEX
la t0,TLB_ROOT
dmtc0 t0,CP0_ENTRYHI
- la t0,_swapper_pg_dir
- srl t0,t0,6
- ori t0,t0,MODE_ALIAS # uncachable, dirty, valid
+ la t0,swapper_pg_dir-KSEG1
+ srl t0,6
+ ori t0,(MODE_ALIAS|MODE_GLOBAL) # uncachable, dirty, valid
dmtc0 t0,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- tlbwi
- /*
- * Make page zero unaccessible to catch zero references
- */
- la t0,_pg0
- li t0,KERNELBASE
- addu t0,t1
- sw zero,(t0)
+ li t0,MODE_GLOBAL
+ dmtc0 t0,CP0_ENTRYLO1
+ nop
+ tlbwi # delayed
+
/*
* Load the context register with a value that allows
* it to be used as fast as possible in tlb exceptions.
- * It is expected that this register's content never
- * will be changed.
+ * It is expected that this register's content will
+ * NEVER be changed.
*/
li t0,TLBMAP
- dsll t0,t0,1
- jr ra
- dmtc0 t0,CP0_CONTEXT # delay slot
-
- /*
- * Flush the TLB
- *
- * FIXME: knows only how to handle R4x00
- * Read appendix f of the R4000 manual before you change
- * something!
- */
- .globl _tlbflush
-_tlbflush: li t0,PM_4K
- mtc0 t0,CP0_PAGEMASK
- lw t0,_boot_info+OFFSET_BOOTINFO_TLB_ENTRIES(t0)
- dmtc0 zero,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- mfc0 t2,CP0_WIRED
-1: subu t0,t0,1
- mtc0 t0,CP0_INDEX
- lui t1,0x0008
- or t1,t0,t1
- dsll t1,t1,13
- dmtc0 t1,CP0_ENTRYHI
- bne t2,t0,1b
- tlbwi # delay slot
- jr ra
- nop
-
-/*
- * Refill icache
- */
-#include <asm/mipsconfig.h>
-#include <asm/regdef.h>
-#include <asm/segment.h>
-
-#define PAGE_SIZE 0x1000
-
-#define CACHELINES 512 /* number of cachelines */
-
- .set noreorder
- .text
-refill:
- /*
- * Refill icache with cache fill command
- */
- li t0,KSEG0
- li t1,CACHELINES
-1: cache 21,0(t0)
- cache 21,32(t0)
- cache 21,64(t0)
- cache 21,96(t0)
- cache 21,128(t0)
- cache 21,160(t0)
- cache 21,192(t0)
- cache 21,224(t0)
- cache 21,256(t0)
- cache 21,288(t0)
- cache 21,320(t0)
- cache 21,352(t0)
- cache 21,384(t0)
- cache 21,416(t0)
- cache 21,448(t0)
- cache 21,480(t0)
- subu t1,t1,1
- bnez t1,1b
- addiu t0,t0,512 # delay slot
-
- jr ra
- nop
-
-/*
- * Just for debugging...
- */
- .globl _beep
-_beep: lw t0,beepflag
- nop
- bnez t0,1f
- lbu t0,0xe0000061
- xori t0,t0,3
- sb t0,0xe0000061
- li t0,1
- sw t0,beepflag
-1: jr ra
+ dsll t0,1
+ dmtc0 t0,CP0_CONTEXT
+ jr ra # delay slot
nop
+ END(wire_mappings)
+ .data
/*
- * Compute kernel code checksum to check kernel code against corruption
+ * Build an entry for table of wired entries
*/
- .globl _csum
-#if 0
-_csum: jal _sys_cacheflush
- move t8,ra # delay slot
-#else
-_csum: move t8,ra
-#endif
- li t0,KSEG1
- la t1,final
- li t2,KSEG1
- or t0,t2
- or t1,t2
- move v0,zero
-1: lw t2,(t0)
- addiu t0,t0,4
- bne t0,t1,1b
- xor v0,v0,t2
- jr t8
- nop
-final:
+#define MAPDATA(q1,q2,q3,w1) \
+ .quad q1; \
+ .quad q2; \
+ .quad q3; \
+ .word w1; \
+ .word 0
- .data
/*
* Initial mapping tables for supported Mips boards.
* First item is always the number of wired TLB entries,
* target system in bootinfo.h
*/
-map0table: .word map0_dummy # machtype = unknown
- .word map0_tyne # Deskstation Tyne
- .word map0_pica61 # Acer Pica-61
+map0table: PTR map0_dummy # machtype = unknown
+ PTR map0_rpc # Deskstation rPC44
+ PTR map0_tyne # Deskstation Tyne
+ PTR map0_pica61 # Acer Pica-61
+ PTR map0_magnum4000 # MIPS Magnum 4000PC (RC4030)
map0_dummy: .word 0 # 0 entries
+ .align 3
/*
- * Initial mappings for Deskstation Tyne boards.
+ * Initial mappings for Deskstation rPC boards.
+ * RB: Untested goodie - I don't have such a board.
*/
- .align 8
-
-map0_tyne: .word 3 # no. of wired TLB entries
+map0_rpc: .word 2 # no. of wired TLB entries
.word 0 # pad for alignment
-# TLB entry 1: ISA I/O
-
- .quad 0xffffffffe0000000 # TLB #0 EntryHi
- .quad 0x24000017 # TLB #0 EntryLo0
- .quad 0 # TLB #0 EntryLo1
- .word PM_64K # page mask
- .word 0 # pad for alignment
+MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache
+MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space
-# TLB entry 2: ISA memory space
-
- .quad 0xffffffffe1000000 # TLB #1 EntryHi
- .quad 0x04000017 # TLB #1 EntryLo0
- .quad 0 # TLB #1 EntryLo1
- .word PM_1M
+/*
+ * Initial mappings for Deskstation Tyne boards.
+ */
+map0_tyne: .word 2 # no. of wired TLB entries
.word 0 # pad for alignment
-# TLB entry 3: ISA DMA cache
-
- .quad 0xffffffffe2000000 # TLB #2 EntryHi
- .quad 0x04020017 # TLB #2 EntryLo0
- .quad 0 # TLB #2 EntryLo1
- .word PM_1M
- .word 0 # pad for alignment
+MAPDATA(0xffffffffe0000000, 0x04020017, 0x00000001, PM_1M) # VESA DMA cache
+MAPDATA(0xffffffffe2000000, 0x24000017, 0x04000017, PM_16M) # VESA I/O and memory space
/*
* Initial mapping for ACER PICA-61 boards.
- * FIXME: These are rather preliminary since many drivers,
- * such as serial, parallel, scsi and ethernet need some
- * changes to distinguish between "local" (built-in) and
- * "optional" (ISA/PCI) I/O hardware.
- * Local video ram is mapped to the same location as the
- * bios maps it to. Console driver has been changed
+ * FIXME: These are rather preliminary since many drivers, such as serial,
+ * parallel, scsi and ethernet need some changes to distinguish between "local"
+ * (built-in) and "optional" (ISA/PCI) I/O hardware. Local video ram is mapped
+ * to the same location as the bios maps it to. Console driver has been changed
* accordingly (new video type: VIDEO_TYPE_PICA_S3).
+ * FIXME: Remove or merge some of the mappings.
*/
-
-map0_pica61: .word 9 # no. wired TLB entries
+map0_pica61: .word 7 # no. wired TLB entries
.word 0 # dummy
-# TLB entry 1: PROM
-
-# .quad 0xffffffffe1000000 # BIOS mapping
- .quad 0xffffffffe4000000 # new mapping
- .quad 0x03ffc013
- .quad 0x00000001 # global, not valid
- .word PM_256K
- .word 0
-
-# TLB entry 2: local I/O space
-
- .quad 0xffffffffe0000000
- .quad 0x02000017
- .quad 0x00000001 # global, not valid
- .word PM_64K
- .word 0
-
-# TLB entry 3: DRAM config register
-
- .quad 0xffffffffe00e0000
- .quad 0x02003817
- .quad 0x02003c17
- .word PM_64K
- .word 0
-
-# TLB entry 4: Interrupt source register
-
- .quad 0xffffffffe0100000
- .quad 0x03c00017
- .quad 0x00000001 # global, not valid
- .word PM_4K
- .word 0
-
-# TLB entry 5: Local video control
-
- .quad 0xffffffffe0200000
- .quad 0x01800017
- .quad 0x01804017
- .word PM_1M
- .word 0
-
-# TLB entry 6: Extended video control
-
- .quad 0xffffffffe0400000
- .quad 0x01808017
- .quad 0x0180c017
- .word PM_1M
- .word 0
-
-# TLB entry 7: Local video memory (BIOS mapping)
-
- .quad 0xffffffffe0800000
- .quad 0x01000017
- .quad 0x01010017
- .word PM_4M
- .word 0
-
-# TLB entry 8: Local video memory (mapped to where Linux expects it)
-# not needed anymore
-# .quad 0xffffffffe1000000
-# .quad 0x01000017
-# .quad 0x01010017
-# .word PM_4M
-# .word 0
-
-# TLB entry 9: ISA I/O and ISA memory space (both 16M)
-
- .quad 0xffffffffe2000000
- .quad 0x02400017
- .quad 0x02440017
- .word PM_16M
- .word 0
-
-# TLB entry 10: PCR (???)
-
- .quad 0xffffffffffffe000
- .quad 0x00000001 # nonsense...
- .quad 0x0001ffd7
- .word PM_4K
- .word 0
+MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, PM_64K) # Local I/O space
+MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, PM_4K) # Interrupt source register
+MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, PM_1M) # Local video control
+MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, PM_1M) # Extended video control
+MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, PM_4M) # Local video memory (BIOS mapping)
+MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, PM_16M) # ISA I/O and ISA memory space (both 16M)
+MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, PM_4K) # PCR (???)
+/*
+ * Initial mapping for Mips Magnum 4000PC systems.
+ * Do you believe me now that the Acer and Mips boxes are nearly the same ? :-)
+ * FIXME: Remove or merge some of the mappings.
+ */
-/* ------------------------------------------------
- * Mapping as presented by the PICA BIOS.
- * This table works. Please leave unmodified!
- * ------------------------------------------------ */
-#if 0
-map0_pica61: .word 11 # no. wired TLB entries
+map0_magnum4000:
+ .word 8 # no. wired TLB entries
.word 0 # dummy
-# TLB entry 0: Don't know what this is good for...
+MAPDATA(0xffffffffe1000000, 0x03ffc013, 0x00000001, 0x7e000) # 0
+MAPDATA(0xffffffffe0000000, 0x02000017, 0x00000001, 0x1e000) # 1 local I/O
+MAPDATA(0xffffffffe0100000, 0x03c00017, 0x00000001, 0) # 2 IRQ source
+MAPDATA(0xffffffffe0200000, 0x01800017, 0x01804017, 0x1fe000) # 3 local video ctrl
+MAPDATA(0xffffffffe0400000, 0x01808017, 0x0180c017, 0x1fe000) # 4 ext. video ctrl
+MAPDATA(0xffffffffe0800000, 0x01000017, 0x01010017, 0x7fe000) # 5 local video mem.
+MAPDATA(0xffffffffe2000000, 0x02400017, 0x02440017, 0x1ffe000) # 6 ISA I/O and mem.
+MAPDATA(0xffffffffffffe000, 0x00000001, 0x0001ffd7, 0) # 7 PCR
- .quad 0xfffffffffffe2000
- .quad 0x0000029e
- .quad 0x00000000
- .word PM_4K
- .word 0
-
-# TLB entry 1: PROM
-
- .quad 0xffffffffe1000000
- .quad 0x03ffc013
- .quad 0x00000001 # nonsense ...
- .word PM_256K
- .word 0
-
-# TLB entry 2: local I/O space
-
- .quad 0xffffffffe0000000
- .quad 0x02000017
- .quad 0x00000001 # nonsense ...
- .word PM_64K
- .word 0
-
-# TLB entry 3: DRAM config register
-
- .quad 0xffffffffe00e0000
- .quad 0x02003817
- .quad 0x02003c17
- .word PM_64K
- .word 0
-
-# TLB entry 4: Interrupt source register
-
- .quad 0xffffffffe0100000
- .quad 0x03c00017
- .quad 0x00000001 # nonsense ...
- .word PM_4K
- .word 0
-
-# TLB entry 5: Local video control
-
- .quad 0xffffffffe0200000
- .quad 0x01800017
- .quad 0x01804017
- .word PM_1M
- .word 0
-
-# TLB entry 6: Extended video control
-
- .quad 0xffffffffe0400000
- .quad 0x01808017
- .quad 0x0180c017
- .word PM_1M
- .word 0
-
-# TLB entry 7: Local video memory
-
- .quad 0xffffffffe0800000
- .quad 0x01000017
- .quad 0x01010017
- .word PM_4M
- .word 0
-# TLB entry 8: ISA I/O space
-
- .quad 0xffffffffe2000000
- .quad 0x02400017
- .quad 0x02440017
- .word PM_16M
- .word 0
-
-# TLB entry 9: PCR (???)
-
- .quad 0xffffffffffffe000
- .quad 0x00000001 # nonsense...
- .quad 0x0001ffd7
- .word PM_4K
- .word 0
-
-# TLB entry 10: Extended video prom
-
- .quad 0xffffffff10000000
- .quad 0x0000141f
- .quad 0x00000001 # nonsense
- .word PM_64K
- .word 0
-#endif
-
-/*
- * page 0 is made non-existent, so that kernel NULL pointer references get
- * caught. Thus the swapper page directory has been moved to 0x1000
- *
- * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte,
- * with the introduction of the compressed boot code. Theoretically,
- * the original design of overlaying the startup code with the swapper
- * page directory is still possible --- it would reduce the size of the kernel
- * by 2-3k. This would be a good thing to do at some point.....
- */
.text
.org 0x1000
-_swapper_pg_dir = 0x1000
+ .globl swapper_pg_dir
+swapper_pg_dir = . + (KSEG1-KSEG0)
+
/*
* The page tables are initialized to only 4MB here - the final page
* tables are set up later depending on memory size.
*/
.org 0x2000
-_pg0 = 0x2000
+ EXPORT(pg0)
.org 0x3000
-_empty_bad_page = 0x3000
+ EXPORT(empty_bad_page)
.org 0x4000
-_empty_bad_page_table = 0x4000
+ EXPORT(empty_bad_page_table)
.org 0x5000
-_empty_zero_page = 0x5000
+ EXPORT(empty_zero_page)
.org 0x6000
+ EXPORT(invalid_pte_table)
-#if defined (CONFIG_DESKSTATION_TYNE) && !defined (CONFIG_ACER_PICA_61)
-#if 0
-/*
- * tmp_floppy_area is used by the floppy-driver when DMA cannot
- * reach to a buffer-block. It needs to be aligned, so that it isn't
- * on a 64kB border.
- */
- .globl _tmp_floppy_area
-_tmp_floppy_area: .fill 1024,1,0
-#endif
-/*
- * floppy_track_buffer is used to buffer one track of floppy data: it
- * has to be separate from the tmp_floppy area, as otherwise a single-
- * sector read/write can mess it up. It can contain one full cylinder (sic) of
- * data (36*2*512 bytes).
- */
- .globl _floppy_track_buffer
-_floppy_track_buffer: .fill 512*2*36,1,0
-#endif /* defined (CONFIG_DESKSTATION_TYNE) && !defined (CONFIG_ACER_PICA_61) */
- .globl _kernelsp
-_kernelsp: .word 0
-beepflag: .word 0
+ .org 0x7000
+
+ EXPORT(cache_error_buffer)
+ .fill 32*4,1,0
+
+ .data
+ EXPORT(kernelsp)
+ PTR 0
#include <linux/types.h>
#include <linux/ioport.h>
-#define IOTABLE_SIZE 32
-
-typedef struct resource_entry_t {
- u_long from, num;
- const char *name;
- struct resource_entry_t *next;
-} resource_entry_t;
-
-/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
-static void set_bitmap(unsigned long *bitmap, short base, short extent, int new_value)
-{
- int mask;
- unsigned long *bitmap_base = bitmap + (base >> 5);
- unsigned short low_index = base & 0x1f;
- int length = low_index + extent;
-
- if (low_index != 0) {
- mask = (~0 << low_index);
- if (length < 32)
- mask &= ~(~0 << length);
- if (new_value)
- *bitmap_base++ |= mask;
- else
- *bitmap_base++ &= ~mask;
- length -= 32;
- }
-
- mask = (new_value ? ~0 : 0);
- while (length >= 32) {
- *bitmap_base++ = mask;
- length -= 32;
- }
-
- if (length > 0) {
- mask = ~(~0 << length);
- if (new_value)
- *bitmap_base++ |= mask;
- else
- *bitmap_base++ &= ~mask;
- }
-}
-
/*
- * this changes the io permissions bitmap in the current task.
+ * This changes the io permissions bitmap in the current task.
*/
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
{
{
return -ENOSYS;
}
-
-/*
- * The workhorse function: find where to put a new entry
- */
-static resource_entry_t *find_gap(resource_entry_t *root,
- u_long from, u_long num)
-{
- unsigned long flags;
- resource_entry_t *p;
-
- if (from > from+num-1)
- return NULL;
- save_flags(flags);
- cli();
- for (p = root; ; p = p->next) {
- if ((p != root) && (p->from+p->num-1 >= from)) {
- p = NULL;
- break;
- }
- if ((p->next == NULL) || (p->next->from > from+num-1))
- break;
- }
- restore_flags(flags);
- return p;
-}
--- /dev/null
+/*
+ * linux/arch/mips/kernel/ipc.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/i386
+ * platform.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+
+#include <asm/segment.h>
+
+/*
+ * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+ *
+ * This is really horribly ugly; removing this will need some minor
+ * changes in libc.
+ */
+asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+{
+#ifdef CONFIG_SYSVIPC
+ int version;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ if (call <= SEMCTL)
+ switch (call) {
+ case SEMOP:
+ return sys_semop (first, (struct sembuf *)ptr, second);
+ case SEMGET:
+ return sys_semget (first, second, third);
+ case SEMCTL: {
+ union semun fourth;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
+ return err;
+ fourth.__pad = (void *) get_fs_long(ptr);
+ return sys_semctl (first, second, third, fourth);
+ }
+ default:
+ return -EINVAL;
+ }
+ if (call <= MSGCTL)
+ switch (call) {
+ case MSGSND:
+ return sys_msgsnd (first, (struct msgbuf *) ptr,
+ second, third);
+ case MSGRCV:
+ switch (version) {
+ case 0: {
+ struct ipc_kludge tmp;
+ int err;
+ if (!ptr)
+ return -EINVAL;
+ if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
+ return err;
+ memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
+ sizeof (tmp));
+ return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
+ }
+ case 1: default:
+ return sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
+ }
+ case MSGGET:
+ return sys_msgget ((key_t) first, second);
+ case MSGCTL:
+ return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ if (call <= SHMCTL)
+ switch (call) {
+ case SHMAT:
+ switch (version) {
+ case 0: default: {
+ ulong raddr;
+ int err;
+ if ((err = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
+ return err;
+ err = sys_shmat (first, (char *) ptr, second, &raddr);
+ if (err)
+ return err;
+ put_fs_long (raddr, (ulong *) third);
+ return 0;
+ }
+ case 1: /* iBCS2 emulator entry point */
+ if (get_fs() != get_ds())
+ return -EINVAL;
+ return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+ }
+ case SHMDT:
+ return sys_shmdt ((char *)ptr);
+ case SHMGET:
+ return sys_shmget (first, second, third);
+ case SHMCTL:
+ return sys_shmctl (first, second, (struct shmid_ds *) ptr);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+#else /* CONFIG_SYSVIPC */
+ return -ENOSYS;
+#endif /* CONFIG_SYSVIPC */
+}
*/
/*
+ * Mips support by Ralf Baechle and Andreas Busse
+ *
* The Deskstation Tyne is almost completely like an IBM compatible PC with
* another type of microprocessor. Therefore this code is almost completely
* the same. More work needs to be done to support Acer PICA and other
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
+#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/random.h>
-#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/bitops.h>
+#include <asm/jazz.h>
+#include <asm/mipsregs.h>
+#include <asm/system.h>
unsigned char cache_21 = 0xff;
unsigned char cache_A1 = 0xff;
for (i = 0 ; i < 16 ; i++, action++) {
if (!action->handler)
continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
+ len += sprintf(buf+len, "%3d: %8d %c %s\n",
i, kstat.interrupts[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name);
struct irqaction * action = irq + irq_action;
kstat.interrupts[irq]++;
+ if (action->flags & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
action->handler(irq, regs);
}
struct irqaction * action = irq + irq_action;
kstat.interrupts[irq]++;
+ if (action->flags & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
action->handler(irq, NULL);
}
return -EBUSY;
if (!handler)
return -EINVAL;
+ if (irqflags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
save_flags(flags);
cli();
action->handler = handler;
* FIXME: Does the SA_INTERRUPT flag make any sense on MIPS???
*/
if (action->flags & SA_INTERRUPT)
- set_intr_gate(irq,fast_interrupt);
+ set_int_vector(irq,fast_interrupt);
else
- set_intr_gate(irq,interrupt);
+ set_int_vector(irq,interrupt);
}
if (irq < 8) {
cache_21 &= ~(1<<irq);
cache_A1 |= 1 << (irq-8);
outb(cache_A1,0xA1);
}
- set_intr_gate(irq,bad_interrupt);
+ set_int_vector(irq,bad_interrupt);
action->handler = NULL;
action->flags = 0;
action->mask = 0;
static void no_action(int cpl, struct pt_regs * regs) { }
-unsigned int probe_irq_on (void)
+unsigned long probe_irq_on (void)
{
unsigned int i, irqs = 0, irqmask;
unsigned long delay;
return irqs;
}
-int probe_irq_off (unsigned int irqs)
+int probe_irq_off (unsigned long irqs)
{
unsigned int i, irqmask;
{
int i;
- /* set the clock to 100 Hz */
- outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , 0x40); /* LSB */
- outb(LATCH >> 8 , 0x40); /* MSB */
+ switch (boot_info.machtype) {
+ case MACH_MIPS_MAGNUM_4000:
+ case MACH_ACER_PICA_61:
+ r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
+ JAZZ_IE_ETHERNET |
+ JAZZ_IE_SERIAL1 |
+ JAZZ_IE_SERIAL2 |
+ JAZZ_IE_PARALLEL |
+ JAZZ_IE_FLOPPY);
+ r4030_read_reg16(JAZZ_IO_IRQ_SOURCE); /* clear pending IRQs */
+ set_cp0_status(ST0_IM, IE_IRQ4 | IE_IRQ1);
+ /* set the clock to 100 Hz */
+ r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
+ break;
+ case MACH_DESKSTATION_TYNE:
+ /* set the clock to 100 Hz */
+ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
+ outb_p(LATCH & 0xff , 0x40); /* LSB */
+ outb(LATCH >> 8 , 0x40); /* MSB */
+
+ if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
+ printk("Unable to get IRQ2 for cascade\n");
+ break;
+ default:
+ panic("Unknown machtype in init_IRQ");
+ }
+
for (i = 0; i < 16 ; i++)
- set_intr_gate(i, bad_interrupt);
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade"))
- printk("Unable to get IRQ2 for cascade\n");
+ set_int_vector(i, bad_interrupt);
/* initialize the bottom half routines. */
for (i = 0; i < 32; i++) {
--- /dev/null
+/*
+ * Jazz specific C parts
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#include <linux/delay.h>
+
+#include <asm/cachectl.h>
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+#include <asm/segment.h>
+
+unsigned char jazz_fd_inb(unsigned int port)
+{
+ unsigned char c;
+
+ c = *(volatile unsigned char *) port;
+ udelay(1);
+
+ return c;
+}
+
+void jazz_fd_outb(unsigned char value, unsigned int port)
+{
+ *(volatile unsigned char *) port = value;
+}
+
+/*
+ * How to access the floppy DMA functions.
+ */
+void jazz_fd_enable_dma(void)
+{
+ vdma_enable(JAZZ_FLOPPY_DMA);
+}
+
+void jazz_fd_disable_dma(void)
+{
+ vdma_disable(JAZZ_FLOPPY_DMA);
+}
+
+int jazz_fd_request_dma(void)
+{
+ return 0;
+}
+
+void jazz_fd_free_dma(void)
+{
+}
+
+void jazz_fd_clear_dma_ff(void)
+{
+}
+
+void jazz_fd_set_dma_mode(char mode)
+{
+ vdma_set_mode(JAZZ_FLOPPY_DMA, mode);
+}
+
+void jazz_fd_set_dma_addr(unsigned int a)
+{
+ vdma_set_addr(JAZZ_FLOPPY_DMA, vdma_phys2log(PHYSADDR(a)));
+}
+
+void jazz_fd_set_dma_count(unsigned int count)
+{
+ vdma_set_count(JAZZ_FLOPPY_DMA, count);
+}
+
+int jazz_fd_get_dma_residue(void)
+{
+ return vdma_get_residue(JAZZ_FLOPPY_DMA);
+}
+
+void jazz_fd_enable_irq(void)
+{
+}
+
+void jazz_fd_disable_irq(void)
+{
+}
+
+void jazz_fd_cacheflush(unsigned char *addr, unsigned int size)
+{
+ sys_cacheflush((void *)addr, size, DCACHE);
+}
+
+unsigned char jazz_rtc_read_data(void)
+{
+ return *(char *)JAZZ_RTC_BASE;
+}
+
+void jazz_rtc_write_data(unsigned char data)
+{
+ *(char *)JAZZ_RTC_BASE = data;
+}
--- /dev/null
+/*
+ * jazzdma.c
+ *
+ * Mips Jazz DMA controller support
+ * (C) 1995 Andreas Busse
+ *
+ * NOTE: Some of the argument checkings could be removed when
+ * things have settled down. Also, instead of returning 0xffffffff
+ * on failure of vdma_alloc() one could leave page #0 unused
+ * and return the more usual NULL pointer as logical address.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/mipsregs.h>
+#include <asm/mipsconfig.h>
+#include <asm/jazz.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/dma.h>
+#include <asm/jazzdma.h>
+
+
+static unsigned long vdma_pagetable_start = 0;
+static unsigned long vdma_pagetable_end = 0;
+
+/*
+ * Debug stuff
+ */
+#define vdma_debug ((CONF_DEBUG_VDMA) ? debuglvl : 0)
+
+static int debuglvl = 3;
+
+/*
+ * Local prototypes
+ */
+static void vdma_pgtbl_init(void);
+
+/*
+ * Initialize the Jazz R4030 dma controller
+ */
+unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end)
+{
+ /*
+ * Allocate 32k of memory for DMA page tables.
+ * This needs to be page aligned and should be
+ * uncached to avoid cache flushing after every
+ * update.
+ */
+ vdma_pagetable_start = KSEG1ADDR((memory_start + 4095) & ~4095);
+ vdma_pagetable_end = vdma_pagetable_start + VDMA_PGTBL_SIZE;
+
+ /*
+ * Clear the R4030 translation table
+ */
+ vdma_pgtbl_init();
+
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_BASE,PHYSADDR(vdma_pagetable_start));
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_LIM,VDMA_PGTBL_SIZE);
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+ printk("VDMA: R4030 DMA pagetables initialized.\n");
+ return KSEG0ADDR(vdma_pagetable_end);
+}
+
+/*
+ * Allocate DMA pagetables using a simple first-fit algorithm
+ */
+unsigned long vdma_alloc(unsigned long paddr, unsigned long size)
+{
+ VDMA_PGTBL_ENTRY *entry = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int first;
+ int last;
+ int pages;
+ unsigned int frame;
+ unsigned long laddr;
+ int i;
+
+ /* check arguments */
+
+ if (paddr > 0x1fffffff)
+ {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid physical address: %08lx\n",paddr);
+ return VDMA_ERROR; /* invalid physical address */
+ }
+ if (size > 0x400000 || size == 0)
+ {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid size: %08lx\n",size);
+ return VDMA_ERROR; /* invalid physical address */
+ }
+
+ /* find free chunk */
+ pages = (size + 4095) >> 12; /* no. of pages to allocate */
+ first = 0;
+ while (1)
+ {
+ while (entry[first].owner != VDMA_PAGE_EMPTY &&
+ first < VDMA_PGTBL_ENTRIES)
+ first++;
+ if (first+pages > VDMA_PGTBL_ENTRIES) /* nothing free */
+ return VDMA_ERROR;
+
+ last = first+1;
+ while (entry[last].owner == VDMA_PAGE_EMPTY && last-first < pages)
+ last++;
+
+ if (last-first == pages)
+ break; /* found */
+ }
+
+ /* mark pages as allocated */
+
+ laddr = (first << 12) + (paddr & (VDMA_PAGESIZE-1));
+ frame = paddr & ~(VDMA_PAGESIZE-1);
+
+ for (i=first; i<last; i++)
+ {
+ entry[i].frame = frame;
+ entry[i].owner = laddr;
+ frame += VDMA_PAGESIZE;
+ }
+
+ /*
+ * update translation table and
+ * return logical start address
+ */
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+ if (vdma_debug > 1)
+ printk("vdma_alloc: Allocated %d pages starting from %08lx\n",
+ pages,laddr);
+
+ if (vdma_debug > 2)
+ {
+ printk("LADDR: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",i<<12);
+ printk("\nPADDR: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",entry[i].frame);
+ printk("\nOWNER: ");
+ for (i=first; i<last; i++)
+ printk("%08x ",entry[i].owner);
+ printk("\n");
+ }
+
+ return laddr;
+}
+
+/*
+ * Free previously allocated dma translation pages
+ * Note that this does NOT change the translation table,
+ * it just marks the free'd pages as unused!
+ */
+int vdma_free(unsigned long laddr)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int i;
+
+ i = laddr >> 12;
+
+ if (pgtbl[i].owner != laddr)
+ {
+ printk("vdma_free: trying to free other's dma pages, laddr=%8lx\n",
+ laddr);
+ return -1;
+ }
+
+ while (pgtbl[i].owner == laddr && i < VDMA_PGTBL_ENTRIES)
+ {
+ pgtbl[i].owner = VDMA_PAGE_EMPTY;
+ i++;
+ }
+
+ if (vdma_debug > 1)
+ printk("vdma_free: freed %ld pages starting from %08lx\n",
+ i-(laddr>>12),laddr);
+
+ return 0;
+}
+
+/*
+ * Map certain page(s) to another physical address.
+ * Caller must have allocated the page(s) before.
+ */
+int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+ int first;
+ int pages;
+
+ if (laddr > 0xffffff)
+ {
+ if (vdma_debug)
+ printk("vdma_map: Invalid logical address: %08lx\n",laddr);
+ return -EINVAL; /* invalid logical address */
+ }
+ if (paddr > 0x1fffffff)
+ {
+ if (vdma_debug)
+ printk("vdma_map: Invalid physical address: %08lx\n",paddr);
+ return -EINVAL; /* invalid physical address */
+ }
+
+ pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1;
+ first = laddr >> 12;
+ if (vdma_debug)
+ printk("vdma_remap: first=%x, pages=%x\n",first,pages);
+ if (first+pages > VDMA_PGTBL_ENTRIES)
+ {
+ if (vdma_debug)
+ printk("vdma_alloc: Invalid size: %08lx\n",size);
+ return -EINVAL;
+ }
+
+ paddr &= ~(VDMA_PAGESIZE-1);
+ while (pages > 0 && first < VDMA_PGTBL_ENTRIES)
+ {
+ if (pgtbl[first].owner != laddr)
+ {
+ if (vdma_debug)
+ printk("Trying to remap other's pages.\n");
+ return -EPERM; /* not owner */
+ }
+ pgtbl[first].frame = paddr;
+ paddr += VDMA_PAGESIZE;
+ first++;
+ pages--;
+ }
+
+ /* update translation table */
+
+ r4030_write_reg32(JAZZ_R4030_TRSTBL_INV,0);
+
+ if (vdma_debug > 2)
+ {
+ int i;
+ pages = (((paddr & (VDMA_PAGESIZE-1)) + size) >> 12) + 1;
+ first = laddr >> 12;
+ printk("LADDR: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",i<<12);
+ printk("\nPADDR: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",pgtbl[i].frame);
+ printk("\nOWNER: ");
+ for (i=first; i<first+pages; i++)
+ printk("%08x ",pgtbl[i].owner);
+ printk("\n");
+ }
+
+ return 0;
+}
+
+/*
+ * Translate a physical address to a logical address.
+ * This will return the logical address of the first
+ * match.
+ */
+unsigned long vdma_phys2log(unsigned long paddr)
+{
+ int i;
+ int frame;
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ frame = paddr & ~(VDMA_PAGESIZE-1);
+
+ for (i=0; i<VDMA_PGTBL_ENTRIES; i++)
+ {
+ if (pgtbl[i].frame == frame)
+ break;
+ }
+
+ if (i == VDMA_PGTBL_ENTRIES)
+ return 0xffffffff;
+
+ return (i<<12) + (paddr & (VDMA_PAGESIZE-1));
+}
+
+/*
+ * Translate a logical DMA address to a physical address
+ */
+unsigned long vdma_log2phys(unsigned long laddr)
+{
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ return pgtbl[laddr >> 12].frame + (laddr & (VDMA_PAGESIZE-1));
+}
+
+/*
+ * Initialize the pagetable with a one-to-one mapping of
+ * the first 16 Mbytes of main memory and declare all
+ * entries to be unused. Using this method will at least
+ * allow some early device driver operations to work.
+ */
+static void vdma_pgtbl_init(void)
+{
+ int i;
+ unsigned long paddr = 0;
+ VDMA_PGTBL_ENTRY *pgtbl = (VDMA_PGTBL_ENTRY *)vdma_pagetable_start;
+
+ for (i=0; i<VDMA_PGTBL_ENTRIES; i++)
+ {
+ pgtbl[i].frame = paddr;
+ pgtbl[i].owner = VDMA_PAGE_EMPTY;
+ paddr += VDMA_PAGESIZE;
+ }
+
+/* vdma_stats(); */
+}
+
+/*
+ * Print DMA statistics
+ */
+void vdma_stats(void)
+{
+ int i;
+
+ printk("vdma_stats: CONFIG: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_CONFIG));
+ printk("R4030 translation table base: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_TRSTBL_BASE));
+ printk("R4030 translation table limit: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_TRSTBL_LIM));
+ printk("vdma_stats: INV_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_INV_ADDR));
+ printk("vdma_stats: R_FAIL_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_R_FAIL_ADDR));
+ printk("vdma_stats: M_FAIL_ADDR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_M_FAIL_ADDR));
+ printk("vdma_stats: IRQ_SOURCE: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_IRQ_SOURCE));
+ printk("vdma_stats: I386_ERROR: %08x\n",
+ r4030_read_reg32(JAZZ_R4030_I386_ERROR));
+ printk("vdma_chnl_modes: ");
+ for (i=0; i<8; i++)
+ printk("%04x ",
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(i<<5)));
+ printk("\n");
+ printk("vdma_chnl_enables: ");
+ for (i=0; i<8; i++)
+ printk("%04x ",
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(i<<5)));
+ printk("\n");
+}
+
+/*
+ * DMA transfer functions
+ */
+
+/*
+ * Enable a DMA channel. Also clear any error conditions.
+ */
+void vdma_enable(int channel)
+{
+ int status;
+
+ if (vdma_debug)
+ printk("vdma_enable: channel %d\n",channel);
+
+ /*
+ * Check error conditions first
+ */
+ status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+ if (status & 0x400)
+ printk("VDMA: Channel %d: Address error!\n",channel);
+ if (status & 0x200)
+ printk("VDMA: Channel %d: Memory error!\n",channel);
+
+ /*
+ * Clear all interrupt flags
+ */
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ R4030_TC_INTR | R4030_MEM_INTR | R4030_ADDR_INTR);
+
+ /*
+ * Enable the desired channel
+ */
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
+ R4030_CHNL_ENABLE);
+}
+
+/*
+ * Disable a DMA channel
+ */
+void vdma_disable(int channel)
+{
+ if (vdma_debug)
+ {
+ int status = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+
+ printk("vdma_disable: channel %d\n",channel);
+ printk("VDMA: channel %d status: %04x (%s) mode: "
+ "%02x addr: %06x count: %06x\n",
+ channel,status,((status & 0x600) ? "ERROR" : "OK"),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5)),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5)),
+ (unsigned)r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5)));
+ }
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) &
+ ~R4030_CHNL_ENABLE);
+
+ /*
+ * After disabling a DMA channel a remote bus register should be
+ * read to ensure that the current DMA acknowledge cycle is completed.
+ */
+ *((volatile unsigned int *)JAZZ_DUMMY_DEVICE);
+}
+
+/*
+ * Set DMA mode. This function accepts the mode values used
+ * to set a PC-style DMA controller. For the SCSI and FDC
+ * channels, we also set the default modes each time we're
+ * called.
+ * NOTE: The FAST and BURST dma modes are supported by the
+ * R4030 Rev. 2 and PICA chipsets only. I leave them disabled
+ * for now.
+ */
+void vdma_set_mode(int channel, int mode)
+{
+ if (vdma_debug)
+ printk("vdma_set_mode: channel %d, mode 0x%x\n",channel,mode);
+
+ switch(channel)
+ {
+ case JAZZ_SCSI_DMA: /* scsi */
+ r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5),
+/* R4030_MODE_FAST | */
+/* R4030_MODE_BURST | */
+ R4030_MODE_INTR_EN |
+ R4030_MODE_WIDTH_16 |
+ R4030_MODE_ATIME_80);
+ break;
+
+ case JAZZ_FLOPPY_DMA: /* floppy */
+ r4030_write_reg32(JAZZ_R4030_CHNL_MODE+(channel<<5),
+/* R4030_MODE_FAST | */
+/* R4030_MODE_BURST | */
+ R4030_MODE_INTR_EN |
+ R4030_MODE_WIDTH_8 |
+ R4030_MODE_ATIME_120);
+ break;
+
+ case JAZZ_AUDIOL_DMA:
+ case JAZZ_AUDIOR_DMA:
+ printk("VDMA: Audio DMA not supported yet.\n");
+ break;
+
+ default:
+ printk("VDMA: vdma_set_mode() called with unsupported channel %d!\n",
+ channel);
+ }
+
+ switch(mode)
+ {
+ case DMA_MODE_READ:
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) &
+ ~R4030_CHNL_WRITE);
+ break;
+
+ case DMA_MODE_WRITE:
+ r4030_write_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5),
+ r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5)) |
+ R4030_CHNL_WRITE);
+ break;
+
+ default:
+ printk("VDMA: vdma_set_mode() called with unknown dma mode 0x%x\n",mode);
+ }
+}
+
+/*
+ * Set Transfer Address
+ */
+void vdma_set_addr(int channel, long addr)
+{
+ if (vdma_debug)
+ printk("vdma_set_addr: channel %d, addr %lx\n",channel,addr);
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_ADDR+(channel<<5),addr);
+}
+
+/*
+ * Set Transfer Count
+ */
+void vdma_set_count(int channel, int count)
+{
+ if (vdma_debug)
+ printk("vdma_set_count: channel %d, count %08x\n",channel,(unsigned)count);
+
+ r4030_write_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5),count);
+}
+
+/*
+ * Get Residual
+ */
+int vdma_get_residue(int channel)
+{
+ int residual;
+
+ residual = r4030_read_reg32(JAZZ_R4030_CHNL_COUNT+(channel<<5));
+
+ if (vdma_debug)
+ printk("vdma_get_residual: channel %d: residual=%d\n",channel,residual);
+
+ return residual;
+}
--- /dev/null
+/*
+ * arch/mips/kernel/magnum4000.S
+ *
+ * Copyright (C) 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/jazz.h>
+#include <asm/stackframe.h>
+
+/*
+ * mips_magnum_4000_handle_int: Interrupt handler for Mips Magnum 4000
+ */
+ .set noreorder
+
+ NESTED(mips_magnum_4000_handle_int, FR_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+
+ /*
+ * Get pending interrupts
+ */
+ mfc0 t0,CP0_CAUSE # get pending interrupts
+ mfc0 t1,CP0_STATUS # get enabled interrupts
+ and t0,t1 # isolate allowed ones
+ andi t0,0xff00 # isolate pending bits
+ beqz t0,spurious_interrupt
+ sll t0,16 # delay slot
+
+ /*
+ * Find irq with highest priority
+ * FIXME: This is slow
+ */
+ la t1,ll_vectors
+1: bltz t0,2f # found pending irq
+ sll t0,1
+ b 1b
+ subu t1,PTRSIZE # delay slot
+
+ /*
+ * Do the low-level stuff
+ */
+2: lw t0,(t1)
+ jr t0
+ nop # delay slot
+ END(mips_magnum_4000_handle_int)
+
+/*
+ * Used for keyboard driver's fake_keyboard_interrupt()
+ */
+ll_sw0: li s1,~IE_SW0
+ mfc0 t0,CP0_CAUSE
+ and t0,s1
+ mtc0 t0,CP0_CAUSE
+ PRINT("sw0 received...\n")
+ li t1,1
+ b call_real
+ li t3,PTRSIZE # delay slot, re-map to irq level 1
+
+ll_sw1: li s1,~IE_SW1
+ PANIC("Unimplemented sw1 handler")
+
+ll_local_dma: li s1,~IE_IRQ0
+ PANIC("Unimplemented local_dma handler")
+
+ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
+#if __mips == 3
+ dsll t0,1
+ ld t0,local_vector(t0)
+#else /* 32 bit */
+ lw t0,local_vector(t0)
+#endif
+ jr t0
+ nop
+
+
+loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
+loc_sound: PANIC("Unimplemented loc_sound handler")
+loc_video: PANIC("Unimplemented loc_video handler")
+loc_scsi: PANIC("Unimplemented loc_scsi handler")
+
+/*
+ * Keyboard interrupt handler
+ */
+loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
+ li t1,JAZZ_KEYBOARD_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # delay slot
+
+/*
+ * Ethernet interrupt handler, remapped to level 2
+ */
+loc_ethernet: /* PRINT ("ethernet IRQ\n"); */
+ li s1,~JAZZ_IE_ETHERNET
+ li t1,JAZZ_ETHERNET_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot
+
+
+loc_mouse: PANIC("Unimplemented loc_mouse handler")
+
+/*
+ * Serial port 1 IRQ, remapped to level 3
+ */
+loc_serial1: li s1,~JAZZ_IE_SERIAL1
+ li t1,JAZZ_SERIAL1_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot
+
+/*
+ * Serial port 2 IRQ, remapped to level 4
+ */
+loc_serial2: li s1,~JAZZ_IE_SERIAL2
+ li t1,JAZZ_SERIAL2_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot
+
+/*
+ * Parallel port IRQ, remapped to level 5
+ */
+loc_parallel: li s1,~JAZZ_IE_PARALLEL
+ li t1,JAZZ_PARALLEL_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot
+
+/*
+ * Floppy IRQ, remapped to level 6
+ */
+loc_floppy: li s1,~JAZZ_IE_FLOPPY
+ li t1,JAZZ_FLOPPY_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot
+
+/*
+ * Now call the real handler
+ */
+loc_call: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * Temporarily disable interrupt source
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ addu t0,t3 # make ptr to IRQ handler
+ lw t0,(t0)
+ and t2,s1 # delay slot
+ sh t2,JAZZ_IO_IRQ_ENABLE
+ jalr t0 # call IRQ handler
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * Reenable interrupt
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ lw t1,%lo(intr_count)(s3) # delay slot
+ or t2,s1
+ sh t2,JAZZ_IO_IRQ_ENABLE
+
+ subu t1,1
+ jr v0
+ sw t1,%lo(intr_count)(s3)
+
+ll_eisa_irq: li s1,~IE_IRQ2
+ PANIC("Unimplemented eisa_irq handler")
+
+ll_eisa_nmi: li s1,~IE_IRQ3
+ PANIC("Unimplemented eisa_nmi handler")
+
+/*
+ * Timer IRQ
+ * We remap the timer irq to be more similar to a IBM compatible
+ */
+ll_timer: lw t0,JAZZ_TIMER_REGISTER # timer irq cleared on read
+ li s1,~IE_IRQ4
+ li t1,0
+ b call_real
+ li t3,0 # delay slot, re-map to irq level 0
+
+/*
+ * CPU count/compare IRQ (unused)
+ */
+ll_count: j return
+ mtc0 zero,CP0_COMPARE
+
+/*
+ * Now call the real handler
+ */
+call_real: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * temporarily disable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ and t2,s1
+
+ addu t0,t3
+ lw t0,(t0)
+ mtc0 t2,CP0_STATUS # delay slot
+ jalr t0
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * reenable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ or t2,s1
+ mtc0 t2,CP0_STATUS
+
+ lw t2,%lo(intr_count)(s3)
+ subu t2,1
+
+ jr v0
+ sw t2,%lo(intr_count)(s3)
+
+/*
+ * Just for debugging...
+ */
+ LEAF(drawline)
+ li t1,0xffffffff
+ li t2,0x100
+1: sw t1,(a0)
+ addiu a0,a0,4
+ addiu t2,t2,-1
+ bnez t2,1b
+ nop
+ jr ra
+ nop
+ END(drawline)
+
+
+ .data
+ PTR ll_sw0 # SW0
+ PTR ll_sw1 # SW1
+ PTR ll_local_dma # Local DMA
+ PTR ll_local_dev # Local devices
+ PTR ll_eisa_irq # EISA IRQ
+ PTR ll_eisa_nmi # EISA NMI
+ PTR ll_timer # Timer
+ll_vectors: PTR ll_count # Count/Compare IRQ
+
+local_vector: PTR loc_no_irq
+ PTR loc_parallel
+ PTR loc_floppy
+ PTR loc_sound
+ PTR loc_video
+ PTR loc_ethernet
+ PTR loc_scsi
+ PTR loc_keyboard
+ PTR loc_mouse
+ PTR loc_serial1
+ PTR loc_serial2
+
+ .align 5
+LEAF(spurious_interrupt)
+ /*
+ * Nothing happened... (whistle)
+ */
+ lui t1,%hi(spurious_count)
+ lw t0,%lo(spurious_count)(t1)
+ la v0,return
+ addiu t0,1
+ jr ra
+ sw t0,%lo(spurious_count)(t1)
+ END(spurious_interrupt)
+
--- /dev/null
+/*
+ * arch/mips/kernel/pica.S
+ *
+ * Copyright (C) 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ *
+ * Acer PICA 61 specific stuff
+ */
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/jazz.h>
+#include <asm/pica.h>
+#include <asm/stackframe.h>
+
+/*
+ * acer_pica_61_handle_int: Interrupt handler for the ACER Pica-61 boards
+ * FIXME: this is *very* experimental!
+ */
+ .set noreorder
+
+ NESTED(acer_pica_61_handle_int, FR_SIZE, ra)
+ .set noat
+ SAVE_ALL
+ CLI
+ .set at
+
+ /*
+ * Get pending interrupts
+ */
+ mfc0 t0,CP0_CAUSE # get pending interrupts
+ mfc0 t1,CP0_STATUS # get enabled interrupts
+ and t0,t1 # isolate allowed ones
+ andi t0,0xff00 # isolate pending bits
+ beqz t0,spurious_interrupt
+ sll t0,16 # delay slot
+
+ /*
+ * Find irq with highest priority
+ * FIXME: This is slow - use binary search
+ */
+ la t1,ll_vectors
+1: bltz t0,2f # found pending irq
+ sll t0,1
+ b 1b
+ subu t1,PTRSIZE # delay slot
+
+ /*
+ * Do the low-level stuff
+ */
+2: lw t0,(t1)
+ jr t0
+ nop # delay slot
+ END(acer_pica_61_handle_int)
+
+/*
+ * Used for keyboard driver's fake_keyboard_interrupt()
+ */
+ll_sw0: li s1,~IE_SW0
+ mfc0 t0,CP0_CAUSE
+ and t0,s1
+ mtc0 t0,CP0_CAUSE
+ PRINT("sw0 received...\n")
+ li t1,1
+ b call_real
+ li t3,PTRSIZE # delay slot, re-map to irq level 1
+
+ll_sw1: li s1,~IE_SW1
+ PANIC("Unimplemented sw1 handler")
+
+ll_local_dma: li s1,~IE_IRQ0
+ PANIC("Unimplemented local_dma handler")
+
+ll_local_dev: lbu t0,JAZZ_IO_IRQ_SOURCE
+#if __mips == 3
+ dsll t0,1
+ ld t0,local_vector(t0)
+#else /* 32 bit */
+ lw t0,local_vector(t0)
+#endif
+ jr t0
+ nop
+
+
+loc_no_irq: PANIC("Unimplemented loc_no_irq handler")
+/*
+ * Parallel port IRQ, remapped to level 5
+ */
+loc_parallel: li s1,~JAZZ_IE_PARALLEL
+ li t1,JAZZ_PARALLEL_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_PARALLEL_IRQ # delay slot
+
+/*
+ * Floppy IRQ, remapped to level 6
+ */
+loc_floppy: li s1,~JAZZ_IE_FLOPPY
+ li t1,JAZZ_FLOPPY_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_FLOPPY_IRQ # delay slot
+
+/*
+ * Now call the real handler
+ */
+loc_call: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors # delay slot
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * Temporarily disable interrupt source
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ addu t0,t3 # make ptr to IRQ handler
+ lw t0,(t0)
+ and t2,s1 # delay slot
+ sh t2,JAZZ_IO_IRQ_ENABLE
+ jalr t0 # call IRQ handler
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * Reenable interrupt
+ */
+ lhu t2,JAZZ_IO_IRQ_ENABLE
+ lw t1,%lo(intr_count)(s3) # delay slot
+ or t2,s1
+ sh t2,JAZZ_IO_IRQ_ENABLE
+
+ subu t1,1
+ jr v0
+ sw t1,%lo(intr_count)(s3) # delay slot
+
+ll_isa_irq: li s1,~IE_IRQ2
+ PANIC("Unimplemented isa_irq handler")
+
+ll_isa_nmi: li s1,~IE_IRQ3
+ PANIC("Unimplemented isa_nmi handler")
+
+/*
+ * Timer IRQ
+ * We remap the timer irq to be more similar to an IBM compatible
+ */
+ll_timer: lw zero,JAZZ_TIMER_REGISTER # timer irq cleared on read
+ li s1,~IE_IRQ4
+ li t1,0
+ b call_real
+ li t3,0 # delay slot, re-map to irq level 0
+
+/*
+ * CPU count/compare IRQ (unused)
+ */
+ll_count: j return
+ mtc0 zero,CP0_COMPARE
+
+/*
+ * Now call the real handler
+ */
+call_real: lui s3,%hi(intr_count)
+ lw t2,%lo(intr_count)(s3)
+ la t0,IRQ_vectors
+ addiu t2,1
+ sw t2,%lo(intr_count)(s3)
+
+ /*
+ * temporarily disable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ and t2,s1
+
+ addu t0,t3
+ lw t0,(t0)
+ mtc0 t2,CP0_STATUS # delay slot
+ jalr t0
+ nor s1,zero,s1 # delay slot
+
+ /*
+ * reenable interrupt
+ */
+ mfc0 t2,CP0_STATUS
+ or t2,s1
+ mtc0 t2,CP0_STATUS
+
+ lw t2,%lo(intr_count)(s3)
+ subu t2,1
+
+ jr v0
+ sw t2,%lo(intr_count)(s3)
+
+ .data
+ PTR ll_sw0 # SW0
+ PTR ll_sw1 # SW1
+ PTR ll_local_dma # Local DMA
+ PTR ll_local_dev # Local devices
+ PTR ll_isa_irq # ISA IRQ
+ PTR ll_isa_nmi # ISA NMI
+ PTR ll_timer # Timer
+ll_vectors: PTR ll_count # Count/Compare IRQ
+
+
+/*
+ * Sound? What sound hardware (whistle) ???
+ */
+loc_sound: PANIC("Unimplemented loc_sound handler")
+loc_video: PANIC("Unimplemented loc_video handler")
+
+/*
+ * Ethernet interrupt handler, remapped to level 2
+ */
+loc_ethernet: li s1,~JAZZ_IE_ETHERNET
+ li t1,JAZZ_ETHERNET_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_ETHERNET_IRQ # delay slot
+
+loc_scsi: PANIC("Unimplemented loc_scsi handler")
+
+/*
+ * Keyboard interrupt handler
+ */
+loc_keyboard: li s1,~JAZZ_IE_KEYBOARD
+ li t1,JAZZ_KEYBOARD_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_KEYBOARD_IRQ # re-map to irq level 1
+
+loc_mouse: PANIC("Unimplemented loc_mouse handler")
+
+/*
+ * Serial port 1 IRQ, remapped to level 3
+ */
+loc_serial1: li s1,~JAZZ_IE_SERIAL1
+ li t1,JAZZ_SERIAL1_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL1_IRQ # delay slot
+
+/*
+ * Serial port 2 IRQ, remapped to level 4
+ */
+loc_serial2: li s1,~JAZZ_IE_SERIAL2
+ li t1,JAZZ_SERIAL2_IRQ
+ b loc_call
+ li t3,PTRSIZE*JAZZ_SERIAL2_IRQ # delay slot
+
+ .data
+local_vector: PTR loc_no_irq
+ PTR loc_parallel
+ PTR loc_floppy
+ PTR loc_sound
+ PTR loc_video
+ PTR loc_ethernet
+ PTR loc_scsi
+ PTR loc_keyboard
+ PTR loc_mouse
+ PTR loc_serial1
+ PTR loc_serial2
+
+ .align 5
+ .text
+LEAF(spurious_interrupt)
+ /*
+ * Nothing happened... (whistle)
+ */
+ lui t1,%hi(spurious_count)
+ lw t0,%lo(spurious_count)(t1)
+ la v0,return
+ addiu t0,1
+ jr ra
+ sw t0,%lo(spurious_count)(t1)
+ END(spurious_interrupt)
+
/*
* linux/arch/mips/kernel/process.c
*
- * Copyright (C) 1995 Waldorf Electronics,
+ * Copyright (C) 1995 Ralf Baechle
* written by Ralf Baechle
+ *
+ * This file handles the architecture-dependent parts of initialization
*/
-
-/*
- * This file handles the architecture-dependent parts of process handling..
- */
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/ldt.h>
+#include <linux/mman.h>
+#include <linux/sys.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <asm/bootinfo.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/mipsregs.h>
-#include <asm/mipsconfig.h>
+#include <asm/processor.h>
#include <asm/stackframe.h>
+#include <asm/io.h>
-asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+asmlinkage void ret_from_sys_call(void);
/*
- * The idle loop on a MIPS..
+ * This routine reboots the machine by asking the keyboard
+ * controller to pulse the reset-line low. We try that for a while,
+ * and if it doesn't work, we do some other stupid things.
+ * Should be ok for Deskstation Tynes. Reseting others needs to be
+ * investigated...
*/
-asmlinkage int sys_idle(void)
+static inline void kb_wait(void)
{
-#if 0
int i;
-#endif
- if (current->pid != 0)
- return -EPERM;
+ for (i=0; i<0x10000; i++)
+ if ((inb_p(0x64) & 0x02) == 0)
+ break;
+}
-#if 0
- /* Map out the low memory: it's no longer needed */
- for (i = 0 ; i < 512 ; i++)
- pgd_clear(swapper_pg_dir + i);
-#endif
+/*
+ * Hard reset for Deskstation Tyne
+ * No hint how this works on Pica boards.
+ */
+void hard_reset_now(void)
+{
+ int i, j;
- /* endless idle loop with no priority at all */
- current->counter = -100;
+ sti();
for (;;) {
- /*
- * R4[26]00 have wait, R4[04]00 don't.
- */
- if (wait_available && !need_resched)
- __asm__("wait");
- schedule();
+ for (i=0; i<100; i++) {
+ kb_wait();
+ for(j = 0; j < 100000 ; j++)
+ /* nothing */;
+ outb(0xfe,0x64); /* pulse reset low */
+ }
}
}
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
+void show_regs(struct pt_regs * regs)
{
- regs->cp0_epc = eip;
- regs->reg29 = esp;
+ /*
+ * Saved main processor registers
+ */
+ printk("$0 : %08x %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ 0, regs->reg1, regs->reg2, regs->reg3,
+ regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+ printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+ regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+ printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+ regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+ printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ regs->reg24, regs->reg25, regs->reg28, regs->reg29,
+ regs->reg30, regs->reg31);
+
+ /*
+ * Saved cp0 registers
+ */
+ printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
+ regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
}
/*
* Nothing to do
*/
}
-
-#define IS_CLONE (regs->orig_reg2 == __NR_clone)
-
-void copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs)
+
+void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
+ unsigned long childksp;
+ childksp = p->kernel_stack_page + PAGE_SIZE - 8;
/*
* set up new TSS
*/
- p->tss.fs = KERNEL_DS;
- p->tss.ksp = (p->kernel_stack_page + PAGE_SIZE - 4) | KSEG0;
childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
- p->tss.reg29 = ((unsigned long) childregs) | KSEG0; /* new sp */
- p->tss.reg31 = (unsigned long) ret_from_sys_call;
*childregs = *regs;
- childregs->reg2 = 0;
+ childregs->reg2 = 0; /* Child gets zero as return value */
+ childregs->reg7 = 0; /* Clear error flag */
+ regs->reg2 = p->pid;
+ if (childregs->cp0_status & ST0_CU0)
+ childregs->reg29 = childksp;
+ else
+ childregs->reg29 = usp;
+ p->tss.ksp = childksp;
+ p->tss.reg29 = (unsigned long) childregs; /* new sp */
+ p->tss.reg31 = (unsigned long) ret_from_sys_call;
/*
* New tasks loose permission to use the fpu. This accelerates context
- * switching for non fp programs, which true for the most programs.
+ * switching for most programs since they don't use the fpu.
*/
- p->tss.cp0_status = regs->cp0_status &
- ~(ST0_CU1|ST0_CU0|ST0_KSU|ST0_ERL|ST0_EXL);
- childregs->cp0_status &= ~(ST0_CU1|ST0_CU0);
+ p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) &
+ ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL);
+ childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1);
}
/*
- * fill in the user structure for a core dump..
+ * fill in the fpu structure for a core dump..
+ *
+ * Actually this is "int dump_fpu (struct elf_fpregset_t *fpu)"
*/
-void dump_thread(struct pt_regs * regs, struct user * dump)
+int dump_fpu (int shutup_the_gcc_warning_about_elf_fpregset_t)
{
+ int fpvalid = 0;
/*
- * Not ready yet
+ * To do...
*/
-#if 0
- int i;
-/* changed the size calculations - should hopefully work better. lbt */
- dump->magic = CMAGIC;
- dump->start_code = 0;
- dump->start_stack = regs->esp & ~(PAGE_SIZE - 1);
- dump->u_tsize = ((unsigned long) current->mm->end_code) >> 12;
- dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> 12;
- dump->u_dsize -= dump->u_tsize;
- dump->u_ssize = 0;
- for (i = 0; i < 8; i++)
- dump->u_debugreg[i] = current->debugreg[i];
-
- if (dump->start_stack < TASK_SIZE)
- dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> 12;
-
- dump->regs = *regs;
-
-/* Flag indicating the math stuff is valid. We don't support this for the
- soft-float routines yet */
- if (hard_math) {
- if ((dump->u_fpvalid = current->used_math) != 0) {
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0": :"m" (dump->i387));
- else
- memcpy(&dump->i387,¤t->tss.i387.hard,sizeof(dump->i387));
- }
- } else {
- /* we should dump the emulator state here, but we need to
- convert it into standard 387 format first.. */
- dump->u_fpvalid = 0;
- }
-#endif
+ return fpvalid;
}
/*
- * sys_execve() executes a new program.
+ * fill in the user structure for a core dump..
*/
-asmlinkage int sys_execve(struct pt_regs regs)
+void dump_thread(struct pt_regs * regs, struct user * dump)
{
- int error;
- char * filename;
-
- error = getname((char *) regs.reg4, &filename);
- if (error)
- return error;
- error = do_execve(filename, (char **) regs.reg5, (char **) regs.reg6, ®s);
- putname(filename);
- return error;
+ /*
+ * To do...
+ */
}
#include <linux/user.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#if 0
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page < high_memory) {
- page += addr & ~PAGE_MASK;
- *(unsigned long *) page = data;
- }
+ if (page < high_memory)
+ *(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 */
set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
case PTRACE_KILL: {
long tmp;
+ if (child->state == TASK_ZOMBIE) /* already dead */
+ return 0;
wake_up_process(child);
child->exit_code = SIGKILL;
/* make sure the single step bit is not set. */
--- /dev/null
+/*
+ * arch/mips/kernel/r4xx0.S
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * Written by Ralf Baechle and Andreas Busse
+ *
+ * This file contains most of the R4xx0 specific routines. Due to the
+ * similarities this should hopefully also be fine for the R10000. For
+ * now we especially support the R10000 by not invalidating entries out of
+ * the TLB before calling the C handlers.
+ *
+ * This code is evil magic. Read appendix f (coprozessor 0 hazards) of
+ * all R4xx0 manuals and think about that MIPS means "Microprocessor without
+ * Interlocked Pipeline Stages" before you even think about changing this code!
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/bootinfo.h>
+#include <asm/cachectl.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/mipsregs.h>
+#include <asm/segment.h>
+#include <asm/stackframe.h>
+
+#ifdef __SMP__
+#error "Fix this for SMP"
+#else
+#define current current_set
+#endif
+
+MODE_ALIAS = 0x0016 # uncachable
+
+ .text
+ .set mips3
+ .set noreorder
+
+ .align 5
+ NESTED(handle_tlbl, FR_SIZE, sp)
+ .set noat
+ /*
+ * Check whether this is a refill or an invalid exception
+ *
+ * NOTE: Some MIPS manuals say that the R4x00 sets the
+ * BadVAddr only when EXL == 0. This is wrong - BadVAddr
+ * is being set for all Reload, Invalid and Modified
+ * exceptions.
+ */
+ mfc0 k0,CP0_BADVADDR
+ mfc0 k1,CP0_ENTRYHI
+ ori k0,0x1fff
+ xori k0,0x1fff
+ andi k1,0xff
+ or k0,k1
+ mfc0 k1,CP0_ENTRYHI
+ mtc0 k0,CP0_ENTRYHI
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ tlbp
+ nop # for R4[04]00 pipeline
+ nop
+ mfc0 k0,CP0_INDEX
+ bgez k0,invalid_tlbl # bad addr in c0_badvaddr
+ mtc0 k1,CP0_ENTRYHI # delay slot
+ /*
+ * Damn... The next nop is required on my R4400PC V5.0, but
+ * I don't know why - at least there is no documented
+ * reason as for the others :-(
+ */
+ nop
+
+#ifdef CONF_DEBUG_TLB
+ /*
+ * OK, this is a double fault. Let's see whether this is
+ * due to an invalid entry in the page_table.
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_ACCESSED)
+ bnez k1,reload_pgd_entries
+ nop # delay slot
+
+ .set noat
+ SAVE_ALL
+ .set at
+ PRINT("Double fault caused by invalid entries in pgd:\n")
+ dmfc0 a1,CP0_BADVADDR
+ PRINT("Double fault address : %08lx\n")
+ dmfc0 a1,CP0_EPC
+ PRINT("c0_epc : %08lx\n")
+ jal show_regs
+ move a0,sp
+ jal dump_tlb_all
+ nop
+ dmfc0 a0,CP0_BADVADDR
+ jal dump_list_current
+ nop
+ .set noat
+ STI
+ .set at
+ PANIC("Corrupted pagedir")
+ .set noat
+
+reload_pgd_entries:
+#endif /* CONF_DEBUG_TLB */
+
+ /*
+ * Load missing pair of entries from the pgd and return.
+ */
+ dmfc0 k1,CP0_CONTEXT
+ dsra k1,1
+ lwu k0,(k1) # Never causes nested exception
+ lwu k1,4(k1)
+ dsrl k0,6 # Convert to EntryLo format
+ dsrl k1,6 # Convert to EntryLo format
+ dmtc0 k0,CP0_ENTRYLO0
+ dmtc0 k1,CP0_ENTRYLO1
+ nop # for R4[04]00 pipeline
+ tlbwr
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ /*
+ * We don't know whether the original access was read or
+ * write, so return and see what happens...
+ */
+ eret
+
+ /*
+ * Handle invalid exception
+ *
+ * There are two possible causes for an invalid (tlbl)
+ * exception:
+ * 1) pages with present bit set but the valid bit clear
+ * 2) nonexistant pages
+ * Case one needs fast handling, therefore don't save
+ * registers yet.
+ *
+ * k0 contains c0_index.
+ */
+invalid_tlbl:
+#ifdef CONFIG_TLB_SHUTDOWN
+ /*
+ * Remove entry so we don't need to care later
+ * For sake of the R4000 V2.2 pipeline the tlbwi insn
+ * has been moved down. Moving it around is juggling with
+ * explosives...
+ */
+ lui k1,0x0008
+ or k0,k1
+ dsll k0,13
+ dmtc0 k0,CP0_ENTRYHI
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+#endif
+ /*
+ * Test present bit in entry
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+#ifdef CONFIG_TLB_SHUTDOWN
+ tlbwi # do not move!
+#endif
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ andi k1,(_PAGE_PRESENT|_PAGE_READ)
+ xori k1,(_PAGE_PRESENT|_PAGE_READ)
+ bnez k1,nopage_tlbl
+ /*
+ * Present and read bits are set -> set valid and accessed bits
+ */
+ lw k1,(k0) # delay slot
+ ori k1,(_PAGE_VALID|_PAGE_ACCESSED)
+ sw k1,(k0)
+ eret
+
+ /*
+ * Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbl: SAVE_ALL
+ dmfc0 a2,CP0_BADVADDR
+ STI
+ .set at
+ /*
+ * a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 0 for read access
+ * a2 (unsigned long) faulting virtual address
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,0 # delay slot
+ j ret_from_sys_call
+ nop # delay slot
+ END(handle_tlbl)
+
+ .text
+ .align 5
+ NESTED(handle_tlbs, FR_SIZE, sp)
+ .set noat
+ /*
+ * It is impossible that is a nested reload exception.
+ * Therefore this must be a invalid exception.
+ * Two possible cases:
+ * 1) Page exists but not dirty.
+ * 2) Page doesn't exist yet. Hand over to the kernel.
+ *
+ * Test whether present bit in entry is set
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,(_PAGE_PRESENT|_PAGE_WRITE)
+ xori k1,(_PAGE_PRESENT|_PAGE_WRITE)
+ bnez k1,nopage_tlbs
+ /*
+ * Present and writable bits set: set accessed and dirty bits.
+ */
+ lw k1,(k0) # delay slot
+ ori k1,k1,(_PAGE_ACCESSED|_PAGE_MODIFIED| \
+ _PAGE_VALID|_PAGE_DIRTY)
+ sw k1,(k0)
+ /*
+ * Now reload the entry into the TLB
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k1,4(k0)
+ lw k0,(k0)
+ srl k1,6
+ srl k0,6
+ dmtc0 k1,CP0_ENTRYLO1
+ dmtc0 k0,CP0_ENTRYLO0
+ nop # for R4[04]00 pipeline
+ tlbwi
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ eret
+
+ /*
+ * Page doesn't exist. Lots of work which is less important
+ * for speed needs to be done, so hand it all over to the
+ * kernel memory management routines.
+ */
+nopage_tlbs:
+nowrite_mod:
+#ifdef CONFIG_TLB_SHUTDOWN
+ /*
+ * Remove entry so we don't need to care later
+ */
+ mfc0 k0,CP0_INDEX
+#ifdef CONF_DEBUG_TLB
+ bgez k0,2f
+ nop
+ /*
+ * We got a tlbs exception but found no matching entry in
+ * the tlb. This should never happen. Paranoia makes us
+ * check it, though.
+ */
+ SAVE_ALL
+ jal show_regs
+ move a0,sp
+ .set at
+ mfc0 a1,CP0_BADVADDR
+ PRINT("c0_badvaddr == %08lx\n")
+ mfc0 a1,CP0_INDEX
+ PRINT("c0_index == %08x\n")
+ mfc0 a1,CP0_ENTRYHI
+ PRINT("c0_entryhi == %08x\n")
+ .set noat
+ STI
+ .set at
+ PANIC("Tlbs or tlbm exception with no matching entry in tlb")
+1: j 1b
+ nop
+2:
+#endif /* CONF_DEBUG_TLB */
+ lui k1,0x0008
+ or k0,k1
+ dsll k0,13
+ dmtc0 k0,CP0_ENTRYHI
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+ nop # for R4[04]00 pipeline
+ nop # R4000 V2.2 requires 4 NOPs
+ nop
+ nop
+ tlbwi
+#endif
+ .set noat
+ SAVE_ALL
+ dmfc0 a2,CP0_BADVADDR
+ STI
+ .set at
+ /*
+ * a0 (struct pt_regs *) regs
+ * a1 (unsigned long) 1 for write access
+ * a2 (unsigned long) faulting virtual address
+ */
+ move a0,sp
+ jal do_page_fault
+ li a1,1 # delay slot
+ j ret_from_sys_call
+ nop # delay slot
+ END(handle_tlbs)
+
+ .align 5
+ NESTED(handle_mod, FR_SIZE, sp)
+ .set noat
+ /*
+ * Two possible cases:
+ * 1) Page is writable but not dirty -> set dirty and return
+ * 2) Page is not writable -> call C handler
+ */
+ dmfc0 k0,CP0_BADVADDR
+ srl k0,12
+ sll k0,2
+ lui k1,%HI(TLBMAP)
+ addu k0,k1
+ lw k1,(k0)
+ tlbp # find faulting entry
+ andi k1,_PAGE_WRITE
+ beqz k1,nowrite_mod
+ /*
+ * Present and writable bits set: set accessed and dirty bits.
+ */
+ lw k1,(k0) # delay slot
+ ori k1,(_PAGE_ACCESSED|_PAGE_DIRTY)
+ sw k1,(k0)
+ /*
+ * Now reload the entry into the tlb
+ */
+ ori k0,0x0004
+ xori k0,0x0004
+ lw k1,4(k0)
+ lw k0,(k0)
+ srl k1,6
+ srl k0,6
+ dmtc0 k1,CP0_ENTRYLO1
+ dmtc0 k0,CP0_ENTRYLO0
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ tlbwi
+ nop # for R4[04]00 pipeline
+ nop
+ nop
+ eret
+ END(handle_mod)
+ .set at
+
+/*
+ * Until SAVE_ALL/RESTORE_ALL handle registers 64-bit wide we have to
+ * disable interrupts here.
+ */
+ .set noreorder
+ LEAF(tlbflush)
+ mfc0 t3,CP0_STATUS
+ ori t4,t3,1
+ xori t4,1
+ mtc0 t4,CP0_STATUS
+ li t0,PM_4K
+ mtc0 t0,CP0_PAGEMASK
+ la t0,boot_info
+ lw t0,OFFSET_BOOTINFO_TLB_ENTRIES(t0)
+ dmtc0 zero,CP0_ENTRYLO0
+ dmtc0 zero,CP0_ENTRYLO1
+ mfc0 t2,CP0_WIRED
+1: subu t0,1
+ mtc0 t0,CP0_INDEX
+ lui t1,0x0008
+ or t1,t0,t1
+ dsll t1,13
+ dmtc0 t1,CP0_ENTRYHI
+ bne t2,t0,1b
+ tlbwi # delay slot
+ jr ra
+ mtc0 t3,CP0_STATUS # delay slot
+ END(tlbflush)
+
+ /*
+ * Code necessary to switch tasks on an Linux/MIPS machine.
+ */
+ .align 5
+ LEAF(resume)
+ /*
+ * Current task's task_struct
+ */
+ lui t5,%hi(current)
+ lw t0,%lo(current)(t5)
+
+ /*
+ * Save status register
+ */
+ mfc0 t1,CP0_STATUS
+ addu t0,a1 # Add tss offset
+ sw t1,TOFF_CP0_STATUS(t0)
+
+ /*
+ * Disable interrupts
+ */
+ ori t2,t1,0x1f
+ xori t2,0x1e
+ mtc0 t2,CP0_STATUS
+
+ /*
+ * Save non-scratch registers
+ * All other registers have been saved on the kernel stack
+ */
+ sw s0,TOFF_REG16(t0)
+ sw s1,TOFF_REG17(t0)
+ sw s2,TOFF_REG18(t0)
+ sw s3,TOFF_REG19(t0)
+ sw s4,TOFF_REG20(t0)
+ sw s5,TOFF_REG21(t0)
+ sw s6,TOFF_REG22(t0)
+ sw s7,TOFF_REG23(t0)
+ sw gp,TOFF_REG28(t0)
+ sw sp,TOFF_REG29(t0)
+ sw fp,TOFF_REG30(t0)
+
+ /*
+ * Save floating point state
+ */
+ sll t2,t1,2
+ bgez t2,2f
+ sw ra,TOFF_REG31(t0) # delay slot
+ sll t2,t1,5
+ bgez t2,1f
+ sdc1 $f0,(TOFF_FPU+0)(t0) # delay slot
+ /*
+ * Store the 16 odd double precision registers
+ */
+ sdc1 $f1,(TOFF_FPU+8)(t0)
+ sdc1 $f3,(TOFF_FPU+24)(t0)
+ sdc1 $f5,(TOFF_FPU+40)(t0)
+ sdc1 $f7,(TOFF_FPU+56)(t0)
+ sdc1 $f9,(TOFF_FPU+72)(t0)
+ sdc1 $f11,(TOFF_FPU+88)(t0)
+ sdc1 $f13,(TOFF_FPU+104)(t0)
+ sdc1 $f15,(TOFF_FPU+120)(t0)
+ sdc1 $f17,(TOFF_FPU+136)(t0)
+ sdc1 $f19,(TOFF_FPU+152)(t0)
+ sdc1 $f21,(TOFF_FPU+168)(t0)
+ sdc1 $f23,(TOFF_FPU+184)(t0)
+ sdc1 $f25,(TOFF_FPU+200)(t0)
+ sdc1 $f27,(TOFF_FPU+216)(t0)
+ sdc1 $f29,(TOFF_FPU+232)(t0)
+ sdc1 $f31,(TOFF_FPU+248)(t0)
+
+ /*
+ * Store the 16 even double precision registers
+ */
+1: cfc1 t1,fcr31
+ sdc1 $f2,(TOFF_FPU+16)(t0)
+ sdc1 $f4,(TOFF_FPU+32)(t0)
+ sdc1 $f6,(TOFF_FPU+48)(t0)
+ sdc1 $f8,(TOFF_FPU+64)(t0)
+ sdc1 $f10,(TOFF_FPU+80)(t0)
+ sdc1 $f12,(TOFF_FPU+96)(t0)
+ sdc1 $f14,(TOFF_FPU+112)(t0)
+ sdc1 $f16,(TOFF_FPU+128)(t0)
+ sdc1 $f18,(TOFF_FPU+144)(t0)
+ sdc1 $f20,(TOFF_FPU+160)(t0)
+ sdc1 $f22,(TOFF_FPU+176)(t0)
+ sdc1 $f24,(TOFF_FPU+192)(t0)
+ sdc1 $f26,(TOFF_FPU+208)(t0)
+ sdc1 $f28,(TOFF_FPU+224)(t0)
+ sdc1 $f30,(TOFF_FPU+240)(t0)
+ sw t1,(TOFF_FPU+256)(t0)
+
+ /*
+ * Switch current task
+ */
+2: sw a0,%lo(current)(t5)
+ addu a0,a1 # Add tss offset
+
+ /*
+ * Switch address space
+ */
+
+ /*
+ * (Choose new ASID for process)
+ * This isn't really required, but would speed up
+ * context switching.
+ */
+
+ /*
+ * Switch the root pointer
+ */
+ lw t0,TOFF_PG_DIR(a0)
+ li t1,TLB_ROOT
+ mtc0 t1,CP0_ENTRYHI
+ mtc0 zero,CP0_INDEX
+ srl t0,6
+ ori t0,MODE_ALIAS
+ mtc0 t0,CP0_ENTRYLO0
+ mtc0 zero,CP0_ENTRYLO1
+ lw a2,TOFF_CP0_STATUS(a0)
+
+ /*
+ * Flush tlb
+ * (probably not needed, doesn't clobber a0-a3)
+ */
+ jal tlbflush
+ tlbwi # delay slot
+
+ /*
+ * Restore fpu state:
+ * - cp0 status register bits
+ * - fp gp registers
+ * - cp1 status/control register
+ */
+ ori t1,a2,1 # pipeline magic
+ xori t1,1
+ mtc0 t1,CP0_STATUS
+ sll t0,a2,2
+ bgez t0,2f
+ sll t0,a2,5 # delay slot
+ bgez t0,1f
+ ldc1 $f0,(TOFF_FPU+0)(a0) # delay slot
+ /*
+ * Restore the 16 odd double precision registers only
+ * when enabled in the cp0 status register.
+ */
+ ldc1 $f1,(TOFF_FPU+8)(a0)
+ ldc1 $f3,(TOFF_FPU+24)(a0)
+ ldc1 $f5,(TOFF_FPU+40)(a0)
+ ldc1 $f7,(TOFF_FPU+56)(a0)
+ ldc1 $f9,(TOFF_FPU+72)(a0)
+ ldc1 $f11,(TOFF_FPU+88)(a0)
+ ldc1 $f13,(TOFF_FPU+104)(a0)
+ ldc1 $f15,(TOFF_FPU+120)(a0)
+ ldc1 $f17,(TOFF_FPU+136)(a0)
+ ldc1 $f19,(TOFF_FPU+152)(a0)
+ ldc1 $f21,(TOFF_FPU+168)(a0)
+ ldc1 $f23,(TOFF_FPU+184)(a0)
+ ldc1 $f25,(TOFF_FPU+200)(a0)
+ ldc1 $f27,(TOFF_FPU+216)(a0)
+ ldc1 $f29,(TOFF_FPU+232)(a0)
+ ldc1 $f31,(TOFF_FPU+248)(a0)
+
+ /*
+ * Restore the 16 even double precision registers
+ * when cp1 was enabled in the cp0 status register.
+ */
+1: lw t0,(TOFF_FPU+256)(a0)
+ ldc1 $f2,(TOFF_FPU+16)(a0)
+ ldc1 $f4,(TOFF_FPU+32)(a0)
+ ldc1 $f6,(TOFF_FPU+48)(a0)
+ ldc1 $f8,(TOFF_FPU+64)(a0)
+ ldc1 $f10,(TOFF_FPU+80)(a0)
+ ldc1 $f12,(TOFF_FPU+96)(a0)
+ ldc1 $f14,(TOFF_FPU+112)(a0)
+ ldc1 $f16,(TOFF_FPU+128)(a0)
+ ldc1 $f18,(TOFF_FPU+144)(a0)
+ ldc1 $f20,(TOFF_FPU+160)(a0)
+ ldc1 $f22,(TOFF_FPU+176)(a0)
+ ldc1 $f24,(TOFF_FPU+192)(a0)
+ ldc1 $f26,(TOFF_FPU+208)(a0)
+ ldc1 $f28,(TOFF_FPU+224)(a0)
+ ldc1 $f30,(TOFF_FPU+240)(a0)
+ ctc1 t0,fcr31
+
+ /*
+ * Restore non-scratch registers
+ */
+2: lw s0,TOFF_REG16(a0)
+ lw s1,TOFF_REG17(a0)
+ lw s2,TOFF_REG18(a0)
+ lw s3,TOFF_REG19(a0)
+ lw s4,TOFF_REG20(a0)
+ lw s5,TOFF_REG21(a0)
+ lw s6,TOFF_REG22(a0)
+ lw s7,TOFF_REG23(a0)
+ lw gp,TOFF_REG28(a0)
+ lw sp,TOFF_REG29(a0)
+ lw fp,TOFF_REG30(a0)
+ lw ra,TOFF_REG31(a0)
+
+ /*
+ * Restore status register
+ */
+ lw t0,TOFF_KSP(a0)
+ sw t0,kernelsp
+
+ jr ra
+ mtc0 a2,CP0_STATUS # delay slot
+ END(resume)
+
+ /*
+ * Load a new root pointer into the tlb
+ */
+ .set noreorder
+ LEAF(load_pgd)
+ /*
+ * Switch the root pointer
+ */
+ mfc0 t0,CP0_STATUS
+ ori t1,t0,1
+ xori t1,1
+ mtc0 t1,CP0_STATUS
+ srl a0,6
+ ori a0,MODE_ALIAS
+ li t1,TLB_ROOT
+ mtc0 t1,CP0_ENTRYHI
+ mtc0 zero,CP0_INDEX
+ mtc0 a0,CP0_ENTRYLO0
+ mtc0 zero,CP0_ENTRYLO1
+ mtc0 t0,CP0_STATUS
+ j tlbflush
+ tlbwi # delay slot
+ END(load_pgd)
+
+/*
+ * Some bits in the config register
+ */
+#define CONFIG_DB (1<<4)
+#define CONFIG_IB (1<<5)
+
+/*
+ * Flush instruction/data caches
+ *
+ * Parameters: a0 - starting address to flush
+ * a1 - size of area to be flushed
+ * a2 - which caches to be flushed
+ *
+ * FIXME: - ignores parameters in a0/a1
+ * - doesn't know about second level caches
+ */
+ .set noreorder
+ LEAF(sys_cacheflush)
+ andi t1,a2,DCACHE
+ beqz t1,do_icache
+ li t0,KSEG0 # delay slot
+
+ /*
+ * Writeback data cache, even lines
+ */
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,0(t0)
+ cache Index_Writeback_Inv_D,32(t0)
+ cache Index_Writeback_Inv_D,64(t0)
+ cache Index_Writeback_Inv_D,96(t0)
+ cache Index_Writeback_Inv_D,128(t0)
+ cache Index_Writeback_Inv_D,160(t0)
+ cache Index_Writeback_Inv_D,192(t0)
+ cache Index_Writeback_Inv_D,224(t0)
+ cache Index_Writeback_Inv_D,256(t0)
+ cache Index_Writeback_Inv_D,288(t0)
+ cache Index_Writeback_Inv_D,320(t0)
+ cache Index_Writeback_Inv_D,352(t0)
+ cache Index_Writeback_Inv_D,384(t0)
+ cache Index_Writeback_Inv_D,416(t0)
+ cache Index_Writeback_Inv_D,448(t0)
+ cache Index_Writeback_Inv_D,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Writeback data cache, odd lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_DB
+ bnez t1,do_icache
+ li t1,CACHELINES-1
+1: cache Index_Writeback_Inv_D,16(t0)
+ cache Index_Writeback_Inv_D,48(t0)
+ cache Index_Writeback_Inv_D,80(t0)
+ cache Index_Writeback_Inv_D,112(t0)
+ cache Index_Writeback_Inv_D,144(t0)
+ cache Index_Writeback_Inv_D,176(t0)
+ cache Index_Writeback_Inv_D,208(t0)
+ cache Index_Writeback_Inv_D,240(t0)
+ cache Index_Writeback_Inv_D,272(t0)
+ cache Index_Writeback_Inv_D,304(t0)
+ cache Index_Writeback_Inv_D,336(t0)
+ cache Index_Writeback_Inv_D,368(t0)
+ cache Index_Writeback_Inv_D,400(t0)
+ cache Index_Writeback_Inv_D,432(t0)
+ cache Index_Writeback_Inv_D,464(t0)
+ cache Index_Writeback_Inv_D,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+do_icache: andi t1,a2,ICACHE
+ beqz t1,done
+
+ /*
+ * Flush instruction cache, even lines
+ */
+ lui t0,0x8000
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,0(t0)
+ cache Index_Invalidate_I,32(t0)
+ cache Index_Invalidate_I,64(t0)
+ cache Index_Invalidate_I,96(t0)
+ cache Index_Invalidate_I,128(t0)
+ cache Index_Invalidate_I,160(t0)
+ cache Index_Invalidate_I,192(t0)
+ cache Index_Invalidate_I,224(t0)
+ cache Index_Invalidate_I,256(t0)
+ cache Index_Invalidate_I,288(t0)
+ cache Index_Invalidate_I,320(t0)
+ cache Index_Invalidate_I,352(t0)
+ cache Index_Invalidate_I,384(t0)
+ cache Index_Invalidate_I,416(t0)
+ cache Index_Invalidate_I,448(t0)
+ cache Index_Invalidate_I,480(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+ /*
+ * Flush instruction cache, even lines
+ * Only needed for 16 byte line size
+ */
+ mfc0 t1,CP0_CONFIG
+ andi t1,CONFIG_IB
+ bnez t1,done
+ li t1,CACHELINES-1
+1: cache Index_Invalidate_I,16(t0)
+ cache Index_Invalidate_I,48(t0)
+ cache Index_Invalidate_I,80(t0)
+ cache Index_Invalidate_I,112(t0)
+ cache Index_Invalidate_I,144(t0)
+ cache Index_Invalidate_I,176(t0)
+ cache Index_Invalidate_I,208(t0)
+ cache Index_Invalidate_I,240(t0)
+ cache Index_Invalidate_I,272(t0)
+ cache Index_Invalidate_I,304(t0)
+ cache Index_Invalidate_I,336(t0)
+ cache Index_Invalidate_I,368(t0)
+ cache Index_Invalidate_I,400(t0)
+ cache Index_Invalidate_I,432(t0)
+ cache Index_Invalidate_I,464(t0)
+ cache Index_Invalidate_I,496(t0)
+ addiu t0,512
+ bnez t1,1b
+ subu t1,1
+
+done: j ra
+ nop
+ END(sys_cacheflush)
+
+/*
+ * Update the TLB - or how instruction scheduling makes code unreadable ...
+ *
+ * MIPS doesn't need any external MMU info: the kernel page tables contain
+ * all the necessary information. We use this hook though to load the
+ * TLB as early as possible with uptodate information avoiding unecessary
+ * exceptions.
+ *
+ * Parameters: a0 - struct vm_area_struct *vma (ignored)
+ * a1 - unsigned long address
+ * a2 - pte_t pte
+ */
+ .set noreorder
+ LEAF(update_mmu_cache)
+ /*
+ * Step 1: Wipe out old TLB information. Not shure if
+ * we really need that step; call it paranoia ...
+ * In order to do that we need to disable interrupts.
+ */
+ mfc0 t0,CP0_STATUS # interrupts off
+ ori t1,t0,1
+ xori t1,1
+ mtc0 t1,CP0_STATUS
+ li t3,TLBMAP # then wait 3 cycles
+ ori t1,a1,0xfff # mask off low 12 bits
+ xori t1,0xfff
+ mfc0 t2,CP0_ENTRYHI # copy ASID into address
+ andi t2,0xff
+ or t2,t1
+ mtc0 t2,CP0_ENTRYHI
+ srl t4,a1,12 # wait again three cycles
+ sll t4,t4,PTRLOG
+ dmtc0 zero,CP0_ENTRYLO0
+ tlbp # now query the TLB
+ addu t3,t4 # wait another three cycles
+ ori t3,0xffff
+ xori t3,0xffff
+ mfc0 t1,CP0_INDEX
+ bltz t1,1f # No old entry?
+ dmtc0 zero,CP0_ENTRYLO1
+ or t3,t1 # wait one cycle
+ tlbwi
+ /*
+ * But there still might be a entry for the pgd ...
+ */
+1: mtc0 t3,CP0_ENTRYHI
+ nop # wait 3 cycles
+ nop
+ nop
+ tlbp # TLB lookup
+ nop
+ nop
+ mfc0 t1,CP0_INDEX # wait 3 cycles
+ bltz t1,1f # No old entry?
+ nop
+ tlbwi # gotcha ...
+ /*
+ * Step 2: Reload the TLB with new information. We can skip
+ * this but this should speed the mess a bit by avoiding
+ * tlbl/tlbs exceptions. (To be done)
+ */
+1: jr ra
+ mtc0 t0,CP0_STATUS # delay slot
+ END(update_mmu_cache)
+++ /dev/null
-/*
- * linux/kernel/mips/sys_call.S
- *
- * Copyright (C) 1994, 1995 Waldorf Electronics
- * written by Ralf Baechle
- */
-
-/*
- * sys_call.S contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all interrupts
- * and faults that can result in a task-switch.
- */
-
-#include <asm/regdef.h>
-#include <asm/processor.h>
-#include <asm/mipsregs.h>
-#include <asm/mipsconfig.h>
-
-/*
- * These are offsets into the task-struct.
- */
-state = 0
-counter = 4
-priority = 8
-signal = 12
-blocked = 16
-flags = 20
-errno = 24 #/* MIPS OK */
-exec_domain = 60 #/* ??? */
-
-ENOSYS = 38
-
-/*
- * Code necessary to switch tasks on an Linux/MIPS machine.
- */
-MODE_ALIAS = 0x0016 # uncachable
-
- .text
- .set noreorder
- .set at
-
- .globl _resume
-_resume:
- /*
- * current task's task_struct
- */
- lui t5,%hi(_current)
- lw t0,%lo(_current)(t5)
-
- /*
- * Save status register
- */
- mfc0 t1,CP0_STATUS
- addu t0,a1 # Add tss offset
- sw t1,TOFF_CP0_STATUS(t0)
-
- /*
- * Disable interrupts
- */
- ori t2,t1,0x1f
- xori t2,0x1e
- mtc0 t2,CP0_STATUS
-
- /*
- * Save non-scratch registers
- * All other registers have been saved on the kernel stack
- */
- sw s0,TOFF_REG16(t0)
- sw s1,TOFF_REG17(t0)
- sw s2,TOFF_REG18(t0)
- sw s3,TOFF_REG19(t0)
- sw s4,TOFF_REG20(t0)
- sw s5,TOFF_REG21(t0)
- sw s6,TOFF_REG22(t0)
- sw s7,TOFF_REG23(t0)
- sw gp,TOFF_REG28(t0)
- sw sp,TOFF_REG29(t0)
- sw fp,TOFF_REG30(t0)
- sw ra,TOFF_REG31(t0)
-
- /*
- * Save floating point state
- */
- srl t2,t1,29
- andi t2,1
- beqz t2,2f
- srl t2,t1,26
- andi t2,1
- beqz t2,1f
- sdc1 $f0,(TOFF_FPU+0)(t0) # delay slot
- /*
- * Store the 16 odd double precision registers
- */
- sdc1 $f1,(TOFF_FPU+8)(t0)
- sdc1 $f3,(TOFF_FPU+24)(t0)
- sdc1 $f5,(TOFF_FPU+40)(t0)
- sdc1 $f7,(TOFF_FPU+56)(t0)
- sdc1 $f9,(TOFF_FPU+72)(t0)
- sdc1 $f11,(TOFF_FPU+88)(t0)
- sdc1 $f13,(TOFF_FPU+104)(t0)
- sdc1 $f15,(TOFF_FPU+120)(t0)
- sdc1 $f17,(TOFF_FPU+136)(t0)
- sdc1 $f19,(TOFF_FPU+152)(t0)
- sdc1 $f21,(TOFF_FPU+168)(t0)
- sdc1 $f23,(TOFF_FPU+184)(t0)
- sdc1 $f25,(TOFF_FPU+200)(t0)
- sdc1 $f27,(TOFF_FPU+216)(t0)
- sdc1 $f29,(TOFF_FPU+232)(t0)
- sdc1 $f31,(TOFF_FPU+248)(t0)
-
- /*
- * Store the 16 even double precision registers
- */
-1: cfc1 t1,$31
- sdc1 $f2,(TOFF_FPU+16)(t0)
- sdc1 $f4,(TOFF_FPU+32)(t0)
- sdc1 $f6,(TOFF_FPU+48)(t0)
- sdc1 $f8,(TOFF_FPU+64)(t0)
- sdc1 $f10,(TOFF_FPU+80)(t0)
- sdc1 $f12,(TOFF_FPU+96)(t0)
- sdc1 $f14,(TOFF_FPU+112)(t0)
- sdc1 $f16,(TOFF_FPU+128)(t0)
- sdc1 $f18,(TOFF_FPU+144)(t0)
- sdc1 $f20,(TOFF_FPU+160)(t0)
- sdc1 $f22,(TOFF_FPU+176)(t0)
- sdc1 $f24,(TOFF_FPU+192)(t0)
- sdc1 $f26,(TOFF_FPU+208)(t0)
- sdc1 $f28,(TOFF_FPU+224)(t0)
- sdc1 $f30,(TOFF_FPU+240)(t0)
- sw t1,(TOFF_FPU+256)(t0)
-
- /*
- * Switch current task
- */
-2: sw a0,%lo(_current)(t5)
- addu a0,a1 # Add tss offset
-
- /*
- * Switch address space
- */
-
- /*
- * (Choose new ASID for process)
- */
-
- /*
- * Switch the root pointer
- */
- lw t0,TOFF_PG_DIR(a0)
- la t1,TLB_ROOT
- mtc0 t1,CP0_ENTRYHI
- mtc0 zero,CP0_INDEX
- srl t0,6
- ori t0,MODE_ALIAS
- mtc0 t0,CP0_ENTRYLO0
- mtc0 zero,CP0_ENTRYLO1
- tlbwi
-
- /*
- * Flush tlb (probably not needed)
- * (Doesn't clobber a0-a3)
- */
- jal _tlbflush
- nop # delay slot
-
- lw a2,TOFF_CP0_STATUS(a0)
-
- /*
- * Restore fpu state:
- * - cp0 status register bits
- * - fp gp registers
- * - cp1 status/control register
- */
- ori t1,a2,1 # pipeline magic
- xori t1,1
- mtc0 t1,CP0_STATUS
- srl t0,a2,29
- andi t0,1
- beqz t0,2f
- srl t0,a2,26
- andi t0,1
- beqz t0,1f
- ldc1 $f0,(TOFF_FPU+0)(a0) # delay slot
- /*
- * Restore the 16 odd double precision registers only
- * when enabled in the cp0 status register.
- */
- ldc1 $f1,(TOFF_FPU+8)(a0)
- ldc1 $f3,(TOFF_FPU+24)(a0)
- ldc1 $f5,(TOFF_FPU+40)(a0)
- ldc1 $f7,(TOFF_FPU+56)(a0)
- ldc1 $f9,(TOFF_FPU+72)(a0)
- ldc1 $f11,(TOFF_FPU+88)(a0)
- ldc1 $f13,(TOFF_FPU+104)(a0)
- ldc1 $f15,(TOFF_FPU+120)(a0)
- ldc1 $f17,(TOFF_FPU+136)(a0)
- ldc1 $f19,(TOFF_FPU+152)(a0)
- ldc1 $f21,(TOFF_FPU+168)(a0)
- ldc1 $f23,(TOFF_FPU+184)(a0)
- ldc1 $f25,(TOFF_FPU+200)(a0)
- ldc1 $f27,(TOFF_FPU+216)(a0)
- ldc1 $f29,(TOFF_FPU+232)(a0)
- ldc1 $f31,(TOFF_FPU+248)(a0)
-
- /*
- * Restore the 16 even double precision registers always
- * when cp1 was enabled in the cp0 status register.
- */
-1: lw t0,(TOFF_FPU+256)(a0)
- ldc1 $f2,(TOFF_FPU+16)(a0)
- ldc1 $f4,(TOFF_FPU+32)(a0)
- ldc1 $f6,(TOFF_FPU+48)(a0)
- ldc1 $f8,(TOFF_FPU+64)(a0)
- ldc1 $f10,(TOFF_FPU+80)(a0)
- ldc1 $f12,(TOFF_FPU+96)(a0)
- ldc1 $f14,(TOFF_FPU+112)(a0)
- ldc1 $f16,(TOFF_FPU+128)(a0)
- ldc1 $f18,(TOFF_FPU+144)(a0)
- ldc1 $f20,(TOFF_FPU+160)(a0)
- ldc1 $f22,(TOFF_FPU+176)(a0)
- ldc1 $f24,(TOFF_FPU+192)(a0)
- ldc1 $f26,(TOFF_FPU+208)(a0)
- ldc1 $f28,(TOFF_FPU+224)(a0)
- ldc1 $f30,(TOFF_FPU+240)(a0)
- ctc1 t0,$31
-
- /*
- * Restore non-scratch registers
- */
-2: lw s0,TOFF_REG16(a0)
- lw s1,TOFF_REG17(a0)
- lw s2,TOFF_REG18(a0)
- lw s3,TOFF_REG19(a0)
- lw s4,TOFF_REG20(a0)
- lw s5,TOFF_REG21(a0)
- lw s6,TOFF_REG22(a0)
- lw s7,TOFF_REG23(a0)
- lw gp,TOFF_REG28(a0)
- lw sp,TOFF_REG29(a0)
- lw fp,TOFF_REG30(a0)
- lw ra,TOFF_REG31(a0)
-
- /*
- * Restore status register
- */
- lw t0,TOFF_KSP(a0)
- sw t0,_kernelsp
-
- jr ra
- mtc0 a2,CP0_STATUS # delay slot
* linux/arch/mips/kernel/setup.c
*
* Copyright (C) 1995 Linus Torvalds
+ * Copyright (C) 1995 Ralf Baechle
*/
-
+#include <linux/config.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/stddef.h>
+#include <linux/string.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/malloc.h>
#include <linux/a.out.h>
#include <linux/tty.h>
+#include <asm/asm.h>
#include <asm/bootinfo.h>
+#include <asm/vector.h>
#include <asm/segment.h>
+#include <asm/stackframe.h>
#include <asm/system.h>
+/*
+ * How to handle the machine's features
+ */
+struct feature *feature;
+
+#ifdef CONFIG_ACER_PICA_61
+void acer_pica_61_handle_int(void);
+/*
+ * How to access the floppy controller's ports
+ */
+unsigned char jazz_fd_inb(unsigned int port);
+void jazz_fd_outb(unsigned char value, unsigned int port);
+/*
+ * How to access the floppy DMA functions.
+ */
+void jazz_fd_enable_dma(void);
+void jazz_fd_disable_dma(void);
+int jazz_fd_request_dma(void);
+void jazz_fd_free_dma(void);
+void jazz_fd_clear_dma_ff(void);
+void jazz_fd_set_dma_mode(char mode);
+void jazz_fd_set_dma_addr(unsigned int a);
+void jazz_fd_set_dma_count(unsigned int count);
+int jazz_fd_get_dma_residue(void);
+void jazz_fd_enable_irq(void);
+void jazz_fd_disable_irq(void);
+void jazz_fd_cacheflush(unsigned char *addr, unsigned int size);
+/*
+ * How to access the RTC functions.
+ */
+unsigned char jazz_rtc_read_data(void);
+void jazz_rtc_write_data(unsigned char data);
+
+struct feature acer_pica_61_feature = {
+ acer_pica_61_handle_int,
+ /*
+ * How to access the floppy controller's ports
+ */
+ jazz_fd_inb,
+ jazz_fd_outb,
+ /*
+ * How to access the floppy DMA functions.
+ */
+ jazz_fd_enable_dma,
+ jazz_fd_disable_dma,
+ jazz_fd_request_dma,
+ jazz_fd_free_dma,
+ jazz_fd_clear_dma_ff,
+ jazz_fd_set_dma_mode,
+ jazz_fd_set_dma_addr,
+ jazz_fd_set_dma_count,
+ jazz_fd_get_dma_residue,
+ jazz_fd_enable_irq,
+ jazz_fd_disable_irq,
+ jazz_fd_cacheflush,
+ /*
+ * How to access the RTC functions.
+ */
+ jazz_rtc_read_data,
+ jazz_rtc_write_data
+};
+#endif
+#ifdef CONFIG_DECSTATION
+void decstation_handle_handle_int(void);
+void isa_outb(unsigned char value, unsigned int port);
+unsigned char isa_inb(unsigned int port);
+struct feature decstation_feature = {
+ decstation_handle_handle_int,
+ isa_inb /* Dummy - dunno how to handle this yet */
+ isa_outb, /* Dummy - dunno how to handle this yet */
+};
+#endif
+#ifdef CONFIG_DESKSTATION_RPC44
+void deskstation_rpc44_handle_int(void);
+void isa_outb(unsigned char value, unsigned int port);
+unsigned char isa_inb(unsigned int port);
+struct feature deskstation_rpc44_feature = {
+ deskstation_rpc44_handle_int,
+ isa_inb
+ isa_outb,
+};
+#endif
+#ifdef CONFIG_DESKSTATION_TYNE
+void deskstation_tyne_handle_int(void);
+void isa_outb(unsigned char value, unsigned int port);
+unsigned char isa_inb(unsigned int port);
+struct feature deskstation_tyne_feature = {
+ deskstation_tyne_handle_int,
+ isa_inb,
+ isa_outb,
+};
+#endif
+#ifdef CONFIG_MIPS_MAGNUM_4000
+void mips_magnum_4000_handle_int(void);
+/*
+ * How to access the floppy controller's ports
+ */
+unsigned char jazz_fd_inb(unsigned int port);
+void jazz_fd_outb(unsigned char value, unsigned int port);
+/*
+ * How to access the floppy DMA functions.
+ */
+void jazz_fd_enable_dma(void);
+void jazz_fd_disable_dma(void);
+int jazz_fd_request_dma(void);
+void jazz_fd_free_dma(void);
+void jazz_fd_clear_dma_ff(void);
+void jazz_fd_set_dma_mode(char mode);
+void jazz_fd_set_dma_addr(unsigned int a);
+void jazz_fd_set_dma_count(unsigned int count);
+int jazz_fd_get_dma_residue(void);
+void jazz_fd_enable_irq(void);
+void jazz_fd_disable_irq(void);
+void jazz_fd_cacheflush(unsigned char *addr, unsigned int size);
+/*
+ * How to access the RTC functions.
+ */
+unsigned char jazz_rtc_read_data(void);
+void jazz_rtc_write_data(unsigned char data);
+
+struct feature mips_magnum_4000_feature = {
+ mips_magnum_4000_handle_int,
+ /*
+ * How to access the floppy controller's ports
+ */
+ jazz_fd_inb,
+ jazz_fd_outb,
+ /*
+ * How to access the floppy DMA functions.
+ */
+ jazz_fd_enable_dma,
+ jazz_fd_disable_dma,
+ jazz_fd_request_dma,
+ jazz_fd_free_dma,
+ jazz_fd_clear_dma_ff,
+ jazz_fd_set_dma_mode,
+ jazz_fd_set_dma_addr,
+ jazz_fd_set_dma_count,
+ jazz_fd_get_dma_residue,
+ jazz_fd_enable_irq,
+ jazz_fd_disable_irq,
+ jazz_fd_cacheflush,
+ /*
+ * How to access the RTC functions.
+ */
+ jazz_rtc_read_data,
+ jazz_rtc_write_data
+};
+#endif
+
/*
* Tell us the machine setup..
*/
* Setup options
*/
struct drive_info_struct drive_info;
-struct screen_info screen_info;
+struct screen_info screen_info = SCREEN_INFO;
unsigned char aux_device_present;
extern int ramdisk_size;
extern int root_mountflags;
-extern int end;
+extern int _end;
extern char empty_zero_page[PAGE_SIZE];
* This is set up by the setup-routine at boot-time
*/
#define PARAM empty_zero_page
-#define EXT_MEM (boot_info.memupper)
-#define DRIVE_INFO (boot_info.drive_info)
-#define SCREEN_INFO (screen_info)
-#define MOUNT_ROOT_RDONLY (boot_info.mount_root_rdonly)
-#define RAMDISK_SIZE (boot_info.ramdisk_size)
#if 0
#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
#endif
-#define COMMAND_LINE (boot_info.command_line)
static char command_line[CL_SIZE] = { 0, };
+#if 0
+/*
+ * Code for easy access to new style bootinfo
+ *
+ * Parameter: tag -- taglist entry
+ *
+ * returns : (tag *) -- pointer to taglist entry, NULL for not found
+ */
+tag *
+bi_TagFind(enum bi_tag tag)
+{
+ /* TBD */
+ return 0;
+}
+
+/*
+ * Only for taglist creators (bootloaders)
+ *
+ * Parameter: tag -- (enum bi_tag) taglist entry
+ *
+ * returns : 1 -- success
+ * 0 -- failure
+ */
+int
+bi_TagAdd(enum bi_tag tag, unsigned long size, void *tagdata)
+{
+ /* TBD */
+ return 0;
+}
+#endif /* 0 */
+
void setup_arch(char **cmdline_p,
unsigned long * memory_start_p, unsigned long * memory_end_p)
{
unsigned long memory_start, memory_end;
- char c = ' ', *to = command_line, *from = COMMAND_LINE;
- int len = 0;
+
+ switch(boot_info.machtype)
+ {
+#ifdef CONFIG_ACER_PICA_61
+ case MACH_ACER_PICA_61:
+ feature = &acer_pica_61_feature;
+ break;
+#endif
+#ifdef CONFIG_DECSTATION
+ case MACH_DECSTATION:
+ feature = &decstation_feature;
+ break;
+#endif
+#ifdef CONFIG_DESKSTATION_RPC
+ case MACH_DESKSTATION_RPC:
+ feature = &deskstation_rpc44_feature;
+ break;
+#endif
+#ifdef CONFIG_DESKSTATION_TYNE
+ case MACH_DESKSTATION_TYNE:
+ feature = &deskstation_tyne_feature;
+ break;
+#endif
+#ifdef CONFIG_MIPS_MAGNUM_4000
+ case MACH_MIPS_MAGNUM_4000:
+ feature = &mips_magnum_4000_feature;
+ break;
+#endif
+ default:
+ panic("Unsupported architecture");
+ }
#if 0
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
+#else
+#ifdef CONFIG_BLK_DEV_FD
+ ROOT_DEV = to_kdev_t(0x021c); /* fd0H1440 */
+#else
+ ROOT_DEV = to_kdev_t(0x0101); /* ram */
#endif
- drive_info = DRIVE_INFO;
- screen_info = SCREEN_INFO;
+/* ROOT_DEV = to_kdev_t(0x00ff); */ /* NFS */
+#endif
+ memcpy(&drive_info, &boot_info.drive_info, sizeof(drive_info));
#if 0
aux_device_present = AUX_DEVICE_INFO;
#endif
- memory_end = EXT_MEM;
+ memory_end = boot_info.memupper;
memory_end &= PAGE_MASK;
- ramdisk_size = RAMDISK_SIZE;
- if (MOUNT_ROOT_RDONLY)
+ ramdisk_size = boot_info.ramdisk_size;
+ if (boot_info.mount_root_rdonly)
root_mountflags |= MS_RDONLY;
- memory_start = (unsigned long) &end - KERNELBASE;
-
- for (;;) {
- if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") {
- memory_end = simple_strtoul(from+4, &from, 0);
- if ( *from == 'K' || *from == 'k' ) {
- memory_end = memory_end << 10;
- from++;
- } else if ( *from == 'M' || *from == 'm' ) {
- memory_end = memory_end << 20;
- from++;
- }
- }
- c = *(from++);
- if (!c)
- break;
- if (CL_SIZE <= ++len)
- break;
- *(to++) = c;
- }
- *to = '\0';
+
+ memory_start = (unsigned long) &_end;
+ memory_start += (ramdisk_size << 10);
+
*cmdline_p = command_line;
*memory_start_p = memory_start;
*memory_end_p = memory_end;
+
+#if 0
+ /*
+ * Check that struct pt_regs is defined properly
+ * (Should be optimized away, but gcc 2.6.3 is too bad..)
+ */
+ if (FR_SIZE != sizeof(struct pt_regs) ||
+ FR_SIZE & 7)
+ {
+ panic("Check_definition_of_struct_pt_regs\n");
+ }
+#endif
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * BUFFER is PAGE_SIZE bytes long.
+ */
+int get_cpuinfo(char *buffer)
+{
+ const char *cpu_name[] = CPU_NAMES;
+ const char *mach_name[] = MACH_NAMES;
+
+ return sprintf(buffer,
+ "cpu\t\t\t: MIPS\n"
+ "cpu model\t\t: %s\n"
+ "system type\t\t: %s\n"
+ "BogoMIPS\t\t: %lu.%02lu\n",
+
+ cpu_name[boot_info.cputype < CPU_LAST ? boot_info.cputype : CPU_UNKNOWN],
+ mach_name[boot_info.machtype < CPU_LAST ? boot_info.machtype : CPU_UNKNOWN],
+ loops_per_sec / 500000, (loops_per_sec / 5000) % 100);
}
+#endif /* CONFIG_PROC_FS */
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <asm/bitops.h>
#include <asm/segment.h>
#include <asm/cachectl.h>
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
+asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs);
/*
* atomically swap in the new signal mask, and wait for a signal.
/*
* This sets regs->reg29 even though we don't actually use sigstacks yet..
*/
-asmlinkage int sys_sigreturn(unsigned long __unused)
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
- struct sigcontext_struct context;
- struct pt_regs * regs;
+ struct sigcontext_struct *context;
- regs = (struct pt_regs *) &__unused;
- if (verify_area(VERIFY_READ, (void *) regs->reg29, sizeof(context)))
+ /*
+ * We don't support fixing ADEL/ADES exceptions for signal stack frames.
+ * No big loss - who doesn't care about the alignment of this stack
+ * really deserves to loose.
+ */
+ context = (struct sigcontext_struct *) regs->reg29;
+ if (verify_area(VERIFY_READ, context, sizeof(struct sigcontext_struct)) ||
+ (regs->reg29 & 3))
goto badframe;
- memcpy_fromfs(&context,(void *) regs->reg29, sizeof(context));
- current->blocked = context.oldmask & _BLOCKABLE;
- regs->reg1 = context.sc_at;
- regs->reg2 = context.sc_v0;
- regs->reg3 = context.sc_v1;
- regs->reg4 = context.sc_a0;
- regs->reg5 = context.sc_a1;
- regs->reg6 = context.sc_a2;
- regs->reg7 = context.sc_a3;
- regs->reg8 = context.sc_t0;
- regs->reg9 = context.sc_t1;
- regs->reg10 = context.sc_t2;
- regs->reg11 = context.sc_t3;
- regs->reg12 = context.sc_t4;
- regs->reg13 = context.sc_t5;
- regs->reg14 = context.sc_t6;
- regs->reg15 = context.sc_t7;
- regs->reg16 = context.sc_s0;
- regs->reg17 = context.sc_s1;
- regs->reg18 = context.sc_s2;
- regs->reg19 = context.sc_s3;
- regs->reg20 = context.sc_s4;
- regs->reg21 = context.sc_s5;
- regs->reg22 = context.sc_s6;
- regs->reg23 = context.sc_s7;
- regs->reg24 = context.sc_t8;
- regs->reg25 = context.sc_t9;
+
+ current->blocked = context->sc_oldmask & _BLOCKABLE;
+ regs->reg1 = context->sc_at;
+ regs->reg2 = context->sc_v0;
+ regs->reg3 = context->sc_v1;
+ regs->reg4 = context->sc_a0;
+ regs->reg5 = context->sc_a1;
+ regs->reg6 = context->sc_a2;
+ regs->reg7 = context->sc_a3;
+ regs->reg8 = context->sc_t0;
+ regs->reg9 = context->sc_t1;
+ regs->reg10 = context->sc_t2;
+ regs->reg11 = context->sc_t3;
+ regs->reg12 = context->sc_t4;
+ regs->reg13 = context->sc_t5;
+ regs->reg14 = context->sc_t6;
+ regs->reg15 = context->sc_t7;
+ regs->reg16 = context->sc_s0;
+ regs->reg17 = context->sc_s1;
+ regs->reg18 = context->sc_s2;
+ regs->reg19 = context->sc_s3;
+ regs->reg20 = context->sc_s4;
+ regs->reg21 = context->sc_s5;
+ regs->reg22 = context->sc_s6;
+ regs->reg23 = context->sc_s7;
+ regs->reg24 = context->sc_t8;
+ regs->reg25 = context->sc_t9;
/*
* Skip k0/k1
*/
- regs->reg28 = context.sc_gp;
- regs->reg29 = context.sc_sp;
- regs->reg30 = context.sc_fp;
- regs->reg31 = context.sc_ra;
- regs->cp0_epc = context.sc_epc;
- regs->cp0_cause = context.sc_cause;
+ regs->reg28 = context->sc_gp;
+ regs->reg29 = context->sc_sp;
+ regs->reg30 = context->sc_fp;
+ regs->reg31 = context->sc_ra;
+ regs->cp0_epc = context->sc_epc;
+ regs->cp0_cause = context->sc_cause;
/*
* disable syscall checks
*/
regs->orig_reg2 = -1;
- return regs->orig_reg2;
+ return context->sc_v0;
+
badframe:
do_exit(SIGSEGV);
}
/*
* Set up a signal frame...
+ *
+ * This routine is somewhat complicated by the fact that if the kernel may be
+ * entered by an exception other than a system call; e.g. a bus error or other
+ * "bad" exception. If this is the case, then *all* the context on the kernel
+ * stack frame must be saved.
+ *
+ * For a large number of exceptions, the stack frame format is the same
+ * as that which will be created when the process traps back to the kernel
+ * when finished executing the signal handler. In this case, nothing
+ * must be done. This information is saved on the user stack and restored
+ * when the signal handler is returned.
+ *
+ * The signal handler will be called with ra pointing to code1 (see below) and
+ * one parameters in a0 (signum).
+ *
+ * usp -> [unused] ; first free word on stack
+ * arg save space ; 16 bytes argument save space
+ * code1 (addiu sp,#1-offset) ; syscall number
+ * code2 (li v0,__NR_sigreturn) ; syscall number
+ * code3 (syscall) ; do sigreturn(2)
+ * #1| at, v0, v1, a0, a1, a2, a3 ; All integer registers
+ * | t0, t1, t2, t3, t4, t5, t6, t7 ; except zero, k0 and k1
+ * | s0, s1, s2, s3, s4, s5, s6, s7
+ * | t8, t9, gp, sp, fp, ra;
+ * | epc ; old program counter
+ * | cause ; CP0 cause register
+ * | oldmask
*/
-static void setup_frame(struct sigaction * sa, unsigned long ** fp,
+
+struct sc {
+ unsigned long ass[4];
+ unsigned int code[4];
+ struct sigcontext_struct scc;
+};
+#define scc_offset ((size_t)&((struct sc *)0)->scc)
+
+static void setup_frame(struct sigaction * sa, struct sc **fp,
unsigned long pc, struct pt_regs *regs,
int signr, unsigned long oldmask)
{
- unsigned long * frame;
+ struct sc *frame;
frame = *fp;
- frame -= 32;
- if (verify_area(VERIFY_WRITE,frame,21*4))
- do_exit(SIGSEGV);
- /*
- * set up the "normal" stack seen by the signal handler
- */
- put_fs_long(regs->reg1 , frame );
- put_fs_long(regs->reg2 , frame+ 1);
- put_fs_long(regs->reg3 , frame+ 2);
- put_fs_long(regs->reg4 , frame+ 3);
- put_fs_long(regs->reg5 , frame+ 4);
- put_fs_long(regs->reg6 , frame+ 5);
- put_fs_long(regs->reg7 , frame+ 6);
- put_fs_long(regs->reg8 , frame+ 7);
- put_fs_long(regs->reg9 , frame+ 8);
- put_fs_long(regs->reg10, frame+ 9);
- put_fs_long(regs->reg11, frame+10);
- put_fs_long(regs->reg12, frame+11);
- put_fs_long(regs->reg13, frame+12);
- put_fs_long(regs->reg14, frame+13);
- put_fs_long(regs->reg15, frame+14);
- put_fs_long(regs->reg16, frame+15);
- put_fs_long(regs->reg17, frame+16);
- put_fs_long(regs->reg18, frame+17);
- put_fs_long(regs->reg19, frame+18);
- put_fs_long(regs->reg20, frame+19);
- put_fs_long(regs->reg21, frame+20);
- put_fs_long(regs->reg22, frame+21);
- put_fs_long(regs->reg23, frame+22);
- put_fs_long(regs->reg24, frame+23);
- put_fs_long(regs->reg25, frame+24);
+ frame--;
+
/*
- * Don't copy k0/k1
+ * We don't support fixing ADEL/ADES exceptions for signal stack frames.
+ * No big loss - who doesn't care about the alignment of this stack
+ * really deserves to loose.
*/
- put_fs_long(regs->reg28, frame+25);
- put_fs_long(regs->reg29, frame+26);
- put_fs_long(regs->reg30, frame+27);
- put_fs_long(regs->reg31, frame+28);
- put_fs_long(pc , frame+29);
- put_fs_long(oldmask , frame+30);
+ if (verify_area(VERIFY_WRITE, frame, sizeof (struct sc)) ||
+ ((unsigned long)frame & 3))
+ do_exit(SIGSEGV);
+
/*
- * set up the return code...
+ * Set up the return code ...
*
* .set noreorder
- * .set noat
+ * addiu sp,24
+ * li v0,__NR_sigreturn
* syscall
- * li $1,__NR_sigreturn
- * .set at
* .set reorder
*/
- put_fs_long(0x24010077, frame+31); /* li $1,119 */
- put_fs_long(0x000000c0, frame+32); /* syscall */
- *fp = frame;
+ frame->code[0] = 0x27bd0000 + scc_offset;
+ frame->code[1] = 0x24020000 + __NR_sigreturn;
+ frame->code[2] = 0x0000000c;
+
/*
- * Flush caches so the instructions will be correctly executed.
+ * Flush caches so that the instructions will be correctly executed.
*/
- sys_cacheflush(frame, 32*4, BCACHE);
+ sys_cacheflush (frame->code, sizeof (frame->code), ICACHE);
+
+ /*
+ * Set up the "normal" sigcontext_struct
+ */
+ frame->scc.sc_at = regs->reg1; /* Assembler temporary */
+ frame->scc.sc_v0 = regs->reg2; /* Result registers */
+ frame->scc.sc_v1 = regs->reg3;
+ frame->scc.sc_a0 = regs->reg4; /* Argument registers */
+ frame->scc.sc_a1 = regs->reg5;
+ frame->scc.sc_a2 = regs->reg6;
+ frame->scc.sc_a3 = regs->reg7;
+
+ frame->scc.sc_t0 = regs->reg8; /* Caller saved */
+ frame->scc.sc_t1 = regs->reg9;
+ frame->scc.sc_t2 = regs->reg10;
+ frame->scc.sc_t3 = regs->reg11;
+ frame->scc.sc_t4 = regs->reg12;
+ frame->scc.sc_t5 = regs->reg13;
+ frame->scc.sc_t6 = regs->reg14;
+ frame->scc.sc_t7 = regs->reg15;
+
+ frame->scc.sc_s0 = regs->reg16; /* Callee saved */
+ frame->scc.sc_s1 = regs->reg17;
+ frame->scc.sc_s2 = regs->reg18;
+ frame->scc.sc_s3 = regs->reg19;
+ frame->scc.sc_s4 = regs->reg20;
+ frame->scc.sc_s5 = regs->reg21;
+ frame->scc.sc_s6 = regs->reg22;
+ frame->scc.sc_s7 = regs->reg23;
+
+ frame->scc.sc_t8 = regs->reg24; /* Caller saved */
+ frame->scc.sc_t9 = regs->reg25;
+
+ /*
+ * Don't copy k0/k1
+ */
+ frame->scc.sc_gp = regs->reg28; /* global pointer / s8 */
+ frame->scc.sc_sp = regs->reg29; /* old stack pointer */
+ frame->scc.sc_fp = regs->reg30; /* old frame pointer */
+ frame->scc.sc_ra = regs->reg31; /* old return address */
+
+ frame->scc.sc_epc = regs->cp0_epc; /* Program counter */
+ frame->scc.sc_cause = regs->cp0_cause; /* c0_epc register */
+
+ frame->scc.sc_oldmask = oldmask;
+ *fp = frame;
+
+ regs->reg4 = signr; /* argument for handler */
}
/*
{
unsigned long mask = ~current->blocked;
unsigned long handler_signal = 0;
- unsigned long *frame = NULL;
+ struct sc *frame = NULL;
unsigned long pc = 0;
unsigned long signr;
struct sigaction * sa;
while ((signr = current->signal & mask)) {
- __asm__(".set\tnoreorder\n\t"
- ".set\tnoat\n\t"
- "li\t%0,31\n"
- "1:\tsllv\t$1,%1,%0\n\t"
- "bgezl\t$1,1b\n\t"
- "subu\t$8,1\n\t"
- "subu\t%0,31\n\t"
- "subu\t%0,$0,%0\n\t"
- "li\t$1,1\n\t"
- "sllv\t$1,$1,%0\n\t"
- "nor\t$1,$0\n\t"
- "xor\t%1,$1\n\t"
- ".set\tat\n\t"
- ".set\treorder"
- :"=r" (signr),"=r" (current->signal)
- :"0" (signr),"1" (current->signal)
- :"$1");
- sa = current->sigaction + signr;
+ signr = ffz(~signr);
+ clear_bit(signr, ¤t->signal);
+ sa = current->sig->action + signr;
signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->signal |= _S(signr);
continue;
}
- sa = current->sigaction + signr - 1;
+ sa = current->sig->action + signr - 1;
}
if (sa->sa_handler == SIG_IGN) {
if (signr != SIGCHLD)
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
notify_parent(current);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGIOT: case SIGFPE: case SIGSEGV:
+ case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS:
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
}
+ /*
+ * Who's code doesn't conform to the restartable syscall convention
+ * dies here!!! The li instruction, a single machine instruction,
+ * must directly be followed by the syscall instruction.
+ */
if (regs->orig_reg2 >= 0 &&
(regs->reg2 == -ERESTARTNOHAND ||
regs->reg2 == -ERESTARTSYS ||
- regs->reg2 == -ERESTARTNOINTR)) {
+ regs->reg2 == -ERESTARTNOINTR))
+ {
regs->reg2 = regs->orig_reg2;
- regs->cp0_epc -= 4;
+ regs->cp0_epc -= 8;
}
if (!handler_signal) /* no handler will be called - return 0 */
return 0;
pc = regs->cp0_epc;
- frame = (unsigned long *) regs->reg29;
+ frame = (struct sc *) regs->reg29;
signr = 1;
- sa = current->sigaction;
+ sa = current->sig->action;
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
if (!(mask & handler_signal))
continue;
- setup_frame(sa,&frame,pc,regs,signr,oldmask);
+ setup_frame(sa, &frame, pc, regs, signr, oldmask);
pc = (unsigned long) sa->sa_handler;
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- /*
- * force a kernel-mode page-in of the signal
- * handler to reduce races
- */
- __asm__(".set\tnoat\n\t"
- "lwu\t$1,(%0)\n\t"
- ".set\tat\n\t"
- :
- :"r" ((char *) pc)
- :"$1");
current->blocked |= sa->sa_mask;
oldmask |= sa->sa_mask;
}
- regs->reg29 = (unsigned long) frame;
+ regs->reg29 = (unsigned long) frame; /* Stack pointer */
+ regs->reg31 = (unsigned long) frame->code; /* Return address */
regs->cp0_epc = pc; /* "return" to the first handler */
+
return 1;
}
--- /dev/null
+/*
+ * MIPS specific syscall handling functions and syscalls
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/segment.h>
+#include <asm/signal.h>
+
+extern asmlinkage void syscall_trace(void);
+typedef asmlinkage int (*syscall_t)(void *a0,...);
+extern asmlinkage int do_syscalls(struct pt_regs *regs, syscall_t fun,
+ int narg);
+extern syscall_t sys_call_table[];
+extern unsigned char sys_narg_table[];
+
+asmlinkage int sys_pipe(struct pt_regs *regs)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (error)
+ return error;
+ regs->reg2 = fd[0];
+ regs->reg3 = fd[1];
+ return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
+ int flags, int fd, off_t offset)
+{
+ struct file * file = NULL;
+
+ if (flags & MAP_RENAME) {
+ 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);
+}
+
+asmlinkage int sys_idle(void)
+{
+ if (current->pid != 0)
+ return -EPERM;
+
+ /* endless idle loop with no priority at all */
+ current->counter = -100;
+ for (;;) {
+ /*
+ * R4[26]00 have wait, R4[04]00 don't.
+ */
+ if (wait_available && !need_resched)
+ __asm__(".set\tmips3\n\t"
+ "wait\n\t"
+ ".set\tmips0\n\t");
+ schedule();
+ }
+}
+
+asmlinkage int sys_fork(struct pt_regs *regs)
+{
+ return do_fork(SIGCHLD, regs->reg29, regs);
+}
+
+asmlinkage int sys_clone(struct pt_regs *regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+
+ clone_flags = regs->reg4;
+ newsp = regs->reg5;
+ if (!newsp)
+ newsp = regs->reg29;
+ return do_fork(clone_flags, newsp, regs);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+asmlinkage int sys_execve(struct pt_regs *regs)
+{
+ int error;
+ char * filename;
+
+ error = getname((char *) regs->reg4, &filename);
+ if (error)
+ return error;
+ error = do_execve(filename, (char **) regs->reg5,
+ (char **) regs->reg6, regs);
+ putname(filename);
+ return error;
+}
+
+/*
+ * Do the indirect syscall syscall.
+ */
+asmlinkage int sys_syscall(unsigned long a0, unsigned long a1, unsigned long a2,
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ unsigned long a6)
+{
+ syscall_t syscall;
+
+ if (a0 > __NR_Linux + __NR_Linux_syscalls)
+ return -ENOSYS;
+
+ syscall = sys_call_table[a0];
+ /*
+ * Prevent stack overflow by recursive
+ * syscall(__NR_syscall, __NR_syscall,...);
+ */
+ if (syscall == (syscall_t) sys_syscall)
+ return -EINVAL;
+
+ if (syscall == NULL)
+ return -ENOSYS;
+
+ return syscall((void *)a0, a1, a2, a3, a4, a5, a6);
+}
+
+void do_sys(struct pt_regs *regs)
+{
+ unsigned long syscallnr, usp;
+ syscall_t syscall;
+ int errno, narg;
+
+ /*
+ * Compute the return address;
+ */
+ if (regs->cp0_cause & CAUSEF_BD)
+ {
+ /*
+ * This syscall is in a branch delay slot. Since we don't do
+ * branch delay slot handling we would get a process trying
+ * to do syscalls ever and ever again. So better zap it.
+ */
+ printk("%s: syscall in branch delay slot.\n", current->comm);
+ current->sig->action[SIGILL-1].sa_handler = NULL;
+ current->blocked &= ~(1<<(SIGILL-1));
+ send_sig(SIGILL, current, 1);
+ return;
+ }
+ regs->cp0_epc += 4;
+
+ syscallnr = regs->reg2;
+ if (syscallnr > (__NR_Linux + __NR_Linux_syscalls))
+ goto illegal_syscall;
+
+ syscall = sys_call_table[syscallnr];
+ if (syscall == NULL)
+ goto illegal_syscall;
+
+ narg = sys_narg_table[syscallnr];
+ if (narg > 4)
+ {
+ /*
+ * Verify that we can savely get the additional parameters
+ * from the user stack. Of course I could read the params
+ * from unaligned addresses ... Consider this a programming
+ * course caliber .45.
+ */
+ usp = regs->reg29;
+ if (usp & 3)
+ {
+ printk("unaligned usp\n");
+ send_sig(SIGSEGV, current, 1);
+ regs->reg2 = EFAULT;
+ regs->reg7 = 1;
+ return;
+ }
+ errno = verify_area(VERIFY_READ, (void *) (usp + 16),
+ (narg - 4) * sizeof(unsigned long));
+ if (errno < 0)
+ goto bad_syscall;
+ }
+
+ if ((current->flags & PF_TRACESYS) == 0)
+ {
+ errno = do_syscalls(regs, syscall, narg);
+ if (errno < 0 || current->errno)
+ goto bad_syscall;
+
+ regs->reg2 = errno;
+ regs->reg7 = 0;
+ }
+ else
+ {
+ syscall_trace();
+
+ errno = do_syscalls(regs, syscall, narg);
+ if (errno < 0 || current->errno)
+ {
+ regs->reg2 = -errno;
+ regs->reg7 = 1;
+ }
+ else
+ {
+ regs->reg2 = errno;
+ regs->reg7 = 0;
+ }
+
+ syscall_trace();
+ }
+ return;
+
+bad_syscall:
+ regs->reg2 = -errno;
+ regs->reg7 = 1;
+ return;
+illegal_syscall:
+ regs->reg2 = ENOSYS;
+ regs->reg7 = 1;
+ return;
+}
--- /dev/null
+/*
+ * List of Linux/MIPS syscalls.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+
+/*
+ * This file is being included twice - once to build a list of all
+ * syscalls and once to build a table of how many arguments each syscall
+ * accepts. Syscalls that receive a pointer to the saved registers are
+ * marked as having zero arguments.
+ *
+ * The binary compatibility calls are still missing in this list.
+ */
+SYS(sys_syscall, 7) /* 4000 */
+SYS(sys_exit, 1)
+SYS(sys_fork, 0)
+SYS(sys_read, 3)
+SYS(sys_write, 3)
+SYS(sys_open, 3) /* 4005 */
+SYS(sys_close, 3)
+SYS(sys_waitpid, 3)
+SYS(sys_creat, 2)
+SYS(sys_link, 2)
+SYS(sys_unlink, 1) /* 4010 */
+SYS(sys_execve, 0)
+SYS(sys_chdir, 1)
+SYS(sys_time, 1)
+SYS(sys_mknod, 3)
+SYS(sys_chmod, 2) /* 4015 */
+SYS(sys_chown, 3)
+SYS(sys_break, 0)
+SYS(sys_stat, 2)
+SYS(sys_lseek, 3)
+SYS(sys_getpid, 0) /* 4020 */
+SYS(sys_mount, 5)
+SYS(sys_umount, 1)
+SYS(sys_setuid, 1)
+SYS(sys_getuid, 0)
+SYS(sys_stime, 1) /* 4025 */
+SYS(sys_ptrace, 4)
+SYS(sys_alarm, 1)
+SYS(sys_fstat, 2)
+SYS(sys_pause, 0)
+SYS(sys_utime, 2) /* 4030 */
+SYS(sys_stty, 0)
+SYS(sys_gtty, 0)
+SYS(sys_access, 2)
+SYS(sys_nice, 1)
+SYS(sys_ftime, 0) /* 4035 */
+SYS(sys_sync, 0)
+SYS(sys_kill, 2)
+SYS(sys_rename, 2)
+SYS(sys_mkdir, 2)
+SYS(sys_rmdir, 1) /* 4040 */
+SYS(sys_dup, 1)
+SYS(sys_pipe, 0)
+SYS(sys_times, 1)
+SYS(sys_prof, 0)
+SYS(sys_brk, 1) /* 4045 */
+SYS(sys_setgid, 1)
+SYS(sys_getgid, 0)
+SYS(sys_signal, 2)
+SYS(sys_geteuid, 0)
+SYS(sys_getegid, 0) /* 4050 */
+SYS(sys_acct, 0)
+SYS(sys_phys, 0)
+SYS(sys_lock, 0)
+SYS(sys_ioctl, 3)
+SYS(sys_fcntl, 3) /* 4055 */
+SYS(sys_mpx, 2)
+SYS(sys_setpgid, 2)
+SYS(sys_ulimit, 0)
+SYS(sys_olduname, 1)
+SYS(sys_umask, 1) /* 4060 */
+SYS(sys_chroot, 1)
+SYS(sys_ustat, 2)
+SYS(sys_dup2, 2)
+SYS(sys_getppid, 0)
+SYS(sys_getpgrp, 0) /* 4065 */
+SYS(sys_setsid, 0)
+SYS(sys_sigaction, 3)
+SYS(sys_sgetmask, 0)
+SYS(sys_ssetmask, 1)
+SYS(sys_setreuid, 2) /* 4070 */
+SYS(sys_setregid, 2)
+SYS(sys_sigsuspend, 3)
+SYS(sys_sigpending, 1)
+SYS(sys_sethostname, 2)
+SYS(sys_setrlimit, 2) /* 4075 */
+SYS(sys_getrlimit, 2)
+SYS(sys_getrusage, 2)
+SYS(sys_gettimeofday, 2)
+SYS(sys_settimeofday, 2)
+SYS(sys_getgroups, 2) /* 4080 */
+SYS(sys_setgroups, 2)
+SYS(sys_ni_syscall, 0) /* old_select */
+SYS(sys_symlink, 2)
+SYS(sys_lstat, 2)
+SYS(sys_readlink, 3) /* 4085 */
+SYS(sys_uselib, 1)
+SYS(sys_swapon, 2)
+SYS(sys_reboot, 3)
+SYS(old_readdir, 3)
+SYS(sys_mmap, 6) /* 4090 */
+SYS(sys_munmap, 2)
+SYS(sys_truncate, 2)
+SYS(sys_ftruncate, 2)
+SYS(sys_fchmod, 2)
+SYS(sys_fchown, 3) /* 4095 */
+SYS(sys_getpriority, 2)
+SYS(sys_setpriority, 3)
+SYS(sys_profil, 0)
+SYS(sys_statfs, 2)
+SYS(sys_fstatfs, 2) /* 4100 */
+SYS(sys_ioperm, 3)
+SYS(sys_socketcall, 2)
+SYS(sys_syslog, 3)
+SYS(sys_setitimer, 3)
+SYS(sys_getitimer, 2) /* 4105 */
+SYS(sys_newstat, 2)
+SYS(sys_newlstat, 2)
+SYS(sys_newfstat, 2)
+SYS(sys_uname, 1)
+SYS(sys_iopl, 0) /* Well, actually 17 args ... */ /* 4110 */
+SYS(sys_vhangup, 0)
+SYS(sys_idle, 0)
+SYS(sys_vm86, 1)
+SYS(sys_wait4, 4)
+SYS(sys_swapoff, 1) /* 4115 */
+SYS(sys_sysinfo, 1)
+SYS(sys_ipc, 6)
+SYS(sys_fsync, 1)
+SYS(sys_sigreturn, 0)
+SYS(sys_clone, 0) /* 4120 */
+SYS(sys_setdomainname, 2)
+SYS(sys_newuname, 1)
+SYS(sys_ni_syscall, 0) /* sys_modify_ldt */
+SYS(sys_adjtimex, 1)
+SYS(sys_mprotect, 3) /* 4125 */
+SYS(sys_sigprocmask, 3)
+SYS(sys_create_module, 2)
+SYS(sys_init_module, 5)
+SYS(sys_delete_module, 1)
+SYS(sys_get_kernel_syms, 1) /* 4130 */
+SYS(sys_quotactl, 0)
+SYS(sys_getpgid, 1)
+SYS(sys_fchdir, 1)
+SYS(sys_bdflush, 2)
+SYS(sys_sysfs, 3) /* 4135 */
+SYS(sys_personality, 1)
+SYS(sys_ni_syscall, 0) /* for afs_syscall */
+SYS(sys_setfsuid, 1)
+SYS(sys_setfsgid, 1)
+SYS(sys_llseek, 5) /* 4140 */
+SYS(sys_getdents, 3)
+SYS(sys_select, 5)
+SYS(sys_flock, 2)
+SYS(sys_msync, 3)
+SYS(sys_readv, 3) /* 4145 */
+SYS(sys_writev, 3)
+SYS(sys_cacheflush, 3)
+SYS(sys_cachectl, 3)
+SYS(sys_sysmips, 4)
+SYS(sys_setup, 0) /* 4150 */
+SYS(sys_getsid, 1)
+SYS(sys_ni_syscall, 0)
+SYS(sys_ni_syscall, 0)
+SYS(sys_mlock, 2)
+SYS(sys_munlock, 2) /* 4155 */
+SYS(sys_mlockall, 1)
+SYS(sys_munlockall, 0)
--- /dev/null
+/*
+ * MIPS specific syscalls
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/utsname.h>
+
+#include <asm/cachectl.h>
+#include <asm/segment.h>
+#include <asm/sysmips.h>
+
+static inline size_t
+strnlen_user(const char *s, size_t count)
+{
+ return strnlen(s, count);
+}
+
+/*
+ * How long a hostname can we get from user space?
+ * -EFAULT if invalid area or too long
+ * 0 if ok
+ * >0 EFAULT after xx bytes
+ */
+static inline int
+get_max_hostname(unsigned long address)
+{
+ struct vm_area_struct * vma;
+
+ vma = find_vma(current, address);
+ if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
+ return -EFAULT;
+ address = vma->vm_end - address;
+ if (address > PAGE_SIZE)
+ return 0;
+ if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
+ (vma->vm_next->vm_flags & VM_READ))
+ return 0;
+ return address;
+}
+
+asmlinkage int
+sys_sysmips(int cmd, int arg1, int arg2, int arg3)
+{
+ int *p;
+ char *name;
+ int flags, len, retval = -EINVAL;
+
+ switch(cmd)
+ {
+ case SETNAME:
+ if (!suser())
+ return -EPERM;
+ name = (char *) arg1;
+ len = get_max_hostname((unsigned long)name);
+ if (retval < 0)
+ return len;
+ len = strnlen_user(name, retval);
+ if (len == 0 || len > __NEW_UTS_LEN)
+ return -EINVAL;
+ memcpy_fromfs(system_utsname.nodename, name, len);
+ system_utsname.nodename[len] = '\0';
+ return 0;
+ case MIPS_ATOMIC_SET:
+ p = (int *) arg1;
+ retval = verify_area(VERIFY_WRITE, p, sizeof(*p));
+ if(retval)
+ return -EINVAL;
+ save_flags(flags);
+ cli();
+ retval = *p;
+ *p = arg2;
+ restore_flags(flags);
+ return retval;
+ case MIPS_FIXADE:
+ if (arg1)
+ current->tss.mflags |= MF_FIXADE;
+ else
+ current->tss.mflags |= MF_FIXADE;
+ retval = 0;
+ break;
+ case FLUSH_CACHE:
+ sys_cacheflush(0, ~0, BCACHE);
+ break;
+ }
+
+ return retval;
+}
+
+/*
+ * No implemented yet ...
+ */
+asmlinkage int
+sys_cachectl(char *addr, int nbytes, int op)
+{
+ return -ENOSYS;
+}
--- /dev/null
+/*
+ * linux/arch/mips/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ *
+ * This file contains the time handling details for PC-style clocks as
+ * found in some MIPS systems.
+ */
+#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 <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+#define TIMER_IRQ 0
+
+/* 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;
+ sti();
+}
+
+/*
+ * 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;
+
+ 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);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_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 & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_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 crystal) 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);
+
+ return retval;
+}
+
+/* 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 void timer_interrupt(int irq, struct pt_regs * regs)
+{
+ 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 */
+ /* As we return to user mode fire off the other CPU schedulers.. this is
+ basically because we don't yet share IRQ's around. This message is
+ rigged to be safe on the 386 - basically its a hack, so don't look
+ closely for now.. */
+ smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
+}
+
+/* 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, struct pt_regs *);
+ 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;
+ xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+ xtime.tv_usec = 0;
+
+ /* FIXME: If we have the CPU hardware time counters, use them */
+ irq_handler = timer_interrupt;
+
+ if (request_irq(TIMER_IRQ, irq_handler, 0, "timer") != 0)
+ panic("Could not allocate timer IRQ!");
+}
+++ /dev/null
-/*
- * arch/mips/kernel/head.S
- *
- * Copyright (C) 1994 Waldorf Electronics
- * Written by Ralf Baechle and Andreas Busse
- *
- * Head.S contains the MIPS exception handler and startup code.
- * Flush the TLB
- *
- * FIXME: knows only how to handle R4x00
- * Read appendix f of the R4000 manual before you change something!
- */
-
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/bootinfo.h>
-
- .globl _tlbflush
-_tlbflush: li t0,PM_4K
- mtc0 t0,CP0_PAGEMASK
- lw t0,_boot_info+OFFSET_BOOTINFO_TLB_ENTRIES(t0)
- li t0,48
- dmtc0 zero,CP0_ENTRYLO0
- dmtc0 zero,CP0_ENTRYLO1
- mfc0 t2,CP0_WIRED
-1: subu t0,t0,1
- mtc0 t0,CP0_INDEX
- lui t1,0x0008
- or t1,t0,t1
- dsll t1,t1,13
- dmtc0 t1,CP0_ENTRYHI
- bne t2,t0,1b
- tlbwi # delay slot
- jr ra
- nop
/*
* arch/mips/kernel/traps.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
+ * 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.
*/
/*
* state in 'asm.s'. Currently mostly a debugging-aid, will be extended
* to mainly kill the offending process (probably by giving it a signal,
* but possibly by killing it outright if necessary).
+ *
+ * FIXME: This is the place for a fpu emulator.
*/
#include <linux/head.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/string.h>
+#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
-#include <linux/config.h>
#include <linux/timer.h>
+#include <linux/mm.h>
+#include <asm/vector.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
console_loglevel = 15;
}
-#define get_seg_byte(seg,addr) ({ \
-register unsigned char __res; \
-__res = get_user_byte(addr); \
-__res;})
-
-#define get_seg_long(seg,addr) ({ \
-register unsigned long __res; \
-__res = get_user_word(addr); \
-__res;})
-
-extern asmlinkage void deskstation_tyne_handle_int(void);
+/*
+ * Machine specific interrupt handlers
+ */
extern asmlinkage void acer_pica_61_handle_int(void);
+extern asmlinkage void decstation_handle_int(void);
+extern asmlinkage void deskstation_rpc44_handle_int(void);
+extern asmlinkage void deskstation_tyne_handle_int(void);
+extern asmlinkage void mips_magnum_4000_handle_int(void);
+
extern asmlinkage void handle_mod(void);
extern asmlinkage void handle_tlbl(void);
extern asmlinkage void handle_tlbs(void);
extern asmlinkage void handle_watch(void);
extern asmlinkage void handle_reserved(void);
-char *cpu_names[] = CPU_NAMES;
+static char *cpu_names[] = CPU_NAMES;
+
+unsigned long page_colour_mask;
int kstack_depth_to_print = 24;
/*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
+ * These constant is for searching for possible module text segments.
+ * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
*/
-#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
void die_if_kernel(char * str, struct pt_regs * regs, long err)
{
- int i;
- unsigned long *sp, *pc;
- unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, etext;
+ int i;
+ int *stack;
+ u32 *sp, *pc, addr, module_start, module_end;
+ extern char start_kernel, _etext;
if ((regs->cp0_status & (ST0_ERL|ST0_EXL)) == 0)
return;
- sp = (unsigned long *)regs->reg29;
- pc = (unsigned long *)regs->cp0_epc;
+ sp = (u32 *)regs->reg29;
+ pc = (u32 *)regs->cp0_epc;
console_verbose();
printk("%s: %08lx\n", str, err );
- /*
- * Saved main processor registers
- */
- printk("at : %08lx\n", regs->reg1);
- printk("v0 : %08lx %08lx\n", regs->reg2, regs->reg3);
- printk("a0 : %08lx %08lx %08lx %08lx\n",
- regs->reg4, regs->reg5, regs->reg6, regs->reg7);
- printk("t0 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg8, regs->reg9, regs->reg10, regs->reg11, regs->reg12);
- printk("t5 : %08lx %08lx %08lx %08lx %08lx\n",
- regs->reg13, regs->reg14, regs->reg15, regs->reg24, regs->reg25);
- printk("s0 : %08lx %08lx %08lx %08lx\n",
- regs->reg16, regs->reg17, regs->reg18, regs->reg19);
- printk("s4 : %08lx %08lx %08lx %08lx\n",
- regs->reg20, regs->reg21, regs->reg22, regs->reg23);
- printk("gp : %08lx\n", regs->reg28);
- printk("sp : %08lx\n", regs->reg29);
- printk("fp/s8: %08lx\n", regs->reg30);
- printk("ra : %08lx\n", regs->reg31);
-
- /*
- * Saved cp0 registers
- */
- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\n",
- regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
-
- /*
- * Some goodies...
- */
- printk("Int : %ld\n", regs->interrupt);
+ show_regs(regs);
/*
* Dump the stack
*/
- if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
+ if (STACK_MAGIC != *(u32 *)current->kernel_stack_page)
printk("Corrupted stack page\n");
- printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 0xffff & i,
- current->kernel_stack_page);
+ printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
+ current->comm, current->pid, current->kernel_stack_page);
for(i=0;i<5;i++)
- printk("%08lx ", *sp++);
- stack = (unsigned long *) sp;
+ printk("%08x ", *sp++);
+ stack = (int *) sp;
for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
+ if (((u32) stack & (PAGE_SIZE -1)) == 0)
break;
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
+ printk("%08lx ", get_user(stack++));
}
printk("\nCall Trace: ");
- stack = (unsigned long *) sp;
+ stack = (int *)sp;
i = 1;
- module_start = ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+ module_start = VMALLOC_START;
module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++);
+ while (((u32)stack & (PAGE_SIZE -1)) != 0) {
+ addr = get_user(stack++);
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
- if (((addr >= (unsigned long) &start_kernel) &&
- (addr <= (unsigned long) &etext)) ||
+ if (((addr >= (u32) &start_kernel) &&
+ (addr <= (u32) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", addr);
+ printk("%08x ", addr);
i++;
}
}
printk("\nCode : ");
- for(i=0;i<5;i++)
- printk("%08lx ", *pc++);
- printk("\n");
+ if ((!verify_area(VERIFY_READ, pc, 5 * sizeof(*pc)) ||
+ KSEGX(pc) == KSEG0 ||
+ KSEGX(pc) == KSEG1) &&
+ (((unsigned long) pc & 3) == 0))
+ {
+ for(i=0;i<5;i++)
+ printk("%08x ", *pc++);
+ printk("\n");
+ }
+ else
+ printk("(Bad address in epc)\n");
+while(1);
do_exit(SIGSEGV);
}
+static void
+fix_ade(struct pt_regs *regs, int write)
+{
+ printk("Received address error (ade%c)\n", write ? 's' : 'l');
+ panic("Fixing address errors not implemented yet");
+}
+
void do_adel(struct pt_regs *regs)
{
+ if(current->tss.mflags & MF_FIXADE)
+ {
+ fix_ade(regs, 0);
+ return;
+ }
+ show_regs(regs);
+while(1);
+ dump_tlb_nonwired();
send_sig(SIGSEGV, current, 1);
}
void do_ades(struct pt_regs *regs)
{
+ unsigned long pc = regs->cp0_epc;
+ int i;
+
+ if(current->tss.mflags & MF_FIXADE)
+ {
+ fix_ade(regs, 1);
+ return;
+ }
+while(1);
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], pc);
+ }
+ show_regs(regs);
+ dump_tlb_nonwired();
send_sig(SIGSEGV, current, 1);
}
+/*
+ * The ibe/dbe exceptions are signaled by onboard hardware and should get
+ * a board specific handlers to get maximum available information. Bus
+ * errors are always symptom of hardware malfunction or a kernel error.
+ *
+ * FIXME: Linux/68k sends a SIGSEGV for a buserror which seems to be wrong.
+ * This is certainly wrong. Actually, all hardware errors (ades,adel,ibe,dbe)
+ * are bus errors and therefor should send a SIGBUS! (Andy)
+ */
void do_ibe(struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+show_regs(regs);
+while(1);
+ send_sig(SIGBUS, current, 1);
}
void do_dbe(struct pt_regs *regs)
{
- send_sig(SIGSEGV, current, 1);
+show_regs(regs);
+while(1);
+ send_sig(SIGBUS, current, 1);
}
void do_ov(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGFPE, current, 1);
}
void do_fpe(struct pt_regs *regs)
{
- /*
- * FIXME: This is the place for a fpu emulator. Not written
- * yet and the demand seems to be quite low.
- */
- printk("Caught FPE exception at %lx.\n", regs->cp0_epc);
+show_regs(regs);
+while(1);
send_sig(SIGFPE, current, 1);
}
void do_bp(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_tr(struct pt_regs *regs)
{
+show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_ri(struct pt_regs *regs)
{
+ int i;
+
+ for(i=0; i<NR_TASKS;i++)
+ if(task[i] && task[i]->pid >= 2)
+ {
+ printk("Process %d\n", task[i]->pid);
+ dump_list_process(task[i], 0x7ffff000);
+ }
+ show_regs(regs);
+while(1);
send_sig(SIGILL, current, 1);
}
void do_cpu(struct pt_regs *regs)
{
- unsigned long pc;
- unsigned int insn;
+ unsigned int cpid;
- /*
- * Check whether this was a cp1 instruction
- */
- pc = regs->cp0_epc;
- if (regs->cp0_cause & (1<<31))
- pc += 4;
- insn = *(unsigned int *)pc;
- insn &= 0xfc000000;
- switch(insn) {
- case 0x44000000:
- case 0xc4000000:
- case 0xe4000000:
- printk("CP1 instruction - enabling cp1.\n");
- regs->cp0_status |= ST0_CU1;
- /*
- * No need to handle branch delay slots
- */
- break;
- default:
- /*
- * This wasn't a cp1 instruction and therefore illegal.
- * Default is to kill the process.
- */
- send_sig(SIGILL, current, 1);
- }
+ cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
+ switch(cpid)
+ {
+ case 1:
+ regs->cp0_status |= ST0_CU1;
+ break;
+ case 0:
+ /*
+ * CPU for cp0 can only happen in user mode
+ */
+ case 2:
+ case 3:
+ send_sig(SIGILL, current, 1);
+ break;
+ }
}
void do_vcei(struct pt_regs *regs)
void do_watch(struct pt_regs *regs)
{
- /*
- * Only possible on R4[04]00. No way to handle this because
- * I don't have such a cpu.
- */
panic("Caught WATCH exception - can't handle yet\n");
}
{
/*
* Game over - no way to handle this if it ever occurs.
- * Most probably caused by a new unknown cpu type or a
+ * Most probably caused by a new unknown cpu type or
* after another deadly hard/software error.
*/
panic("Caught reserved exception - can't handle.\n");
void trap_init(void)
{
- int i;
+ unsigned long i;
+ void watch_set(unsigned long, unsigned long);
- /*
- * FIXME: Mips Magnum R4000 has an EISA bus!
- */
- EISA_bus = 0;
+ if(boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+ EISA_bus = 1;
/*
* Setup default vectors
* Handling the following exceptions depends mostly of the cpu type
*/
switch(boot_info.cputype) {
+ /*
+ * The R10000 is in most aspects similar to the R4400. It however
+ * should get some special optimizations.
+ */
+ case CPU_R10000:
+ write_32bit_cp0_register(CP0_FRAMEMASK, 0);
+ set_cp0_status(ST0_XX, ST0_XX);
+ page_colour_mask = 0x3000;
+ panic("CPU too expensive - making holiday in the ANDES!");
+ break;
case CPU_R4000MC:
case CPU_R4400MC:
case CPU_R4000SC:
case CPU_R4400SC:
/*
- * Handlers not implemented yet
+ * Handlers not implemented yet. If should ever be used -
+ * otherwise it's a bug in the Linux/MIPS kernel, anyway.
*/
set_except_vector(14, handle_vcei);
set_except_vector(31, handle_vced);
case CPU_R4000PC:
case CPU_R4400PC:
+ case CPU_R4200:
+ /* case CPU_R4300: */
/*
- * Handler not implemented yet
+ * Use watch exception to trap on access to address zero
*/
set_except_vector(23, handle_watch);
- case CPU_R4200:
+ watch_set(KSEG0, 3);
case CPU_R4600:
set_except_vector(1, handle_mod);
set_except_vector(2, handle_tlbl);
set_except_vector(3, handle_tlbs);
set_except_vector(4, handle_adel);
set_except_vector(5, handle_ades);
+ /*
+ * The following two are signaled by onboard hardware and
+ * should get board specific handlers to get maximum
+ * available information.
+ */
set_except_vector(6, handle_ibe);
set_except_vector(7, handle_dbe);
+
set_except_vector(8, handle_sys);
set_except_vector(9, handle_bp);
set_except_vector(10, handle_ri);
set_except_vector(12, handle_ov);
set_except_vector(13, handle_tr);
set_except_vector(15, handle_fpe);
+
+ /*
+ * Compute mask for page_colour(). This is based on the
+ * size of the data cache. Does the size of the icache
+ * need to be accounted for?
+ */
+ i = read_32bit_cp0_register(CP0_CONFIG);
+ i = (i >> 26) & 7;
+ page_colour_mask = 1 << (12 + i);
break;
case CPU_R2000:
case CPU_R3000:
case CPU_R6000:
case CPU_R6000A:
case CPU_R8000:
- case CPU_R10000:
printk("Detected unsupported CPU type %s.\n",
- cpu_names[boot_info.cputype]);
+ cpu_names[boot_info.cputype]);
panic("Can't handle CPU\n");
break;
+
case CPU_UNKNOWN:
default:
- panic("Unknown type of CPU");
- }
+ panic("Unknown CPU type");
+ }
/*
- * The interrupt handler depends of both type of the board and cpu
+ * The interrupt handler mostly depends of the board type.
*/
- switch(boot_info.machtype) {
- case MACH_DESKSTATION_TYNE:
- set_except_vector(0, deskstation_tyne_handle_int);
- break;
- case MACH_ACER_PICA_61:
- set_except_vector(0, acer_pica_61_handle_int);
- break;
- default:
- panic("Unknown machine type");
- }
+ set_except_vector(0, feature->handle_int);
}
--- /dev/null
+/*
+ * Deskstation Tyne specific C parts
+ *
+ * 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.
+ *
+ * Copyright (C) 1994, 1995 by Ralf Baechle
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/bootinfo.h>
+#include <asm/cachectl.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+/*
+ * How to access the FDC's registers.
+ */
+unsigned char deskstation_tyne_fd_inb(unsigned int port)
+{
+ return inb_p(port);
+}
+
+void deskstation_tyne_fd_outb(unsigned char value, unsigned int port)
+{
+ outb_p(value, port);
+}
+
+/*
+ * How to access the floppy DMA functions.
+ */
+void deskstation_tyne_fd_enable_dma(void)
+{
+ enable_dma(FLOPPY_DMA);
+}
+
+void deskstation_tyne_fd_disable_dma(void)
+{
+ disable_dma(FLOPPY_DMA);
+}
+
+int deskstation_tyne_fd_request_dma(void)
+{
+ return request_dma(FLOPPY_DMA, "floppy");
+}
+
+void deskstation_tyne_fd_free_dma(void)
+{
+ free_dma(FLOPPY_DMA);
+}
+
+void deskstation_tyne_fd_clear_dma_ff(void)
+{
+ clear_dma_ff(FLOPPY_DMA);
+}
+
+int deskstation_tyne_fd_set_dma_mode(char mode)
+{
+ return set_dma_mode(FLOPPY_DMA, mode);
+}
+
+void deskstation_tyne_fd_set_dma_addr(unsigned int a)
+{
+ set_dma_addr(FLOPPY_DMA, addr);
+}
+
+void deskstation_tyne_fd_set_dma_count(unsigned int count)
+{
+ set_dma_count(FLOPPY_DMA, count);
+}
+
+int deskstation_tyne_fd_get_dma_residue(void)
+{
+ return get_dma_residue(FLOPPY_DMA);
+}
+
+void deskstation_tyne_fd_enable_irq(void)
+{
+ enable_irq(FLOPPY_IRQ);
+}
+
+void deskstation_tyne_fd_disable_irq(void)
+{
+ disable_irq(FLOPPY_IRQ);
+}
+
+void deskstation_tyne_fd_cacheflush(unsigned char *addr, unsigned int)
+{
+ sys_cacheflush((void *)addr, size, DCACHE);
+}
+
+
+/*
+ * Tiny Tyne DMA buffer allocator
+ *
+ * Untested for a long time and changed again and again ...
+ * Sorry, but no hardware to test ...
+ */
+static unsigned long allocated;
+
+/*
+ * Not very sophisticated, but should suffice for now...
+ */
+unsigned long deskstation_tyne_dma_alloc(size_t size)
+{
+ unsigned long ret = allocated;
+ allocated += size;
+ if (allocated > boot_info.dma_cache_size)
+ ret = -1;
+ return ret;
+}
+
+void deskstation_tyne_dma_init(void)
+{
+ if (boot_info.machtype != MACH_DESKSTATION_TYNE)
+ return;
+ allocated = 0;
+ printk ("Deskstation Tyne DMA (%luk) buffer initialized.\n",
+ boot_info.dma_cache_size >> 10);
+}
--- /dev/null
+/*
+ * arch/mips/kernel/tyne.S
+ *
+ * Deskstation Tyne specific Assembler code
+ *
+ * Copyright (C) 1994, 1995 Waldorf Electronics
+ * written by Ralf Baechle and Andreas Busse
+ */
+#include <asm/asm.h>
+#include <asm/mipsconfig.h>
+#include <asm/mipsregs.h>
+#include <asm/stackframe.h>
+
+/*
+ * Deskstation Tyne interrupt handler
+ */
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(deskstation_tyne_handle_int, FR_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+ lui s0,%hi(PORT_BASE)
+ li t1,0x0f
+ sb t1,%lo(PORT_BASE+0x20)(s0) # poll command
+ lb t1,%lo(PORT_BASE+0x20)(s0) # read result
+ li s1,1
+ bgtz t1,Lpoll_second
+ andi t1,t1,7
+ /*
+ * Acknowledge first pic
+ */
+ lb t2,%lo(PORT_BASE+0x21)(s0)
+ lui s4,%hi(cache_21)
+ lb t0,%lo(cache_21)(s4)
+ sllv s1,s1,t1
+ or t0,t0,s1
+ sb t0,%lo(cache_21)(s4)
+ sb t0,%lo(PORT_BASE+0x21)(s0)
+ lui s3,%hi(intr_count)
+ lw t0,%lo(intr_count)(s3)
+ li t2,0x20
+ sb t2,%lo(PORT_BASE+0x20)(s0)
+ /*
+ * Now call the real handler
+ */
+ la t3,IRQ_vectors
+ sll t2,t1,2
+ addu t3,t3,t2
+ lw t3,(t3)
+ addiu t0,t0,1
+ jalr t3
+ sw t0,%lo(intr_count)(s3) # delay slot
+ lw t0,%lo(intr_count)(s3)
+ /*
+ * Unblock first pic
+ */
+ lbu t1,%lo(PORT_BASE+0x21)(s0)
+ lb t1,%lo(cache_21)(s4)
+ subu t0,t0,1
+ sw t0,%lo(intr_count)(s3)
+ nor s1,zero,s1
+ and t1,t1,s1
+ sb t1,%lo(cache_21)(s4)
+ jr v0
+ sb t1,%lo(PORT_BASE+0x21)(s0) # delay slot
+
+ .align 5
+Lpoll_second: li t1,0x0f
+ sb t1,%lo(PORT_BASE+0xa0)(s0) # poll command
+ lb t1,%lo(PORT_BASE+0xa0)(s0) # read result
+ lui s4,%hi(cache_A1)
+ bgtz t1,spurious_interrupt
+ andi t1,t1,7
+ /*
+ * Acknowledge second pic
+ */
+ lbu t2,%lo(PORT_BASE+0xa1)(s0)
+ lb t3,%lo(cache_A1)(s4)
+ sllv s1,s1,t1
+ or t3,t3,s1
+ sb t3,%lo(cache_A1)(s4)
+ sb t3,%lo(PORT_BASE+0xa1)(s0)
+ li t3,0x20
+ sb t3,%lo(PORT_BASE+0xa0)(s0)
+ lui s3,%hi(intr_count)
+ lw t0,%lo(intr_count)(s3)
+ sb t3,%lo(PORT_BASE+0x20)(s0)
+ /*
+ * Now call the real handler
+ */
+ la t0,IRQ_vectors
+ sll t2,t1,2
+ addu t0,t0,t2
+ lw t0,32(t0)
+ addiu t0,t0,1
+ jalr t0
+ sw t0,%lo(intr_count)(s3) # delay slot
+ lw t0,%lo(intr_count)(s3)
+ /*
+ * Unblock second pic
+ */
+ lb t1,%lo(PORT_BASE+0xa1)(s0)
+ lb t1,%lo(cache_A1)(s4)
+ subu t0,t0,1
+ lw t0,%lo(intr_count)(s3)
+ nor s1,zero,s1
+ and t1,t1,s1
+ sb t1,%lo(cache_A1)(s4)
+ jr v0
+ sb t1,%lo(PORT_BASE+0xa1)(s0) # delay slot
+ END(deskstation_tyne_handle_int)
+
+ .align 5
+LEAF(spurious_interrupt)
+ /*
+ * Nothing happened... (whistle)
+ */
+ lui t1,%hi(spurious_count)
+ lw t0,%lo(spurious_count)(t1)
+ la v0,return
+ addiu t0,1
+ jr ra
+ sw t0,%lo(spurious_count)(t1)
+ END(spurious_interrupt)
+
+++ /dev/null
-/*
- * Tiny Tyne DMA buffer allocator
- *
- * Copyright (C) 1995 Ralf Baechle
- */
-#include <linux/autoconf.h>
-#include <linux/types.h>
-#include <asm/bootinfo.h>
-
-#ifdef CONFIG_DESKSTATION_TYNE
-
-static unsigned long allocated;
-
-/*
- * Not very sophisticated, but should suffice for now...
- */
-unsigned long deskstation_tyne_dma_alloc(size_t size)
-{
- unsigned long ret = allocated;
- allocated += size;
- if (allocated > boot_info.dma_cache_size)
- ret = -1;
- return ret;
-}
-
-void deskstation_tyne_dma_init(void)
-{
- if (boot_info.machtype != MACH_DESKSTATION_TYNE)
- return;
- allocated = 0;
- printk ("Deskstation Tyne DMA (%luk) buffer initialized.\n",
- boot_info.dma_cache_size >> 10);
-}
-
-#endif /* CONFIG_DESKSTATION_TYNE */
--- /dev/null
+OUTPUT_FORMAT("elf32-littlemips")
+OUTPUT_ARCH(mips)
+ENTRY(kernel_entry)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0x80000000;
+ .rel.text : { *(.rel.text) }
+ .rela.text : { *(.rela.text) }
+ .rel.data : { *(.rel.data) }
+ .rela.data : { *(.rela.data) }
+ .rel.rodata : { *(.rel.rodata) }
+ .rela.rodata : { *(.rela.rodata) }
+ .rel.got : { *(.rel.got) }
+ .rela.got : { *(.rela.got) }
+ .rel.ctors : { *(.rel.ctors) }
+ .rela.ctors : { *(.rela.ctors) }
+ .rel.dtors : { *(.rel.dtors) }
+ .rela.dtors : { *(.rela.dtors) }
+ .rel.init : { *(.rel.init) }
+ .rela.init : { *(.rela.init) }
+ .rel.fini : { *(.rel.fini) }
+ .rela.fini : { *(.rela.fini) }
+ .rel.bss : { *(.rel.bss) }
+ .rela.bss : { *(.rela.bss) }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init : { *(.init) } =0
+ .text :
+ {
+ _ftext = . ;
+ *(.text)
+ *(.rodata)
+ *(.rodata1)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0
+ _etext = .;
+ PROVIDE (etext = .);
+ .fini : { *(.fini) } =0
+ .reginfo : { *(.reginfo) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. It would
+ be more correct to do this:
+ . = .;
+ The current expression does not correctly handle the case of a
+ text segment ending precisely at the end of a page; it causes the
+ data segment to skip a page. The above expression does not have
+ this problem, but it will currently (2/95) cause BFD to allocate
+ a single segment, combining both text and data, for this case.
+ This will prevent the text segment from being shared among
+ multiple executions of the program; I think that is more
+ important than losing a page of the virtual address space (note
+ that no actual memory is lost; the page which is skipped can not
+ be referenced). */
+ . = .;
+ .data :
+ {
+ _fdata = . ;
+ *(.data)
+ CONSTRUCTORS
+ }
+ .data1 : { *(.data1) }
+ _gp = . + 0x8000;
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ .ctors : { *(.ctors) }
+ .dtors : { *(.dtors) }
+ .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 = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ _fbss = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss)
+ *(COMMON)
+ _end = . ;
+ PROVIDE (end = .);
+ *(.sbss)
+ *(.scommon)
+ }
+ /* These are needed for ELF backends which have not yet been
+ converted to the new style linker. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ /* DWARF debug sections.
+ Symbols in the .debug DWARF section are relative to the beginning of the
+ section so we begin .debug at 0. It's not clear yet what needs to happen
+ for the others. */
+ .debug 0 : { *(.debug) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .line 0 : { *(.line) }
+ /* These must appear regardless of . */
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+}
--- /dev/null
+#
+# Makefile for MIPS-specific library files..
+#
+# Many of these routines are just left over debugging trash of ancient
+# times when I just make my Tyne beep and so ...
+#
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+L_TARGET = lib.a
+L_OBJS = beep.o checksum.o csum.o dump_tlb.o tinycon.o watch.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * MIPS specific IP/TCP/UDP checksumming routines
+ *
+ * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <net/checksum.h>
+#include <asm/string.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+{
+ unsigned long scratch1;
+ unsigned long scratch2;
+
+ /*
+ * The GCC generated code for handling carry bits makes
+ * it strongly desireable to do this in assembler!
+ */
+ __asm__("
+ .set noreorder
+ .set noat
+ andi $1,%5,2 # Check alignment
+ beqz $1,2f # Branch if ok
+ subu $1,%4,2 # delay slot, Alignment uses up two bytes
+ bgez $1,1f # Jump if we had at least two bytes
+ move %4,$1 # delay slot
+ j 4f
+ addiu %4,2 # delay slot; len was < 2. Deal with it
+
+1: lw %2,(%5)
+ addiu %4,2
+ addu %0,%2
+ sltu $1,%0,%2
+ addu %0,$1
+
+2: move %1,%4
+ srl %1,%1,5
+ beqz %1,2f
+ sll %1,%1,5 # delay slot
+
+ addu %1,%5
+1: lw %2,0(%5)
+ addu %5,32
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-28(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-24(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-20(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-16(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-12(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-8(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ lw %2,-4(%5)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+
+ bne %5,%1,1b
+ addu %0,$1 # delay slot
+
+2: andi %1,%4,0x1c
+ srl %1,%1,2
+ beqz %1,4f
+ addu %1,%5 # delay slot
+3: lw %2,0(%5)
+ addu %5,4
+ addu %0,%2
+ sltu $1,%0,%2
+ bne %5,%1,3b
+ addu %0,$1 # delay slot
+
+4: andi $1,%3,2
+ beqz $1,5f
+ move %2,$0 # delay slot
+ lhu %2,(%5)
+ addiu %5,2
+
+5: andi $1,%3,1
+ beqz $1,6f
+ sll %1,16 # delay slot
+ lbu %1,(%5)
+ nop # NOP ALERT (spit, gasp)
+6: or %2,%1
+ addu %0,%2
+ sltu $1,%0,%2
+ addu %0,$1
+7: .set at
+ .set reorder"
+ : "=r"(sum), "=r" (scratch1), "=r" (scratch2)
+ : "0"(sum), "r"(len), "r"(buff)
+ : "$1");
+
+ return sum;
+}
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+unsigned int csum_partial_copy(const char *src, char *dst,
+ int len, int sum)
+{
+ /*
+ * It's 2:30 am and I don't feel like doing it real ...
+ * This is lots slower than the real thing (tm)
+ */
+ sum = csum_partial(src, len, sum);
+ memcpy(dst, src, len);
+
+ return sum;
+}
#
-# Makefile for the linux mips-specific parts of the memory manager.
+# Makefile for the Linux/MIPS-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
/*
* arch/mips/mm/fault.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to MIPS by Ralf Baechle
+ * Copyright (C) 1995 by Ralf Baechle
*/
-
-#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <asm/mipsconfig.h>
+#include <asm/pgtable.h>
extern void die_if_kernel(char *, struct pt_regs *, long);
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
- *
- * The error_code parameter just the same as in the i386 version:
- *
- * 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
*/
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+asmlinkage void
+do_page_fault(struct pt_regs *regs, unsigned long writeaccess, unsigned long address)
{
struct vm_area_struct * vma;
- unsigned long address;
- unsigned long page;
- /* get the address */
- __asm__("dmfc0\t%0,$8"
- : "=r" (address));
-
- for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
- if (!vma)
- goto bad_area;
- if (vma->vm_end > address)
- break;
- }
+#if 0
+ printk("do_page_fault() #1: %s %08lx (epc == %08lx, ra == %08lx)\n",
+ writeaccess ? "writeaccess to" : "readaccess from",
+ address, regs->cp0_epc, regs->reg31);
+#endif
+ vma = find_vma(current, address);
+ if (!vma)
+ goto bad_area;
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+ if (expand_stack(vma, address))
goto bad_area;
- vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
- vma->vm_start = (address & PAGE_MASK);
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
- /*
- * was it a write?
- */
- if (error_code & 2) {
+ if (writeaccess) {
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
- /* read with protection fault? */
- if (error_code & 1)
- goto bad_area;
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- if (error_code & 1) {
- do_wp_page(vma, address, error_code & 2);
- return;
- }
- do_no_page(vma, address, error_code & 2);
- return;
+ handle_mm_fault(vma, address, writeaccess);
+ /* FIXME: This flushes the cache far to often */
+ sys_cacheflush(address, PAGE_SIZE, BCACHE);
+
+ return;
/*
* Something tried to access memory that isn't in our memory map..
bad_area:
if (user_mode(regs)) {
current->tss.cp0_badvaddr = address;
- current->tss.error_code = error_code;
-#if 0
- current->tss.trap_no = 14;
-#endif
+ current->tss.error_code = writeaccess;
send_sig(SIGSEGV, current, 1);
return;
}
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
- if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
- } else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
- page = current->tss.pg_dir;
- printk(KERN_ALERT "current->tss.pg_dir = %08lx\n", page);
- page = ((unsigned long *) page)[address >> PGDIR_SHIFT];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & 1) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((unsigned long *) page)[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
- die_if_kernel("Oops", regs, error_code);
+ printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
+ "address %08lx\n", address);
+ die_if_kernel("Oops", regs, writeaccess);
do_exit(SIGKILL);
}
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
* Ported to MIPS by Ralf Baechle
*/
-
#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <asm/cachectl.h>
+#include <asm/jazzdma.h>
+#include <asm/vector.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <asm/mipsconfig.h>
-
-extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */
+#include <asm/pgtable.h>
extern void deskstation_tyne_dma_init(void);
extern void scsi_mem_init(unsigned long);
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
+extern char empty_zero_page[PAGE_SIZE];
+
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
pte_t * __bad_pagetable(void)
{
extern char empty_bad_page_table[PAGE_SIZE];
- unsigned long dummy;
+ unsigned long page;
+ unsigned long dummy1, dummy2;
+ page = ((unsigned long)empty_bad_page_table) + (PT_OFFSET - PAGE_OFFSET);
+#if __mips__ >= 3
+ /*
+ * Use 64bit code even for Linux/MIPS 32bit on R4000
+ */
__asm__ __volatile__(
- ".set\tnoreorder\n\t"
+ ".set\tnoreorder\n"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "dsll32\t$1,%2,0\n\t"
+ "dsrl32\t%2,$1,0\n\t"
+ "or\t%2,$1\n"
+ "1:\tsd\t%2,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,8\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"r" (pte_val(BAD_PAGE)),
+ "0" (page),
+ "1" (PAGE_SIZE/8));
+#else
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
"1:\tsw\t%2,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,4\n\t"
".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
+ :"=r" (dummy1),
+ "=r" (dummy2)
:"r" (pte_val(BAD_PAGE)),
- "0" ((long) empty_bad_page_table),
- "1" (PTRS_PER_PAGE));
+ "0" (page),
+ "1" (PAGE_SIZE/4));
+#endif
- return (pte_t *) empty_bad_page_table;
+ return (pte_t *)page;
}
-pte_t __bad_page(void)
+static inline void
+__zeropage(unsigned long page)
{
- extern char empty_bad_page[PAGE_SIZE];
- unsigned long dummy;
+ unsigned long dummy1, dummy2;
+#ifdef __R4000__
+ /*
+ * Use 64bit code even for Linux/MIPS 32bit on R4000
+ */
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n"
+ "1:\tsd\t$0,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,8\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"0" (page),
+ "1" (PAGE_SIZE/8));
+#else
__asm__ __volatile__(
- ".set\tnoreorder\n\t"
+ ".set\tnoreorder\n"
"1:\tsw\t$0,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,4\n\t"
".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
- :"0" ((long) empty_bad_page),
- "1" (PTRS_PER_PAGE));
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"0" (page),
+ "1" (PAGE_SIZE/4));
+#endif
+}
- return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
+static inline void
+zeropage(unsigned long page)
+{
+ sys_cacheflush((void *)page, PAGE_SIZE, BCACHE);
+ sync_mem();
+ __zeropage(page + (PT_OFFSET - PAGE_OFFSET));
+}
+
+pte_t __bad_page(void)
+{
+ extern char empty_bad_page[PAGE_SIZE];
+ unsigned long page = (unsigned long)empty_bad_page;
+
+ zeropage(page);
+ return pte_mkdirty(mk_pte(page, PAGE_SHARED));
}
unsigned long __zero_page(void)
{
- extern char empty_zero_page[PAGE_SIZE];
- unsigned long dummy;
+ unsigned long page = (unsigned long) empty_zero_page;
- __asm__ __volatile__(
- ".set\tnoreorder\n\t"
- "1:\tsw\t$0,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
- "bne\t$0,%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
- ".set\treorder"
- :"=r" (dummy),
- "=r" (dummy)
- :"0" ((long) empty_zero_page),
- "1" (PTRS_PER_PAGE));
+ zeropage(page);
+ return page;
+}
- return (unsigned long) empty_zero_page;
+/*
+ * This is horribly inefficient ...
+ */
+void __copy_page(unsigned long from, unsigned long to)
+{
+ /*
+ * Now copy page from uncached KSEG1 to KSEG0. The copy destination
+ * is in KSEG0 so that we keep stupid L2 caches happy.
+ */
+ if(from == (unsigned long) empty_zero_page)
+ {
+ /*
+ * The page copied most is the COW empty_zero_page. Since we
+ * know it's contents we can avoid the writeback reading of
+ * the page. Speeds up the standard case alot.
+ */
+ __zeropage(to);
+ }
+ else
+ {
+ /*
+ * Force writeback of old page to memory. We don't know the
+ * virtual address, so we have to flush the entire cache ...
+ */
+ sys_cacheflush(0, ~0, DCACHE);
+ sync_mem();
+ memcpy((void *) to,
+ (void *) (from + (PT_OFFSET - PAGE_OFFSET)), PAGE_SIZE);
+ }
+ /*
+ * Now writeback the page again if colour has changed.
+ * Actually this does a Hit_Writeback, but due to an artifact in
+ * the R4xx0 implementation this should be slightly faster.
+ * Then sweep chipset controlled secondary caches and the ICACHE.
+ */
+ if (page_colour(from) != page_colour(to))
+ sys_cacheflush(0, ~0, DCACHE);
+ sys_cacheflush(0, ~0, ICACHE);
}
void show_mem(void)
{
- int i,free = 0,total = 0,reserved = 0;
+ int i, free = 0, total = 0, reserved = 0;
int shared = 0;
printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = high_memory >> PAGE_SHIFT;
+ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ i = (high_memory - PAGE_OFFSET) >> PAGE_SHIFT;
while (i-- > 0) {
total++;
- if (mem_map[i] & MAP_PAGE_RESERVED)
+ if (mem_map[i].reserved)
reserved++;
- else if (!mem_map[i])
+ else if (!mem_map[i].count)
free++;
else
- shared += mem_map[i]-1;
+ shared += mem_map[i].count-1;
}
- 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);
+ 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();
extern unsigned long free_area_init(unsigned long, unsigned long);
-/*
- * paging_init() sets up the page tables - note that the first 4MB are
- * already mapped by head.S.
- *
- * This routines also unmaps the page at virtual kernel address 0, so
- * that we can trap those pesky NULL-reference errors in the kernel.
- */
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
{
- pgd_t * pg_dir;
- pte_t * pg_table;
- unsigned long tmp;
- unsigned long address;
-
- start_mem = PAGE_ALIGN(start_mem);
- address = 0;
- pg_dir = swapper_pg_dir;
- while (address < end_mem) {
- if (pgd_none(pg_dir[0])) {
- pgd_set(pg_dir, (pte_t *) start_mem);
- start_mem += PAGE_SIZE;
- }
- /*
- * also map it in at 0x00000000 for init
- */
- pg_table = (pte_t *) pgd_page(pg_dir[0]);
- pgd_set(pg_dir, pg_table);
- pg_dir++;
- for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) {
- if (address < end_mem)
- set_pte(pg_table, mk_pte(address, PAGE_SHARED));
- else
- pte_clear(pg_table);
- address += PAGE_SIZE;
- }
- }
-#if KERNELBASE == KSEG0
- cacheflush();
-#endif
- invalidate();
+ pgd_init((unsigned long)swapper_pg_dir - (PT_OFFSET - PAGE_OFFSET));
return free_area_init(start_mem, end_mem);
}
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
int codepages = 0;
- int reservedpages = 0;
int datapages = 0;
unsigned long tmp;
- extern int etext;
+ extern int _etext;
+
+#ifdef CONFIG_MIPS_JAZZ
+ start_mem = vdma_init(start_mem, end_mem);
+#endif
end_mem &= PAGE_MASK;
high_memory = end_mem;
/* mark usable pages in the mem_map[] */
start_mem = PAGE_ALIGN(start_mem);
- while (start_mem < high_memory) {
- mem_map[MAP_NR(start_mem)] = 0;
- start_mem += PAGE_SIZE;
+ tmp = start_mem;
+ while (tmp < high_memory) {
+ mem_map[MAP_NR(tmp)].reserved = 0;
+ tmp += PAGE_SIZE;
}
+
#ifdef CONFIG_DESKSTATION_TYNE
deskstation_tyne_dma_init();
#endif
#ifdef CONFIG_SOUND
sound_mem_init();
#endif
- for (tmp = 0 ; tmp < high_memory ; tmp += PAGE_SIZE) {
- if (mem_map[MAP_NR(tmp)]) {
- /*
- * We don't have any reserved pages on the
- * MIPS systems supported until now
- */
- if (0)
- reservedpages++;
- else if (tmp < ((unsigned long) &etext - KERNELBASE))
+ for (tmp = PAGE_OFFSET ; tmp < high_memory ; tmp += PAGE_SIZE) {
+ if (mem_map[MAP_NR(tmp)].reserved) {
+ if (tmp < (unsigned long) &_etext)
codepages++;
- else
+ else if (tmp < start_mem)
datapages++;
continue;
}
- mem_map[MAP_NR(tmp)] = 1;
+ 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 reserved, %dk data)\n",
+ printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
tmp >> 10,
- high_memory >> 10,
+ (high_memory - PAGE_OFFSET) >> 10,
codepages << (PAGE_SHIFT-10),
- reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10));
- pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
- invalidate();
return;
}
val->freeram = nr_free_pages << PAGE_SHIFT;
val->bufferram = buffermem;
while (i-- > 0) {
- if (mem_map[i] & MAP_PAGE_RESERVED)
+ if (mem_map[i].reserved)
continue;
val->totalram++;
- if (!mem_map[i])
+ if (!mem_map[i].count)
continue;
- val->sharedram += mem_map[i]-1;
+ val->sharedram += mem_map[i].count-1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
SUB_DIRS := block char net #streams
MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sound
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sound cdrom
ifdef CONFIG_PCI
SUB_DIRS += pci
L_TARGET := block.a
-L_OBJS := ll_rw_blk.o ramdisk.o genhd.o
+L_OBJS := ll_rw_blk.o rd.o genhd.o
M_OBJS :=
MOD_LIST_NAME := BLOCK_MODULES
Major features of ide.c & ide-cd.c:
+NEW! - support for IDE ATAPI *tape* drives, courtesy of Gadi Oxman
+ (run MAKEDEV.ide to create the tape device entries in /dev/)
NEW! - support for up to *four* IDE interfaces on one or more IRQs
NEW! - support for any mix of up to *eight* disk and/or cdrom drives
- support for reading IDE ATAPI cdrom drives (NEC,MITSUMI,VERTOS,SONY)
{
int i;
int second_port;
- int read_ahead;
+ int cmd_read_ahead;
byte b;
for (i = 0; i < MAX_HWIFS; i++)
*/
bus_speed = (bus_type == vlb) ? 50 : 40;
-#if 0 /* don't know if this is reliable yet */
+#if 1 /* don't know if this is reliable yet */
/*
* Enable readahead for versions above 'A'
*/
- read_ahead = (cmd640_chip_version > 1);
+ cmd_read_ahead = (cmd640_chip_version > 1);
#else
- read_ahead = 0;
+ cmd_read_ahead = 0;
#endif
/*
* Setup Control Register
b |= CNTRL_ENA_2ND;
else
b &= ~CNTRL_ENA_2ND;
- if (read_ahead)
+ if (cmd_read_ahead)
b &= ~(CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
else
b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
*/
if (second_port) {
/* We reset timings, and setup read-ahead */
- b = read_ahead ? 0 : (DIS_RA2 | DIS_RA3);
+ b = cmd_read_ahead ? 0 : (DIS_RA2 | DIS_RA3);
put_cmd640_reg(cmd640_key, ARTTIM23, b);
put_cmd640_reg(cmd640_key, DRWTIM23, 0);
}
put_cmd640_reg(cmd640_key, CMDTIM, 0);
printk("\n ... serialized, %s read-ahead, secondary interface %s\n",
- read_ahead ? "enabled" : "disabled",
+ cmd_read_ahead ? "enabled" : "disabled",
second_port ? "enabled" : "disabled");
return 1;
static int current_minor = 0;
extern int *blk_size[];
extern void rd_load(void);
-extern int ramdisk_size;
extern int chr_dev_init(void);
extern int blk_dev_init(void);
nr += p->nr_real;
}
- if (ramdisk_size)
- rd_load();
+ rd_load();
}
/*
- * linux/drivers/block/ide-tape.c Version 1.0 - ALPHA Dec 3, 1995
+ * linux/drivers/block/ide-tape.c Version 1.1 - ALPHA Dec 14, 1995
*
* Copyright (C) 1995 Gadi Oxman <tgud@tochnapc2.technion.ac.il>
*
* This driver is a part of the Linux ide driver and works in co-operation
* with linux/drivers/block/ide.c.
*
- * This driver provides both a block device and a character device interface to
- * the tape. The driver, in co-operation with ide.c, basically traverses the
- * request-list for the block device interface. The character device interface,
- * on the other hand, creates new requests, adds them to the request-list
- * of the block device, and waits for their completion.
+ * The driver, in co-operation with ide.c, basically traverses the
+ * request-list for the block device interface. The character device
+ * interface, on the other hand, creates new requests, adds them
+ * to the request-list of the block device, and waits for their completion.
+ *
+ * Pipelined operation mode is now supported on writes.
*
* The block device major and minor numbers are determined from the
- * tape relative position in the ide interfaces, as explained in ide.c.
+ * tape's relative position in the ide interfaces, as explained in ide.c.
*
* The character device interface consists of two devices:
*
* Run /usr/src/linux/drivers/block/MAKEDEV.ide to create the above entries.
* We currently support only one ide tape drive.
*
- * Although we do support requests which originate from the buffer cache to
- * some extent, it is recommended to use the character device interface when
- * performing a long read or write operation (relative to the amount of free
- * memory in your system). Otherwise, free memory will be used to cache tape
- * blocks, those cached blocks won't be used, Linux's responsiveness will
- * suffer as we start to swap.
- *
* The general magnetic tape commands compatible interface, as defined by
* include/linux/mtio.h, is accessible through the character device.
- * Our own ide-tape ioctl's can can be issued to either the block device or
- * the character device.
*
- * Opening the block device interface will be refused by default.
+ * General ide driver configuration options, such as the interrupt-unmask
+ * flag, can be configured by issuing an ioctl to the block device interface,
+ * as any other ide device.
+ *
+ * Our own ide-tape ioctl's can can be issued to either the block device or
+ * the character device interface.
*
* Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive.
*
* performing one tape r/w request, a lot of requests
* from the other device can be queued and ide.c will
* service all of them after this single tape request.
- * Ver 1.0 ??? Integrated into Linux 1.3.??? development tree.
+ * Ver 1.0 Dec 11 95 Integrated into Linux 1.3.46 development tree.
* On each read / write request, we now ask the drive
* if we can transfer a constant number of bytes
* (a parameter of the drive) only to its buffers,
* without causing actual media access. If we can't,
* we just wait until we can by polling the DSC bit.
* This ensures that while we are not transferring
- * more bytes than the constant reffered to above, the
+ * more bytes than the constant referred to above, the
* interrupt latency will not become too high and
* we won't cause an interrupt timeout, as happened
* occasionally in the previous version.
* Our data transfer buffer is allocated on startup,
* rather than before each data transfer. This should
* ensure that we will indeed have a data buffer.
+ * Ver 1.1 Dec 14 95 Fixed random problems which occured when the tape
+ * shared an interface with another device.
+ * (poll_for_dsc was a complete mess).
+ * Removed some old (non-active) code which had
+ * to do with supporting buffer cache originated
+ * requests.
+ * The block device interface can now be opened, so
+ * that general ide driver features like the unmask
+ * interrupts flag can be selected with an ioctl.
+ * This is the only use of the block device interface.
+ * New fast pipelined operation mode (currently only on
+ * writes). When using the pipelined mode, the
+ * throughput can potentially reach the maximum
+ * tape supported throughput, regardless of the
+ * user backup program. On my tape drive, it sometimes
+ * boosted performance by a factor of 2. Pipelined
+ * mode is enabled by default, but since it has a few
+ * downfalls as well, you may want to disable it.
+ * A short explanation of the pipelined operation mode
+ * is available below.
*
* We are currently in an *alpha* stage. The driver is not complete and not
* much tested. I would strongly suggest to:
*
*/
+/*
+ * A short explanation of the pipelined operation mode.
+ *
+ * Pipelined mode is currently only implemented on writes. Reads are still
+ * performed in the slow non-pipelined mode.
+ *
+ * The pipeline mode, when enough pipeline stages are available, manages to
+ * keep the tape constantly streaming with the maximum device supported
+ * throughput, regardless of the user backup program, since even when Linux
+ * is busy doing other tasks, we still have job to be done.
+ *
+ * On my tape drive, using pipelined mode and giving the tape its own
+ * interface and irq, I get a constant over 400 KBps throughput, which seems
+ * to be the maximum throughput supported by my tape. When sharing the
+ * interface between the tape and another ata-2 disk drive, I receive around
+ * 350 KBps.
+ *
+ * Using the non-pipelined mode, I get anything between 150 to 380 KBps,
+ * with the average being around 150 or 250 KBps, depending mainly on
+ * the double buffering capabilities of the user backup program, but also
+ * on some additional factors, such as the user block size and the ongoing
+ * disk activity.
+ *
+ * However, there are some downfalls:
+ *
+ * 1. We use memory (for data buffers) in proportional to the number
+ * of pipeline stages (each stage is about 26 KB with my tape).
+ * 2. We cheat and postpone error codes to the user task. Again,
+ * the postponing period is proportional to the number of stages.
+ *
+ * Concerning (1):
+ *
+ * 1. We allocate stages dynamically only when we need them. When
+ * we don't need them, we don't consume additional memory. In
+ * case we can't allocate stages, we just manage without them
+ * (at the expense of decreased throughput) so when Linux is
+ * tight in memory, we will not pose additional difficulties.
+ *
+ * 2. The maximum number of stages (which is, in fact, the maximum
+ * amount of memory) which we allocate is limited by the compile
+ * time parameter IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * 3. The maximum number of stages is a controlled parameter - We
+ * don't start from the user defined maximum number of stages
+ * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we
+ * will not even allocate this amount of stages if the user
+ * program can't handle the speed). We then implement a feedback
+ * loop which checks if the pipeline is empty, and if it is, we
+ * increase the maximum number of stages as necessary until we
+ * reach the optimum value which just manages to keep the tape
+ * busy with with minimum allocated memory or until we reach
+ * IDETAPE_MAX_PIPELINE_STAGES.
+ *
+ * Concerning (2):
+ *
+ * In pipelined mode, ide-tape can not return accurate error codes to
+ * the user program since we usually just add the request to the
+ * pipeline without waiting for it to be serviced. In case an error
+ * occurs, I will report it on the next user request.
+ *
+ * For accurate error codes, you should disable pipelined mode.
+ *
+ * You can enable/disable/tune the pipelined operation mode by adjusting
+ * the compile time parameters in ide-tape.h.
+ */
+
#include <linux/hdreg.h>
#include <linux/types.h>
#include <linux/string.h>
/*
* Main Linux ide driver include file
*
- * Automatically includes our first include file - ide-tape1.h.
+ * Automatically includes our include file - ide-tape.h.
*/
#include "ide.h"
*
*/
+#define IDETAPE_FIRST_REQUEST 90
+
/*
* IDETAPE_PACKET_COMMAND_REQUEST_TYPE1 is used to queue a packet command
* in the request queue. We will wait for DSC before issuing the command
#define IDETAPE_READ_REQUEST 92
#define IDETAPE_WRITE_REQUEST 93
+#define IDETAPE_LAST_REQUEST 93
+
+/*
+ * A macro which can be used to check if a we support a given
+ * request command.
+ */
+
+#define IDETAPE_REQUEST_CMD(cmd) ((cmd >= IDETAPE_FIRST_REQUEST) && (cmd <= IDETAPE_LAST_REQUEST))
+
/*
* We are now able to postpone an idetape request in the stage
* where it is polling for DSC and service requests from the other
void idetape_postpone_request (ide_drive_t *drive);
void idetape_poll_for_dsc (unsigned long data);
-void idetape_put_back_postponed_request (ide_drive_t *drive);
+void idetape_poll_for_dsc_direct (unsigned long data);
void idetape_media_access_finished (ide_drive_t *drive);
/*
*/
int idetape_mtioctop (ide_drive_t *drive,short mt_op,int mt_count);
+
+/*
+ * idetape_add_chrdev_write_request adds a character device write
+ * request to the pipeline.
+ */
+
+int idetape_add_chrdev_write_request (ide_drive_t *drive,int cmd,int blocks,char *buffer);
+
+/*
+ * idetape_queue_rw_tail will add a command to the tail of the device
+ * request queue and wait for it to finish. This is used when we
+ * can not allocate pipeline stages (or in non-pipelined mode).
+ */
+
int idetape_queue_rw_tail (ide_drive_t *drive,int cmd,int blocks,char *buffer);
+
+/*
+ * Adds a packet command request to the tail of the device request
+ * queue and waits for it to be serviced.
+ */
+
int idetape_queue_pc_tail (ide_drive_t *drive,idetape_packet_command_t *pc);
-void idetape_fake_read (ide_drive_t *drive);
int idetape_position_tape (ide_drive_t *drive,unsigned long block);
int idetape_rewind_tape (ide_drive_t *drive);
* General utility functions
*/
-void idetape_fixstring (byte *s, const int bytecount, const int byteswap);
unsigned long idetape_swap_long (unsigned long temp);
unsigned short idetape_swap_short (unsigned short temp);
+/*
+ * Pipeline related functions
+ */
+
+idetape_pipeline_stage_t *idetape_kmalloc_stage (ide_drive_t *drive);
+void idetape_kfree_stage (idetape_pipeline_stage_t *stage);
+void idetape_copy_buffer_from_stage (idetape_pipeline_stage_t *stage,char *buffer);
+void idetape_copy_buffer_to_stage (idetape_pipeline_stage_t *stage,char *buffer);
+void idetape_increase_max_pipeline_stages (ide_drive_t *drive);
+void idetape_add_stage_tail (ide_drive_t *drive,idetape_pipeline_stage_t *stage);
+void idetape_active_next_stage (ide_drive_t *drive);
+void idetape_empty_pipeline (ide_drive_t *drive);
+void idetape_insert_pipeline_into_queue (ide_drive_t *drive);
+
/*
* For general magnetic tape device compatibility.
*/
void idetape_setup (ide_drive_t *drive)
{
- int buffer_size;
idetape_tape_t *tape=&(drive->tape);
-
+ unsigned int allocation_length;
+
#if IDETAPE_DEBUG
printk ("ide-tape: Reached idetape_setup\n");
#endif /* IDETAPE_DEBUG */
drive->ready_stat = 0; /* With an ATAPI device, we can issue packet commands */
/* regardless of the state of DRDY */
+ HWIF(drive)->tape_drive=drive;
+
tape->block_address=0;
tape->block_address_valid=0;
- tape->locate_to=0;
- tape->locate_retries=0;
tape->pc_stack_index=0;
tape->failed_pc=NULL;
tape->postponed_rq=NULL;
- tape->last_written_valid=0;
tape->busy=0;
+ tape->active_data_request=NULL;
+ tape->current_number_of_stages=0;
+ tape->first_stage=tape->last_stage=NULL;
+ tape->pipeline_was_full_once=0;
+ tape->error_in_pipeline_stage=0;
+ tape->pipeline_locked=0;
+
+ tape->request_status=0;
+ tape->request_dsc_callback=0;
+#if IDETAPE_PIPELINE
+ tape->max_number_of_stages=IDETAPE_MIN_PIPELINE_STAGES;
+ printk ("ide-tape: Operating in pipelined (fast and tricky) write mode.\n");
+#else
+ tape->max_number_of_stages=0;
+ printk ("ide-tape: Operating in non-pipelined (slow and safe) write mode.\n");
+#endif /* IDETAPE_PIPELINE */
+ printk ("ide-tape: Operating in non-pipelined (slow and safe) read mode.\n");
+
idetape_get_mode_sense_results (drive);
- buffer_size=tape->capabilities.ctl*tape->tape_block_size;
- tape->data_buffer=kmalloc (buffer_size,GFP_KERNEL);
- if (tape->data_buffer == NULL) {
- printk ("ide-tape: FATAL - Can not allocate %d bytes for data transfer buffer\n",buffer_size);
+ tape->data_buffer_size=tape->capabilities.ctl*tape->tape_block_size;
+
+ allocation_length=tape->data_buffer_size;
+ if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK)
+ allocation_length+=IDETAPE_ALLOCATION_BLOCK;
+
+ tape->data_buffer=kmalloc (allocation_length,GFP_KERNEL);
+ tape->temp_data_buffer=kmalloc (allocation_length,GFP_KERNEL);
+ if (tape->data_buffer == NULL || tape->temp_data_buffer == NULL) {
+ printk ("ide-tape: FATAL - Can not allocate 2 buffers of %d bytes each\n",allocation_length);
printk ("ide-tape: Aborting character device installation\n");
idetape_drive_already_found=0;
unregister_chrdev (idetape_chrdev.major,idetape_chrdev.name);
return;
}
- printk ("ide-tape: Speed - %d KBps. Recommended transfer unit - %d bytes.\n",tape->capabilities.speed,buffer_size);
+
+ printk ("ide-tape: Tape speed - %d KBps. Recommended transfer unit - %d bytes.\n",tape->capabilities.speed,tape->data_buffer_size);
+
return;
}
tape=&(drive->tape);
-#ifdef IDETAPE_DEBUG
+#if IDETAPE_DEBUG
if (tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD && pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
printk ("ide-tape: ide-tape.c bug - Two request sense in serial were issued\n");
/* ??? Need to rethink about that */
if (pc->callback==NULL)
printk ("ide-tape: ide-tape bug - Callback function not set !\n");
else
-#endif IDETAPE_DEBUG
+#endif /* IDETAPE_DEBUG */
(*pc->callback)(drive); /* Command finished - Call the callback function */
return;
}
idetape_tape_t *tape;
unsigned long flags;
struct request *rq;
-
+ idetape_status_reg_t status;
+
tape=&(drive->tape);
+ status.all=IN_BYTE (IDETAPE_STATUS_REG);
+ sti ();
+
#if IDETAPE_DEBUG
printk ("Reached idetape_postpone_request\n");
if (tape->postponed_rq != NULL)
printk ("ide-tape.c bug - postponed_rq not NULL in idetape_postpone_request\n");
#endif /* IDETAPE_DEBUG */
- tape->dsc_count=0;
tape->dsc_timer.expires=jiffies + tape->dsc_polling_frequency; /* Set timer to poll for */
tape->dsc_timeout=jiffies+IDETAPE_DSC_TIMEOUT; /* actual completion */
tape->dsc_timer.data=(unsigned long) drive;
/*
* Remove current request from the request queue:
*/
- save_flags(flags); /* Let ide.c handle another request */
- cli();
+
tape->postponed_rq = rq = HWGROUP(drive)->rq;
rq->rq_status = IDETAPE_RQ_POSTPONED;
+ save_flags(flags);cli (); /* Let ide.c handle another request */
blk_dev[MAJOR(rq->rq_dev)].current_request = rq->next;
HWGROUP(drive)->rq = NULL;
restore_flags(flags);
-
- tape->dsc_polling_start=jiffies;
+
+ tape->request_status=0;
+ tape->request_dsc_callback=0;
+ tape->last_status=status.all;
+
+ tape->dsc_polling_start=jiffies;
add_timer(&(tape->dsc_timer)); /* Activate the polling timer */
}
-
/*
- * idetape_poll_for_dsc gets invoked by a timer (which was set
- * by idetape_postpone_request) to poll for the DSC bit
- * in the status register. When the DSC bit is set, or a timeout is
- * reached, we put back the postponed request in front of the request
- * queue.
+ * idetape_poll_for_dsc_direct is called from idetape_poll_for_dsc
+ * to handle the case in which we can safely communicate with the tape
+ * (since no other request for this hwgroup is active).
*/
-void idetape_poll_for_dsc (unsigned long data)
+void idetape_poll_for_dsc_direct (unsigned long data)
{
- ide_drive_t *drive;
- idetape_tape_t *tape;
-
+ ide_drive_t *drive=(ide_drive_t *) data;
+ ide_hwgroup_t *hwgroup=HWGROUP (drive);
+ idetape_tape_t *tape=&(drive->tape);
idetape_status_reg_t status;
- idetape_packet_command_t *pc;
+ unsigned long flags;
- drive=(ide_drive_t *) data;
- tape=&(drive->tape);
- pc=tape->pc;
-
#if IDETAPE_DEBUG
- printk ("%s: idetape_poll_for_dsc called\n",drive->name);
+ printk ("%s: idetape_poll_for_dsc_direct called\n",drive->name);
#endif /* IDETAPE_DEBUG */
+ save_flags (flags);cli ();
+ OUT_BYTE(drive->select.all,IDE_SELECT_REG);
status.all=IN_BYTE (IDETAPE_STATUS_REG);
+ if (hwgroup->drive != NULL)
+ OUT_BYTE (hwgroup->drive->select.all,IDE_SELECT_REG);
+ restore_flags (flags);
- if (status.b.dsc)
- tape->dsc_count++;
- else {
- if (tape->dsc_count)
- printk ("ide-tape: DSC fluctuation detected - Restarting DSC count\n");
- tape->dsc_count=0;
- }
-
- if (tape->dsc_count == IDETAPE_DSC_COUNT) { /* DSC received */
+ if (status.b.dsc) { /* DSC received */
tape->dsc_received=1;
del_timer (&(tape->dsc_timer)); /* Stop polling and put back the postponed */
idetape_put_back_postponed_request (drive); /* request in the request queue */
return;
}
-
+
if (jiffies > tape->dsc_timeout) { /* Timeout */
tape->dsc_received=0;
del_timer (&(tape->dsc_timer));
idetape_put_back_postponed_request (drive);
return;
}
-
+
/* Poll again */
+
+ if (jiffies - tape->dsc_polling_start > IDETAPE_FAST_SLOW_THRESHOLD)
+ tape->dsc_timer.expires = jiffies + IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY;
+ else
+ tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency;
+ add_timer(&(tape->dsc_timer));
+ return;
+}
+
+/*
+ * idetape_poll_for_dsc gets invoked by a timer (which was set
+ * by idetape_postpone_request) to poll for the DSC bit
+ * in the status register.
+ *
+ * We take care not to perform any tape access and not to touch the
+ * device request queue if the driver is accessing the other device.
+ * We will instead ask ide.c to perform those functions on the next
+ * call to do_request, at the point in which the other device is idle.
+ *
+ * However, in case the other device is already idle, we will read
+ * the status register from our timer handler.
+ *
+ * I am also a bit paranoid with the use of cli (), all through the
+ * code. I still need to think harder about each one whether we can
+ * avoid it and still be free of race conditions ...
+ */
+
+void idetape_poll_for_dsc (unsigned long data)
+{
+ ide_drive_t *drive=(ide_drive_t *) data;
+ unsigned int major = HWIF(drive)->major;
+ idetape_tape_t *tape=&(drive->tape);
+ struct blk_dev_struct *bdev = &blk_dev[major];
+ unsigned long flags;
+
+ idetape_status_reg_t status;
+
+ save_flags (flags);cli ();
+
+#if IDETAPE_DEBUG
+ printk ("%s: idetape_poll_for_dsc called\n",drive->name);
+#endif /* IDETAPE_DEBUG */
+
+ /*
+ * Check if the other device is idle. If there are no requests,
+ * we can safely access the tape.
+ */
+
+ if (bdev->current_request == NULL) {
+ restore_flags (flags);
+ idetape_poll_for_dsc_direct (data);
+ return;
+ }
+
+ if (bdev->current_request->next == NULL) {
+ /*
+ * There will not be another request after the currently
+ * ongoing request, so ide.c won't be able to sample
+ * the status register on our behalf in do_request. Just
+ * give up and poll again (in a faster frequency), until
+ * we are lucky.
+ */
+ restore_flags (flags);
+ tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency/2;
+ add_timer(&(tape->dsc_timer));
+ return;
+ }
+
+ /*
+ * We now know that:
+ *
+ * 1. The ide driver is potentially accessing
+ * the other device -- We can not touch it.
+ * 2. do_request will be called after the current
+ * request is finished.
+ *
+ * We will therefor ask ide.c to perform the tasks on our behalf.
+ */
+
+ status.all=tape->last_status;
+
+ if (status.b.dsc) { /* DSC received */
+ tape->dsc_received=1;
+ del_timer (&(tape->dsc_timer)); /* Stop polling and request ide.c to call */
+ tape->request_dsc_callback=1; /* our idetape_put_back_postponed_request later */
+ restore_flags (flags);
+ return;
+ }
+
+ if (jiffies > tape->dsc_timeout) { /* Timeout */
+ tape->dsc_received=1;
+ del_timer (&(tape->dsc_timer));
+ /* ??? */
+ tape->request_dsc_callback=1;
+ restore_flags (flags);
+ return;
+ }
+
+ /*
+ * Request ide.c to sample for us the tape's status register on
+ * the next time in which it can be safely done.
+ */
+
+ tape->request_status=1;
+ restore_flags (flags);
+
+ /* Poll again */
+
if (jiffies - tape->dsc_polling_start > IDETAPE_FAST_SLOW_THRESHOLD)
tape->dsc_timer.expires = jiffies + IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY;
else
tape->dsc_timer.expires = jiffies + tape->dsc_polling_frequency;
-/* init_timer (&(tape->dsc_timer)); */
add_timer(&(tape->dsc_timer));
return;
}
/*
- * idetape_put_back_postponed_request gets called by
- * idetape_poll_for_dsc when we decided to stop polling - Either
- * becase we received DSC or because we decided to give up and
- * stop waiting.
+ * idetape_put_back_postponed_request gets called by do_request
+ * in ide.c when we decided to stop polling for DSC and continue
+ * servicing our postponed request.
*/
void idetape_put_back_postponed_request (ide_drive_t *drive)
#if IDETAPE_DEBUG
printk ("ide-tape: Reached idetape_read_callback\n");
#endif /* IDETAPE_DEBUG */
- tape->block_address+=tape->pc->actually_transferred/512;
+ tape->block_address+=tape->pc->actually_transferred/tape->tape_block_size;
if (!tape->pc->error) {
#if IDETAPE_DEBUG
printk ("Request completed\n");
return;
}
-void idetape_fake_read (ide_drive_t *drive)
-
-{
- idetape_tape_t *tape;
- struct request *rq;
- unsigned long i;
-
- tape=&(drive->tape);
- rq=HWGROUP(drive)->rq;
-#if IDETAPE_DEBUG
- printk ("ide-tape: Reached idetape_fake_read\n");
-#endif /* IDETAPE_DEBUG */
-
-#if IDETAPE_DEBUG
- printk ("Request completed\n");
-#endif /* IDETAPE_DEBUG */
-
- for (i=0;i<rq->current_nr_sectors*512;i++)
- rq->buffer [i]=0;
-
- tape->block_address+=rq->current_nr_sectors;
- rq->sector+=rq->current_nr_sectors;
- rq->nr_sectors-=rq->current_nr_sectors;
- rq->current_nr_sectors=0;
- idetape_end_request (1,HWGROUP (drive));
-}
-
void idetape_write_callback (ide_drive_t *drive)
{
#if IDETAPE_DEBUG
printk ("ide-tape: Reached idetape_write_callback\n");
#endif /* IDETAPE_DEBUG */
- tape->block_address+=tape->pc->actually_transferred/512;
+ tape->block_address+=tape->pc->actually_transferred/tape->tape_block_size;
if (!tape->pc->error) {
#if IDETAPE_DEBUG
printk ("Request completed\n");
idetape_inquiry_result_t *result;
result=(idetape_inquiry_result_t *) buffer;
- idetape_fixstring (result->vendor_id,8,0);
- idetape_fixstring (result->product_id,16,0);
- idetape_fixstring (result->revision_level,4,0);
+ ide_fixstring (result->vendor_id,8,0);
+ ide_fixstring (result->product_id,16,0);
+ ide_fixstring (result->revision_level,4,0);
if (result->response_format != 2) {
printk ("The INQUIRY Data Format is unknown to us !\n");
{
ide_drive_t *drive = hwgroup->drive;
struct request *rq = hwgroup->rq;
-
- if (rq->cmd == READ || rq->cmd == WRITE) { /* Buffer cache originated request */
- ide_end_request (uptodate,hwgroup); /* Let the common code handle it */
- return;
- }
+ idetape_tape_t *tape = &(drive->tape);
+
/* Our own originated request */
rq->errors=!uptodate; /* rq->errors will tell us if the request was successfull */
- ide_end_drive_cmd (drive, 0, 0);
+
+ if (tape->active_data_request == rq) { /* The request was a data transfer request */
+#if IDETAPE_DEBUG
+ if (!tape->max_number_of_stages)
+ printk ("ide-tape: non pipelined mode bug\n");
+ printk ("Finished our active data request\n");
+ printk ("Requests in pipeline: %d\n",tape->current_number_of_stages);
+#endif /* IDETAPE_DEBUG */
+ if (rq->errors)
+ tape->error_in_pipeline_stage=1;
- /* The "up(rq->sem);" does the necessary "wake_up()" for us,
- * providing we started sleeping with a "down()" call.
- * This may not be the case if the driver converts a READ or WRITE
- * request into a special internal rq->cmd type. -ml
- */
-
- /*
- * As Mark explained, we do not need a "wake_up()" call here,
- * since we are always sleeping with a "down()" call.
- */
+ /*
+ * Pass to the next stage, but avoid a possible
+ * race condition which could occur since
+ * active_data_request is set to NULL until
+ * idetape_active_next_stage returns, and in that
+ * time, the higher level of the driver can get
+ * an inaccurate sampling of this variable.
+ */
+
+ tape->pipeline_locked=1;
+ tape->active_data_request = NULL;
+ if (tape->first_stage == NULL) {
+ tape->pipeline_locked=0;
+ idetape_increase_max_pipeline_stages (drive);
+ return;
+ }
+ idetape_active_next_stage (drive);
+ tape->pipeline_locked=0;
+#if IDETAPE_DEBUG
+ printk ("Using ide_end\n");
+#endif /* IDETAPE_DEBUG */
+ /*
+ * Insert the next request into the request queue.
+ *
+ * We currently give higher priority to the other devie
+ * by using ide_end. ide_next can be used to give us
+ * a higher priority.
+ */
+
+ ide_do_drive_cmd (drive,tape->active_data_request,ide_end);
+ }
+ ide_end_drive_cmd (drive, 0, 0);
}
/*
void idetape_do_request (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- idetape_tape_t *tape;
+ idetape_tape_t *tape=&(drive->tape);
idetape_packet_command_t *pc;
- struct request *new_rq;
idetape_status_reg_t status;
- tape=&(drive->tape);
-
#if IDETAPE_DEBUG
printk ("Current request:\n");
printk ("rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);
printk ("sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
#endif /* IDETAPE_DEBUG */
+ if (!IDETAPE_REQUEST_CMD (rq->cmd)) {
+
+ /*
+ * We do not support buffer cache originated requests.
+ */
+
+ printk ("ide-tape: Unsupported command in request queue\n");
+ printk ("ide-tape: The block device interface should not be used for data transfers.\n");
+ printk ("ide-tape: Use the character device interfaces\n");
+ printk ("ide-tape: /dev/ht0 and /dev/nht0 instead.\n");
+ printk ("ide-tape: (Run linux/drivers/block/MAKEDEV.ide to create them)\n");
+ printk ("ide-tape: Aborting request.\n");
+
+ ide_end_request (0,HWGROUP (drive)); /* Let the common code handle it */
+ return;
+ }
+
/* Retry a failed packet command */
if (tape->failed_pc != NULL && tape->pc->c[0] == IDETAPE_REQUEST_SENSE_CMD) {
/* Check if we have a postponed request */
if (tape->postponed_rq != NULL) {
-/* #if IDETAPE_DEBUG */
+ #if IDETAPE_DEBUG
if (tape->postponed_rq->rq_status != RQ_ACTIVE || rq != tape->postponed_rq) {
printk ("ide-tape: ide-tape.c bug - Two DSC requests were queued\n");
idetape_end_request (0,HWGROUP (drive));
return;
}
-/* #endif */ /* IDETAPE_DEBUG */
+#endif /* IDETAPE_DEBUG */
if (rq->cmd == IDETAPE_PACKET_COMMAND_REQUEST_TYPE1) {
/* Media access command */
tape->postponed_rq = NULL;
}
-
- if (rq->cmd == READ || rq->cmd == IDETAPE_READ_REQUEST || rq->cmd == WRITE || rq->cmd == IDETAPE_WRITE_REQUEST) {
-
- if (!tape->block_address_valid || tape->block_address!=rq->sector) { /* Re-position the tape */
-
- if (tape->locate_to == rq->sector && tape->locate_retries > IDETAPE_LOCATE_RETRIES) {
- printk ("ide-tape: Can not reach block %lu - Aborting request\n",rq->sector);
- tape->locate_retries=0;
- idetape_end_request (0,HWGROUP (drive));
- return;
- }
-
- if (tape->locate_to == rq->sector)
- tape->locate_retries++;
- else {
- tape->locate_to=rq->sector;
- tape->locate_retries=1;
- }
-#if IDETAPE_DEBUG
- printk ("ide-tape: We are not at the requested block\n");
- printk ("ide-tape: Re-positioning tape\n");
- printk ("ide-tape: Adding READ POSITION command to the head of the queue\n");
-#endif /* IDETAPE_DEBUG */
- pc=idetape_next_pc_storage (drive);
- new_rq=idetape_next_rq_storage (drive);
- idetape_create_read_position_cmd (pc);
- pc->buffer=pc->temp_buffer;
- pc->buffer_size=IDETAPE_TEMP_BUFFER_SIZE;
- pc->current_position=pc->temp_buffer;
- idetape_queue_pc_head (drive,pc,new_rq);
-#if IDETAPE_DEBUG
- printk ("ide-tape: Adding LOCATE %lu command to the head of the queue\n",rq->sector);
-#endif /* IDETAPE_DEBUG */
- pc=idetape_next_pc_storage (drive);
- new_rq=idetape_next_rq_storage (drive);
- idetape_create_locate_cmd (pc,rq->sector,0);
- idetape_queue_pc_head (drive,pc,new_rq);
-
- if (!tape->block_address_valid) { /* The tape doesn't know the position - help it */
- /* by rewinding the tape */
-#if IDETAPE_DEBUG
- printk ("ide-tape: Adding LOCATE 0 command to the head of the queue\n");
-#endif /* IDETAPE_DEBUG */
- pc=idetape_next_pc_storage (drive);
- new_rq=idetape_next_rq_storage (drive);
- idetape_create_locate_cmd (pc,0,0);
- idetape_queue_pc_head (drive,pc,new_rq);
- }
-
- return;
- }
- else
- tape->locate_retries=0;
- }
-
switch (rq->cmd) {
- case READ:
case IDETAPE_READ_REQUEST:
#if IDETAPE_DEBUG
- if (rq->cmd == READ)
- printk ("ide-tape: Handling buffer cache READ request\n");
- else
- printk ("ide-tape: Handling our own (not buffer cache originated) READ request\n");
+ printk ("ide-tape: Handling our own (not buffer cache originated) READ request\n");
#endif /* IDETAPE_DEBUG */
status.all=IN_BYTE (IDETAPE_STATUS_REG);
if (!status.b.dsc) { /* Tape buffer not ready to accept r/w command */
return;
}
- tape->last_written_valid=0;
-
pc=idetape_next_pc_storage (drive);
idetape_create_read_cmd (pc,rq->current_nr_sectors);
pc->buffer=rq->buffer;
- pc->buffer_size=rq->current_nr_sectors*512;
+ pc->buffer_size=rq->current_nr_sectors*tape->tape_block_size;
pc->current_position=rq->buffer;
- pc->request_transfer=rq->current_nr_sectors*512;
+ pc->request_transfer=rq->current_nr_sectors*tape->tape_block_size;
idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
return;
- case WRITE:
case IDETAPE_WRITE_REQUEST:
#if IDETAPE_DEBUG
- if (rq->cmd == WRITE)
- printk ("ide-tape: Handling buffer cache WRITE request\n");
- else
- printk ("ide-tape: Handling our own (not buffer cache originated) WRITE request\n");
+ printk ("ide-tape: Handling our own (not buffer cache originated) WRITE request\n");
#endif /* IDETAPE_DEBUG */
status.all=IN_BYTE (IDETAPE_STATUS_REG);
return;
}
- tape->last_written_valid=1;
- tape->last_written_block=rq->sector;
-
pc=idetape_next_pc_storage (drive);
idetape_create_write_cmd (pc,rq->current_nr_sectors);
pc->buffer=rq->buffer;
- pc->buffer_size=rq->current_nr_sectors*512;
+ pc->buffer_size=rq->current_nr_sectors*tape->tape_block_size;
pc->current_position=rq->buffer;
- pc->request_transfer=rq->current_nr_sectors*512;
+ pc->request_transfer=rq->current_nr_sectors*tape->tape_block_size;
idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
return;
if (!status.b.dsc) { /* Tape buffers are still not ready */
#if IDETAPE_DEBUG
printk ("ide-tape: DSC != 1 - Postponing packet command request\n");
-#endif IDETAPE_DEBUG
+#endif /* IDETAPE_DEBUG */
rq->cmd=IDETAPE_PACKET_COMMAND_REQUEST_TYPE2; /* Note that we are waiting for DSC *before* we */
/* even issued the command */
tape->dsc_polling_frequency=IDETAPE_DSC_READ_WRITE_FREQUENCY;
pc=(idetape_packet_command_t *) rq->buffer;
idetape_issue_packet_command (drive,pc,&idetape_pc_intr);
return;
-
+#if IDETAPE_DEBUG
default:
- printk ("ide-tape: Unknown command in request - Aborting request\n");
+ printk ("ide-tape: bug in IDETAPE_REQUEST_CMD macro\n");
idetape_end_request (0,HWGROUP (drive));
+#endif /* IDETAPE_DEBUG */
}
}
(void) ide_do_drive_cmd (drive, rq, ide_preempt);
}
+void idetape_wait_for_request (struct request *rq)
+
+{
+ unsigned long flags;
+ struct semaphore sem = MUTEX_LOCKED;
+
+ save_flags (flags);cli ();
+ rq->sem=&sem;
+ restore_flags (flags);
+
+ down (&sem);
+}
+
/*
* idetape_queue_rw_tail is typically called from the character device
* interface to generate a read/write request for the block device interface
rq.sector = tape->block_address;
rq.nr_sectors = blocks;
rq.current_nr_sectors = blocks;
+ tape->active_data_request=NULL; /* Non-pipelined mode */
+#if IDETAPE_DEBUG
+ printk ("Using ide_tail\n");
+#endif /* IDETAPE_DEBUG */
return ide_do_drive_cmd (drive, &rq, ide_wait);
}
-/*
- * Copied from ide.c (declared static there)
+ /*
+ * idetape_add_chrdev_write_request tries to add a character device
+ * originated write request to our pipeline. In case we don't succeed,
+ * we revert to non-piplined operation mode for this request.
+ *
+ * 1. Try to allocate a new pipeline stage.
+ * 2. If we can't, wait for more and more requests to be serviced
+ * and try again each time.
+ * 3. If we still can't allocate a stage, fallback to
+ * non-pipelined operation mode for this request.
*/
-void idetape_fixstring (byte *s, const int bytecount, const int byteswap)
+int idetape_add_chrdev_write_request (ide_drive_t *drive,int cmd,int blocks,char *buffer)
+
{
- byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
+ idetape_tape_t *tape = &(drive->tape);
+ idetape_pipeline_stage_t *new_stage;
+ struct request *rq;
- if (byteswap) {
- /* convert from big-endian to host byte order */
- for (p = end ; p != s;) {
- unsigned short *pp = (unsigned short *) (p -= 2);
- *pp = ntohs(*pp);
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_add_chrdev_write_request\n");
+ printk ("Trying to allocate stage - ");
+#endif /* IDETAPE_DEBUG */
+
+ if (tape->error_in_pipeline_stage) /* Return a deferred error */
+ return (-EIO);
+
+ new_stage=idetape_kmalloc_stage (drive);
+
+ /*
+ * If we don't have a new stage, wait for more and more requests
+ * to finish, and try to allocate after each one.
+ *
+ * Pay special attention to possible race conditions.
+ */
+
+ while (new_stage == NULL) {
+
+ /*
+ * Wait for the time in which we can safely inspect
+ * tape->first_stage.
+ */
+
+ while (tape->pipeline_locked);
+
+ if (tape->first_stage != NULL) {
+ idetape_wait_for_request (&(tape->first_stage->rq));
+ new_stage=idetape_kmalloc_stage (drive);
}
+ else
+ break; /* Linux is short on memory */
+ }
+
+ /*
+ * If we don't have a new_stage, fallback to non-pipelined
+ * operation mode for this request.
+ */
+
+ if (new_stage == NULL) {
+ if (tape->active_data_request != NULL)
+ idetape_wait_for_request (tape->active_data_request);
+ return (idetape_queue_rw_tail (drive,cmd,blocks,buffer));
}
- /* strip leading blanks */
- while (s != end && *s == ' ')
- ++s;
+ rq=&(new_stage->rq);
- /* compress internal blanks and strip trailing blanks */
- while (s != end && *s) {
- if (*s++ != ' ' || (s != end && *s && *s != ' '))
- *p++ = *(s-1);
- }
+ ide_init_drive_cmd (rq);
+ rq->buffer = NULL; /* We will correct this when we will actually service the request */
+ rq->cmd = cmd;
+ rq->sector = tape->block_address; /* Doesn't actually matter - We always assume sequential access */
+ rq->nr_sectors = blocks;
+ rq->current_nr_sectors = blocks;
+
+ idetape_copy_buffer_to_stage (new_stage,buffer);
+ idetape_add_stage_tail (drive,new_stage);
+
+ return (0);
+}
+
+void idetape_empty_pipeline (ide_drive_t *drive)
+
+{
+ idetape_tape_t *tape = &(drive->tape);
+
+ tape->pipeline_was_full_once=0;
+
+ while (tape->pipeline_locked);
+
+ if (tape->active_data_request == NULL)
+ idetape_insert_pipeline_into_queue (drive);
+
+ if (tape->last_stage != NULL)
+ idetape_wait_for_request (&(tape->last_stage->rq));
+
+ else if (tape->active_data_request != NULL)
+ idetape_wait_for_request (tape->active_data_request);
- /* wipe out trailing garbage */
- while (p != end)
- *p++ = '\0';
+ tape->error_in_pipeline_stage=0;
+
+ /*
+ * On the next backup, perform the feedback loop again.
+ * (I don't want to keep sense information between backups,
+ * as some systems are constantly on, and the system load
+ * can be totally different on the next backup).
+ */
+
+#if IDETAPE_PIPELINE
+ tape->max_number_of_stages=IDETAPE_MIN_PIPELINE_STAGES;
+#else
+ tape->max_number_of_stages=0;
+#endif /* IDETAPE_PIPELINE */
+
+#if IDETAPE_DEBUG
+ if (tape->first_stage != NULL || tape->last_stage != NULL || tape->current_number_of_stages != 0) {
+ printk ("ide-tape: ide-tape pipeline bug\n");
+ }
+#endif /* IDETAPE_DEBUG */
}
+
/*
* idetape_zero_packet_command just zeros a packet command and
* sets the number of retries to 0, as we haven't retried it yet.
/*
* Block device interface functions
*
- * The default action is not to allow direct access to the block device
- * interface (-EBUSY will be returned on open).
+ * The block device interface should not be used for data transfers.
+ * However, we still allow opening it so that we can issue general
+ * ide driver configuration ioctl's, such as the interrupt unmask feature.
*/
int idetape_blkdev_open (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
-#if IDETAPE_ALLOW_OPENING_BLOCK_DEVICE
+ idetape_tape_t *tape=&(drive->tape);
+ unsigned long flags;
+
+ save_flags (flags);cli();
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_blkdev_open\n");
+#endif /* IDETAPE_DEBUG */
+
+ if (tape->busy) {
+ restore_flags (flags); /* Allowing access only through one */
+ return (-EBUSY); /* one file descriptor */
+ }
+
+ tape->busy=1;
+ restore_flags (flags);
+
return (0);
-#else
- printk ("ide-tape: The block device interface should not be used.\n");
- printk ("ide-tape: Use the character device interfaces\n");
- printk ("ide-tape: /dev/ht0 and /dev/nht0 instead.\n");
- printk ("ide-tape: (Run linux/drivers/block/MAKEDEV.ide to create them)\n");
- printk ("ide-tape: Refusing open request.\n");
- return (-EBUSY);
-#endif /* IDETAPE_ALLOW_OPENING_BLOCK_DEVICE */
}
void idetape_blkdev_release (struct inode *inode, struct file *filp, ide_drive_t *drive)
{
+ idetape_tape_t *tape=&(drive->tape);
+ unsigned long flags;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_blkdev_release\n");
+#endif /* IDETAPE_DEBUG */
+
+ save_flags (flags);cli();
+ tape->busy=0;
+ restore_flags (flags);
+
return;
}
/*
* Our character device read / write functions.
*
- * The tape is optimized to maximize throughpot when it is transfering
+ * The tape is optimized to maximize throughput when it is transfering
* an integral number of the "continous transfer limit", which is
* a parameter of the specific tape (26 KB on my particular tape). The
* resulting increase in performance should be dramatical. In the
if (count==0)
return (0);
-
- blocks=count/512;
- remainder=count%512;
+ blocks=count/tape->tape_block_size;
+ remainder=count%tape->tape_block_size;
if (remainder) {
#if IDETAPE_DEBUG
printk ("ide-tape: Padding read to block boundary\n");
retval=idetape_queue_rw_tail (drive,IDETAPE_READ_REQUEST,blocks,tape->data_buffer);
if (retval) {
printk ("ide-tape: Error occured while reading\n");
- actually_read=512*(tape->block_address-previous_block_address);
+ actually_read=tape->tape_block_size*(tape->block_address-previous_block_address);
if (actually_read > count)
actually_read=count;
if (actually_read != 0)
{
ide_drive_t *drive;
idetape_tape_t *tape;
- int blocks,remainder,retval,ctl_bytes;
+ int blocks,remainder,retval;
const char *buf_ptr;
unsigned long previous_block_address,actually_written;
drive=idetape_chrdev.drive;
tape=&(drive->tape);
+
tape->last_dt_was_write=1;
if (count==0)
actually_written=0;
buf_ptr=buf;
- ctl_bytes=tape->capabilities.ctl*tape->tape_block_size;
- blocks=count/ctl_bytes;
- remainder=count%ctl_bytes;
+ blocks=count/tape->data_buffer_size;
+ remainder=count%tape->data_buffer_size;
while (blocks) {
-#if IDETAPE_DEBUG
- printk ("Copying %d bytes from the user space memory\n",ctl_bytes);
-#endif /* IDETAPE_DEBUG */
- memcpy_fromfs (tape->data_buffer,buf_ptr,ctl_bytes);
- buf_ptr+=ctl_bytes;
-#if IDETAPE_DEBUG
- printk ("Adding a WRITE request to the block device request queue\n");
-#endif /* IDETAPE_DEBUG */
+ memcpy_fromfs (tape->temp_data_buffer,buf_ptr,tape->data_buffer_size);
+ buf_ptr+=tape->data_buffer_size;
previous_block_address=tape->block_address;
- retval=idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,tape->capabilities.ctl,tape->data_buffer);
- actually_written+=tape->tape_block_size*(tape->block_address-previous_block_address);
+ retval=idetape_add_chrdev_write_request (drive,IDETAPE_WRITE_REQUEST,tape->capabilities.ctl,tape->temp_data_buffer);
+ if (tape->max_number_of_stages)
+ actually_written+=tape->data_buffer_size; /* Pipelined mode - Cheat :-) */
+ else
+ actually_written+=tape->tape_block_size*(tape->block_address-previous_block_address);
if (retval) {
printk ("ide-tape: Error occured while writing\n");
- return (actually_written);
+ if (tape->max_number_of_stages)
+ return (0);
+ else
+ return (actually_written);
}
blocks--;
}
drive=idetape_chrdev.drive;
tape=&(drive->tape);
- blocks=count/512;
- remainder=count%512;
+ blocks=count/tape->tape_block_size;
+ remainder=count%tape->tape_block_size;
if (remainder)
blocks++;
#if IDETAPE_DEBUG
printk ("Copying %d bytes from the user space memory\n",count);
#endif /* IDETAPE_DEBUG */
- memcpy_fromfs (tape->data_buffer,buf,count);
+ memcpy_fromfs (tape->temp_data_buffer,buf,count);
if (remainder) {
#if IDETAPE_DEBUG
printk ("ide-tape: Padding written data to block boundary\n");
#endif /* IDETAPE_DEBUG */
- ptr=tape->data_buffer+(blocks-1)*512;
+ ptr=tape->temp_data_buffer+(blocks-1)*tape->tape_block_size;
memset (ptr,0,remainder);
}
#if IDETAPE_DEBUG
#endif /* IDETAPE_DEBUG */
previous_block_address=tape->block_address;
- retval=idetape_queue_rw_tail (drive,IDETAPE_WRITE_REQUEST,blocks,tape->data_buffer);
+ retval=idetape_add_chrdev_write_request (drive,IDETAPE_WRITE_REQUEST,blocks,tape->temp_data_buffer);
if (retval) {
printk ("ide-tape: Error occured while writing\n");
- actually_written=512*(tape->block_address-previous_block_address);
+ if (tape->max_number_of_stages)
+ actually_written=0;
+ else
+ actually_written=tape->tape_block_size*(tape->block_address-previous_block_address);
if (actually_written > count)
actually_written=count;
return (actually_written);
idetape_tape_t *tape;
unsigned long flags;
unsigned int minor;
-
- save_flags (flags);
- cli();
+
+ save_flags (flags);cli();
#if IDETAPE_DEBUG
printk ("Reached idetape_chrdev_open\n");
}
tape->last_dt_was_write=0;
-
+
return (0);
}
tape=&(drive->tape);
minor=MINOR (inode->i_rdev);
+ idetape_empty_pipeline (drive);
+
if (tape->last_dt_was_write) {
idetape_create_write_filemark_cmd (&pc,1); /* Write a filemark */
if (idetape_queue_pc_tail (drive,&pc)) {
}
}
- save_flags (flags);
- cli();
+ save_flags (flags);cli();
tape->busy=0;
restore_flags (flags);
-
+
return;
}
pc.current_position=pc.temp_buffer;
return (idetape_queue_pc_tail (drive,&pc));
}
+
+/*
+ * Pipeline related functions
+ */
+
+/*
+ * idetape_kmalloc_stage uses kmalloc to allocate a pipeline stage,
+ * along with all the necessary small buffers which together make
+ * a buffer of size tape->data_buffer_size or a bit more, in case
+ * it is not a multiply of IDETAPE_ALLOCATION_BLOCK (it isn't ...).
+ *
+ * Returns a pointer to the new allocated stage, or NULL if we
+ * can't (or don't want to, in case we already have too many stages)
+ * allocate a stage.
+ *
+ * Pipeline stages are optional and are used to increase performance.
+ * If we can't allocate them, we'll manage without them.
+ */
+
+idetape_pipeline_stage_t *idetape_kmalloc_stage (ide_drive_t *drive)
+
+{
+ idetape_tape_t *tape=&(drive->tape);
+ idetape_pipeline_stage_t *new_stage;
+ idetape_buffer_head_t *prev_bh,*bh;
+ int buffers_num,i;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_kmalloc_stage\n");
+#endif /* IDETAPE_DEBUG */
+
+ if (tape->current_number_of_stages==tape->max_number_of_stages) {
+ tape->pipeline_was_full_once=1;
+ return (NULL);
+ }
+
+ new_stage=(idetape_pipeline_stage_t *) kmalloc (sizeof (idetape_pipeline_stage_t),GFP_KERNEL);
+ if (new_stage==NULL)
+ return (NULL);
+
+ new_stage->next=new_stage->prev=NULL;
+
+ buffers_num=tape->data_buffer_size / IDETAPE_ALLOCATION_BLOCK;
+ if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK)
+ buffers_num++;
+
+ prev_bh=new_stage->bh=(idetape_buffer_head_t *) kmalloc (sizeof (idetape_buffer_head_t),GFP_KERNEL);
+ if (new_stage->bh==NULL) {
+ idetape_kfree_stage (new_stage);
+ return (NULL);
+ }
+ new_stage->bh->next=NULL;
+
+ new_stage->bh->data=kmalloc (IDETAPE_ALLOCATION_BLOCK,GFP_KERNEL);
+ if (new_stage->bh->data==NULL) {
+ idetape_kfree_stage (new_stage);
+ return (NULL);
+ }
+
+ for (i=1;i<buffers_num;i++) {
+ bh=(idetape_buffer_head_t *) kmalloc (sizeof (idetape_buffer_head_t),GFP_KERNEL);
+ if (bh==NULL) {
+ idetape_kfree_stage (new_stage);
+ return (NULL);
+ }
+ bh->next=NULL;
+ prev_bh->next=bh;
+ bh->data=kmalloc (IDETAPE_ALLOCATION_BLOCK,GFP_KERNEL);
+ if (bh->data == NULL) {
+ idetape_kfree_stage (new_stage);
+ return (NULL);
+ }
+ prev_bh=bh;
+ }
+ return (new_stage);
+}
+
+/*
+ * idetape_kfree_stage calls kfree to completly free a stage, along with
+ * its related buffers.
+ */
+
+void idetape_kfree_stage (idetape_pipeline_stage_t *stage)
+
+{
+ idetape_buffer_head_t *prev_bh,*bh;
+
+ if (stage == NULL)
+ return;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_kfree_stage\n");
+#endif /* IDETAPE_DEBUG */
+
+ bh=stage->bh;
+
+ while (bh != NULL) {
+ prev_bh=bh;
+ if (bh->data != NULL)
+ kfree (bh->data);
+ bh=bh->next;
+ kfree (prev_bh);
+ }
+
+ kfree (stage);
+ return;
+}
+
+/*
+ * idetape_copy_buffer_from_stage and idetape_copy_buffer_to_stage
+ * copy data from/to the small buffers into/from a continous buffer.
+ */
+
+void idetape_copy_buffer_from_stage (idetape_pipeline_stage_t *stage,char *buffer)
+
+{
+ idetape_buffer_head_t *bh;
+ char *ptr;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_copy_buffer_from_stage\n");
+#endif /* IDETAPE_DEBUG */
+
+ ptr=buffer;
+ bh=stage->bh;
+
+ while (bh != NULL) {
+ memcpy (ptr,bh->data,IDETAPE_ALLOCATION_BLOCK);
+ bh=bh->next;
+ ptr=ptr+IDETAPE_ALLOCATION_BLOCK;
+ }
+ return;
+}
+
+/*
+ * Here we copy a continuous data buffer to the various small buffers
+ * in the pipeline stage.
+ */
+
+void idetape_copy_buffer_to_stage (idetape_pipeline_stage_t *stage,char *buffer)
+
+{
+ idetape_buffer_head_t *bh;
+ char *ptr;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_copy_buffer_to_stage\n");
+#endif /* IDETAPE_DEBUG */
+
+ ptr=buffer;
+ bh=stage->bh;
+
+ while (bh != NULL) {
+ memcpy (bh->data,ptr,IDETAPE_ALLOCATION_BLOCK);
+ bh=bh->next;
+ ptr=ptr+IDETAPE_ALLOCATION_BLOCK;
+ }
+ return;
+}
+
+/*
+ * idetape_increase_max_pipeline_stages is a part of the feedback
+ * loop which tries to find the optimum number of stages. In the
+ * feedback loop, we are starting from a minimum maximum number of
+ * stages, and if we sense that the pipeline is empty, we try to
+ * increase it, until we reach the user compile time memory limit.
+ */
+
+void idetape_increase_max_pipeline_stages (ide_drive_t *drive)
+
+{
+ idetape_tape_t *tape=&(drive->tape);
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_increase_max_pipeline_stages\n");
+#endif /* IDETAPE_DEBUG */
+
+ if (!tape->pipeline_was_full_once)
+ return;
+
+ tape->max_number_of_stages+=IDETAPE_INCREASE_STAGES_RATE*
+ (IDETAPE_MAX_PIPELINE_STAGES-IDETAPE_MIN_PIPELINE_STAGES);
+
+ if (tape->max_number_of_stages >= IDETAPE_MAX_PIPELINE_STAGES)
+ tape->max_number_of_stages = IDETAPE_MAX_PIPELINE_STAGES;
+
+#if IDETAPE_DEBUG
+ printk ("Maximum number of stages: %d\n",tape->max_number_of_stages);
+#endif /* IDETAPE_DEBUG */
+
+ return;
+}
+
+/*
+ * idetape_add_stage_tail adds a new stage at the end of the pipeline.
+ */
+
+void idetape_add_stage_tail (ide_drive_t *drive,idetape_pipeline_stage_t *stage)
+
+{
+ idetape_tape_t *tape=&(drive->tape);
+ unsigned long flags;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_add_stage_tail\n");
+#endif /* IDETAPE_DEBUG */
+
+ stage->next=NULL;
+
+#if IDETAPE_DEBUG
+ printk ("Adding to the tail of the pipeline\n");
+#endif /* IDETAPE_DEBUG */
+
+ /*
+ * Avoid a race condition - pipeline_locked is set whenever
+ * we modify active_data_request from the lower level of
+ * the driver. We wait until active_data_request is valid.
+ */
+
+ while (tape->pipeline_locked);
+
+ save_flags (flags);cli ();
+ stage->prev=tape->last_stage;
+ if (tape->first_stage != NULL)
+ tape->last_stage->next=stage;
+ else
+ tape->first_stage=stage;
+ tape->last_stage=stage;
+ tape->current_number_of_stages++;
+
+ /*
+ * Check if we are currently servicing requests in the bottom
+ * part of the driver.
+ *
+ * If not, wait for the pipeline to be full enough (75%) before
+ * starting to service requests, so that we will be able to
+ * keep up with the higher speeds of the tape.
+ */
+
+ if (tape->active_data_request == NULL &&
+ tape->current_number_of_stages >= 0.75*tape->max_number_of_stages) {
+
+ restore_flags (flags);
+ idetape_insert_pipeline_into_queue (drive);
+ }
+ else
+ restore_flags (flags);
+}
+
+/*
+ * idetape_insert_pipeline_into_queue is used to start servicing the
+ * pipeline stages.
+ */
+
+void idetape_insert_pipeline_into_queue (ide_drive_t *drive)
+
+{
+ idetape_tape_t *tape=&(drive->tape);
+
+ if (tape->first_stage == NULL)
+ return;
+
+ if (tape->active_data_request == NULL) {
+ idetape_active_next_stage (drive);
+#if IDETAPE_DEBUG
+ printk ("Using ide_end\n");
+#endif /* IDETAPE_DEBUG */
+ (void) (ide_do_drive_cmd (drive,tape->active_data_request,ide_end));
+ return;
+ }
+}
+
+/*
+ * idetape_active_next_stage will "move the pipeline" one stage -
+ * Inserting the first stage into the "active place", and using kfree
+ * to free the stage.
+ */
+
+void idetape_active_next_stage (ide_drive_t *drive)
+
+{
+ idetape_tape_t *tape=&(drive->tape);
+ idetape_pipeline_stage_t *stage;
+ struct request *rq;
+ unsigned long flags;
+
+#if IDETAPE_DEBUG
+ printk ("Reached idetape_active_next_stage\n");
+ if (tape->first_stage == NULL) {
+ printk ("ide-tape: ide-tape.c bug - tape->first_stage is NULL\n");
+ return;
+ }
+#endif /* IDETAPE_DEBUG */
+
+ stage=tape->first_stage;
+
+ idetape_copy_buffer_from_stage (stage,tape->data_buffer);
+ rq=idetape_next_rq_storage (drive);
+ *rq=stage->rq;
+ rq->buffer=tape->data_buffer;
+
+ save_flags (flags);cli ();
+ tape->first_stage=stage->next;
+ if (tape->first_stage == NULL)
+ tape->last_stage=NULL;
+ tape->current_number_of_stages--;
+ tape->active_data_request=rq;
+ restore_flags (flags);
+
+ idetape_kfree_stage (stage);
+}
/*
- * linux/drivers/block/ide-tape.h Version 1.0 - ALPHA Dec 3, 1995
+ * linux/drivers/block/ide-tape.h Version 1.1 - ALPHA Dec 14, 1995
*
* Copyright (C) 1995 Gadi Oxman <tgud@tochnapc2.technion.ac.il>
*/
/**************************** Tunable parameters *****************************/
+/*
+ * This is probably the most important configuration option.
+ *
+ * Pipelined operation mode has the potential to maximize the
+ * performance of the driver and thus to saturate the throughput
+ * to the maximum value supported by the tape. Currently, pipelined
+ * mode is supported only on writes.
+ *
+ * In pipelined mode we are servicing requests without blocking the
+ * user backup program. For example, on a write request, we will add it
+ * to the pipeline and return without waiting for it to complete. The
+ * user program will then have enough time to prepare the next blocks
+ * while the tape is still busy working on the previous requests.
+ *
+ * Pipelined (write) operation mode is enabled by default, but since
+ * it has a few downfalls as well (Use of additional memory and deferred
+ * error code to the application), you may wish to disable it.
+ * Further explanation of pipelined mode is available in ide-tape.c .
+ */
+
+#define IDETAPE_PIPELINE 1
+
+/*
+ * Pipelined mode parameters.
+ *
+ * We try to use the minimum number of stages which is enough to
+ * keep the tape constantly streaming. To accomplish that, we implement
+ * a feedback loop around the maximum number of stages:
+ *
+ * We start from MIN maximum stages (we will not even use MIN stages
+ * if we don't need them), increment it by RATE*(MAX-MIN)
+ * whenever we sense that the pipeline is empty, until we reach
+ * the optimum value or until we reach MAX.
+ */
+
+#define IDETAPE_MIN_PIPELINE_STAGES 100
+#define IDETAPE_MAX_PIPELINE_STAGES 200
+#define IDETAPE_INCREASE_STAGES_RATE 0.2
+
+/*
+ * It seems that dynamically allocating buffers of about 32KB
+ * each is doomed to fail, unless we are in or very near the
+ * initialization stage. Take care when changing this value, as it
+ * is now optimized with the design of kmalloc, so that we will not
+ * allocate parts of a page. Setting the size to 512 bytes, for example,
+ * would cause kmalloc to allocate for us 1024 bytes, and to
+ * unnecessarily waste double amount of memory.
+ */
+
+#if PAGE_SIZE == 4096
+ #define IDETAPE_ALLOCATION_BLOCK 500
+#elif PAGE_SIZE == 8192
+ #define IDETAPE_ALLOCATION_BLOCK 496
+#else /* ??? Not defined by linux/mm/kmalloc.c */
+ #define IDETAPE_ALLOCATION_BLOCK 512
+#endif
+
/*
* Setting IDETAPE_DEBUG to 1 will:
*
#define IDETAPE_MAX_PC_RETRIES 2
-/*
- * In case the tape is not at the requested block, we re-position the
- * tape. Repeat the procedure for IDETAPE_LOCATE_RETRIES times before
- * we give up and abort the request. Note that this should not usually
- * happen when using only the character device interface.
- */
-
-#define IDETAPE_LOCATE_RETRIES 1
-
/*
* With each packet command, we allocate a buffer of
* IDETAPE_TEMP_BUFFER_SIZE bytes. This is used for several packet
* the handling of a specific request.
*
* Follows a worse case calculation of the required storage, with a
- * large safety margin. Hopefully. :-)
+ * large safety margin.
*/
-#define IDETAPE_PC_STACK 10+\
- IDETAPE_MAX_PC_RETRIES+\
- 3*IDETAPE_LOCATE_RETRIES*IDETAPE_MAX_PC_RETRIES
+#define IDETAPE_PC_STACK 20+IDETAPE_MAX_PC_RETRIES
+
/*
- * Media access packet command (like the LOCATE command) have immediate
- * status with a delayed (and usually long) execution. The tape doesn't
- * issue an interrupt when the command is actually complete (so that the
- * bus is freed to use the other IDE device on the same interface), so we
- * must for poll for this event.
+ * DSC polling parameters.
+ *
+ * Polling for DSC (a single bit in the status register) is a very
+ * important function in ide-tape. There are two cases in which we
+ * poll for DSC:
+ *
+ * 1. Before a read/write packet command, to ensure that we
+ * can transfer data from/to the tape's data buffers, without
+ * causing an actual media access. In case the tape is not
+ * ready yet, we take out our request from the device
+ * request queue, so that ide.c will service requests from
+ * the other device on the same interface meanwhile.
*
- * We set a timer with polling frequency of 1/IDETAPE_DSC_MEDIA_ACCESS_FREQUENCY
- * in this case. We also poll for DSC *before* read/write commands. At
- * this time the DSC role is changed and instead of signalling command
- * completion, it will signal buffer availability. Since read/write
- * commands are fast in comparision to media access commands, the polling
- * frequency here should be much higher.
+ * The polling frequency is 1/IDETAPE_DSC_READ_WRITE_FREQUENCY,
+ * and it should be relatively fast. The default is a period
+ * of 50 msec.
*
- * We will insist of reading DSC=1 for IDETAPE_DSC_COUNT times in a row,
- * to accommodate for random fluctuations in the sampling of DSC.
- * We will also set IDETAPE_DSC_POLLING_FREQUENCY to a rather low
- * frequency which besides freeing the CPU and the bus will let
- * random fluctuations a time to settle down.
+ * 2. After the successful initialization of a "media access
+ * packet command", which is a command which can take a long
+ * time to complete (it can be several seconds or even an hour).
*
+ * Again, we postpone our request in the middle to free the bus
+ * for the other device. The polling frequency here should be
+ * lower than the read/write frequency since those media access
+ * commands are slow. We start from a "fast" frequency -
+ * IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY (one second), and
+ * if we don't receive DSC after IDETAPE_FAST_SLOW_THRESHOLD
+ * (5 minutes), we switch it to a lower frequency -
+ * IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY (1 minute).
+ *
* We also set a timeout for the timer, in case something goes wrong.
* The timeout should be longer then the maximum execution time of a
* tape operation. I still have to measure exactly how much time does
* it take to space over a far filemark, etc. It seemed that 15 minutes
* was way too low, so I am meanwhile setting it to a rather large
- * timeout - 2 Hours.
+ * timeout - 2 Hours ...
*
- * Once we pass a threshold, the polling frequency will change to
- * a slow frequency: On relatively fast operations, there is a point
- * in polling fast, but if we sense that the operation is taking too
- * much time, we will poll at a lower frequency.
*/
+#define IDETAPE_DSC_READ_WRITE_FREQUENCY 5*HZ/100 /* 50 msec */
#define IDETAPE_DSC_FAST_MEDIA_ACCESS_FREQUENCY 1*HZ /* 1 second */
#define IDETAPE_FAST_SLOW_THRESHOLD 5*60*HZ /* 5 minutes */
#define IDETAPE_DSC_SLOW_MEDIA_ACCESS_FREQUENCY 60*HZ /* 1 minute */
-#define IDETAPE_DSC_READ_WRITE_FREQUENCY HZ/20 /* 50 msec */
#define IDETAPE_DSC_TIMEOUT 2*60*60*HZ /* 2 hours */
-#define IDETAPE_DSC_COUNT 1 /* Assume no DSC fluctuations */
-
-/*
- * As explained in many places through the code, we provide both a block
- * device and a character device interface to the tape. The block device
- * interface is needed for compatibility with ide.c. The character device
- * interface is the higher level of the driver, and passes requests
- * to the lower part of the driver which interfaces with ide.c.
- * Using the block device interface, we can bypass this high level
- * of the driver, talking directly with the lower level part.
- *
- * It is intended that the character device interface will be used by
- * the user. To prevent mistakes in this regard, opening of the block
- * device interface will be refused if ALLOW_OPENING_BLOCK_DEVICE is 0.
- *
- * Do not change the following parameter unless you are developing
- * the driver itself.
- */
-
-#define IDETAPE_ALLOW_OPENING_BLOCK_DEVICE 0
/*************************** End of tunable parameters ***********************/
byte reserved19;
} idetape_capabilities_page_t;
+/*
+ * A pipeline stage contains several small buffers of type
+ * idetape_buffer_head_t. This is necessary since dynamical allocation
+ * of large (32 KB or so) continuous memory blocks will usually fail.
+ */
+
+typedef struct idetape_buffer_head_s {
+ char *data; /* Pointer to data (512 bytes by default) */
+ struct idetape_buffer_head_s *next;
+} idetape_buffer_head_t;
+
+/*
+ * A pipeline stage.
+ *
+ * In a pipeline stage we have a request, pointer to a list of small
+ * buffers, and pointers to the near stages.
+ */
+
+typedef struct idetape_pipeline_stage_s {
+ struct request rq; /* The correspoding request */
+ idetape_buffer_head_t *bh; /* The data buffers */
+ struct idetape_pipeline_stage_s *next,*prev; /* Pointers to the next and previous stages */
+} idetape_pipeline_stage_t;
+
/*
* Most of our global data which we need to save even as we leave the
* driver due to an interrupt or a timer event is stored in a variable
* another ide block device which receives requests and completes
* them.
*
- * However, our requests usually don't originate in the buffer
- * cache but rather in ide-tape.c itself. Here we provide safe
- * storage for such requests.
+ * However, our requests don't originate in the buffer cache but
+ * rather in ide-tape.c itself. Here we provide safe storage for
+ * such requests.
*/
struct request rq_stack [IDETAPE_PC_STACK];
/*
* While polling for DSC we use postponed_rq to postpone the
* current request so that ide.c will be able to service
- * pending requests on the other device.
+ * pending requests on the other device. Note that at most
+ * we will have only one DSC (usually data transfer) request
+ * in the device request queue. Additional request can be
+ * queued in our internal pipeline, but they will be visible
+ * to ide.c only one at a time.
*/
struct request *postponed_rq;
- byte dsc_count;
- unsigned long dsc_polling_start;
+
+ /*
+ * DSC polling variables.
+ */
+
+ byte dsc_count; /* We received DSC dsc_count times in a row */
+ unsigned long dsc_polling_start; /* The time in which we started polling for DSC */
struct timer_list dsc_timer; /* Timer used to poll for dsc */
- unsigned long dsc_polling_frequency;
+ unsigned long dsc_polling_frequency; /* The current polling frequency */
unsigned long dsc_timeout; /* Maximum waiting time */
- byte dsc_received;
+ byte dsc_received; /* Set when we receive DSC */
+ byte request_status;
+ byte request_dsc_callback;
+ byte last_status; /* Contents of the tape status register */
+ /* before the current request (saved for us */
+ /* by ide.c) */
/* Position information */
byte partition_num; /* Currently not used */
unsigned long block_address; /* Current block */
byte block_address_valid; /* 0 When the tape position is unknown */
/* (To the tape or to us) */
- unsigned long locate_to; /* We want to reach this block, as a part */
- /* of handling the current request */
- byte locate_retries; /* Each time, increase locate_retries */
-
- unsigned long last_written_block; /* Once writing started, we don't allow read */
- byte last_written_valid; /* access beyond the last written block */
- /* ??? Should I remove this ? */
-
/* Last error information */
byte sense_key,asc,ascq;
/* Character device operation */
unsigned char last_dt_was_write; /* Last character device data transfer was a write */
- byte busy; /* Device already opened */
+ byte busy; /* Device already opened */
/* Device information */
- unsigned short tape_block_size;
- idetape_capabilities_page_t capabilities; /* Capabilities and Mechanical Page */
+ unsigned short tape_block_size; /* Usually 512 or 1024 bytes */
+ idetape_capabilities_page_t capabilities; /* Copy of the tape's Capabilities and Mechanical Page */
- /* Data buffer */
+ /*
+ * Active data transfer request parameters.
+ *
+ * At most, there is only one ide-tape originated data transfer
+ * request in the device request queue. This allows ide.c to
+ * easily service requests from the other device when we
+ * postpone our active request. In the pipelined operation
+ * mode, we use our internal pipeline structure to hold
+ * more data requests.
+ *
+ * The data buffer size is chosen based on the tape's
+ * recommendation.
+ */
- char *data_buffer;
+ struct request *active_data_request; /* Pointer to the request which is waiting in the device request queue */
+ char *data_buffer; /* The correspoding data buffer (for read/write requests) */
+ int data_buffer_size; /* Data buffer size (chosen based on the tape's recommendation */
+ char *temp_data_buffer; /* Temporary buffer for user <-> kernel space data transfer */
+ /*
+ * Pipeline parameters.
+ *
+ * To accomplish non-pipelined mode, we simply set the following
+ * variables to zero (or NULL, where appropriate).
+ */
+
+ int current_number_of_stages; /* Number of currently used stages */
+ int max_number_of_stages; /* We will not allocate more than this number of stages */
+ idetape_pipeline_stage_t *first_stage; /* Will be serviced after the currently active request */
+ idetape_pipeline_stage_t *last_stage; /* New write requests will be added to the pipeline here */
+ int pipeline_was_full_once; /* Set at the first time we fill the pipeline since the tape was opened */
+ int error_in_pipeline_stage; /* Set when an error was detected in one of the pipeline stages */
+ int pipeline_locked; /* Against race conditions ... */
+
} idetape_tape_t;
+#define POLL_HWIF_TAPE_DRIVE \
+ if (hwif->tape_drive != NULL) { \
+ if (hwif->tape_drive->tape.request_status) { \
+ OUT_BYTE(hwif->tape_drive->select.all,IDE_SELECT_REG); \
+ hwif->tape_drive->tape.last_status=GET_STAT(); \
+ hwif->tape_drive->tape.request_status=0; \
+ } \
+ if (hwif->tape_drive->tape.request_dsc_callback) { \
+ hwif->tape_drive->tape.request_dsc_callback=0; \
+ idetape_put_back_postponed_request(hwif->tape_drive); \
+ } \
+ }
+
#endif /* IDETAPE_H */
/*
- * linux/drivers/block/ide.c Version 5.22 Dec 10, 1995
+ * linux/drivers/block/ide.c Version 5.23 Dec 15, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
* generalized ide_do_drive_cmd() for tape/cdrom driver use
* Version 5.21 fix nasty cdrom/tape bug (ide_preempt was messed up)
* Version 5.22 fix ide_xlate_1024() to work with/without drive->id
+ * Version 5.23 miscellaneous touch-ups
*
* Driver compile-time options are in ide.h
*
* - add ioctls to get/set interface timings on various interfaces
* - add Promise Caching controller support from peterd@pnd-pc.demon.co.uk
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
+ * - add new HT6560B code from malafoss@snakemail.hut.fi
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
hwif->name[1] = 'd';
hwif->name[2] = 'e';
hwif->name[3] = '0' + h;
-
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ hwif->tape_drive = NULL;
+#endif /* CONFIG_BLK_DEV_IDETAPE */
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
static byte current_select = 0;
if (hwif->select != current_select) {
+ byte t;
unsigned long flags;
save_flags (flags);
cli();
(void) inb(0x3e6);
(void) inb(0x3e6);
(void) inb(0x3e6);
- (void) inb(0x3e6);
- outb(current_select,0x3e6);
+ /*
+ * Avoid clobbering existing bits at 0x3e6:
+ * bit5 (0x20) - disables fast interface speed
+ * bit0 (0x01) - enables secondary interface
+ * we don't touch any other bits
+ */
+ t = inb(0x3e6);
+ t &= (~0x21);
+ t |= (current_select & 0x21);
+ outb(t,0x3e6);
restore_flags (flags);
}
}
} else {
if (drive->media == ide_disk && (stat & ERR_STAT)) {
/* err has different meaning on cdrom and tape */
- if (err & BBD_ERR) /* retries won't help this! */
+ if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */
rq->errors = ERROR_MAX;
else if (err & TRK0_ERR) /* help it find track zero */
rq->errors |= ERROR_RECAL;
if (rq->cmd == IDE_DRIVE_CMD) {
byte *args = rq->buffer;
if (args) {
+#ifdef DEBUG
printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n",
drive->name, args[0], args[1], args[2]);
+#endif
OUT_BYTE(args[2],io_base+IDE_FEATURE_OFFSET);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
if (hwif->select)
ide_hwif_select (hwif);
#endif
+
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ POLL_HWIF_TAPE_DRIVE; /* macro from ide-tape.h */
+#endif /* CONFIG_BLK_DEV_IDETAPE */
+
OUT_BYTE(drive->select.all,IDE_SELECT_REG);
if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {
printk("%s: drive not ready for command\n", drive->name);
return;
}
+
if (!drive->special.all) {
#ifdef CONFIG_BLK_DEV_IDEATAPI
switch (drive->media) {
* returns without waiting for the new rq to be completed. As above,
* This is VERY DANGEROUS, and is intended for careful use by the
* ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
+ * when operating in the pipelined operation mode).
*/
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action)
{
if (action != ide_preempt)
bdev->request_fn();
} else {
- if (action == ide_wait) {
+ if (action == ide_wait || action == ide_end) {
while (cur_rq->next != NULL) /* find end of list */
cur_rq = cur_rq->next;
}
check_disk_change(inode->i_rdev);
ide_init_drive_cmd (&rq);
rq.buffer = door_lock;
- return ide_do_drive_cmd(drive, &rq, ide_wait);
+ /*
+ * Ignore the return code from door_lock,
+ * since the open() has already succeeded,
+ * and the door_lock is irrelevant at this point.
+ */
+ (void) ide_do_drive_cmd(drive, &rq, ide_wait);
}
return 0;
}
return 0;
}
-static void fixstring (byte *s, const int bytecount, const int byteswap)
+void ide_fixstring (byte *s, const int bytecount, const int byteswap)
{
byte *p = s, *end = &s[bytecount & ~1]; /* bytecount must be even */
|| (id->model[0] == 'P' && id->model[1] == 'i'))/* Pioneer */
bswap = 0; /* Vertos drives may still be weird */
}
- fixstring (id->model, sizeof(id->model), bswap);
- fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
- fixstring (id->serial_no, sizeof(id->serial_no), bswap);
+ ide_fixstring (id->model, sizeof(id->model), bswap);
+ ide_fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
+ ide_fixstring (id->serial_no, sizeof(id->serial_no), bswap);
/*
* Check for an ATAPI device
/*
* Using 0x1c and 0x1d apparently selects a
* faster interface speed than 0x3c and 0x3d.
+ * (bit5 (0x20) selects fast speed when set)
+ * (bit0 (0x01) selects second interface)
*
- * Need to add an ioctl to select between them.
+ * Need to set these per-drive, rather than
+ * per-hwif, and also add an ioctl to select
+ * between them.
*/
if (check_region(0x3e6,1)) {
printk(" -- HT6560 PORT 0x3e6 ALREADY IN USE");
goto done;
}
request_region(0x3e6, 1, hwif->name);
- ide_hwifs[0].select = 0x3c;
+ ide_hwifs[0].select = 0x1c;
ide_hwifs[1].select = 0x3d;
goto do_serialize;
#endif /* SUPPORT_HT6560B */
return 0;
if (drive->id) {
- drive->bios_cyl = drive->id->cyls;
- drive->bios_head = drive->id->heads;
- drive->bios_sect = drive->id->sectors;
+ drive->cyl = drive->id->cyls;
+ drive->head = drive->id->heads;
+ drive->sect = drive->id->sectors;
}
- drive->cyl = drive->bios_cyl;
- drive->head = drive->bios_head;
- drive->sect = drive->bios_sect;
+ drive->bios_cyl = drive->cyl;
+ drive->bios_head = drive->head;
+ drive->bios_sect = drive->sect;
drive->special.b.set_geometry = 1;
tracks = drive->bios_cyl * drive->bios_head * drive->bios_sect / 63;
struct request request_sense_request; /* from ide-cd.c */
struct packet_command request_sense_pc; /* from ide-cd.c */
#endif /* CONFIG_BLK_DEV_IDECD */
+#ifdef CONFIG_BLK_DEV_IDETAPE
+ ide_drive_t *tape_drive; /* Pointer to the tape on this interface */
+#endif /* CONFIG_BLK_DEV_IDETAPE */
} ide_hwif_t;
/*
*/
void ide_error (ide_drive_t *drive, const char *msg, byte stat);
+/*
+ * ide_fixstring() cleans up and (optionally) byte-swaps a text string,
+ * removing leading/trailing blanks and compressing internal blanks.
+ * It is primarily used to tidy up the model name/number fields as
+ * returned by the WIN_[P]IDENTIFY commands.
+ */
+void ide_fixstring (byte *s, const int bytecount, const int byteswap);
+
/*
* This routine busy-waits for the drive status to be not "busy".
* It then checks the status for all of the "good" bits and none
typedef enum
{ide_wait, /* insert rq at end of list, and wait for it */
ide_next, /* insert rq immediately after current request */
- ide_preempt} /* insert rq in front of current request */
+ ide_preempt, /* insert rq in front of current request */
+ ide_end} /* insert rq at end of list, but don't wait for it */
ide_action_t;
/*
* returns without waiting for the new rq to be completed. As above,
* This is VERY DANGEROUS, and is intended for careful use by the
* ATAPI tape/cdrom driver code.
+ *
+ * If action is ide_end, then the rq is queued at the end of the
+ * request queue, and the function returns immediately without waiting
+ * for the new rq to be completed. This is again intended for careful
+ * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c,
+ * when operating in the pipelined operation mode).
*/
int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action);
void idetape_register_chrdev (void);
+/*
+ * The following function is called to re-insert a postponed tape
+ * request into the request queue.
+ */
+
+void idetape_put_back_postponed_request (ide_drive_t *drive);
+
#endif /* CONFIG_BLK_DEV_IDETAPE */
#ifdef CONFIG_BLK_DEV_TRITON
req->next = NULL;
}
memset(ro_bits,0,sizeof(ro_bits));
+ rd_init();
#ifdef CONFIG_BLK_DEV_IDE
ide_init(); /* this MUST preceed hd_init */
#endif
+++ /dev/null
-/*
- * linux/kernel/blk_drv/ramdisk.c
- *
- * Written by Theodore Ts'o, 12/2/91
- *
- * Modifications by Fred N. van Kempen to allow for bootable root
- * disks (which are used in LINUX/Pro). Also some cleanups. 03/03/93
- */
-
-
-#include <linux/sched.h>
-#include <linux/minix_fs.h>
-#include <linux/ext2_fs.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-
-#include <asm/system.h>
-#include <asm/segment.h>
-
-#define MAJOR_NR MEM_MAJOR
-#include <linux/blk.h>
-
-#define RAMDISK_MINOR 1
-
-extern void wait_for_keypress(void);
-
-char *rd_start;
-int rd_length = 0;
-static int rd_blocksizes[2] = {0, 0};
-
-static void do_rd_request(void)
-{
- int len;
- char *addr;
-
-repeat:
- INIT_REQUEST;
- addr = rd_start + (CURRENT->sector << 9);
- len = CURRENT->current_nr_sectors << 9;
-
- if ((MINOR(CURRENT->rq_dev) != RAMDISK_MINOR) ||
- (addr+len > rd_start+rd_length)) {
- end_request(0);
- goto repeat;
- }
- if (CURRENT-> cmd == WRITE) {
- (void ) memcpy(addr,
- CURRENT->buffer,
- len);
- } else if (CURRENT->cmd == READ) {
- (void) memcpy(CURRENT->buffer,
- addr,
- len);
- } else
- panic("RAMDISK: unknown RAM disk command !\n");
- end_request(1);
- goto repeat;
-}
-
-static struct file_operations rd_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- NULL, /* ioctl */
- NULL, /* mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- block_fsync /* fsync */
-};
-
-/*
- * Returns amount of memory which needs to be reserved.
- */
-long rd_init(long mem_start, int length)
-{
- int i;
- char *cp;
-
- if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) {
- printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR);
- return 0;
- }
- blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST;
- rd_start = (char *) mem_start;
- rd_length = length;
- cp = rd_start;
- for (i=0; i < length; i++)
- *cp++ = '\0';
-
- for(i=0;i<2;i++) rd_blocksizes[i] = 1024;
- blksize_size[MAJOR_NR] = rd_blocksizes;
-
- return(length);
-}
-
-static void do_load(void)
-{
- struct buffer_head *bh;
- struct super_block {
- union
- {
- char minix [sizeof (struct minix_super_block)];
- char ext2 [sizeof (struct ext2_super_block)];
- } record;
- } sb;
- struct minix_super_block *minixsb =
- (struct minix_super_block *)&sb;
- struct ext2_super_block *ext2sb =
- (struct ext2_super_block *)&sb;
- int block, tries;
- int i = 1;
- int nblocks;
- char *cp;
-
- /*
- * Check for a super block on the diskette.
- * The old-style boot/root diskettes had their RAM image
- * starting at block 512 of the boot diskette. LINUX/Pro
- * uses the entire diskette as a file system, so in that
- * case, we have to look at block 0. Be intelligent about
- * this, and check both... - FvK
- */
- for (tries = 0; tries < 1000; tries += 512) {
- block = tries;
- bh = breada(ROOT_DEV,block+1,BLOCK_SIZE, 0, PAGE_SIZE);
- if (!bh) {
- printk("RAMDISK: I/O error while looking for super block!\n");
- return;
- }
-
- /* This is silly- why do we require it to be a MINIX FS? */
- *((struct super_block *) &sb) =
- *((struct super_block *) bh->b_data);
- brelse(bh);
-
-
- /* Try Minix */
- nblocks = -1;
- if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
- minixsb->s_magic == MINIX_SUPER_MAGIC2) {
- printk("RAMDISK: Minix filesystem found at block %d\n",
- block);
- nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
- }
-
- /* Try ext2 */
- if (nblocks == -1 && ext2sb->s_magic == EXT2_SUPER_MAGIC)
- {
- printk("RAMDISK: Ext2 filesystem found at block %d\n",
- block);
- nblocks = ext2sb->s_blocks_count;
- }
-
- if (nblocks == -1)
- {
- printk("RAMDISK: trying old-style RAM image.\n");
- continue;
- }
-
- if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) {
- printk("RAMDISK: image too big! (%d/%d blocks)\n",
- nblocks, rd_length >> BLOCK_SIZE_BITS);
- return;
- }
- printk("RAMDISK: Loading %d blocks into RAM disk", nblocks);
-
- /* We found an image file system. Load it into core! */
- cp = rd_start;
- while (nblocks) {
- if (nblocks > 2)
- bh = breada(ROOT_DEV, block, BLOCK_SIZE, 0, PAGE_SIZE);
- else
- bh = bread(ROOT_DEV, block, BLOCK_SIZE);
- if (!bh) {
- printk("RAMDISK: I/O error on block %d, aborting!\n",
- block);
- return;
- }
- (void) memcpy(cp, bh->b_data, BLOCK_SIZE);
- brelse(bh);
- if (!(nblocks-- & 15)) printk(".");
- cp += BLOCK_SIZE;
- block++;
- i++;
- }
- printk("\ndone\n");
-
- /* We loaded the file system image. Prepare for mounting it. */
- ROOT_DEV = MKDEV(MEM_MAJOR, RAMDISK_MINOR);
- return;
- }
-}
-
-/*
- * If the root device is the RAM disk, try to load it.
- * In order to do this, the root device is originally set to the
- * floppy, and we later change it to be RAM disk.
- */
-void rd_load(void)
-{
- struct inode inode;
- struct file filp;
-
- /* If no RAM disk specified, give up early. */
- if (!rd_length)
- return;
- printk("RAMDISK: %d bytes, starting at 0x%p\n",
- rd_length, rd_start);
-
- /* If we are doing a diskette boot, we might have to pre-load it. */
- if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR)
- return;
-
- /* for Slackware install disks */
- printk(KERN_NOTICE "VFS: Insert root floppy to be loaded into ramdisk and press ENTER\n");
- wait_for_keypress();
-
- memset(&filp, 0, sizeof(filp));
- memset(&inode, 0, sizeof(inode));
- inode.i_rdev = ROOT_DEV;
- filp.f_mode = 1; /* read only */
- filp.f_inode = &inode;
- if(blkdev_open(&inode, &filp) == 0 ){
- do_load();
- if(filp.f_op && filp.f_op->release)
- filp.f_op->release(&inode,&filp);
- }
-}
--- /dev/null
+/*
+ * ramdisk.c - Multiple ramdisk driver - gzip-loading version - v. 0.8 beta.
+ *
+ * (C) Chad Page, Theodore Ts'o, et. al, 1995.
+ *
+ * This ramdisk is designed to have filesystems created on it and mounted
+ * just like a regular floppy disk.
+ *
+ * It also does something suggested by Linus: use the buffer cache as the
+ * ramdisk data. This makes it possible to dynamically allocate the ramdisk
+ * buffer - with some consequences I have to deal with as I write this.
+ *
+ * This code is based on the original ramdisk.c, written mostly by
+ * Theodore Ts'o (TYT) in 1991. The code was largely rewritten by
+ * Chad Page to use the buffer cache to store the ramdisk data in
+ * 1995; Theodore then took over the driver again, and cleaned it up
+ * for inclusion in the mainline kernel.
+ *
+ * The original CRAMDISK code was written by Richard Lyons, and
+ * adapted by Chad Page to use the new ramdisk interface. Theodore
+ * Ts'o rewrote it so that both the compressed ramdisk loader and the
+ * kernel decompressor uses the same inflate.c codebase. The ramdisk
+ * loader now also loads into a dynamic (buffer cache based) ramdisk,
+ * not the old static ramdisk. Support for the old static ramdisk has
+ * been completely removed.
+ */
+
+#include <linux/sched.h>
+#include <linux/minix_fs.h>
+#include <linux/ext2_fs.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/malloc.h>
+#include <linux/ioctl.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+extern void wait_for_keypress(void);
+
+/*
+ * 35 has been officially registered as the RAMDISK major number, but
+ * so is the original MAJOR number of 1. We're using 1 in
+ * include/linux/major.h for now
+ */
+#define MAJOR_NR RAMDISK_MAJOR
+#include <linux/blk.h>
+
+#define BUILD_CRAMDISK
+#define NUM_RAMDISKS 8
+
+void rd_load(void);
+static int crd_load(struct file *fp, struct file *outfp);
+
+/* Various static variables go here... mostly used within the ramdisk code only. */
+
+static int rd_length[NUM_RAMDISKS];
+static int rd_blocksizes[NUM_RAMDISKS];
+
+/*
+ * Parameters for the boot-loading of the ramdisk. These are set by
+ * init/main.c (from arguments to the kernel command line) or from the
+ * architecture-specific setup routine (from the stored bootsector
+ * information).
+ */
+int rd_doload = 0; /* 1 = load ramdisk, 0 = don't load */
+int rd_prompt = 1; /* 1 = prompt for ramdisk, 0 = don't prompt */
+int rd_image_start = 0; /* starting block # of image */
+
+int rd_loading = 0;
+
+/*
+ * Basically, my strategy here is to set up a buffer-head which can't be
+ * deleted, and make that my Ramdisk. If the request is outside of the
+ * allocated size, we must get rid of it...
+ *
+ */
+static void rd_request(void)
+{
+ unsigned int minor;
+ int offset, len;
+
+repeat:
+ INIT_REQUEST;
+
+ minor = MINOR(CURRENT->rq_dev);
+
+ if (minor >= NUM_RAMDISKS) {
+ end_request(0);
+ goto repeat;
+ }
+
+ offset = CURRENT->sector << 9;
+ len = CURRENT->current_nr_sectors << 9;
+
+ if ((offset + len) > rd_length[minor]) {
+ end_request(0);
+ goto repeat;
+ }
+
+ if (CURRENT->cmd == READ) {
+ memset(CURRENT->buffer, 0, len);
+ }
+ set_bit(BH_Protected, &CURRENT->bh->b_state);
+
+ end_request(1);
+ goto repeat;
+}
+
+static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int err;
+
+ if (!inode || !inode->i_rdev)
+ return -EINVAL;
+
+ switch (cmd) {
+ case BLKFLSBUF:
+ if (!suser()) return -EACCES;
+ invalidate_buffers(inode->i_rdev);
+ break;
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EINVAL;
+ err = verify_area(VERIFY_WRITE, (long *) arg,
+ sizeof(long));
+ if (err)
+ return err;
+ put_user(rd_length[MINOR(inode->i_rdev)] / 512,
+ (long *) arg);
+ return 0;
+
+ default:
+ break;
+ };
+
+ return 0;
+}
+
+static int rd_open(struct inode * inode, struct file * filp)
+{
+
+ if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS)
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct file_operations fd_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - block dev write */
+ block_write, /* write - block dev write */
+ NULL, /* readdir - not here! */
+ NULL, /* select */
+ rd_ioctl, /* ioctl */
+ NULL, /* mmap */
+ rd_open, /* open */
+ NULL, /* no special release code... */
+ block_fsync /* fsync */
+};
+
+/* This is the registration and initialization section of the ramdisk driver */
+int rd_init(void)
+{
+ int i;
+
+ if (register_blkdev(MAJOR_NR, "ramdisk", &fd_fops)) {
+ printk("RAMDISK2 : Could not get major %d", MAJOR_NR);
+ return -EIO;
+ }
+
+ blk_dev[MAJOR_NR].request_fn = &rd_request;
+
+ for (i = 0; i < NUM_RAMDISKS; i++) {
+ rd_length[i] = (16384 * 1024);
+ rd_blocksizes[i] = 1024;
+ }
+
+ blksize_size[MAJOR_NR] = rd_blocksizes;
+
+ return 0;
+}
+
+/*
+ * This routine tries to a ramdisk image to load, and returns the
+ * number of blocks to read for a non-compressed image, 0 if the image
+ * is a compressed image, and -1 if an image with the right magic
+ * numbers could not be found.
+ *
+ * We currently check for the following magic numbers:
+ * minix
+ * ext2
+ * gzip
+ */
+int
+identify_ramdisk_image(int device, struct file *fp, int start_block)
+{
+ const int size = 512;
+ struct minix_super_block *minixsb;
+ struct ext2_super_block *ext2sb;
+ int nblocks = -1;
+ int max_blocks;
+ unsigned char *buf;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == 0)
+ return -1;
+
+ minixsb = (struct minix_super_block *) buf;
+ ext2sb = (struct ext2_super_block *) buf;
+ memset(buf, 0xe5, size);
+
+ /*
+ * Read block 0 to test for gzipped kernel
+ */
+ if (fp->f_op->lseek)
+ fp->f_op->lseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
+ fp->f_pos = start_block * BLOCK_SIZE;
+
+ fp->f_op->read(fp->f_inode, fp, buf, size);
+
+ /*
+ * If it matches the gzip magic numbers, return -1
+ */
+ if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
+ printk(KERN_NOTICE
+ "RAMDISK: Compressed image found at block %d\n",
+ start_block);
+ nblocks = 0;
+ goto done;
+ }
+
+ /*
+ * Read block 1 to test for minix and ext2 superblock
+ */
+ if (fp->f_op->lseek)
+ fp->f_op->lseek(fp->f_inode, fp,
+ (start_block+1) * BLOCK_SIZE, 0);
+ fp->f_pos = (start_block+1) * BLOCK_SIZE;
+
+ fp->f_op->read(fp->f_inode, fp, buf, size);
+
+ /* Try minix */
+ if (minixsb->s_magic == MINIX_SUPER_MAGIC ||
+ minixsb->s_magic == MINIX_SUPER_MAGIC2) {
+ printk(KERN_NOTICE
+ "RAMDISK: Minix filesystem found at block %d\n",
+ start_block);
+ nblocks = minixsb->s_nzones << minixsb->s_log_zone_size;
+ goto done;
+ }
+
+ /* Try ext2 */
+ printk("ext2 magic = %d\n", ext2sb->s_magic);
+ if (ext2sb->s_magic == EXT2_SUPER_MAGIC) {
+ printk(KERN_NOTICE
+ "RAMDISK: Ext2 filesystem found at block %d\n",
+ start_block);
+ nblocks = ext2sb->s_blocks_count;
+ goto done;
+ }
+ printk(KERN_NOTICE
+ "RAMDISK: Couldn't find valid ramdisk image starting at %d.\n",
+ start_block);
+
+done:
+ if (fp->f_op->lseek)
+ fp->f_op->lseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0);
+ fp->f_pos = start_block * BLOCK_SIZE;
+
+ if ((nblocks > 0) && blk_size[MAJOR(device)]) {
+ max_blocks = blk_size[MAJOR(device)][MINOR(device)];
+ max_blocks -= start_block;
+ if (nblocks > max_blocks) {
+ printk(KERN_NOTICE
+ "RAMDISK: Restricting filesystem size "
+ "from %d to %d blocks.\n",
+ nblocks, max_blocks);
+ nblocks = max_blocks;
+ }
+ }
+ kfree(buf);
+ return nblocks;
+}
+
+/*
+ * This routine loads in the ramdisk image.
+ */
+void rd_load()
+{
+ struct inode inode, out_inode;
+ struct file infile, outfile;
+ unsigned short fs;
+ int device, ram_device;
+ int nblocks, i;
+ char *buf;
+
+ if (rd_doload == 0)
+ return;
+
+ device = ROOT_DEV;
+ ram_device = (MAJOR_NR << 8);
+
+ if (MAJOR(device) != FLOPPY_MAJOR) return;
+
+ if (rd_prompt) {
+ printk(KERN_NOTICE
+ "VFS: Insert ramdisk floppy and press ENTER\n");
+ wait_for_keypress();
+ }
+
+ memset(&infile, 0, sizeof(infile));
+ memset(&inode, 0, sizeof(inode));
+ inode.i_rdev = device;
+ infile.f_mode = 1; /* read only */
+ infile.f_inode = &inode;
+
+ memset(&outfile, 0, sizeof(outfile));
+ memset(&out_inode, 0, sizeof(out_inode));
+ out_inode.i_rdev = ram_device;
+ outfile.f_mode = 3; /* read/write */
+ outfile.f_inode = &out_inode;
+
+ if (blkdev_open(&inode, &infile) != 0) return;
+ if (blkdev_open(&out_inode, &outfile) != 0) return;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ rd_loading = 1;
+
+ nblocks = identify_ramdisk_image(device, &infile, rd_image_start);
+ if (nblocks < 0)
+ goto done;
+
+ if (nblocks == 0) {
+#ifdef BUILD_CRAMDISK
+ if (crd_load(&infile, &outfile) == 0)
+ goto successful_load;
+#else
+ printk(KERN_NOTICE
+ "RAMDISK: Kernel does not support compressed "
+ "ramdisk images\n");
+#endif
+ goto done;
+ }
+
+ if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) {
+ printk("RAMDISK: image too big! (%d/%d blocks)\n",
+ nblocks, rd_length[0] >> BLOCK_SIZE_BITS);
+ goto done;
+ }
+
+ /*
+ * OK, time to copy in the data
+ */
+ buf = kmalloc(BLOCK_SIZE, GFP_KERNEL);
+ if (buf == 0) {
+ printk(KERN_ERR "RAMDISK: could not allocate buffer\n");
+ goto done;
+ }
+ for (i=0; i < nblocks; i++) {
+ infile.f_op->read(infile.f_inode, &infile, buf,
+ BLOCK_SIZE);
+ outfile.f_op->write(outfile.f_inode, &outfile, buf,
+ BLOCK_SIZE);
+ }
+ kfree(buf);
+
+successful_load:
+ invalidate_buffers(ROOT_DEV);
+ ROOT_DEV = (MAJOR_NR << 8);
+
+done:
+ if (infile.f_op->release)
+ infile.f_op->release(&inode, &infile);
+ set_fs(fs);
+ rd_loading = 0;
+}
+
+#ifdef BUILD_CRAMDISK
+
+#include <string.h>
+
+/*
+ * 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 exit_code = 0;
+static long bytes_out = 0;
+static struct file *crd_infp, *crd_outfp;
+
+#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 *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+#include "../../lib/inflate.c"
+
+static void *malloc(int size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+static void free(void *where)
+{
+ kfree(where);
+}
+
+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()
+{
+ if (exit_code) return -1;
+
+ insize = crd_infp->f_op->read(crd_infp->f_inode, crd_infp,
+ 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()
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, ch;
+
+ crd_outfp->f_op->write(crd_outfp->f_inode, crd_outfp, window,
+ outcnt);
+ 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)
+{
+ printk(KERN_ERR "%s", x);
+ exit_code = 1;
+}
+
+static int
+crd_load(struct file * fp, struct file *outfp)
+{
+ int result;
+
+ crd_infp = fp;
+ crd_outfp = outfp;
+ inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
+ if (inbuf == 0) {
+ printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n");
+ return -1;
+ }
+ window = kmalloc(WSIZE, GFP_KERNEL);
+ if (window == 0) {
+ printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n");
+ kfree(inbuf);
+ return -1;
+ }
+ makecrc();
+ result = gunzip();
+ kfree(inbuf);
+ kfree(window);
+ return result;
+}
+
+#endif
+
+
+
* - much better than its 1Gig cousin, this drive is reported to work
* very well with DMA (7.3MB/sec).
*
+ * Other drives:
+ *
+ * Maxtor 7540AV (515Meg w/32kB buffer), DMA modes mword0/sword2, PIO mode3.
+ * - a budget drive, with budget performance, around 3MB/sec.
+ *
+ * Western Digital AC2850F (814Meg w/64kB buffer), DMA mode1, PIO mode3.
+ * - another "caviar" drive, similar to the AC31000, except that this one
+ * worked with DMA in at least one system. Throughput is about 3.8MB/sec
+ * for both DMA and PIO.
+ *
+ * Conner CFS850A (812Meg w/64kB buffer), DMA mode2, PIO mode4.
+ * - like most Conner models, this drive proves that even a fast interface
+ * cannot improve slow media. Both DMA and PIO peak around 3.5MB/sec.
+ *
* If you have any drive models to add, email your results to: mlord@bnr.ca
* Keep an eye on /var/adm/messages for "DMA disabled" messages.
*
*/
#include <linux/major.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/segment.h>
#include <stdarg.h>
#include <linux/sbpcd.h>
+#include <linux/config.h>
#if !(SBPCD_ISSUE-1)
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
+Tue Dec 5 13:21:27 1995 <tytso@rsts-11.mit.edu>
+
+ * serial.c (check_modem_status, rs_ioctl): Support the new
+ ioctl()'s TIOCGICOUNT, TIOCMIWAIT. These allow an
+ application program to wait on a modem serial register
+ status bit change, and to find out how many changes have
+ taken place for the MSR bits.
+
+ (rs_write): Eliminate a race condition which is introduced
+ if it is necessary to wait for the semaphore.
+
Sat Nov 4 17:14:45 1995 <tytso@rsts-11.mit.edu>
* tty_io.c (tty_init): Move registration of TTY_MAJOR and
* Replaced dumb busy loop with udelay() 16 Nov 95
* Nathan Laredo <laredo@gnu.ai.mit.edu>
*
+ * Track I/O ports with request_region(). 12 Dec 95 Philip Blundell
*/
#include <linux/module.h>
#include <linux/mouse.h>
#include <linux/random.h>
#include <linux/delay.h>
+#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/segment.h>
return -EINVAL;
if (mouse.active++)
return 0;
- if (request_irq(mouse_irq, mouse_interrupt, 0, "Busmouse")) {
+ if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse")) {
mouse.active--;
return -EBUSY;
}
int bus_mouse_init(void)
{
- int i;
+ if (check_region(LOGIBM_BASE, LOGIBM_EXTENT)) {
+ mouse.present = 0;
+ return -EIO;
+ }
outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT);
}
outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT);
MSE_INT_OFF();
+
+ request_region(LOGIBM_BASE, LOGIBM_EXTENT, "busmouse");
+
mouse.present = 1;
mouse.active = 0;
mouse.ready = 0;
mouse.dx = 0;
mouse.dy = 0;
mouse.wait = NULL;
- printk("Logitech Bus mouse detected and installed with IRQ %d.\n",
+ printk("Logitech bus mouse detected, using IRQ %d.\n",
mouse_irq);
mouse_register(&bus_mouse);
return 0;
void cleanup_module(void)
{
mouse_deregister(&bus_mouse);
+ release_region(LOGIBM_BASE, LOGIBM_EXTENT);
}
#endif
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
*
+ * TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
status = serial_in(info, UART_MSR);
+ if (status & UART_MSR_ANY_DELTA) {
+ /* update input line counters */
+ if (status & UART_MSR_TERI)
+ info->icount.rng++;
+ if (status & UART_MSR_DDSR)
+ info->icount.dsr++;
+ if (status & UART_MSR_DDCD)
+ info->icount.dcd++;
+ if (status & UART_MSR_DCTS)
+ info->icount.cts++;
+ wake_up_interruptible(&info->delta_msr_wait);
+ }
+
if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
if (!tty || !info->xmit_buf || !tmp_buf)
return 0;
+ if (from_user)
+ down(&tmp_buf_sem);
save_flags(flags);
while (1) {
cli();
break;
if (from_user) {
- down(&tmp_buf_sem);
memcpy_fromfs(tmp_buf, buf, c);
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- up(&tmp_buf_sem);
} else
memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
count -= c;
total += c;
}
+ if (from_user)
+ up(&tmp_buf_sem);
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
int error;
struct async_struct * info = (struct async_struct *)tty->driver_data;
int retval;
+ struct async_icount cprev, cnow; /* kernel counter temps */
+ struct serial_icounter_struct *p_cuser; /* user space */
if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
return -ENODEV;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+ (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
case TIOCSERSETMULTI:
return set_multiport_struct(info,
(struct serial_multiport_struct *) arg);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ cli();
+ cprev = info->icount; /* note the counters on entry */
+ sti();
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ cli();
+ cnow = info->icount; /* atomic copy */
+ sti();
+ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_icounter_struct));
+ if (error)
+ return error;
+ cli();
+ cnow = info->icount;
+ sti();
+ p_cuser = (struct serial_icounter_struct *) arg;
+ put_user(cnow.cts, &p_cuser->cts);
+ put_user(cnow.dsr, &p_cuser->dsr);
+ put_user(cnow.rng, &p_cuser->rng);
+ put_user(cnow.dcd, &p_cuser->dcd);
+ return 0;
+
default:
return -ENOIOCTLCMD;
}
info->normal_termios = serial_driver.init_termios;
info->open_wait = 0;
info->close_wait = 0;
+ info->delta_msr_wait = 0;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
info->next_port = 0;
info->prev_port = 0;
if (info->irq == 2)
dev->hard_start_xmit = &ei_start_xmit;
dev->get_stats = get_stats;
-#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
-#endif
ether_setup(dev);
dev->hard_start_xmit = &de4x5_queue_pkt;
dev->stop = &de4x5_close;
dev->get_stats = &de4x5_get_stats;
-#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
-#endif
dev->do_ioctl = &de4x5_ioctl;
dev->mem_start = 0;
dev->hard_start_xmit = &ewrk3_queue_pkt;
dev->stop = &ewrk3_close;
dev->get_stats = &ewrk3_get_stats;
-#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
-#endif
dev->do_ioctl = &ewrk3_ioctl;
dev->mem_start = 0;
return &lp->stats;
}
-#ifdef HAVE_MULTICAST
/* Set or clear the multicast filter for this adaptor.
As a side effect this routine must also initialize the device parameters.
This is taken advantage of in open().
}
#endif
}
-#endif
void show_dma(void)
{
dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
dep_tristate 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
-bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380
+dep_tristate 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
if [ "$CONFIG_PCI" = "y" ]; then
dep_tristate 'NCR53c7,8xx SCSI support' CONFIG_SCSI_NCR53C7xx $CONFIG_SCSI
fi
dep_tristate 'Always IN2000 SCSI support (test release)' CONFIG_SCSI_IN2000 $CONFIG_SCSI
-bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16
+dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
dep_tristate 'QLOGIC SCSI support' CONFIG_SCSI_QLOGIC $CONFIG_SCSI
dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI
-bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128
+dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI
dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
MOD_LIST_NAME := SCSI_MODULES
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
-AHA152X = -DDEBUG_AHA152X -DAUTOCONF -DSKIP_BIOSTEST -DIRQ=11
+AHA152X = -DDEBUG_AHA152X -DAUTOCONF
ifeq (${CFLAGS},)
CFLAGS = -D__KERNEL__=1 \
ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),y)
L_OBJS += g_NCR5380.o
+else
+ ifeq ($(CONFIG_SCSI_GENERIC_NCR5380),m)
+ M_OBJS += g_NCR5380.o
+ endif
endif
ifeq ($(CONFIG_SCSI_NCR53C7xx),y)
ifeq ($(CONFIG_SCSI_PAS16),y)
L_OBJS += pas16.o
+else
+ ifeq ($(CONFIG_SCSI_PAS16),m)
+ M_OBJS += pas16.o
+ endif
endif
ifeq ($(CONFIG_SCSI_SEAGATE),y)
ifeq ($(CONFIG_SCSI_T128),y)
L_OBJS += t128.o
+else
+ ifeq ($(CONFIG_SCSI_T128),m)
+ M_OBJS += t128.o
+ endif
endif
ifeq ($(CONFIG_SCSI_ULTRASTOR),y)
This file contains brief information about the SCSI tape driver.
-Last modified: Sun Sep 24 23:40:06 1995 by root@kai.makisara.fi
+Last modified: Sun Nov 26 12:54:21 1995 by root@kai.makisara.fi
BASICS
The buffer size is defined (in 1024 byte units) by ST_BUFFER_BLOCKS or
at boot time. If this size is not enough, the driver tries to allocate
a large enough temporary buffer that is released when the device is
-closed.
+closed. The maximum buffer size is defined by the kernel memory
+allocation (currently 256 kB for Alphas and 128 kB for other
+architectures).
+
+Allocation of the buffers is done at run-time when they are
+needed. Allocation of the specified number of buffers can be done at
+initialization if ST_RUNTIME_BUFFERS is defined non-zero. The
+advantage of run-time allocation is that memory is not wasted for
+buffers not being used. The disadvantage is that there may not be
+memory available at the time when a buffer is needed for the first
+time (once a buffer is allocated, it is not released).
The maximum number of buffers allocated at initialization is defined by
ST_MAX_BUFFERS. One buffer is allocated for each drive detected when
default for ST_EXTRA_DEVS is two. The driver tries to allocate new
buffers at run-time if necessary.
-Allocation of the buffers can be postponed to run-time if
-(ST_RUNTIME_BUFFERS). The advantage is that memory is not wasted for
-buffers not being used. The disadvantage is that there may not be
-memory available at the time when a buffer is needed for the first
-time (once a buffer is allocated, it is not released).
-
The threshold for triggering asynchronous write in fixed block mode
-is defined by ST_WRITE_THRESHOLD.
+is defined by ST_WRITE_THRESHOLD. This may be optimized for each
+use pattern. The default triggers asynchronous write after three
+default sized writes (10 kB) from tar.
BOOT TIME CONFIGURATION
/* aha152x.c -- Adaptec AHA-152x driver
- * Author: Juergen E. Fischer, fischer@server.et-inf.fho-emden.de
- * Copyright 1993, 1994 Juergen E. Fischer
+ * Author: Juergen E. Fischer, fischer@et-inf.fho-emden.de
+ * Copyright 1993, 1994, 1995 Juergen E. Fischer
*
*
* This driver is based on
* which is
* Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
*
-
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, 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.
-
*
- * $Id: aha152x.c,v 1.9 1995/03/18 09:20:24 root Exp root $
*
-
+ * $Id: aha152x.c,v 1.11 1995/12/06 21:18:35 fischer Exp $
+ *
* $Log: aha152x.c,v $
+ * Revision 1.11 1995/12/06 21:18:35 fischer
+ * - some minor updates
+ *
+ * Revision 1.10 1995/07/22 19:18:45 fischer
+ * - support for 2 controllers
+ * - started synchronous data transfers (not working yet)
+ *
* Revision 1.9 1995/03/18 09:20:24 root
* - patches for PCMCIA and modules
*
* Revision 0.0 1993/08/14 19:54:25 root
* empty function bodies; detect() works.
*
-
+ *
**************************************************************************
PER-DEFINE CONFIGURABLE OPTIONS:
- AUTOCONF : use configuration the controller reports (only 152x)
- IRQ : override interrupt channel (9,10,11 or 12) (default 11)
- SCSI_ID : override scsiid of AIC-6260 (0-7) (default 7)
- RECONNECT : override target dis-/reconnection/multiple outstanding commands (default on)
- PARITY : override parity check (default on)
- SKIP_BIOSTEST : Don't test for BIOS signature (AHA-1510 or disabled BIOS)
- PORTBASE : Force port base. Don't try to probe
+ AUTOCONF:
+ use configuration the controller reports (only 152x)
+
+ SKIP_BIOSTEST:
+ Don't test for BIOS signature (AHA-1510 or disabled BIOS)
+
+ SETUP0 { IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS }:
+ override for the first controller
+
+ SETUP1 { IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS }:
+ override for the second controller
LILO COMMAND LINE OPTIONS:
- aha152x=<PORTBASE>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>]]]]
+ aha152x=<IOPORT>[,<IRQ>[,<SCSI-ID>[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>]]]]]
The normal configuration can be overridden by specifying a command line.
When you do this, the BIOS test is skipped. Entered values have to be
- valid (known). Don't use values that aren't support under normal operation.
- If you think that you need other values: contact me.
+ valid (known). Don't use values that aren't supported under normal operation.
+ If you think that you need other values: contact me. For two controllers
+ use the aha152x statement twice.
REFERENCES USED:
#include <linux/proc_fs.h>
#include "aha152x.h"
-#include<linux/stat.h>
+#include <linux/stat.h>
struct proc_dir_entry proc_scsi_aha152x = {
PROC_SCSI_AHA152X, 7, "aha152x",
#endif
#endif
-/* If auto configuration is disabled, IRQ, SCSI_ID and RECONNECT have to
- be predefined */
-#if !defined(AUTOCONF)
-#if !defined(IRQ)
-#error undefined IRQ; define AUTOCONF or IRQ
-#endif
-#if !defined(SCSI_ID)
-#error undefined SCSI_ID; define AUTOCONF or SCSI_ID
-#endif
-#if !defined(RECONNECT)
-#error undefined RECONNECT; define AUTOCONF or RECONNECT
+#if !defined(AUTOCONF) && !defined(SETUP0)
+#error define AUTOCONF or SETUP0
#endif
-#if !defined(PARITY)
-#error undefined PARITY; define AUTOCONF or PARITY
-#endif
-#endif
-
-/* I use this when I'm looking for weird bugs */
-#define DEBUG_TIMING
#if defined(DEBUG_AHA152X)
#if 0
#endif
+#define DEBUG_SELECTION
#define DEBUG_PHASES
#define DEBUG_RESET
#define DEBUG_ABORT
/* END OF DEFINES */
+extern long loops_per_sec;
+
/* some additional "phases" for getphase() */
#define P_BUSFREE 1
#define P_PARITY 2
-static int port_base = 0;
-static int this_host = 0;
-static int can_disconnect = 0;
-static int can_doparity = 0;
-static int commands = 0;
+/* possible irq range */
+#define IRQ_MIN 9
+#define IRQ_MAX 12
+#define IRQS IRQ_MAX-IRQ_MIN+1
-#ifdef DEBUG_AHA152X
-unsigned int aha152x_debug = DEBUG_DEFAULT;
-#endif
+enum {
+ not_issued = 0x0001,
+ in_selection = 0x0002,
+ disconnected = 0x0004,
+ aborted = 0x0008,
+ sent_ident = 0x0010,
+ in_other = 0x0020,
+ in_sync = 0x0040,
+ sync_ok = 0x0080,
+};
/* set by aha152x_setup according to the command line */
-static int setup_called = 0;
-static int setup_portbase = 0;
-static int setup_irq = 0;
-static int setup_scsiid = 0;
-static int setup_reconnect = 0;
-static int setup_doparity = 0;
+static int setup_count=0;
+static struct aha152x_setup {
+ char *conf;
+ int io_port;
+ int irq;
+ int scsiid;
+ int reconnect;
+ int parity;
+ int synchronous;
+#ifdef DEBUG_AHA152X
+ int debug;
+#endif
+} setup[2];
+
+static struct Scsi_Host *aha152x_host[IRQS];
+
+#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata)
+#define CURRENT_SC (HOSTDATA(shpnt)->current_SC)
+#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC)
+#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC)
+#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target])
+#define MSG(i) (HOSTDATA(shpnt)->message[i])
+#define MSGLEN (HOSTDATA(shpnt)->message_len)
+#define ADDMSG(x) (MSG(MSGLEN++)=x)
+
+struct aha152x_hostdata {
+ Scsi_Cmnd *issue_SC;
+ Scsi_Cmnd *current_SC;
+ Scsi_Cmnd *disconnected_SC;
+ int aborting;
+ int abortion_complete;
+ int abort_result;
+ int commands;
+
+ int reconnect;
+ int parity;
+ int synchronous;
+
+ unsigned char syncrate[8];
+
+ unsigned char message[256];
+ int message_len;
#ifdef DEBUG_AHA152X
-static int setup_debug = 0;
+ int debug;
#endif
-
-static char *setup_str = (char *)NULL;
-
-enum {
- not_issued = 0x01,
- in_selection = 0x02,
- disconnected = 0x04,
- aborted = 0x08,
- sent_ident = 0x10,
- in_other = 0x20,
};
-
-/*
- * Command queues:
- * issue_SC : commands that are queued to be issued
- * current_SC : command that's currently using the bus
- * disconnected_SC : commands that that have been disconnected
- */
-static Scsi_Cmnd *issue_SC = NULL;
-static Scsi_Cmnd *current_SC = NULL;
-static Scsi_Cmnd *disconnected_SC = NULL;
-
-static int aborting=0, abortion_complete=0, abort_result;
-void aha152x_intr( int irq, struct pt_regs * );
-void aha152x_done( int error );
-void aha152x_setup( char *str, int *ints );
+void aha152x_intr(int irq, struct pt_regs *);
+void aha152x_done(struct Scsi_Host *shpnt, int error);
+void aha152x_setup(char *str, int *ints);
+int aha152x_checksetup(struct aha152x_setup *setup);
-static void aha152x_reset_ports(void);
-static void aha152x_panic(const char *msg);
+static void aha152x_reset_ports(struct Scsi_Host *shpnt);
+static void aha152x_panic(struct Scsi_Host *shpnt, char *msg);
-static void disp_ports(void);
+static void disp_ports(struct Scsi_Host *shpnt);
static void show_command(Scsi_Cmnd *ptr);
-static void show_queues(void);
-static void disp_enintr(void);
+static void show_queues(struct Scsi_Host *shpnt);
+static void disp_enintr(struct Scsi_Host *shpnt);
#if defined(DEBUG_RACE)
static void enter_driver(const char *);
0x340, /* default first */
0x140
};
-#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
-
-/* possible interrupt channels */
-static unsigned short irqs[] = { 9, 10, 11, 12, 0 };
+#define PORT_COUNT (sizeof(ports) / sizeof(unsigned short))
#if !defined(SKIP_BIOSTEST)
/* possible locations for the Adaptec BIOS */
(void *) 0xd4000,
(void *) 0xd8000,
(void *) 0xe0000,
- (void *) 0xf0000,
(void *) 0xeb800, /* VTech Platinum SMP */
+ (void *) 0xf0000,
};
-#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( void * ))
+#define ADDRESS_COUNT (sizeof(addresses) / sizeof(void *))
/* signatures for various AIC-6[23]60 based controllers.
The point in detecting signatures is to avoid useless
{ "Adaptec BIOS: ASW-B626", 0x0f, 22 }, /* on-board controller */
{ "Adaptec ASW-B626 S2", 0x2e6c, 19 }, /* on-board controller */
{ "Adaptec BIOS:AIC-6360", 0xc, 21 }, /* on-board controller */
- { "ScsiPro SP-360 BIOS", 0x2873, 19 }, /* ScsiPro-Controller with AIC-6360 */
+ { "ScsiPro SP-360 BIOS", 0x2873, 19 }, /* ScsiPro-Controller */
{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, /* Gigabyte Local-Bus-SCSI */
+ { "Adaptec BIOS:AVA-282X", 0xc, 21 }, /* Adaptec 282x */
+ { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, /* IBM Thinkpad Dock II */
+ { "Adaptec BIOS:AHA-1532P", 0x1c, 22 }, /* IBM Thinkpad Dock II SCSI */
};
-#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+#define SIGNATURE_COUNT (sizeof(signatures) / sizeof(struct signature))
#endif
-static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
+static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */
{
unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
/*
* queue services:
*/
-static inline void append_SC( Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
{
Scsi_Cmnd *end;
*SC=new_SC;
else
{
- for( end=*SC;
- end->host_scribble;
- end = (Scsi_Cmnd *) end->host_scribble )
+ for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble)
;
end->host_scribble = (unsigned char *) new_SC;
}
}
-static inline Scsi_Cmnd *remove_first_SC( Scsi_Cmnd **SC )
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
{
Scsi_Cmnd *ptr;
return ptr;
}
-static inline Scsi_Cmnd *remove_SC( Scsi_Cmnd **SC, int target, int lun )
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
{
Scsi_Cmnd *ptr, *prev;
- for( ptr=*SC, prev=NULL;
+ for(ptr=*SC, prev=NULL;
ptr && ((ptr->target!=target) || (ptr->lun!=lun));
- prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
;
if(ptr)
/*
* read inbound byte and wait for ACK to get low
*/
-static void make_acklow(void)
+static void make_acklow(struct Scsi_Host *shpnt)
{
- SETPORT( SXFRCTL0, CH1|SPIOEN );
+ SETPORT(SXFRCTL0, CH1|SPIOEN);
GETPORT(SCSIDAT);
- SETPORT( SXFRCTL0, CH1 );
+ SETPORT(SXFRCTL0, CH1);
- while( TESTHI( SCSISIG, ACKI ) )
+ while(TESTHI(SCSISIG, ACKI))
;
}
* P_BUSFREE BUS FREE phase detected
* P_PARITY parity error in DATA phase
*/
-static int getphase(void)
+static int getphase(struct Scsi_Host *shpnt)
{
int phase, sstat1;
- while( 1 )
+ while(1)
{
do
{
- while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
+ while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT)))
;
- if( sstat1 & BUSFREE )
+ if(sstat1 & BUSFREE)
return P_BUSFREE;
- if( sstat1 & SCSIRSTI )
+ if(sstat1 & SCSIRSTI)
{
- /* IBM drive responds with RSTI to RSTO */
printk("aha152x: RESET IN\n");
- SETPORT( SSTAT1, SCSIRSTI );
+ SETPORT(SSTAT1, SCSIRSTI);
}
}
- while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) );
+ while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT));
- SETPORT( SSTAT1, CLRSCSIPERR );
+ SETPORT(SSTAT1, CLRSCSIPERR);
- phase = GETPORT( SCSISIG ) & P_MASK ;
+ phase = GETPORT(SCSISIG) & P_MASK ;
- if( TESTHI( SSTAT1, SCSIPERR ) )
+ if(TESTHI(SSTAT1, SCSIPERR))
{
- if( (phase & (CDO|MSGO))==0 ) /* DATA phase */
+ if((phase & (CDO|MSGO))==0) /* DATA phase */
return P_PARITY;
- make_acklow();
+ make_acklow(shpnt);
}
else
return phase;
}
/* called from init/main.c */
-void aha152x_setup( char *str, int *ints)
+void aha152x_setup(char *str, int *ints)
{
- if(setup_called)
- panic("aha152x: aha152x_setup called twice.\n");
-
- setup_called=ints[0];
- setup_str=str;
-
- setup_portbase = ints[0] >= 1 ? ints[1] : 0x340;
- setup_irq = ints[0] >= 2 ? ints[2] : 11;
- setup_scsiid = ints[0] >= 3 ? ints[3] : 7;
- setup_reconnect = ints[0] >= 4 ? ints[4] : 1;
- setup_doparity = ints[0] >= 5 ? ints[5] : 1;
+ if(setup_count>2)
+ panic("aha152x: you can only configure up to two controllers\n");
+
+ setup[setup_count].conf = str;
+ setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340;
+ setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11;
+ setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7;
+ setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1;
+ setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1;
+ setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */;
#ifdef DEBUG_AHA152X
- setup_debug = ints[0] >= 6 ? ints[6] : DEBUG_DEFAULT;
+ setup[setup_count].debug = ints[0] >= 7 ? ints[7] : DEBUG_DEFAULT;
+ if(ints[0]>7)
+ {
+ printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>"
+ "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>,[,<DEBUG>]]]]]]\n");
+#else
+ if(ints[0]>6)
+ {
+ printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>"
+ "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>]]]]]\n");
#endif
+ }
+ else
+ setup_count++;
}
/*
Test, if port_base is valid.
*/
-static int aha152x_porttest(int port_base)
+static int aha152x_porttest(int io_port)
{
int i;
- if(check_region(port_base, 0x20))
+ if(check_region(io_port, IO_RANGE))
return 0;
- SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
+ SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */
for(i=0; i<16; i++)
- SETPORT( STACK, i );
+ SETPORT(io_port+O_STACK, i);
- SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
- for(i=0; i<16 && GETPORT(STACK)==i; i++)
+ SETPORT(io_port+O_DMACNTRL1, 0); /* reset stack pointer */
+ for(i=0; i<16 && GETPORT(io_port+O_STACK)==i; i++)
;
return(i==16);
}
+int aha152x_checksetup(struct aha152x_setup *setup)
+{
+ int i;
+
+#ifndef PCMCIA
+ for(i=0; i<PORT_COUNT && (setup->io_port != ports[i]); i++)
+ ;
+
+ if(i==PORT_COUNT)
+ return 0;
+#endif
+
+ if(!aha152x_porttest(setup->io_port))
+ return 0;
+
+ if((setup->irq < IRQ_MIN) && (setup->irq > IRQ_MAX))
+ return 0;
+
+ if((setup->scsiid < 0) || (setup->scsiid > 7))
+ return 0;
+
+ if((setup->reconnect < 0) || (setup->reconnect > 1))
+ return 0;
+
+ if((setup->parity < 0) || (setup->parity > 1))
+ return 0;
+
+ if((setup->synchronous < 0) || (setup->synchronous > 1))
+ return 0;
+
+ return 1;
+}
+
+
int aha152x_detect(Scsi_Host_Template * tpnt)
{
- int i, ok;
+ int i, j, ok;
#if defined(AUTOCONF)
aha152x_config conf;
#endif
- int interrupt_level;
- struct Scsi_Host *hreg;
tpnt->proc_dir = &proc_scsi_aha152x;
- if(setup_called)
+ for(i=0; i<IRQS; i++)
+ aha152x_host[i] = (struct Scsi_Host *) NULL;
+
+ if(setup_count)
{
printk("aha152x: processing commandline: ");
-#ifdef DEBUG_AHA152X
- if(setup_called>6)
-#else
- if(setup_called>5)
-#endif
+ for(i=0; i<setup_count; i++)
+ if(!aha152x_checksetup(&setup[i]))
{
- printk("\naha152x: %s\n", setup_str );
-#ifdef DEBUG_AHA152X
- printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
-#else
- printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
-#endif
- panic("aha152x panics in line %d", __LINE__);
+ printk("\naha152x: %s\n", setup[i].conf);
+ printk("aha152x: invalid line (controller=%d)\n", i+1);
}
- port_base = setup_portbase;
- interrupt_level = setup_irq;
- this_host = setup_scsiid;
- can_disconnect = setup_reconnect;
- can_doparity = setup_doparity;
-#ifdef DEBUG_AHA152X
- aha152x_debug = setup_debug;
-#endif
-
-#ifndef PCMCIA
- for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
- ;
-
- if(i==PORT_COUNT)
- {
- printk("unknown portbase 0x%03x\n", port_base);
- panic("aha152x panics in line %d", __LINE__);
+ printk("ok\n");
}
-#endif
- if(!aha152x_porttest(port_base))
+#ifdef SETUP0
+ if(setup_count<2)
{
- printk("portbase 0x%03x fails probe\n", port_base);
-#ifdef PCMCIA
- return 0;
-#else
- panic("aha152x panics in line %d", __LINE__);
-#endif
- }
+ struct aha152x_setup override = SETUP0;
-#ifndef PCMCIA
- i=0;
- while(irqs[i] && (interrupt_level!=irqs[i]))
- i++;
- if(!irqs[i])
+ if(setup_count==0 || (override.io_port != setup[0].io_port))
+ if(!aha152x_checksetup(&override))
{
- printk("illegal IRQ %d\n", interrupt_level);
- panic("aha152x panics in line %d", __LINE__);
+ printk("\naha152x: SETUP0 (0x%x, %d, %d, %d, %d, %d) invalid\n",
+ override.io_port,
+ override.irq,
+ override.scsiid,
+ override.reconnect,
+ override.parity,
+ override.synchronous);
}
-#endif
-
- if( (this_host < 0) || (this_host > 7) )
- {
- printk("illegal SCSI ID %d\n", this_host);
- panic("aha152x panics in line %d", __LINE__);
+ else
+ setup[setup_count++] = override;
}
+#endif
- if( (can_disconnect < 0) || (can_disconnect > 1) )
+#ifdef SETUP1
+ if(setup_count<2)
{
- printk("reconnect %d should be 0 or 1\n", can_disconnect);
- panic("aha152x panics in line %d", __LINE__);
- }
+ struct aha152x_setup override = SETUP1;
- if( (can_doparity < 0) || (can_doparity > 1) )
+ if(setup_count==0 || (override.io_port != setup[0].io_port))
+ if(!aha152x_checksetup(&override))
{
- printk("parity %d should be 0 or 1\n", can_doparity);
- panic("aha152x panics in line %d", __LINE__);
- }
- printk("ok\n");
+ printk("\naha152x: SETUP1 (0x%x, %d, %d, %d, %d, %d) invalid\n",
+ override.io_port,
+ override.irq,
+ override.scsiid,
+ override.reconnect,
+ override.parity,
+ override.synchronous);
}
else
+ setup[setup_count++] = override;
+ }
+#endif
+
+#if defined(AUTOCONF)
+ if(setup_count<2)
{
#if !defined(SKIP_BIOSTEST)
- int j;
-
ok=0;
- for( i=0; i < ADDRESS_COUNT && !ok; i++)
- for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
+ for(i=0; i < ADDRESS_COUNT && !ok; i++)
+ for(j=0; (j < SIGNATURE_COUNT) && !ok; j++)
ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
(void *) signatures[j].signature,
(int) signatures[j].sig_length);
- if(!ok)
+ if(!ok && setup_count==0)
return 0;
printk("aha152x: BIOS test: passed, ");
printk("aha152x: ");
#endif /* !SKIP_BIOSTEST */
-#if !defined(PORTBASE)
- printk("porttest: ");
- for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++)
- ;
+ for(i=0; i<PORT_COUNT && setup_count<2; i++)
+ {
+ if((setup_count==1) && (setup[0].io_port == ports[i]))
+ continue;
- if(i==PORT_COUNT)
+ if(aha152x_porttest(ports[i]))
{
- printk("failed\n");
- return 0;
+ setup[setup_count].io_port = ports[i];
+
+ conf.cf_port =
+ (GETPORT(ports[i]+O_PORTA)<<8) + GETPORT(ports[i]+O_PORTB);
+
+ setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+ setup[setup_count].scsiid = conf.cf_id;
+ setup[setup_count].reconnect = conf.cf_tardisc;
+ setup[setup_count].parity = !conf.cf_parity;
+ setup[setup_count].synchronous = 0 /* FIXME: conf.cf_syncneg */;
+ setup[setup_count].debug = DEBUG_DEFAULT;
+ setup_count++;
+ }
}
- else
- port_base=ports[i];
- printk("ok, ");
-#else
- port_base=PORTBASE;
-#endif /* !PORTBASE */
-#if defined(AUTOCONF)
+ printk("auto configuration: ok, ");
+ }
+#endif
- conf.cf_port = (GETPORT(PORTA)<<8) + GETPORT(PORTB);
+ printk("detection complete\n");
- interrupt_level = irqs[conf.cf_irq];
- this_host = conf.cf_id;
- can_disconnect = conf.cf_tardisc;
- can_doparity = !conf.cf_parity;
+ for(i=0; i<setup_count; i++)
+ {
+ struct Scsi_Host *shpnt;
- printk("auto configuration: ok, ");
+ shpnt = aha152x_host[setup[i].irq-IRQ_MIN] =
+ scsi_register(tpnt, sizeof(struct aha152x_hostdata));
-#endif /* AUTOCONF */
+ shpnt->io_port = setup[i].io_port;
+ shpnt->n_io_port = IO_RANGE;
+ shpnt->irq = setup[i].irq;
-#if defined(IRQ)
- interrupt_level = IRQ;
-#endif
+ ISSUE_SC = (Scsi_Cmnd *) NULL;
+ CURRENT_SC = (Scsi_Cmnd *) NULL;
+ DISCONNECTED_SC = (Scsi_Cmnd *) NULL;
-#if defined(SCSI_ID)
- this_host = SCSI_ID;
-#endif
+ HOSTDATA(shpnt)->reconnect = setup[i].reconnect;
+ HOSTDATA(shpnt)->parity = setup[i].parity;
+ HOSTDATA(shpnt)->synchronous = setup[i].synchronous;
+ HOSTDATA(shpnt)->debug = setup[i].debug;
-#if defined(RECONNECT)
- can_disconnect=RECONNECT;
-#endif
+ HOSTDATA(shpnt)->aborting = 0;
+ HOSTDATA(shpnt)->abortion_complete = 0;
+ HOSTDATA(shpnt)->abort_result = 0;
+ HOSTDATA(shpnt)->commands = 0;
-#if defined(PARITY)
- can_doparity=PARITY;
-#endif
- }
+ HOSTDATA(shpnt)->message_len = 0;
- printk("detection complete\n");
+ for(j=0; j<8; j++)
+ HOSTDATA(shpnt)->syncrate[j] = 0;
- ok = request_irq(interrupt_level, aha152x_intr, SA_INTERRUPT, "aha152x");
+ ok = request_irq(setup[i].irq, aha152x_intr, SA_INTERRUPT, "aha152x");
if(ok<0)
{
if(ok == -EINVAL)
{
- printk("aha152x: bad IRQ %d.\n", interrupt_level);
+ printk("aha152x%d: bad IRQ %d.\n", i, setup[i].irq);
printk(" Contact author.\n");
}
else
- if( ok == -EBUSY)
- printk( "aha152x: IRQ %d already in use. Configure another.\n",
- interrupt_level);
+ if(ok == -EBUSY)
+ printk("aha152x%d: IRQ %d already in use. Configure another.\n",
+ i, setup[i].irq);
else
{
- printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
- interrupt_level);
+ printk("\naha152x%d: Unexpected error code on"
+ " requesting IRQ %d.\n", i, setup[i].irq);
printk(" Contact author.\n");
}
- panic("aha152x: driver needs an IRQ.\n");
+ printk("aha152x: driver needs an IRQ.\n");
+ continue;
}
- SETPORT( SCSIID, this_host << 4 );
- tpnt->this_id=this_host;
+ SETPORT(SCSIID, setup[i].scsiid << 4);
+ shpnt->this_id=setup[i].scsiid;
- if(can_disconnect)
- tpnt->can_queue=AHA152X_MAXQUEUE;
+ if(setup[i].reconnect)
+ shpnt->hostt->can_queue=AHA152X_MAXQUEUE;
/* RESET OUT */
- SETBITS(SCSISEQ, SCSIRSTO );
+ SETBITS(SCSISEQ, SCSIRSTO);
do_pause(30);
- CLRBITS(SCSISEQ, SCSIRSTO );
+ CLRBITS(SCSISEQ, SCSIRSTO);
do_pause(60);
- aha152x_reset(NULL);
-
- printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=%s\n",
- port_base,
- interrupt_level,
- this_host,
- can_disconnect ? "enabled" : "disabled",
- can_doparity ? "enabled" : "disabled");
-
- request_region(port_base, 0x20, "aha152x"); /* Register */
-
- hreg = scsi_register(tpnt, 0);
- hreg->io_port = port_base;
- hreg->n_io_port = 0x20;
- hreg->irq = interrupt_level;
+ aha152x_reset_ports(shpnt);
+
+ printk("aha152x%d: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d,"
+ " reconnect=%s, parity=%s, synchronous=%s\n",
+ i,
+ shpnt->io_port,
+ shpnt->irq,
+ shpnt->this_id,
+ HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled",
+ HOSTDATA(shpnt)->parity ? "enabled" : "disabled",
+ HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+
+ request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */
/* not expecting any interrupts */
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- SETBITS( DMACNTRL0, INTEN);
- return 1;
+ SETBITS(DMACNTRL0, INTEN);
+ }
+
+ return (setup_count>0);
}
/*
* Queue a command and setup interrupts for a free bus.
*/
-int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+int aha152x_queue(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
+ struct Scsi_Host *shpnt = SCpnt->host;
unsigned long flags;
#if defined(DEBUG_RACE)
enter_driver("queue");
#else
#if defined(DEBUG_QUEUE)
- if(aha152x_debug & debug_queue)
+ if(HOSTDATA(shpnt)->debug & debug_queue)
printk("aha152x: queue(), ");
#endif
#endif
#if defined(DEBUG_QUEUE)
- if(aha152x_debug & debug_queue)
+ if(HOSTDATA(shpnt)->debug & debug_queue)
{
- printk( "SCpnt (target = %d lun = %d cmnd = ", SCpnt->target, SCpnt->lun);
+ printk("SCpnt (target = %d lun = %d cmnd = ",
+ SCpnt->target, SCpnt->lun);
print_command(SCpnt->cmnd);
- printk( ", cmd_len=%d, pieces = %d size = %u), ",
- SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
- disp_ports();
+ printk(", cmd_len=%d, pieces = %d size = %u), ",
+ SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+ disp_ports(shpnt);
}
#endif
SCpnt->SCp.phase = not_issued;
if (SCpnt->use_sg)
{
- SCpnt->SCp.buffer = (struct scatterlist *)SCpnt->request_buffer;
+ SCpnt->SCp.buffer =
+ (struct scatterlist *) SCpnt->request_buffer;
SCpnt->SCp.ptr = SCpnt->SCp.buffer->address;
SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
/* Turn led on, when this is the first command. */
save_flags(flags);
cli();
- commands++;
- if(commands==1)
- SETPORT( PORTA, 1 );
+ HOSTDATA(shpnt)->commands++;
+ if(HOSTDATA(shpnt)->commands==1)
+ SETPORT(PORTA, 1);
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
- printk("i+ (%d), ", commands );
+ if(HOSTDATA(shpnt)->debug & debug_queues)
+ printk("i+ (%d), ", HOSTDATA(shpnt)->commands);
#endif
- append_SC( &issue_SC, SCpnt);
+ append_SC(&ISSUE_SC, SCpnt);
/* Enable bus free interrupt, when we aren't currently on the bus */
- if(!current_SC)
+ if(!CURRENT_SC)
{
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
}
restore_flags(flags);
}
/*
- * We only support command in interrupt-driven fashion
+ * We only support commands in interrupt-driven fashion
*/
-int aha152x_command( Scsi_Cmnd *SCpnt )
+int aha152x_command(Scsi_Cmnd *SCpnt)
{
- printk( "aha152x: interrupt driven driver; use aha152x_queue()\n" );
+ printk("aha152x: interrupt driven driver; use aha152x_queue()\n");
return -1;
}
* Abort a queued command
* (commands that are on the bus can't be aborted easily)
*/
-int aha152x_abort( Scsi_Cmnd *SCpnt)
+int aha152x_abort(Scsi_Cmnd *SCpnt)
{
+ struct Scsi_Host *shpnt = SCpnt->host;
unsigned long flags;
Scsi_Cmnd *ptr, *prev;
cli();
#if defined(DEBUG_ABORT)
- if(aha152x_debug & debug_abort)
+ if(HOSTDATA(shpnt)->debug & debug_abort)
{
- printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt );
-
- show_queues();
+ printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt);
+ show_queues(shpnt);
}
#endif
/* look for command in issue queue */
- for( ptr=issue_SC, prev=NULL;
+ for(ptr=ISSUE_SC, prev=NULL;
ptr && ptr!=SCpnt;
prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
;
if(prev)
prev->host_scribble = ptr->host_scribble;
else
- issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble;
restore_flags(flags);
ptr->host_scribble = NULL;
/* if the bus is busy or a command is currently processed,
we can't do anything more */
- if ( TESTLO(SSTAT1, BUSFREE) || (current_SC && current_SC!=SCpnt))
+ if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt))
{
/* fail abortion, if bus is busy */
- if(!current_SC)
+ if(!CURRENT_SC)
printk("bus busy w/o current command, ");
restore_flags(flags);
/* bus is free */
- if(current_SC)
+ if(CURRENT_SC)
{
/* target entered bus free before COMMAND COMPLETE, nothing to abort */
restore_flags(flags);
- current_SC->result = DID_ERROR << 16;
- current_SC->scsi_done(current_SC);
- current_SC = (Scsi_Cmnd *) NULL;
+ CURRENT_SC->result = DID_ERROR << 16;
+ CURRENT_SC->scsi_done(CURRENT_SC);
+ CURRENT_SC = (Scsi_Cmnd *) NULL;
return SCSI_ABORT_SUCCESS;
}
/* look for command in disconnected queue */
- for( ptr=disconnected_SC, prev=NULL;
+ for(ptr=DISCONNECTED_SC, prev=NULL;
ptr && ptr!=SCpnt;
prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
;
if(ptr)
- if(!aborting)
+ if(!HOSTDATA(shpnt)->aborting)
{
/* dequeue */
if(prev)
prev->host_scribble = ptr->host_scribble;
else
- disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
/* set command current and initiate selection,
let the interrupt routine take care of the abortion */
- current_SC = ptr;
+ CURRENT_SC = ptr;
ptr->SCp.phase = in_selection|aborted;
- SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
+
+ ADDMSG(ABORT);
/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
- SETPORT( SIMODE1, ENSELTIMO );
+ SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+ SETPORT(SIMODE1, ENSELTIMO);
/* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
- SETBITS( DMACNTRL0, INTEN );
- abort_result=SCSI_ABORT_SUCCESS;
- aborting++;
- abortion_complete=0;
+ SETBITS(DMACNTRL0, INTEN);
+ HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS;
+ HOSTDATA(shpnt)->aborting++;
+ HOSTDATA(shpnt)->abortion_complete=0;
sti(); /* Hi Eric, guess what ;-) */
/* sleep until the abortion is complete */
- while(!abortion_complete)
+ while(!HOSTDATA(shpnt)->abortion_complete)
barrier();
- aborting=0;
- return abort_result;
+ HOSTDATA(shpnt)->aborting=0;
+ return HOSTDATA(shpnt)->abort_result;
}
else
{
/*
* Restore default values to the AIC-6260 registers and reset the fifos
*/
-static void aha152x_reset_ports(void)
+static void aha152x_reset_ports(struct Scsi_Host *shpnt)
{
/* disable interrupts */
SETPORT(DMACNTRL0, RSTFIFO);
SETPORT(SCSISEQ, 0);
SETPORT(SXFRCTL1, 0);
- SETPORT( SCSISIG, 0);
+ SETPORT(SCSISIG, 0);
SETPORT(SCSIRATE, 0);
/* clear all interrupt conditions */
SETPORT(SXFRCTL0, CH1);
/* enable interrupts */
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
}
/*
* Reset registers, reset a hanging bus and
* kill active and disconnected commands for target w/o soft reset
*/
-int aha152x_reset(Scsi_Cmnd * __unused)
+int aha152x_reset(Scsi_Cmnd *SCpnt)
{
+ struct Scsi_Host *shpnt = SCpnt->host;
unsigned long flags;
Scsi_Cmnd *ptr, *prev, *next;
- aha152x_reset_ports();
+ aha152x_reset_ports(shpnt);
/* Reset, if bus hangs */
- if( TESTLO( SSTAT1, BUSFREE ) )
+ if(TESTLO(SSTAT1, BUSFREE))
{
- CLRBITS( DMACNTRL0, INTEN );
+ CLRBITS(DMACNTRL0, INTEN);
#if defined(DEBUG_RESET)
- if(aha152x_debug & debug_reset)
+ if(HOSTDATA(shpnt)->debug & debug_reset)
{
printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
- show_queues();
+ show_queues(shpnt);
}
#endif
- if(current_SC && !current_SC->device->soft_reset)
+ ptr=CURRENT_SC;
+ if(ptr && !ptr->device->soft_reset)
{
- current_SC->host_scribble = NULL;
- current_SC->result = DID_RESET << 16;
- current_SC->scsi_done(current_SC);
- current_SC=NULL;
+ ptr->host_scribble = NULL;
+ ptr->result = DID_RESET << 16;
+ ptr->scsi_done(CURRENT_SC);
+ CURRENT_SC=NULL;
}
save_flags(flags);
cli();
- prev=NULL; ptr=disconnected_SC;
+ prev=NULL; ptr=DISCONNECTED_SC;
while(ptr)
{
if(!ptr->device->soft_reset)
if(prev)
prev->host_scribble = ptr->host_scribble;
else
- disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble;
next = (Scsi_Cmnd *) ptr->host_scribble;
ptr->host_scribble = NULL;
ptr->result = DID_RESET << 16;
- ptr->scsi_done(ptr);
+ ptr->scsi_done(ptr);
ptr = next;
}
}
restore_flags(flags);
-#if defined( DEBUG_RESET )
- if(aha152x_debug & debug_reset)
+#if defined(DEBUG_RESET)
+ if(HOSTDATA(shpnt)->debug & debug_reset)
{
printk("commands on targets w/ soft-resets:\n");
- show_queues();
+ show_queues(shpnt);
}
#endif
SETPORT(SCSISEQ, 0);
do_pause(60);
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETPORT( DMACNTRL0, INTEN );
+ SETPORT(DMACNTRL0, INTEN);
}
return SCSI_RESET_SUCCESS;
/*
* Return the "logical geometry"
*/
-int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array )
+int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array)
{
int size = disk->capacity;
#if defined(DEBUG_BIOSPARAM)
- if(aha152x_debug & debug_biosparam)
- printk("aha152x_biosparam: dev=%s, size=%d, ",
- kdevname(dev), size);
+ if(HOSTDATA(shpnt)->debug & debug_biosparam)
+ printk("aha152x_biosparam: dev=%s, size=%d, ", kdevname(dev), size);
#endif
/* I took this from other SCSI drivers, since it provides
info_array[2]=size>>11;
#if defined(DEBUG_BIOSPARAM)
- if(aha152x_debug & debug_biosparam)
+ if(HOSTDATA(shpnt)->debug & debug_biosparam)
{
printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
info_array[0], info_array[1], info_array[2]);
/*
* Internal done function
*/
-void aha152x_done( int error )
+void aha152x_done(struct Scsi_Host *shpnt, int error)
{
unsigned long flags;
Scsi_Cmnd *done_SC;
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
+ if(HOSTDATA(shpnt)->debug & debug_done)
{
printk("\naha152x: done(), ");
- disp_ports();
+ disp_ports(shpnt);
}
#endif
- if (current_SC)
+ if (CURRENT_SC)
{
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
+ if(HOSTDATA(shpnt)->debug & debug_done)
printk("done(%x), ", error);
#endif
save_flags(flags);
cli();
- done_SC = current_SC;
- current_SC = NULL;
+ done_SC = CURRENT_SC;
+ CURRENT_SC = NULL;
/* turn led off, when no commands are in the driver */
- commands--;
- if(!commands)
- SETPORT( PORTA, 0 ); /* turn led off */
+ HOSTDATA(shpnt)->commands--;
+ if(!HOSTDATA(shpnt)->commands)
+ SETPORT(PORTA, 0); /* turn led off */
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
- printk("ok (%d), ", commands);
+ if(HOSTDATA(shpnt)->debug & debug_queues)
+ printk("ok (%d), ", HOSTDATA(shpnt)->commands);
#endif
restore_flags(flags);
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
#if defined(DEBUG_PHASES)
- if(aha152x_debug & debug_phases)
+ if(HOSTDATA(shpnt)->debug & debug_phases)
printk("BUS FREE loop, ");
#endif
- while( TESTLO( SSTAT1, BUSFREE ) )
+ while(TESTLO(SSTAT1, BUSFREE))
;
#if defined(DEBUG_PHASES)
- if(aha152x_debug & debug_phases)
+ if(HOSTDATA(shpnt)->debug & debug_phases)
printk("BUS FREE\n");
#endif
if(done_SC->scsi_done)
{
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
+ if(HOSTDATA(shpnt)->debug & debug_done)
printk("calling scsi_done, ");
#endif
- done_SC->scsi_done( done_SC );
+ done_SC->scsi_done(done_SC);
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
+ if(HOSTDATA(shpnt)->debug & debug_done)
printk("done returned, ");
#endif
}
else
- panic( "aha152x: current_SC->scsi_done() == NULL" );
+ panic("aha152x: current_SC->scsi_done() == NULL");
}
else
- aha152x_panic( "done() called outside of command" );
+ aha152x_panic(shpnt, "done() called outside of command");
}
/*
* Interrupts handler (main routine of the driver)
*/
-void aha152x_intr( int irqno, struct pt_regs * regs )
+void aha152x_intr(int irqno, struct pt_regs * regs)
{
+ struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN];
unsigned int flags;
int done=0, phase;
enter_driver("intr");
#else
#if defined(DEBUG_INTR)
- if(aha152x_debug & debug_intr)
+ if(HOSTDATA(shpnt)->debug & debug_intr)
printk("\naha152x: intr(), ");
#endif
#endif
INTEN has to be restored, when we're ready to leave
intr(). To avoid race conditions we have to return
immediately afterwards. */
- CLRBITS( DMACNTRL0, INTEN);
+ CLRBITS(DMACNTRL0, INTEN);
sti(); /* Yes, sti() really needs to be here */
/* disconnected target is trying to reconnect.
Only possible, if we have disconnected nexuses and
nothing is occupying the bus.
*/
- if( TESTHI( SSTAT0, SELDI ) &&
- disconnected_SC &&
- ( !current_SC || ( current_SC->SCp.phase & in_selection ) )
+ if(TESTHI(SSTAT0, SELDI) &&
+ DISCONNECTED_SC &&
+ (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection))
)
{
int identify_msg, target, i;
/* Avoid conflicts when a target reconnects
while we are trying to connect to another. */
- if(current_SC)
+ if(CURRENT_SC)
{
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
+ if(HOSTDATA(shpnt)->debug & debug_queues)
printk("i+, ");
#endif
save_flags(flags);
cli();
- append_SC( &issue_SC, current_SC);
- current_SC=NULL;
+ append_SC(&ISSUE_SC, CURRENT_SC);
+ CURRENT_SC=NULL;
restore_flags(flags);
}
/* disable sequences */
- SETPORT( SCSISEQ, 0 );
- SETPORT( SSTAT0, CLRSELDI );
- SETPORT( SSTAT1, CLRBUSFREE );
+ SETPORT(SCSISEQ, 0);
+ SETPORT(SSTAT0, CLRSELDI);
+ SETPORT(SSTAT1, CLRBUSFREE);
#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_queues|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases))
printk("reselected, ");
#endif
- i = GETPORT(SELID) & ~(1 << this_host);
+ i = GETPORT(SELID) & ~(1 << shpnt->this_id);
target=0;
if(i)
- for( ; (i & 1)==0; target++, i>>=1)
+ for(; (i & 1)==0; target++, i>>=1)
;
else
- aha152x_panic("reconnecting target unknown");
+ aha152x_panic(shpnt, "reconnecting target unknown");
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
- printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
+ if(HOSTDATA(shpnt)->debug & debug_queues)
+ printk("SELID=%02x, target=%d, ", GETPORT(SELID), target);
#endif
- SETPORT( SCSIID, (this_host << OID_) | target );
- SETPORT( SCSISEQ, ENRESELI );
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+ SETPORT(SCSISEQ, ENRESELI);
+
+ if(TESTLO(SSTAT0, SELDI))
+ aha152x_panic(shpnt, "RESELI failed");
- if(TESTLO( SSTAT0, SELDI ))
- aha152x_panic("RESELI failed");
+ SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f);
- SETPORT( SCSISIG, P_MSGI );
+ SETPORT(SCSISIG, P_MSGI);
/* Get identify message */
- if((i=getphase())!=P_MSGI)
+ if((i=getphase(shpnt))!=P_MSGI)
{
printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
- aha152x_panic("unknown lun");
+ aha152x_panic(shpnt, "unknown lun");
}
- SETPORT( SCSISEQ, 0 );
+ SETPORT(SCSISEQ, 0);
- SETPORT( SXFRCTL0, CH1);
+ SETPORT(SXFRCTL0, CH1);
identify_msg = GETPORT(SCSIBUS);
{
printk("target=%d, inbound message (%02x) != IDENTIFY\n",
target, identify_msg);
- aha152x_panic("unknown lun");
+ aha152x_panic(shpnt, "unknown lun");
}
- make_acklow();
- getphase();
+ make_acklow(shpnt);
+ getphase(shpnt);
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
- printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
+ if(HOSTDATA(shpnt)->debug & debug_queues)
+ printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f);
#endif
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
+ if(HOSTDATA(shpnt)->debug & debug_queues)
printk("d-, ");
#endif
- current_SC = remove_SC( &disconnected_SC,
+ CURRENT_SC = remove_SC(&DISCONNECTED_SC,
target,
- identify_msg & 0x3f );
+ identify_msg & 0x3f);
- if(!current_SC)
+ if(!CURRENT_SC)
{
- printk("lun=%d, ", identify_msg & 0x3f );
- aha152x_panic("no disconnected command for that lun");
+ printk("lun=%d, ", identify_msg & 0x3f);
+ aha152x_panic(shpnt, "no disconnected command for that lun");
}
- current_SC->SCp.phase &= ~disconnected;
+ CURRENT_SC->SCp.phase &= ~disconnected;
restore_flags(flags);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
#if defined(DEBUG_RACE)
leave_driver("(reselected) intr");
#endif
- SETBITS( DMACNTRL0, INTEN);
+ SETBITS(DMACNTRL0, INTEN);
return;
}
/* Check, if we aren't busy with a command */
- if(!current_SC)
+ if(!CURRENT_SC)
{
/* bus is free to issue a queued command */
- if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
+ if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC)
{
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
+ if(HOSTDATA(shpnt)->debug & debug_queues)
printk("i-, ");
#endif
- current_SC = remove_first_SC( &issue_SC );
+ CURRENT_SC = remove_first_SC(&ISSUE_SC);
restore_flags(flags);
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases))
printk("issuing command, ");
#endif
- current_SC->SCp.phase = in_selection;
+ CURRENT_SC->SCp.phase = in_selection;
- #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
- printk("selecting %d, ", current_SC->target);
- #endif
- SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+ if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases))
+ printk("selecting %d, ", CURRENT_SC->target);
+#endif
+ SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target);
/* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
- SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
+ SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
/* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
- SETPORT( SIMODE1, ENSELTIMO );
+ SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+ SETPORT(SIMODE1, ENSELTIMO);
/* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO);
- #if defined(DEBUG_RACE)
+#if defined(DEBUG_RACE)
leave_driver("(selecting) intr");
- #endif
- SETBITS( DMACNTRL0, INTEN );
+#endif
+ SETBITS(DMACNTRL0, INTEN);
return;
}
/* the bus is busy with something */
#if defined(DEBUG_INTR)
- if(aha152x_debug & debug_intr)
- disp_ports();
+ if(HOSTDATA(shpnt)->debug & debug_intr)
+ disp_ports(shpnt);
#endif
/* we are waiting for the result of a selection attempt */
- if(current_SC->SCp.phase & in_selection)
+ if(CURRENT_SC->SCp.phase & in_selection)
{
- if( TESTLO( SSTAT1, SELTO ) )
+ if(TESTLO(SSTAT1, SELTO))
/* no timeout */
- if( TESTHI( SSTAT0, SELDO ) )
+ if(TESTHI(SSTAT0, SELDO))
{
/* clear BUS FREE interrupt */
- SETPORT( SSTAT1, CLRBUSFREE);
+ SETPORT(SSTAT1, CLRBUSFREE);
/* Disable SELECTION OUT sequence */
- CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+ CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO);
/* Disable SELECTION OUT DONE interrupt */
CLRBITS(SIMODE0, ENSELDO);
CLRBITS(SIMODE1, ENSELTIMO);
- if( TESTLO(SSTAT0, SELDO) )
+ if(TESTLO(SSTAT0, SELDO))
{
printk("aha152x: passing bus free condition\n");
#if defined(DEBUG_RACE)
leave_driver("(passing bus free) intr");
#endif
- SETBITS( DMACNTRL0, INTEN);
+ SETBITS(DMACNTRL0, INTEN);
- if(current_SC->SCp.phase & aborted)
+ if(CURRENT_SC->SCp.phase & aborted)
{
- abort_result=SCSI_ABORT_ERROR;
- abortion_complete++;
+ HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR;
+ HOSTDATA(shpnt)->abortion_complete++;
}
- aha152x_done( DID_NO_CONNECT << 16 );
+ aha152x_done(shpnt, DID_NO_CONNECT << 16);
return;
}
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_selection|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases))
printk("SELDO (SELID=%x), ", GETPORT(SELID));
#endif
/* selection was done */
- SETPORT( SSTAT0, CLRSELDO );
+ SETPORT(SSTAT0, CLRSELDO);
#if defined(DEBUG_ABORT)
- if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
+ if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted))
printk("(ABORT) target selected, ");
#endif
- current_SC->SCp.phase &= ~in_selection;
- current_SC->SCp.phase |= in_other;
+ CURRENT_SC->SCp.phase &= ~in_selection;
+ CURRENT_SC->SCp.phase |= in_other;
+
+ ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun));
+
+ if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous)
+ {
+ ADDMSG(EXTENDED_MESSAGE);
+ ADDMSG(3);
+ ADDMSG(EXTENDED_SDTR);
+ ADDMSG(50);
+ ADDMSG(8);
+
+ printk("outbound SDTR: ");
+ print_msg(&MSG(MSGLEN-5));
+
+ SYNCRATE=0x80;
+ CURRENT_SC->SCp.phase |= in_sync;
+ }
#if defined(DEBUG_RACE)
leave_driver("(SELDO) intr");
#endif
+ SETPORT(SCSIRATE, SYNCRATE&0x7f);
- SETPORT( SCSISIG, P_MSGO );
+ SETPORT(SCSISIG, P_MSGO);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
- SETBITS( DMACNTRL0, INTEN);
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENREQINIT|ENBUSFREE);
+ SETBITS(DMACNTRL0, INTEN);
return;
}
else
- aha152x_panic("neither timeout nor selection\007");
+ aha152x_panic(shpnt, "neither timeout nor selection\007");
else
{
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_selection|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases))
printk("SELTO, ");
#endif
/* end selection attempt */
- CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+ CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO);
/* timeout */
- SETPORT( SSTAT1, CLRSELTIMO );
+ SETPORT(SSTAT1, CLRSELTIMO);
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
- SETBITS( DMACNTRL0, INTEN );
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+ SETBITS(DMACNTRL0, INTEN);
#if defined(DEBUG_RACE)
leave_driver("(SELTO) intr");
#endif
- if(current_SC->SCp.phase & aborted)
+ if(CURRENT_SC->SCp.phase & aborted)
{
#if defined(DEBUG_ABORT)
- if(aha152x_debug & debug_abort)
+ if(HOSTDATA(shpnt)->debug & debug_abort)
printk("(ABORT) selection timeout, ");
#endif
- abort_result=SCSI_ABORT_ERROR;
- abortion_complete++;
+ HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR;
+ HOSTDATA(shpnt)->abortion_complete++;
}
- if( TESTLO( SSTAT0, SELINGO ) )
+ if(TESTLO(SSTAT0, SELINGO))
/* ARBITRATION not won */
- aha152x_done( DID_BUS_BUSY << 16 );
+ aha152x_done(shpnt, DID_BUS_BUSY << 16);
else
/* ARBITRATION won, but SELECTION failed */
- aha152x_done( DID_NO_CONNECT << 16 );
+ aha152x_done(shpnt, DID_NO_CONNECT << 16);
+
return;
}
}
/* enable interrupt, when target leaves current phase */
- phase = getphase();
+ phase = getphase(shpnt);
if(!(phase & ~P_MASK)) /* "real" phase */
SETPORT(SCSISIG, phase);
SETPORT(SSTAT1, CLRPHASECHG);
- current_SC->SCp.phase =
- (current_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16 );
+ CURRENT_SC->SCp.phase =
+ (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16);
/* information transfer phase */
- switch( phase )
+ switch(phase)
{
case P_MSGO: /* MESSAGE OUT */
{
- unsigned char message;
+ int i, identify=0, abort=0;
#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases))
printk("MESSAGE OUT, ");
#endif
-
- if( current_SC->SCp.phase & aborted )
+ if(MSGLEN==0)
{
-#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
- if(aha152x_debug & (debug_msgo|debug_abort))
- printk("ABORT, ");
+ ADDMSG(MESSAGE_REJECT);
+#if defined(DEBUG_MSGO)
+ if(HOSTDATA(shpnt)->debug & debug_msgo)
+ printk("unexpected MSGO; rejecting, ");
#endif
- message=ABORT;
}
- else
- /* If we didn't identify yet, do it. Otherwise there's nothing to do,
- but reject (probably we got an message before, that we have to
- reject (SDTR, WDTR, etc.) */
- if( !(current_SC->SCp.phase & sent_ident))
- {
- message=IDENTIFY(can_disconnect,current_SC->lun);
+
+
+ CLRBITS(SXFRCTL0, ENDMA);
+
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE);
+
+ /* wait for data latch to become ready or a phase change */
+ while(TESTLO(DMASTAT, INTSTAT))
+ ;
+
#if defined(DEBUG_MSGO)
- if(aha152x_debug & debug_msgo)
- printk("IDENTIFY (reconnect=%s;lun=%d), ",
- can_disconnect ? "enabled" : "disabled", current_SC->lun);
-#endif
+ if(HOSTDATA(shpnt)->debug & debug_msgo)
+ {
+ int i;
+
+ printk("messages (");
+ for(i=0; i<MSGLEN; i+=print_msg(&MSG(i)), printk(" "))
+ ;
+ printk("), ");
}
- else
+#endif
+
+ for(i=0; i<MSGLEN && TESTLO(SSTAT1, PHASEMIS); i++)
{
- message=MESSAGE_REJECT;
#if defined(DEBUG_MSGO)
- if(aha152x_debug & debug_msgo)
- printk("REJECT, ");
+ if(HOSTDATA(shpnt)->debug & debug_msgo)
+ printk("%x ", MSG(i));
#endif
+ if(i==MSGLEN-1)
+ {
+ /* Leave MESSAGE OUT after transfer */
+ SETPORT(SSTAT1, CLRATNO);
}
- CLRBITS( SXFRCTL0, ENDMA);
+ SETPORT(SCSIDAT, MSG(i));
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
+ make_acklow(shpnt);
+ getphase(shpnt);
- /* wait for data latch to become ready or a phase change */
- while( TESTLO( DMASTAT, INTSTAT ) )
- ;
+ if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun))
+ identify++;
- if( TESTHI( SSTAT1, PHASEMIS ) )
- aha152x_panic("unable to send message");
+ if(MSG(i)==ABORT)
+ abort++;
- /* Leave MESSAGE OUT after transfer */
- SETPORT( SSTAT1, CLRATNO);
+ }
- SETPORT( SCSIDAT, message );
+ MSGLEN=0;
- make_acklow();
- getphase();
+ if(MSGLEN>0)
+ aha152x_panic(shpnt, "oops, MSGLEN>0 !?");
- if(message==IDENTIFY(can_disconnect,current_SC->lun))
- current_SC->SCp.phase |= sent_ident;
+ if(identify)
+ CURRENT_SC->SCp.phase |= sent_ident;
- if(message==ABORT)
+ if(abort)
{
/* revive abort(); abort() enables interrupts */
- abort_result=SCSI_ABORT_SUCCESS;
- abortion_complete++;
+ HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS;
+ HOSTDATA(shpnt)->abortion_complete++;
- current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+ CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
/* exit */
- SETBITS( DMACNTRL0, INTEN );
+ SETBITS(DMACNTRL0, INTEN);
#if defined(DEBUG_RACE)
leave_driver("(ABORT) intr");
#endif
- aha152x_done(DID_ABORT<<16);
+ aha152x_done(shpnt, DID_ABORT<<16);
return;
}
}
case P_CMD: /* COMMAND phase */
#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases))
printk("COMMAND, ");
#endif
- if( !(current_SC->SCp.sent_command) )
+ if(!(CURRENT_SC->SCp.sent_command))
{
- if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
- printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
- GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+ int i;
- /* reset fifo and enable writes */
- SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
- SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+ CLRBITS(SXFRCTL0, ENDMA);
- /* clear transfer count and scsi fifo */
- SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
- SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE);
- /* missing phase raises INTSTAT */
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
-
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- printk("waiting, ");
-#endif
- /* wait for FIFO to get empty */
- while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ /* wait for data latch to become ready or a phase change */
+ while(TESTLO(DMASTAT, INTSTAT))
;
- if( TESTHI( SSTAT1, PHASEMIS ) )
- aha152x_panic("target left COMMAND phase");
-
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
+ for(i=0; i<CURRENT_SC->cmd_len && TESTLO(SSTAT1, PHASEMIS); i++)
{
- printk("DFIFOEMP, outsw (%d bytes, %d words), ",
- current_SC->cmd_len, current_SC->cmd_len >> 1 );
- disp_ports();
- }
-#endif
-
- outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 );
+ SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]);
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- {
- printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
- disp_ports();
+ make_acklow(shpnt);
+ getphase(shpnt);
}
-#endif
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- printk("waiting for SEMPTY, ");
-#endif
-
- /* wait for SCSI FIFO to get empty.
- very important to send complete commands. */
- while( TESTLO ( SSTAT2, SEMPTY ) )
- ;
-
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- printk("SEMPTY, ");
-#endif
-
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
- /* transfer can be considered ended, when SCSIEN reads back zero */
- while( TESTHI( SXFRCTL0, SCSIEN ) )
- ;
-
-#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- printk("!SEMPTY, ");
-#endif
-
- CLRBITS(DMACNTRL0, ENDMA);
-
-#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
- if(debug_cmd & debug_intr)
- printk("sent %d/%d command bytes, ", GETSTCNT(),
- current_SC->cmd_len);
-#endif
+ if(i<CURRENT_SC->cmd_len && TESTHI(SSTAT1, PHASEMIS))
+ aha152x_panic(shpnt, "target left COMMAND");
+ CURRENT_SC->SCp.sent_command++;
}
else
- aha152x_panic("Nothing to sent while in COMMAND OUT");
+ aha152x_panic(shpnt, "Nothing to send while in COMMAND");
break;
case P_MSGI: /* MESSAGE IN phase */
+ {
+ int start_sync=0;
+
#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases))
printk("MESSAGE IN, ");
#endif
- SETPORT( SXFRCTL0, CH1);
+ SETPORT(SXFRCTL0, CH1);
- SETPORT( SIMODE0, 0);
- SETPORT( SIMODE1, ENBUSFREE);
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENBUSFREE);
- while( phase == P_MSGI )
+ while(phase == P_MSGI)
{
- current_SC->SCp.Message = GETPORT( SCSIBUS );
- switch(current_SC->SCp.Message)
+ CURRENT_SC->SCp.Message = GETPORT(SCSIDAT);
+ switch(CURRENT_SC->SCp.Message)
{
case DISCONNECT:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_msgi|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases))
printk("target disconnected, ");
#endif
- current_SC->SCp.Message = 0;
- current_SC->SCp.phase |= disconnected;
- if(!can_disconnect)
- aha152x_panic("target was not allowed to disconnect");
+ CURRENT_SC->SCp.Message = 0;
+ CURRENT_SC->SCp.phase |= disconnected;
+ if(!HOSTDATA(shpnt)->reconnect)
+ aha152x_panic(shpnt, "target was not allowed to disconnect");
break;
case COMMAND_COMPLETE:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_msgi|debug_phases))
- printk("inbound message ( COMMAND COMPLETE ), ");
+ if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases))
+ printk("inbound message (COMMAND COMPLETE), ");
#endif
done++;
break;
case MESSAGE_REJECT:
+ if(CURRENT_SC->SCp.phase & in_sync)
+ {
+ CURRENT_SC->SCp.phase &= ~in_sync;
+ SYNCRATE=0x80;
+ printk("synchronous rejected, ");
+ }
+ else
+ printk("inbound message (MESSAGE REJECT), ");
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("inbound message ( MESSAGE REJECT ), ");
+ if(HOSTDATA(shpnt)->debug & debug_msgi)
+ printk("inbound message (MESSAGE REJECT), ");
#endif
break;
case SAVE_POINTERS:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("inbound message ( SAVE DATA POINTERS ), ");
+ if(HOSTDATA(shpnt)->debug & debug_msgi)
+ printk("inbound message (SAVE DATA POINTERS), ");
#endif
break;
case EXTENDED_MESSAGE:
{
- int i, code;
+ char buffer[16];
+ int i;
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("inbound message ( EXTENDED MESSAGE ), ");
+ if(HOSTDATA(shpnt)->debug & debug_msgi)
+ printk("inbound message (EXTENDED MESSAGE), ");
#endif
- make_acklow();
- if(getphase()!=P_MSGI)
+ make_acklow(shpnt);
+ if(getphase(shpnt)!=P_MSGI)
break;
- i=GETPORT(SCSIBUS);
+ buffer[0]=EXTENDED_MESSAGE;
+ buffer[1]=GETPORT(SCSIDAT);
+
+ for(i=0; i<buffer[1] &&
+ (make_acklow(shpnt), getphase(shpnt)==P_MSGI); i++)
+ buffer[2+i]=GETPORT(SCSIDAT);
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("length (%d), code ( ", i);
-#endif
-
- make_acklow();
- if(getphase()!=P_MSGI)
+ if(HOSTDATA(shpnt)->debug & debug_msgi)
+ print_msg(buffer);
+#endif
+
+ switch(buffer [2])
+ {
+ case EXTENDED_SDTR:
+ {
+ long ticks;
+
+ if(buffer[1]!=3)
+ aha152x_panic(shpnt, "SDTR message length != 3");
+
+ if(!HOSTDATA(shpnt)->synchronous)
break;
- code = GETPORT(SCSIBUS);
+ printk("inbound SDTR: "); print_msg(buffer);
+
+ ticks=(buffer[3]*4+49)/50;
- switch( code )
+ if(CURRENT_SC->SCp.phase & in_sync)
{
- case 0x00:
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("MODIFY DATA POINTER ");
-#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- case 0x01:
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
-#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- case 0x02:
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("EXTENDED IDENTIFY ");
-#endif
- break;
- case 0x03:
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("WIDE DATA TRANSFER REQUEST ");
-#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- default:
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- if( code & 0x80 )
- printk("reserved (%d) ", code );
+ /* we initiated SDTR */
+ if(ticks>9 || buffer[4]<1 || buffer[4]>8)
+ aha152x_panic(shpnt, "received SDTR invalid");
+
+ SYNCRATE |= ((ticks-2)<<4) + buffer[4];
+ }
+ else if(ticks<=9 && buffer[4]>=1)
+ {
+ if(buffer[4]>8)
+ buffer[4]=8;
+
+ ADDMSG(EXTENDED_MESSAGE);
+ ADDMSG(3);
+ ADDMSG(EXTENDED_SDTR);
+ if(ticks<4)
+ {
+ ticks=4;
+ ADDMSG(50);
+ }
else
- printk("vendor specific (%d) ", code);
-#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
+ ADDMSG(buffer[3]);
+
+ ADDMSG(buffer[4]);
+
+ printk("outbound SDTR: ");
+ print_msg(&MSG(MSGLEN-5));
+
+ CURRENT_SC->SCp.phase |= in_sync;
+
+ SYNCRATE |= ((ticks-2)<<4) + buffer[4];
+
+ start_sync++;
}
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk(" ), data ( ");
-#endif
- while( --i && (make_acklow(), getphase()==P_MSGI))
+ else
{
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("%x ", GETPORT(SCSIBUS) );
-#else
- GETPORT(SCSIBUS);
-#endif
+ /* request SDTR is to slow, do it asynchronously */
+ ADDMSG(MESSAGE_REJECT);
+ SYNCRATE = 0;
+ }
+
+ SETPORT(SCSIRATE, SYNCRATE&0x7f);
+ }
+ break;
+
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ case EXTENDED_WDTR:
+ default:
+ ADDMSG(MESSAGE_REJECT);
+ break;
}
-#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk(" ), ");
-#endif
- /* We reject all extended messages. To do this
- we just enter MSGO by asserting ATN. Since
- we have already identified a REJECT message
- will be sent. */
- SETPORT(SCSISIG, P_MSGI|ATNO);
}
break;
default:
- printk("unsupported inbound message %x, ", current_SC->SCp.Message);
+ printk("unsupported inbound message %x, ",
+ CURRENT_SC->SCp.Message);
break;
}
- make_acklow();
- phase=getphase();
+ make_acklow(shpnt);
+ phase=getphase(shpnt);
}
+ if(start_sync)
+ CURRENT_SC->SCp.phase |= in_sync;
+ else
+ CURRENT_SC->SCp.phase &= ~in_sync;
+
+ if(MSGLEN>0)
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+
/* clear SCSI fifo on BUSFREE */
if(phase==P_BUSFREE)
SETPORT(SXFRCTL0, CH1|CLRCH1);
- if(current_SC->SCp.phase & disconnected)
+ if(CURRENT_SC->SCp.phase & disconnected)
{
save_flags(flags);
cli();
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
+ if(HOSTDATA(shpnt)->debug & debug_queues)
printk("d+, ");
#endif
- append_SC( &disconnected_SC, current_SC);
- current_SC = NULL;
+ append_SC(&DISCONNECTED_SC, CURRENT_SC);
+ CURRENT_SC = NULL;
restore_flags(flags);
- SETBITS( SCSISEQ, ENRESELI );
+ SETBITS(SCSISEQ, ENRESELI);
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
- SETBITS( DMACNTRL0, INTEN );
+ SETBITS(DMACNTRL0, INTEN);
return;
}
+ }
break;
case P_STATUS: /* STATUS IN phase */
#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_status|debug_intr|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases))
printk("STATUS, ");
#endif
- SETPORT( SXFRCTL0, CH1);
+ SETPORT(SXFRCTL0, CH1);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENREQINIT|ENBUSFREE);
- if( TESTHI( SSTAT1, PHASEMIS ) )
+ if(TESTHI(SSTAT1, PHASEMIS))
printk("aha152x: passing STATUS phase");
- current_SC->SCp.Status = GETPORT( SCSIBUS );
- make_acklow();
- getphase();
+ CURRENT_SC->SCp.Status = GETPORT(SCSIBUS);
+ make_acklow(shpnt);
+ getphase(shpnt);
#if defined(DEBUG_STATUS)
- if(aha152x_debug & debug_status)
+ if(HOSTDATA(shpnt)->debug & debug_status)
{
printk("inbound status ");
- print_status( current_SC->SCp.Status );
+ print_status(CURRENT_SC->SCp.Status);
printk(", ");
}
#endif
int fifodata, data_count, done;
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases))
printk("DATA IN, ");
#endif
+#if 0
if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+#endif
/* reset host fifo */
SETPORT(DMACNTRL0, RSTFIFO);
SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
- SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
/* done is set when the FIFO is empty after the target left DATA IN */
done=0;
/* while the target stays in DATA to transfer data */
- while ( !done )
+ while (!done)
{
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
printk("expecting data, ");
#endif
/* wait for PHASEMIS or full FIFO */
- while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
+ while(TESTLO (DMASTAT, DFIFOFULL|INTSTAT))
;
- if( TESTHI( DMASTAT, DFIFOFULL ) )
+#if defined(DEBUG_DATAI)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
+ printk("ok, ");
+#endif
+
+ if(TESTHI(DMASTAT, DFIFOFULL))
fifodata=GETPORT(FIFOSTAT);
else
{
/* wait for SCSI fifo to get empty */
- while( TESTLO( SSTAT2, SEMPTY ) )
+ while(TESTLO(SSTAT2, SEMPTY))
;
/* rest of data in FIFO */
fifodata=GETPORT(FIFOSTAT);
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
printk("last transfer, ");
#endif
done=1;
}
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
printk("fifodata=%d, ", fifodata);
#endif
- while( fifodata && current_SC->SCp.this_residual )
+ while(fifodata && CURRENT_SC->SCp.this_residual)
{
data_count=fifodata;
/* limit data transfer to size of first sg buffer */
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
+ if (data_count > CURRENT_SC->SCp.this_residual)
+ data_count = CURRENT_SC->SCp.this_residual;
fifodata -= data_count;
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
printk("data_count=%d, ", data_count);
#endif
if(data_count&1)
{
/* get a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT );
- *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
- current_SC->SCp.this_residual--;
+ SETBITS(DMACNTRL0, _8BIT);
+ *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+ CURRENT_SC->SCp.this_residual--;
}
if(data_count>1)
{
- CLRBITS(DMACNTRL0, _8BIT );
+ CLRBITS(DMACNTRL0, _8BIT);
data_count >>= 1; /* Number of words */
- insw( DATAPORT, current_SC->SCp.ptr, data_count );
+ insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
-/* show what comes with the last transfer */
+ if(HOSTDATA(shpnt)->debug & debug_datai)
+ /* show what comes with the last transfer */
if(done)
{
+#ifdef 0
int i;
unsigned char *data;
+#endif
+ printk("data on last transfer (%d bytes) ",
+ 2*data_count);
+#ifdef 0
printk("data on last transfer (%d bytes: ",
2*data_count);
- data = (unsigned char *) current_SC->SCp.ptr;
- for( i=0; i<2*data_count; i++)
+ data = (unsigned char *) CURRENT_SC->SCp.ptr;
+ for(i=0; i<2*data_count; i++)
printk("%2x ", *data++);
printk("), ");
+#endif
}
#endif
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
}
/* if this buffer is full and there are more buffers left */
- if (!current_SC->SCp.this_residual &&
- current_SC->SCp.buffers_residual)
+ if (!CURRENT_SC->SCp.this_residual &&
+ CURRENT_SC->SCp.buffers_residual)
{
/* advance to next buffer */
- current_SC->SCp.buffers_residual--;
- current_SC->SCp.buffer++;
- current_SC->SCp.ptr =
- current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual =
- current_SC->SCp.buffer->length;
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr =
+ CURRENT_SC->SCp.buffer->address;
+ CURRENT_SC->SCp.this_residual =
+ CURRENT_SC->SCp.buffer->length;
}
}
{
printk("aha152x: more data than expected (%d bytes)\n",
GETPORT(FIFOSTAT));
- SETBITS(DMACNTRL0, _8BIT );
- printk("aha152x: data ( ");
+ SETBITS(DMACNTRL0, _8BIT);
+ printk("aha152x: data (");
while(fifodata--)
- printk("%2x ", GETPORT( DATAPORT ));
+ printk("%2x ", GETPORT(DATAPORT));
printk(")\n");
}
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(HOSTDATA(shpnt)->debug & debug_datai)
if(!fifodata)
printk("fifo empty, ");
else
}
#if defined(DEBUG_DATAI)
- if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
+ if((HOSTDATA(shpnt)->debug & debug_datai) &&
+ (CURRENT_SC->SCp.buffers_residual ||
+ CURRENT_SC->SCp.this_residual))
printk("left buffers (buffers=%d, bytes=%d), ",
- current_SC->SCp.buffers_residual,
- current_SC->SCp.this_residual);
+ CURRENT_SC->SCp.buffers_residual,
+ CURRENT_SC->SCp.this_residual);
#endif
/* transfer can be considered ended, when SCSIEN reads back zero */
CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
- while( TESTHI( SXFRCTL0, SCSIEN ) )
+ while(TESTHI(SXFRCTL0, SCSIEN))
;
- CLRBITS(DMACNTRL0, ENDMA );
+ CLRBITS(DMACNTRL0, ENDMA);
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
- if(aha152x_debug & (debug_datai|debug_intr))
+ if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr))
printk("got %d bytes, ", GETSTCNT());
#endif
- current_SC->SCp.have_data_in++;
+ CURRENT_SC->SCp.have_data_in++;
}
break;
int data_count;
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
+ if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases))
printk("DATA OUT, ");
#endif
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("got data to send (bytes=%d, buffers=%d), ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual );
+ CURRENT_SC->SCp.this_residual,
+ CURRENT_SC->SCp.buffers_residual);
#endif
- if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
+ if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
{
- printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
- aha152x_panic("FIFO should be empty");
+ printk("%d(%d) left in FIFO, ",
+ GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+ aha152x_panic(shpnt, "FIFO should be empty");
}
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1);
+ SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+
SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
- SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
- SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
-
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
/* while current buffer is not empty or
there are more buffers to transfer */
- while( TESTLO( SSTAT1, PHASEMIS ) &&
- (current_SC->SCp.this_residual ||
- current_SC->SCp.buffers_residual) )
+ while(TESTLO(SSTAT1, PHASEMIS) &&
+ (CURRENT_SC->SCp.this_residual ||
+ CURRENT_SC->SCp.buffers_residual))
{
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual);
+ CURRENT_SC->SCp.this_residual,
+ CURRENT_SC->SCp.buffers_residual);
#endif
/* transfer rest of buffer, but max. 128 byte */
- data_count = current_SC->SCp.this_residual > 128 ?
- 128 : current_SC->SCp.this_residual ;
+ data_count =
+ CURRENT_SC->SCp.this_residual > 128 ?
+ 128 : CURRENT_SC->SCp.this_residual ;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("data_count=%d, ", data_count);
#endif
if(data_count&1)
{
/* put a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT );
- SETPORT(DATAPORT, *current_SC->SCp.ptr++);
- current_SC->SCp.this_residual--;
+ SETBITS(DMACNTRL0, _8BIT);
+ SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+ CURRENT_SC->SCp.this_residual--;
}
if(data_count>1)
{
- CLRBITS(DMACNTRL0, _8BIT );
- data_count >>= 1; /* Number of words */
- outsw( DATAPORT, current_SC->SCp.ptr, data_count );
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
+ CLRBITS(DMACNTRL0, _8BIT);
+ data_count >>= 1; /* number of words */
+ outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
}
/* wait for FIFO to get empty */
- while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT))
;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("fifo (%d bytes), transfered (%d bytes), ",
- GETPORT(FIFOSTAT), GETSTCNT() );
+ GETPORT(FIFOSTAT), GETSTCNT());
#endif
/* if this buffer is empty and there are more buffers left */
- if ( TESTLO( SSTAT1, PHASEMIS ) &&
- !current_SC->SCp.this_residual &&
- current_SC->SCp.buffers_residual)
+ if (TESTLO(SSTAT1, PHASEMIS) &&
+ !CURRENT_SC->SCp.this_residual &&
+ CURRENT_SC->SCp.buffers_residual)
{
/* advance to next buffer */
- current_SC->SCp.buffers_residual--;
- current_SC->SCp.buffer++;
- current_SC->SCp.ptr =
- current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual =
- current_SC->SCp.buffer->length;
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr =
+ CURRENT_SC->SCp.buffer->address;
+ CURRENT_SC->SCp.this_residual =
+ CURRENT_SC->SCp.buffer->length;
}
}
- if ( current_SC->SCp.this_residual ||
- current_SC->SCp.buffers_residual )
+ if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual)
{
/* target leaves DATA OUT for an other phase
(perhaps disconnect) */
data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
data_count += GETPORT(FIFOSTAT) ;
- current_SC->SCp.ptr -= data_count;
- current_SC->SCp.this_residual += data_count;
+ CURRENT_SC->SCp.ptr -= data_count;
+ CURRENT_SC->SCp.this_residual += data_count;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual,
- data_count );
+ if(HOSTDATA(shpnt)->debug & debug_datao)
+ printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), "
+ "transfer incomplete, resetting fifo, ",
+ CURRENT_SC->SCp.this_residual,
+ CURRENT_SC->SCp.buffers_residual,
+ data_count);
#endif
SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
CLRBITS(DMACNTRL0, ENDMA);
}
else
{
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("waiting for SCSI fifo to get empty, ");
#endif
/* wait for SCSI fifo to get empty */
- while( TESTLO( SSTAT2, SEMPTY ) )
+ while(TESTLO(SSTAT2, SEMPTY))
;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
+ if(HOSTDATA(shpnt)->debug & debug_datao)
printk("ok, left data (bytes=%d, buffers=%d) ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual);
+ CURRENT_SC->SCp.this_residual,
+ CURRENT_SC->SCp.buffers_residual);
#endif
CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
/* transfer can be considered ended, when SCSIEN reads back zero */
- while( TESTHI( SXFRCTL0, SCSIEN ) )
+ while(TESTHI(SXFRCTL0, SCSIEN))
;
CLRBITS(DMACNTRL0, ENDMA);
}
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
- if(aha152x_debug & (debug_datao|debug_intr))
- printk("sent %d data bytes, ", GETSTCNT() );
+ if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr))
+ printk("sent %d data bytes, ", GETSTCNT());
#endif
}
break;
leave_driver("(BUSFREE) intr");
#endif
#if defined(DEBUG_PHASES)
- if(aha152x_debug & debug_phases)
+ if(HOSTDATA(shpnt)->debug & debug_phases)
printk("unexpected BUS FREE, ");
#endif
- current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+ CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
- aha152x_done( DID_ERROR << 16 ); /* Don't know any better */
+ aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */
return;
break;
#endif
printk("PARITY error in DATA phase, ");
- current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+ CURRENT_SC->SCp.phase &= ~(P_MASK<<16);
- SETBITS( DMACNTRL0, INTEN );
- aha152x_done( DID_PARITY << 16 );
+ SETBITS(DMACNTRL0, INTEN);
+ aha152x_done(shpnt, DID_PARITY << 16);
return;
break;
if(done)
{
#if defined(DEBUG_INTR)
- if(aha152x_debug & debug_intr)
+ if(HOSTDATA(shpnt)->debug & debug_intr)
printk("command done.\n");
#endif
#if defined(DEBUG_RACE)
leave_driver("(done) intr");
#endif
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
- SETPORT(SCSISEQ, disconnected_SC ? ENRESELI : 0 );
-
- SETBITS( DMACNTRL0, INTEN );
-
- aha152x_done( (current_SC->SCp.Status & 0xff)
- | ( (current_SC->SCp.Message & 0xff) << 8)
- | ( DID_OK << 16) );
+ SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+ SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0);
+ SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+
+ SETBITS(DMACNTRL0, INTEN);
+
+ aha152x_done(shpnt,
+ (CURRENT_SC->SCp.Status & 0xff)
+ | ((CURRENT_SC->SCp.Message & 0xff) << 8)
+ | (DID_OK << 16));
#if defined(DEBUG_RACE)
printk("done returned (DID_OK: Status=%x; Message=%x).\n",
- current_SC->SCp.Status, current_SC->SCp.Message);
+ CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message);
#endif
return;
}
- if(current_SC)
- current_SC->SCp.phase |= 1<<16 ;
+ if(CURRENT_SC)
+ CURRENT_SC->SCp.phase |= 1<<16 ;
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
#if defined(DEBUG_INTR)
- if(aha152x_debug & debug_intr)
- disp_enintr();
+ if(HOSTDATA(shpnt)->debug & debug_intr)
+ disp_enintr(shpnt);
#endif
#if defined(DEBUG_RACE)
leave_driver("(PHASEEND) intr");
#endif
- SETBITS( DMACNTRL0, INTEN);
+ SETBITS(DMACNTRL0, INTEN);
return;
}
/*
* Dump the current driver status and panic...
*/
-static void aha152x_panic(const char *msg)
+static void aha152x_panic(struct Scsi_Host *shpnt, char *msg)
{
- printk("\naha152x_panic: %s\n", msg);
- show_queues();
+ printk("\naha152x: %s\n", msg);
+ show_queues(shpnt);
panic("aha152x panic");
}
/*
* Display registers of AIC-6260
*/
-static void disp_ports(void)
+static void disp_ports(struct Scsi_Host *shpnt)
{
#ifdef DEBUG_AHA152X
int s;
#ifdef SKIP_PORTS
- if(aha152x_debug & debug_skipports)
+ if(HOSTDATA(shpnt)->debug & debug_skipports)
return;
#endif
- printk("\n%s: ", current_SC ? "on bus" : "waiting");
+ printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting");
s=GETPORT(SCSISEQ);
- printk("SCSISEQ ( ");
- if( s & TEMODEO ) printk("TARGET MODE ");
- if( s & ENSELO ) printk("SELO ");
- if( s & ENSELI ) printk("SELI ");
- if( s & ENRESELI ) printk("RESELI ");
- if( s & ENAUTOATNO ) printk("AUTOATNO ");
- if( s & ENAUTOATNI ) printk("AUTOATNI ");
- if( s & ENAUTOATNP ) printk("AUTOATNP ");
- if( s & SCSIRSTO ) printk("SCSIRSTO ");
+ printk("SCSISEQ (");
+ if(s & TEMODEO) printk("TARGET MODE ");
+ if(s & ENSELO) printk("SELO ");
+ if(s & ENSELI) printk("SELI ");
+ if(s & ENRESELI) printk("RESELI ");
+ if(s & ENAUTOATNO) printk("AUTOATNO ");
+ if(s & ENAUTOATNI) printk("AUTOATNI ");
+ if(s & ENAUTOATNP) printk("AUTOATNP ");
+ if(s & SCSIRSTO) printk("SCSIRSTO ");
printk(");");
- printk(" SCSISIG ( ");
+ printk(" SCSISIG (");
s=GETPORT(SCSISIG);
switch(s & P_MASK)
{
break;
}
- printk(" ); ");
+ printk("); ");
- printk("INTSTAT ( %s ); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+ printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- printk("SSTAT ( ");
+ printk("SSTAT (");
s=GETPORT(SSTAT0);
- if( s & TARGET ) printk("TARGET ");
- if( s & SELDO ) printk("SELDO ");
- if( s & SELDI ) printk("SELDI ");
- if( s & SELINGO ) printk("SELINGO ");
- if( s & SWRAP ) printk("SWRAP ");
- if( s & SDONE ) printk("SDONE ");
- if( s & SPIORDY ) printk("SPIORDY ");
- if( s & DMADONE ) printk("DMADONE ");
+ if(s & TARGET) printk("TARGET ");
+ if(s & SELDO) printk("SELDO ");
+ if(s & SELDI) printk("SELDI ");
+ if(s & SELINGO) printk("SELINGO ");
+ if(s & SWRAP) printk("SWRAP ");
+ if(s & SDONE) printk("SDONE ");
+ if(s & SPIORDY) printk("SPIORDY ");
+ if(s & DMADONE) printk("DMADONE ");
s=GETPORT(SSTAT1);
- if( s & SELTO ) printk("SELTO ");
- if( s & ATNTARG ) printk("ATNTARG ");
- if( s & SCSIRSTI ) printk("SCSIRSTI ");
- if( s & PHASEMIS ) printk("PHASEMIS ");
- if( s & BUSFREE ) printk("BUSFREE ");
- if( s & SCSIPERR ) printk("SCSIPERR ");
- if( s & PHASECHG ) printk("PHASECHG ");
- if( s & REQINIT ) printk("REQINIT ");
+ if(s & SELTO) printk("SELTO ");
+ if(s & ATNTARG) printk("ATNTARG ");
+ if(s & SCSIRSTI) printk("SCSIRSTI ");
+ if(s & PHASEMIS) printk("PHASEMIS ");
+ if(s & BUSFREE) printk("BUSFREE ");
+ if(s & SCSIPERR) printk("SCSIPERR ");
+ if(s & PHASECHG) printk("PHASECHG ");
+ if(s & REQINIT) printk("REQINIT ");
printk("); ");
- printk("SSTAT ( ");
+ printk("SSTAT (");
s=GETPORT(SSTAT0) & GETPORT(SIMODE0);
- if( s & TARGET ) printk("TARGET ");
- if( s & SELDO ) printk("SELDO ");
- if( s & SELDI ) printk("SELDI ");
- if( s & SELINGO ) printk("SELINGO ");
- if( s & SWRAP ) printk("SWRAP ");
- if( s & SDONE ) printk("SDONE ");
- if( s & SPIORDY ) printk("SPIORDY ");
- if( s & DMADONE ) printk("DMADONE ");
+ if(s & TARGET) printk("TARGET ");
+ if(s & SELDO) printk("SELDO ");
+ if(s & SELDI) printk("SELDI ");
+ if(s & SELINGO) printk("SELINGO ");
+ if(s & SWRAP) printk("SWRAP ");
+ if(s & SDONE) printk("SDONE ");
+ if(s & SPIORDY) printk("SPIORDY ");
+ if(s & DMADONE) printk("DMADONE ");
s=GETPORT(SSTAT1) & GETPORT(SIMODE1);
- if( s & SELTO ) printk("SELTO ");
- if( s & ATNTARG ) printk("ATNTARG ");
- if( s & SCSIRSTI ) printk("SCSIRSTI ");
- if( s & PHASEMIS ) printk("PHASEMIS ");
- if( s & BUSFREE ) printk("BUSFREE ");
- if( s & SCSIPERR ) printk("SCSIPERR ");
- if( s & PHASECHG ) printk("PHASECHG ");
- if( s & REQINIT ) printk("REQINIT ");
+ if(s & SELTO) printk("SELTO ");
+ if(s & ATNTARG) printk("ATNTARG ");
+ if(s & SCSIRSTI) printk("SCSIRSTI ");
+ if(s & PHASEMIS) printk("PHASEMIS ");
+ if(s & BUSFREE) printk("BUSFREE ");
+ if(s & SCSIPERR) printk("SCSIPERR ");
+ if(s & PHASECHG) printk("PHASECHG ");
+ if(s & REQINIT) printk("REQINIT ");
printk("); ");
- printk("SXFRCTL0 ( ");
+ printk("SXFRCTL0 (");
s=GETPORT(SXFRCTL0);
- if( s & SCSIEN ) printk("SCSIEN ");
- if( s & DMAEN ) printk("DMAEN ");
- if( s & CH1 ) printk("CH1 ");
- if( s & CLRSTCNT ) printk("CLRSTCNT ");
- if( s & SPIOEN ) printk("SPIOEN ");
- if( s & CLRCH1 ) printk("CLRCH1 ");
+ if(s & SCSIEN) printk("SCSIEN ");
+ if(s & DMAEN) printk("DMAEN ");
+ if(s & CH1) printk("CH1 ");
+ if(s & CLRSTCNT) printk("CLRSTCNT ");
+ if(s & SPIOEN) printk("SPIOEN ");
+ if(s & CLRCH1) printk("CLRCH1 ");
printk("); ");
- printk("SIGNAL ( ");
+ printk("SIGNAL (");
s=GETPORT(SCSISIG);
- if( s & ATNI ) printk("ATNI ");
- if( s & SELI ) printk("SELI ");
- if( s & BSYI ) printk("BSYI ");
- if( s & REQI ) printk("REQI ");
- if( s & ACKI ) printk("ACKI ");
+ if(s & ATNI) printk("ATNI ");
+ if(s & SELI) printk("SELI ");
+ if(s & BSYI) printk("BSYI ");
+ if(s & REQI) printk("REQI ");
+ if(s & ACKI) printk("ACKI ");
printk("); ");
- printk("SELID ( %02x ), ", GETPORT(SELID) );
+ printk("SELID (%02x), ", GETPORT(SELID));
- printk("SSTAT2 ( ");
+ printk("SSTAT2 (");
s=GETPORT(SSTAT2);
- if( s & SOFFSET) printk("SOFFSET ");
- if( s & SEMPTY) printk("SEMPTY ");
- if( s & SFULL) printk("SFULL ");
- printk("); SFCNT ( %d ); ", s & (SFULL|SFCNT) );
+ if(s & SOFFSET) printk("SOFFSET ");
+ if(s & SEMPTY) printk("SEMPTY ");
+ if(s & SFULL) printk("SFULL ");
+ printk("); SFCNT (%d); ", s & (SFULL|SFCNT));
-#if 0
- printk("SSTAT4 ( ");
+ s=GETPORT(SSTAT3);
+ printk("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f);
+
+ printk("SSTAT4 (");
s=GETPORT(SSTAT4);
- if( s & SYNCERR) printk("SYNCERR ");
- if( s & FWERR) printk("FWERR ");
- if( s & FRERR) printk("FRERR ");
+ if(s & SYNCERR) printk("SYNCERR ");
+ if(s & FWERR) printk("FWERR ");
+ if(s & FRERR) printk("FRERR ");
printk("); ");
-#endif
-
- printk("FCNT ( %d ); ", GETPORT(FIFOSTAT) );
- printk("DMACNTRL0 ( ");
+ printk("DMACNTRL0 (");
s=GETPORT(DMACNTRL0);
- printk( "%s ", s & _8BIT ? "8BIT" : "16BIT" );
- printk( "%s ", s & DMA ? "DMA" : "PIO" );
- printk( "%s ", s & WRITE_READ ? "WRITE" : "READ" );
- if( s & ENDMA ) printk("ENDMA ");
- if( s & INTEN ) printk("INTEN ");
- if( s & RSTFIFO ) printk("RSTFIFO ");
- if( s & SWINT ) printk("SWINT ");
+ printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
+ printk("%s ", s & DMA ? "DMA" : "PIO" );
+ printk("%s ", s & WRITE_READ ? "WRITE" : "READ" );
+ if(s & ENDMA) printk("ENDMA ");
+ if(s & INTEN) printk("INTEN ");
+ if(s & RSTFIFO) printk("RSTFIFO ");
+ if(s & SWINT) printk("SWINT ");
printk("); ");
#if 0
- printk("DMACNTRL1 ( ");
+ printk("DMACNTRL1 (");
s=GETPORT(DMACNTRL1);
- if( s & PWRDWN ) printk("PWRDN ");
+ if(s & PWRDWN) printk("PWRDN ");
printk("); ");
- printk("STK ( %d ); ", s & 0xf);
+ printk("STK (%d); ", s & 0xf);
+
+#endif
printk("DMASTAT (");
s=GETPORT(DMASTAT);
- if( s & ATDONE ) printk("ATDONE ");
- if( s & WORDRDY ) printk("WORDRDY ");
- if( s & DFIFOFULL ) printk("DFIFOFULL ");
- if( s & DFIFOEMP ) printk("DFIFOEMP ");
+ if(s & ATDONE) printk("ATDONE ");
+ if(s & WORDRDY) printk("WORDRDY ");
+ if(s & DFIFOFULL) printk("DFIFOFULL ");
+ if(s & DFIFOEMP) printk("DFIFOEMP ");
printk(")");
-#endif
-
printk("\n");
#endif
}
/*
* display enabled interrupts
*/
-static void disp_enintr(void)
+static void disp_enintr(struct Scsi_Host *shpnt)
{
int s;
- printk("enabled interrupts ( ");
+ printk("enabled interrupts (");
s=GETPORT(SIMODE0);
- if( s & ENSELDO ) printk("ENSELDO ");
- if( s & ENSELDI ) printk("ENSELDI ");
- if( s & ENSELINGO ) printk("ENSELINGO ");
- if( s & ENSWRAP ) printk("ENSWRAP ");
- if( s & ENSDONE ) printk("ENSDONE ");
- if( s & ENSPIORDY ) printk("ENSPIORDY ");
- if( s & ENDMADONE ) printk("ENDMADONE ");
+ if(s & ENSELDO) printk("ENSELDO ");
+ if(s & ENSELDI) printk("ENSELDI ");
+ if(s & ENSELINGO) printk("ENSELINGO ");
+ if(s & ENSWRAP) printk("ENSWRAP ");
+ if(s & ENSDONE) printk("ENSDONE ");
+ if(s & ENSPIORDY) printk("ENSPIORDY ");
+ if(s & ENDMADONE) printk("ENDMADONE ");
s=GETPORT(SIMODE1);
- if( s & ENSELTIMO ) printk("ENSELTIMO ");
- if( s & ENATNTARG ) printk("ENATNTARG ");
- if( s & ENPHASEMIS ) printk("ENPHASEMIS ");
- if( s & ENBUSFREE ) printk("ENBUSFREE ");
- if( s & ENSCSIPERR ) printk("ENSCSIPERR ");
- if( s & ENPHASECHG ) printk("ENPHASECHG ");
- if( s & ENREQINIT ) printk("ENREQINIT ");
+ if(s & ENSELTIMO) printk("ENSELTIMO ");
+ if(s & ENATNTARG) printk("ENATNTARG ");
+ if(s & ENPHASEMIS) printk("ENPHASEMIS ");
+ if(s & ENBUSFREE) printk("ENBUSFREE ");
+ if(s & ENSCSIPERR) printk("ENSCSIPERR ");
+ if(s & ENPHASECHG) printk("ENPHASECHG ");
+ if(s & ENREQINIT) printk("ENREQINIT ");
printk(")\n");
}
*/
static void show_command(Scsi_Cmnd *ptr)
{
- printk("0x%08x: target=%d; lun=%d; cmnd=( ",
+ printk("0x%08x: target=%d; lun=%d; cmnd=(",
(unsigned int) ptr, ptr->target, ptr->lun);
print_command(ptr->cmnd);
printk("); residual=%d; buffers=%d; phase |",
ptr->SCp.this_residual, ptr->SCp.buffers_residual);
- if( ptr->SCp.phase & not_issued ) printk("not issued|");
- if( ptr->SCp.phase & in_selection ) printk("in selection|");
- if( ptr->SCp.phase & disconnected ) printk("disconnected|");
- if( ptr->SCp.phase & aborted ) printk("aborted|");
- if( ptr->SCp.phase & sent_ident ) printk("send_ident|");
- if( ptr->SCp.phase & in_other )
+ if(ptr->SCp.phase & not_issued ) printk("not issued|");
+ if(ptr->SCp.phase & in_selection) printk("in selection|");
+ if(ptr->SCp.phase & disconnected) printk("disconnected|");
+ if(ptr->SCp.phase & aborted ) printk("aborted|");
+ if(ptr->SCp.phase & sent_ident ) printk("send_ident|");
+ if(ptr->SCp.phase & in_other)
{
printk("; in other(");
- switch( (ptr->SCp.phase >> 16) & P_MASK )
+ switch((ptr->SCp.phase >> 16) & P_MASK)
{
case P_DATAO:
printk("DATA OUT");
/*
* Dump the queued data
*/
-static void show_queues(void)
+static void show_queues(struct Scsi_Host *shpnt)
{
unsigned long flags;
Scsi_Cmnd *ptr;
save_flags(flags);
cli();
printk("QUEUE STATUS:\nissue_SC:\n");
- for(ptr=issue_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
show_command(ptr);
printk("current_SC:\n");
- if(current_SC)
- show_command(current_SC);
+ if(CURRENT_SC)
+ show_command(CURRENT_SC);
else
printk("none\n");
printk("disconnected_SC:\n");
- for(ptr=disconnected_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
show_command(ptr);
- disp_ports();
- disp_enintr();
+ disp_ports(shpnt);
+ disp_enintr(shpnt);
restore_flags(flags);
}
+int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+ return(-ENOSYS); /* Currently this is a no-op */
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+static int get_command(char *pos, Scsi_Cmnd *ptr)
+{
+ char *start = pos;
+ int i;
+
+ SPRINTF("0x%08x: target=%d; lun=%d; cmnd=(",
+ (unsigned int) ptr, ptr->target, ptr->lun);
+
+ for(i=0; i<COMMAND_SIZE(ptr->cmnd[0]); i++)
+ SPRINTF("0x%02x", ptr->cmnd[i]);
+
+ SPRINTF("); residual=%d; buffers=%d; phase |",
+ ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+ if(ptr->SCp.phase & not_issued ) SPRINTF("not issued|");
+ if(ptr->SCp.phase & in_selection) SPRINTF("in selection|");
+ if(ptr->SCp.phase & disconnected) SPRINTF("disconnected|");
+ if(ptr->SCp.phase & aborted ) SPRINTF("aborted|");
+ if(ptr->SCp.phase & sent_ident ) SPRINTF("send_ident|");
+ if(ptr->SCp.phase & in_other)
+ {
+ SPRINTF("; in other(");
+ switch((ptr->SCp.phase >> 16) & P_MASK)
+ {
+ case P_DATAO:
+ SPRINTF("DATA OUT");
+ break;
+ case P_DATAI:
+ SPRINTF("DATA IN");
+ break;
+ case P_CMD:
+ SPRINTF("COMMAND");
+ break;
+ case P_STATUS:
+ SPRINTF("STATUS");
+ break;
+ case P_MSGO:
+ SPRINTF("MESSAGE OUT");
+ break;
+ case P_MSGI:
+ SPRINTF("MESSAGE IN");
+ break;
+ default:
+ SPRINTF("*illegal*");
+ break;
+ }
+ SPRINTF(")");
+ if(ptr->SCp.phase & (1<<16))
+ SPRINTF("; phaseend");
+ }
+ SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
+
+ return(pos-start);
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+
+int aha152x_proc_info(
+ char *buffer,
+ char **start,
+ off_t offset,
+ int length,
+ int hostno,
+ int inout
+ )
+{
+ int i;
+ char *pos = buffer;
+ Scsi_Device *scd;
+ struct Scsi_Host *shpnt;
+ unsigned long flags;
+ Scsi_Cmnd *ptr;
+
+ for(i=0, shpnt= (struct Scsi_Host *) NULL; i<IRQS; i++)
+ if(aha152x_host[i] && aha152x_host[i]->host_no == hostno)
+ shpnt=aha152x_host[i];
+
+ if(!shpnt)
+ return(-ESRCH);
+
+ if(inout) /* Has data been written to the file ? */
+ return(aha152x_set_info(buffer, length, shpnt));
+
+ SPRINTF(AHA152X_REVID "\n");
+
+ save_flags(flags);
+ cli();
+
+ SPRINTF("vital data:\nioports 0x%04x to 0x%04x\n",
+ shpnt->io_port, shpnt->io_port+shpnt->n_io_port-1);
+ SPRINTF("interrupt 0x%02x\n", shpnt->irq);
+ SPRINTF("disconnection/reconnection %s\n",
+ HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled");
+ SPRINTF("parity checking %s\n",
+ HOSTDATA(shpnt)->parity ? "enabled" : "disabled");
+ SPRINTF("synchronous transfers %s\n",
+ HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled");
+ SPRINTF("current queued %d commands\n",
+ HOSTDATA(shpnt)->commands);
+
+#if 0
+ SPRINTF("synchronously operating targets (tick=%ld ns):\n",
+ 250000000/loops_per_sec);
+ for(i=0; i<8; i++)
+ if(HOSTDATA(shpnt)->syncrate[i]&0x7f)
+ SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n",
+ i,
+ (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2),
+ (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*
+ 250000000/loops_per_sec,
+ HOSTDATA(shpnt)->syncrate[i]&0x0f);
+#else
+ SPRINTF("synchronously operating targets (tick=50 ns):\n");
+ for(i=0; i<8; i++)
+ if(HOSTDATA(shpnt)->syncrate[i]&0x7f)
+ SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
+ i,
+ (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2),
+ (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50,
+ HOSTDATA(shpnt)->syncrate[i]&0x0f);
+#endif
+
+#ifdef DEBUG_AHA152X
+#define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+
+ SPRINTF("enabled debugging options:\n");
+
+ PDEBUG(debug_skipports, "skip ports");
+ PDEBUG(debug_queue, "queue");
+ PDEBUG(debug_intr, "interrupt");
+ PDEBUG(debug_selection, "selection");
+ PDEBUG(debug_msgo, "message out");
+ PDEBUG(debug_msgi, "message in");
+ PDEBUG(debug_status, "status");
+ PDEBUG(debug_cmd, "command");
+ PDEBUG(debug_datai, "data in");
+ PDEBUG(debug_datao, "data out");
+ PDEBUG(debug_abort, "abort");
+ PDEBUG(debug_done, "done");
+ PDEBUG(debug_biosparam, "bios parameters");
+ PDEBUG(debug_phases, "phases");
+ PDEBUG(debug_queues, "queues");
+ PDEBUG(debug_reset, "reset");
+
+ SPRINTF("\n");
+#endif
+
+ SPRINTF("queue status:\nnot yet issued commands:\n");
+ for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ pos += get_command(pos, ptr);
+
+ if(CURRENT_SC)
+ {
+ SPRINTF("current command:\n");
+ pos += get_command(pos, CURRENT_SC);
+ }
+
+ SPRINTF("disconnected commands:\n");
+ for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ pos += get_command(pos, ptr);
+
+ restore_flags(flags);
+
+ scd = scsi_devices;
+
+ SPRINTF("Attached devices: %s\n", (scd)?"":"none");
+
+ while (scd) {
+ if (scd->host == shpnt) {
+
+ SPRINTF("Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
+ scd->channel, scd->id, scd->lun);
+ for (i=0; i<8; i++) {
+ if (scd->vendor[i] >= 0x20)
+ SPRINTF("%c", scd->vendor[i]);
+ else
+ SPRINTF(" ");
+ }
+ SPRINTF(" Model: ");
+ for (i = 0; i < 16; i++) {
+ if (scd->model[i] >= 0x20)
+ SPRINTF("%c", scd->model[i]);
+ else
+ SPRINTF(" ");
+ }
+ SPRINTF(" Rev: ");
+ for (i = 0; i < 4; i++) {
+ if (scd->rev[i] >= 0x20)
+ SPRINTF("%c", scd->rev[i]);
+ else
+ SPRINTF(" ");
+ }
+ SPRINTF("\n");
+
+ SPRINTF(" Type: %d ", scd->type);
+ SPRINTF(" ANSI SCSI revision: %02x",
+ (scd->scsi_level < 3)?1:2);
+
+ if (scd->scsi_level == 2)
+ SPRINTF(" CCS\n");
+ else
+ SPRINTF("\n");
+ }
+ scd = scd->next;
+ }
+
+ *start=buffer;
+ return (pos-buffer < length ? pos-buffer : length);
+}
+
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = AHA152X;
#define _AHA152X_H
/*
- * $Id: aha152x.h,v 1.9 1995/03/18 09:21:04 root Exp root $
+ * $Id: aha152x.h,v 1.11 1995/12/07 01:03:20 fischer Exp root $
*/
#if defined(__KERNEL__)
int aha152x_abort(Scsi_Cmnd *);
int aha152x_reset(Scsi_Cmnd *);
int aha152x_biosparam(Disk *, kdev_t, int*);
+int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
/* number of queueable commands
(unless we support more than 1 cmd_per_lun this should do) */
#define AHA152X_MAXQUEUE 7
-#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.9 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.11 $"
extern struct proc_dir_entry proc_scsi_aha152x;
/* Initial value of Scsi_Host entry */
#define AHA152X { /* next */ NULL, \
/* usage_count */ NULL, \
- &proc_scsi_aha152x, \
- NULL, \
+ /* proc_dir */ &proc_scsi_aha152x, \
+ /* proc_info */ aha152x_proc_info, \
/* name */ AHA152X_REVID, \
/* detect */ aha152x_detect, \
/* release */ NULL, \
/* port addresses */
-#define SCSISEQ (port_base+0x00) /* SCSI sequence control */
-#define SXFRCTL0 (port_base+0x01) /* SCSI transfer control 0 */
-#define SXFRCTL1 (port_base+0x02) /* SCSI transfer control 1 */
-#define SCSISIG (port_base+0x03) /* SCSI signal in/out */
-#define SCSIRATE (port_base+0x04) /* SCSI rate control */
-#define SELID (port_base+0x05) /* selection/reselection ID */
+#define SCSISEQ (shpnt->io_port+0x00) /* SCSI sequence control */
+#define SXFRCTL0 (shpnt->io_port+0x01) /* SCSI transfer control 0 */
+#define SXFRCTL1 (shpnt->io_port+0x02) /* SCSI transfer control 1 */
+#define SCSISIG (shpnt->io_port+0x03) /* SCSI signal in/out */
+#define SCSIRATE (shpnt->io_port+0x04) /* SCSI rate control */
+#define SELID (shpnt->io_port+0x05) /* selection/reselection ID */
#define SCSIID SELID /* SCSI ID */
-#define SCSIDAT (port_base+0x06) /* SCSI latched data */
-#define SCSIBUS (port_base+0x07) /* SCSI data bus */
-#define STCNT0 (port_base+0x08) /* SCSI transfer count 0 */
-#define STCNT1 (port_base+0x09) /* SCSI transfer count 1 */
-#define STCNT2 (port_base+0x0a) /* SCSI transfer count 2 */
-#define SSTAT0 (port_base+0x0b) /* SCSI interrupt status 0 */
-#define SSTAT1 (port_base+0x0c) /* SCSI interrupt status 1 */
-#define SSTAT2 (port_base+0x0d) /* SCSI interrupt status 2 */
-#define SCSITEST (port_base+0x0e) /* SCSI test control */
-#define SSTAT4 (port_base+0x0f) /* SCSI status 4 */
-#define SIMODE0 (port_base+0x10) /* SCSI interrupt mode 0 */
-#define SIMODE1 (port_base+0x11) /* SCSI interrupt mode 1 */
-#define DMACNTRL0 (port_base+0x12) /* DMA control 0 */
-#define DMACNTRL1 (port_base+0x13) /* DMA control 1 */
-#define DMASTAT (port_base+0x14) /* DMA status */
-#define FIFOSTAT (port_base+0x15) /* FIFO status */
-#define DATAPORT (port_base+0x16) /* DATA port */
-#define BRSTCNTRL (port_base+0x18) /* burst control */
-#define PORTA (port_base+0x1a) /* PORT A */
-#define PORTB (port_base+0x1b) /* PORT B */
-#define REV (port_base+0x1c) /* revision */
-#define STACK (port_base+0x1d) /* stack */
-#define TEST (port_base+0x1e) /* test register */
-
+#define SCSIDAT (shpnt->io_port+0x06) /* SCSI latched data */
+#define SCSIBUS (shpnt->io_port+0x07) /* SCSI data bus */
+#define STCNT0 (shpnt->io_port+0x08) /* SCSI transfer count 0 */
+#define STCNT1 (shpnt->io_port+0x09) /* SCSI transfer count 1 */
+#define STCNT2 (shpnt->io_port+0x0a) /* SCSI transfer count 2 */
+#define SSTAT0 (shpnt->io_port+0x0b) /* SCSI interrupt status 0 */
+#define SSTAT1 (shpnt->io_port+0x0c) /* SCSI interrupt status 1 */
+#define SSTAT2 (shpnt->io_port+0x0d) /* SCSI interrupt status 2 */
+#define SCSITEST (shpnt->io_port+0x0e) /* SCSI test control */
+#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */
+#define SSTAT4 (shpnt->io_port+0x0f) /* SCSI status 4 */
+#define SIMODE0 (shpnt->io_port+0x10) /* SCSI interrupt mode 0 */
+#define SIMODE1 (shpnt->io_port+0x11) /* SCSI interrupt mode 1 */
+#define DMACNTRL0 (shpnt->io_port+0x12) /* DMA control 0 */
+#define DMACNTRL1 (shpnt->io_port+0x13) /* DMA control 1 */
+#define DMASTAT (shpnt->io_port+0x14) /* DMA status */
+#define FIFOSTAT (shpnt->io_port+0x15) /* FIFO status */
+#define DATAPORT (shpnt->io_port+0x16) /* DATA port */
+#define BRSTCNTRL (shpnt->io_port+0x18) /* burst control */
+#define PORTA (shpnt->io_port+0x1a) /* PORT A */
+#define PORTB (shpnt->io_port+0x1b) /* PORT B */
+#define REV (shpnt->io_port+0x1c) /* revision */
+#define STACK (shpnt->io_port+0x1d) /* stack */
+#define TEST (shpnt->io_port+0x1e) /* test register */
+
+/* used in aha152x_porttest */
+#define O_PORTA (0x1a) /* PORT A */
+#define O_PORTB (0x1b) /* PORT B */
+#define O_DMACNTRL1 (0x13) /* DMA control 1 */
+#define O_STACK (0x1d) /* stack */
+#define IO_RANGE 0x20
/* bits and bitmasks to ports */
}
#else
void print_hostbyte(int scsiresult)
-{ printk("Hostbyte=0x%02x ",hostbyte(scsiresult));
+{ printk("Hostbyte=0x%02x ",host_byte(scsiresult));
}
#endif
}
#include "NCR5380.c"
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = GENERIC_NCR5380;
+
+#include <linux/module.h>
+#include "scsi_module.c"
+#endif
#define CAN_QUEUE 16
#endif
-#ifdef HOSTS_C
-
+#if defined(HOSTS_C) || defined(MODULE)
#define GENERIC_NCR5380 {NULL, NULL, NULL, NULL, \
"Trantor T128/T128F/T228", \
NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
-#else
+#endif
+
+#ifndef HOSTS_C
+
#define NCR5380_implementation_fields \
int port
}
#include "NCR5380.c"
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = MV_PAS16;
+
+#include <linux/module.h>
+#include "scsi_module.c"
+#endif
* macros when this is being used solely for the host stub.
*/
-#ifdef HOSTS_C
+#if defined(HOSTS_C) || defined(MODULE)
#define MV_PAS16 {NULL, NULL, NULL, NULL, \
"Pro Audio Spectrum-16 SCSI", \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
-#else
+#endif
+#ifndef HOSTS_C
#define NCR5380_implementation_fields \
volatile unsigned short io_port
Copyright 1992, 1993, 1994, 1995 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sat Nov 4 22:23:54 1995 by root@kai.makisara.fi
+ Last modified: Thu Dec 14 21:51:16 1995 by root@kai.makisara.fi
Some small formal changes - aeb, 950809
*/
is defined and non-zero. */
#define DEBUG 0
+/* The message level for the debug messages is currently set to KERN_NOTICE
+ so that people can easily see the messages. Later when the debugging messages
+ in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
+#define ST_DEB_MSG KERN_NOTICE
+
#define MAJOR_NR SCSI_TAPE_MAJOR
#include <linux/blk.h>
#include "scsi.h"
return 0;
#if DEBUG
if (debugging) {
- printk("st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", dev, result,
+ printk(ST_DEB_MSG "st%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+ dev, result,
SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
SCpnt->request_bufflen);
((sense[0] & 0x70) == 0x70 &&
scode != NO_SENSE &&
scode != RECOVERED_ERROR &&
- scode != UNIT_ATTENTION &&
+/* scode != UNIT_ATTENTION && */
scode != BLANK_CHECK &&
scode != VOLUME_OVERFLOW &&
- SCpnt->data_cmnd[0] != MODE_SENSE)) { /* Abnormal conditions for tape */
- printk("st%d: Error %x. ", dev, result);
+ SCpnt->data_cmnd[0] != MODE_SENSE &&
+ SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
#if !DEBUG
- if (driver_byte(result) & DRIVER_SENSE)
+ if (driver_byte(result) & DRIVER_SENSE) {
+ printk(KERN_WARNING "st%d: Error with sense data: ", dev);
print_sense("st", SCpnt);
+ }
else
- printk("\n");
+ printk(KERN_WARNING "st%d: Error %x.\n", dev, result);
#endif
}
stp = "write";
else
stp = "ioctl";
- printk("st%d: Recovered %s error (%d).\n", dev, stp,
+ printk(ST_DEB_MSG "st%d: Recovered %s error (%d).\n", dev, stp,
scsi_tapes[dev].recover_count);
}
#endif
}
#if DEBUG
else if (debugging)
- printk("st?: Illegal interrupt device %x\n", st_nbr);
+ printk(KERN_ERR "st?: Illegal interrupt device %x\n", st_nbr);
#endif
}
{
if (SCpnt == NULL)
if ((SCpnt = allocate_device(NULL, STp->device, 1)) == NULL) {
- printk("st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+ printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
return NULL;
}
SCpnt->request.rq_status = RQ_INACTIVE;
if ((STp->buffer)->last_result != 0) {
- printk("st%d: Backing over filemark failed.\n", TAPE_NR(STp->devt));
+ printk(KERN_ERR "st%d: Backing over filemark failed.\n", TAPE_NR(STp->devt));
if ((STp->mt_status)->mt_fileno >= 0)
(STp->mt_status)->mt_fileno += 1;
(STp->mt_status)->mt_blkno = 0;
if ((STp->buffer)->last_result_fatal) {
#if DEBUG
if (debugging)
- printk("st%d: Async write error (flush) %x.\n", TAPE_NR(STp->devt),
- (STp->buffer)->last_result);
+ printk(ST_DEB_MSG "st%d: Async write error (flush) %x.\n",
+ TAPE_NR(STp->devt), (STp->buffer)->last_result);
#endif
if ((STp->buffer)->last_result == INT_MAX)
return (-ENOSPC);
STp->block_size) * STp->block_size;
#if DEBUG
if (debugging)
- printk("st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
+ printk(ST_DEB_MSG "st%d: Flushing %d bytes.\n", TAPE_NR(STp->devt), transfer);
#endif
memset((STp->buffer)->b_data + offset, 0, transfer - offset);
return (-EBUSY);
if ((STp->buffer)->last_result_fatal != 0) {
- printk("st%d: Error on flush.\n", TAPE_NR(STp->devt));
+ printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt));
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40) &&
(SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) {
return (-ENXIO);
STp = &(scsi_tapes[dev]);
if (STp->in_use) {
- printk("st%d: Device already in use.\n", dev);
+#if DEBUG
+ printk(ST_DEB_MSG "st%d: Device already in use.\n", dev);
+#endif
return (-EBUSY);
}
+ STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
/* Allocate buffer for this user */
for (i=0; i < st_nbr_buffers; i++)
if (i >= st_nbr_buffers) {
STp->buffer = new_tape_buffer(FALSE);
if (STp->buffer == NULL) {
- printk("st%d: No free buffers.\n", dev);
+ printk(KERN_WARNING "st%d: No free buffers.\n", dev);
return (-EBUSY);
}
}
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) {
(STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
- printk("st%d: No tape.\n", dev);
+ printk(KERN_NOTICE "st%d: No tape.\n", dev);
STp->ready = ST_NO_TAPE;
} else {
(STp->mt_status)->mt_fileno = STp->drv_block = (-1);
(STp->buffer)->b_data[5];
#if DEBUG
if (debugging)
- printk("st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
+ printk(ST_DEB_MSG "st%d: Block limits %d - %d bytes.\n", dev, STp->min_block,
STp->max_block);
#endif
}
STp->min_block = STp->max_block = (-1);
#if DEBUG
if (debugging)
- printk("st%d: Can't read block limits.\n", dev);
+ printk(ST_DEB_MSG "st%d: Can't read block limits.\n", dev);
#endif
}
if ((STp->buffer)->last_result_fatal != 0) {
#if DEBUG
if (debugging)
- printk("st%d: No Mode Sense.\n", dev);
+ printk(ST_DEB_MSG "st%d: No Mode Sense.\n", dev);
#endif
STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */
(STp->buffer)->last_result_fatal = 0; /* Prevent error propagation */
#if DEBUG
if (debugging)
- printk("st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev,
+ printk(ST_DEB_MSG "st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
+ dev,
(STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
(STp->buffer)->b_data[2], (STp->buffer)->b_data[3]);
#endif
(STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
#if DEBUG
if (debugging)
- printk("st%d: Density %x, tape length: %x, drv buffer: %d\n",
+ printk(ST_DEB_MSG "st%d: Density %x, tape length: %x, drv buffer: %d\n",
dev, STp->density, (STp->buffer)->b_data[5] * 65536 +
(STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
STp->drv_buffer);
if (STp->block_size > (STp->buffer)->buffer_size &&
!enlarge_buffer(STp->buffer, STp->block_size)) {
- printk("st%d: Blocksize %d too large for buffer.\n", dev,
+ printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
STp->block_size);
(STp->buffer)->in_use = 0;
STp->in_use = 0;
#if DEBUG
if (debugging)
- printk("st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
+ printk(ST_DEB_MSG "st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev,
STp->block_size, (STp->buffer)->buffer_size,
(STp->buffer)->buffer_blocks);
#endif
STp->write_prot = 1;
#if DEBUG
if (debugging)
- printk( "st%d: Write protected\n", dev);
+ printk(ST_DEB_MSG "st%d: Write protected\n", dev);
#endif
if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
(STp->buffer)->in_use = 0;
scsi_tape_close(struct inode * inode, struct file * filp)
{
int result;
- int rewind;
static unsigned char cmd[10];
Scsi_Cmnd * SCpnt;
Scsi_Tape * STp;
int dev;
dev = TAPE_NR(devt);
- rewind = (MINOR(devt) & 0x80) == 0;
-
STp = &(scsi_tapes[dev]);
if ( STp->rw == ST_WRITING && !(STp->device)->was_reset) {
#if DEBUG
if (debugging) {
- printk("st%d: File length %ld bytes.\n", dev, (long)(filp->f_pos));
- printk("st%d: Async write waits %d, finished %d.\n", dev,
- STp->nbr_waits, STp->nbr_finished);
+ printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
+ dev, (long)(filp->f_pos));
+ printk(ST_DEB_MSG "st%d: Async write waits %d, finished %d.\n",
+ dev, STp->nbr_waits, STp->nbr_finished);
}
#endif
SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
if ((STp->buffer)->last_result_fatal != 0)
- printk("st%d: Error on write filemark.\n", dev);
+ printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
else {
if ((STp->mt_status)->mt_fileno >= 0)
(STp->mt_status)->mt_fileno++ ;
#if DEBUG
if (debugging)
- printk("st%d: Buffer flushed, %d EOF(s) written\n", dev, cmd[4]);
+ printk(ST_DEB_MSG "st%d: Buffer flushed, %d EOF(s) written\n",
+ dev, cmd[4]);
#endif
}
- else if (!rewind) {
+ else if (!STp->rew_at_close) {
#if ST_IN_FILE_POS
flush_buffer(inode, filp, 0);
#else
#endif
}
- if (rewind)
+ if (STp->rew_at_close)
st_int_ioctl(inode, filp, MTREW, 1);
if (STp->door_locked == ST_LOCKED_AUTO)
#if DEBUG
if (!STp->in_use) {
- printk("st%d: Incorrect device.\n", dev);
+ printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
return (-EIO);
}
#endif
return (-EACCES);
if (STp->block_size == 0 &&
- count > (STp->buffer)->buffer_size &&
- !enlarge_buffer(STp->buffer, count))
+ count > (STp->buffer)->buffer_size &&
+ !enlarge_buffer(STp->buffer, count))
return (-EOVERFLOW);
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(inode, filp, MTLOCK, 0))
+ !st_int_ioctl(inode, filp, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO;
if (STp->rw == ST_READING) {
retval = flush_buffer(inode, filp, 0);
if (retval)
- return retval;
+ return retval;
STp->rw = ST_WRITING;
}
if ((STp->buffer)->last_result_fatal) {
#if DEBUG
if (debugging)
- printk("st%d: Async write error (write) %x.\n", dev,
+ printk(ST_DEB_MSG "st%d: Async write error (write) %x.\n", dev,
(STp->buffer)->last_result);
#endif
if ((STp->buffer)->last_result == INT_MAX) {
return retval;
}
}
-
if (STp->eof == ST_EOM_OK)
return (-ENOSPC);
else if (STp->eof == ST_EOM_ERROR)
if ((STp->buffer)->last_result_fatal != 0) {
#if DEBUG
if (debugging)
- printk("st%d: Error on write:\n", dev);
+ printk(ST_DEB_MSG "st%d: Error on write:\n", dev);
#endif
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
retval = (-ENOSPC); /* EOM within current request */
#if DEBUG
if (debugging)
- printk("st%d: EOM with %d bytes unwritten.\n",
+ printk(ST_DEB_MSG "st%d: EOM with %d bytes unwritten.\n",
dev, transfer);
#endif
}
retval = (-EIO); /* EOM for old data */
#if DEBUG
if (debugging)
- printk("st%d: EOM with lost data.\n", dev);
+ printk(ST_DEB_MSG "st%d: EOM with lost data.\n", dev);
#endif
}
}
return (-EIO);
#if DEBUG
if (!STp->in_use) {
- printk("st%d: Incorrect device.\n", dev);
+ printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
return (-EIO);
}
#endif
#if DEBUG
if (debugging && STp->eof != ST_NOEOF)
- printk("st%d: EOF flag up. Bytes %d\n", dev,
+ printk(ST_DEB_MSG "st%d: EOF flag up. Bytes %d\n", dev,
(STp->buffer)->buffer_bytes);
#endif
if (((STp->buffer)->buffer_bytes == 0) &&
if ((STp->buffer)->last_result_fatal) {
#if DEBUG
if (debugging)
- printk("st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev,
+ printk(ST_DEB_MSG "st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+ dev,
SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
(STp->buffer)->buffer_bytes = bytes - transfer;
}
else {
- printk("st%d: Incorrect block size.\n", dev);
+ printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
return (-EIO);
}
bytes - transfer * STp->block_size;
#if DEBUG
if (debugging)
- printk("st%d: EOM detected (%d bytes read).\n", dev,
+ printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev,
(STp->buffer)->buffer_bytes);
#endif
}
bytes - transfer * STp->block_size;
#if DEBUG
if (debugging)
- printk(
+ printk(ST_DEB_MSG
"st%d: EOF detected (%d bytes read, transferred %d bytes).\n",
dev, (STp->buffer)->buffer_bytes, total);
#endif
else { /* nonzero sense key */
#if DEBUG
if (debugging)
- printk("st%d: Tape error while reading.\n", dev);
+ printk(ST_DEB_MSG "st%d: Tape error while reading.\n", dev);
#endif
SCpnt->request.rq_status = RQ_INACTIVE;
STp->drv_block = (-1);
(SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) {
#if DEBUG
if (debugging)
- printk("st%d: Zero returned for first BLANK CHECK after EOF.\n",
+ printk(ST_DEB_MSG
+ "st%d: Zero returned for first BLANK CHECK after EOF.\n",
dev);
#endif
STp->eof = ST_EOD;
if ((STp->buffer)->buffer_bytes > 0) {
#if DEBUG
if (debugging && STp->eof != ST_NOEOF)
- printk("st%d: EOF up. Left %d, needed %d.\n", dev,
+ printk(ST_DEB_MSG "st%d: EOF up. Left %d, needed %d.\n", dev,
(STp->buffer)->buffer_bytes, count - total);
#endif
transfer = (STp->buffer)->buffer_bytes < count - total ?
STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
#if DEBUG
debugging = (options & MT_ST_DEBUGGING) != 0;
- printk(
-"st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
- dev, STp->do_buffer_writes, STp->do_async_writes,
- STp->do_read_ahead);
- printk(" two FMs: %d, fast mteom: %d auto lock: %d, debugging: %d\n",
- STp->two_fm, STp->fast_mteom, STp->do_auto_lock, debugging);
+ printk(ST_DEB_MSG
+ "st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+ dev, STp->do_buffer_writes, STp->do_async_writes, STp->do_read_ahead);
+ printk(ST_DEB_MSG
+ "st%d: two FMs: %d, fast mteom: %d auto lock: %d, debugging: %d\n",
+ dev, STp->two_fm, STp->fast_mteom, STp->do_auto_lock, debugging);
#endif
}
else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) {
value = (options & ~MT_ST_OPTIONS) * ST_BLOCK_SIZE;
if (value < 1 || value > st_buffer_size) {
- printk("st: Write threshold %d too small or too large.\n",
+ printk(KERN_WARNING "st: Write threshold %d too small or too large.\n",
value);
return (-EIO);
}
STp->write_threshold = value;
#if DEBUG
- printk("st%d: Write threshold set to %d bytes.\n", dev,
+ printk(ST_DEB_MSG "st%d: Write threshold set to %d bytes.\n", dev,
STp->write_threshold);
#endif
}
cmd[4] = arg;
#if DEBUG
if (debugging)
- printk("st%d: Spacing tape forward over %d filemarks.\n", dev,
- cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+ printk(ST_DEB_MSG "st%d: Spacing tape forward over %d filemarks.\n",
+ dev, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
if (fileno >= 0)
fileno += arg;
if (cmd[2] & 0x80)
ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk("st%d: Spacing tape backward over %ld filemarks.\n", dev, (-ltmp));
+ printk(ST_DEB_MSG "st%d: Spacing tape backward over %ld filemarks.\n",
+ dev, (-ltmp));
}
#endif
if (fileno >= 0)
cmd[4] = arg;
#if DEBUG
if (debugging)
- printk("st%d: Spacing tape forward %d blocks.\n", dev,
+ printk(ST_DEB_MSG "st%d: Spacing tape forward %d blocks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
if (blkno >= 0)
if (cmd[2] & 0x80)
ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk("st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
+ printk(ST_DEB_MSG "st%d: Spacing tape backward %ld blocks.\n", dev, (-ltmp));
}
#endif
if (blkno >= 0)
cmd[4] = arg;
#if DEBUG
if (debugging)
- printk("st%d: Spacing tape forward %d setmarks.\n", dev,
+ printk(ST_DEB_MSG "st%d: Spacing tape forward %d setmarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
#endif
if (arg != 0) {
if (cmd[2] & 0x80)
ltmp = 0xff000000;
ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
- printk("st%d: Spacing tape backward %ld setmarks.\n", dev, (-ltmp));
+ printk(ST_DEB_MSG "st%d: Spacing tape backward %ld setmarks.\n",
+ dev, (-ltmp));
}
#endif
if (arg != 0) {
#if DEBUG
if (debugging) {
if (cmd_in == MTWEOF)
- printk("st%d: Writing %d filemarks.\n", dev,
+ printk(ST_DEB_MSG "st%d: Writing %d filemarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
else
- printk("st%d: Writing %d setmarks.\n", dev,
+ printk(ST_DEB_MSG "st%d: Writing %d setmarks.\n", dev,
cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
}
#endif
#endif
#if DEBUG
if (debugging)
- printk("st%d: Rewinding tape.\n", dev);
+ printk(ST_DEB_MSG "st%d: Rewinding tape.\n", dev);
#endif
fileno = blkno = at_sm = 0 ;
break;
case MTOFFL:
+ case MTLOAD:
+ case MTUNLOAD:
cmd[0] = START_STOP;
+ if (cmd_in == MTLOAD)
+ cmd[4] |= 1;
#if ST_NOWAIT
cmd[1] = 1; /* Don't wait for completion */
timeout = ST_TIMEOUT;
+#else
+ timeout = ST_LONG_TIMEOUT * 8;
#endif
#if DEBUG
if (debugging)
- printk("st%d: Unloading tape.\n", dev);
+ printk(ST_DEB_MSG "st%d: Unloading tape.\n", dev);
#endif
fileno = blkno = at_sm = 0 ;
break;
case MTNOP:
#if DEBUG
if (debugging)
- printk("st%d: No op on tape.\n", dev);
+ printk(ST_DEB_MSG "st%d: No op on tape.\n", dev);
#endif
return 0; /* Should do something ? */
break;
cmd[4] = 3;
#if DEBUG
if (debugging)
- printk("st%d: Retensioning tape.\n", dev);
+ printk(ST_DEB_MSG "st%d: Retensioning tape.\n", dev);
#endif
fileno = blkno = at_sm = 0;
break;
cmd[1] = 3;
#if DEBUG
if (debugging)
- printk("st%d: Spacing to end of recorded medium.\n", dev);
+ printk(ST_DEB_MSG "st%d: Spacing to end of recorded medium.\n", dev);
#endif
blkno = 0;
at_sm = 0;
#endif
#if DEBUG
if (debugging)
- printk("st%d: Erasing tape.\n", dev);
+ printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev);
#endif
fileno = blkno = at_sm = 0 ;
break;
cmd[4] = SCSI_REMOVAL_PREVENT;
#if DEBUG
if (debugging)
- printk("st%d: Locking drive door.\n", dev);
+ printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev);
#endif;
break;
case MTUNLOCK:
cmd[4] = SCSI_REMOVAL_ALLOW;
#if DEBUG
if (debugging)
- printk("st%d: Unlocking drive door.\n", dev);
+ printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev);
#endif;
break;
- case MTLOAD:
- case MTUNLOAD:
- cmd[0] = START_STOP;
- if (cmd_in == MTLOAD)
- cmd[4] |= 1;
-#if ST_NOWAIT
- cmd[1] |= 2; /* Don't wait for completion */
- timeout = ST_TIMEOUT;
-#else
- timeout = ST_LONG_TIMEOUT * 8;
-#endif
- break;
case MTSEEK:
if ((STp->device)->scsi_level < SCSI_2) {
cmd[0] = QFA_SEEK_BLOCK;
#endif
#if DEBUG
if (debugging)
- printk("st%d: Seeking tape to block %ld.\n", dev, arg);
+ printk(ST_DEB_MSG "st%d: Seeking tape to block %ld.\n", dev, arg);
#endif
fileno = blkno = (-1);
at_sm = 0;
arg != 0 &&
(arg < STp->min_block || arg > STp->max_block ||
arg > st_buffer_size)) {
- printk("st%d: Illegal block size.\n", dev);
+ printk(KERN_WARNING "st%d: Illegal block size.\n", dev);
return (-EINVAL);
}
cmd[0] = MODE_SELECT;
#if DEBUG
if (debugging) {
if (cmd_in == MTSETBLK)
- printk("st%d: Setting block size to %d bytes.\n", dev,
+ printk(ST_DEB_MSG "st%d: Setting block size to %d bytes.\n", dev,
(STp->buffer)->b_data[9] * 65536 +
(STp->buffer)->b_data[10] * 256 +
(STp->buffer)->b_data[11]);
else if (cmd_in == MTSETDENSITY)
- printk("st%d: Setting density code to %x.\n", dev,
+ printk(ST_DEB_MSG "st%d: Setting density code to %x.\n", dev,
(STp->buffer)->b_data[4]);
else
- printk("st%d: Setting drive buffer code to %d.\n", dev,
+ printk(ST_DEB_MSG "st%d: Setting drive buffer code to %d.\n", dev,
((STp->buffer)->b_data[2] >> 4) & 7);
}
#endif
break;
default:
- printk("st%d: Unknown st_ioctl command %x.\n", dev, cmd_in);
return (-ENOSYS);
}
STp->eof = ST_NOEOF;
STp->eof_hit = 0;
}
+ if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
+ STp->rew_at_close = 0;
+ else if (cmd_in == MTLOAD)
+ STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+
} else { /* SCSI command was not completely successful */
if (SCpnt->sense_buffer[2] & 0x40) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
STp = &(scsi_tapes[dev]);
#if DEBUG
if (debugging && !STp->in_use) {
- printk("st%d: Incorrect device.\n", dev);
+ printk(ST_DEB_MSG "st%d: Incorrect device.\n", dev);
return (-EIO);
}
#endif
memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
if (!(STp->device)->was_reset) {
+
+ if (STp->eof_hit) {
+ if (mtc.mt_op == MTFSF || mtc.mt_op == MTEOM) {
+ mtc.mt_count -= 1;
+ (STp->mt_status)->mt_fileno += 1;
+ }
+ else if (mtc.mt_op == MTBSF) {
+ mtc.mt_count += 1;
+ (STp->mt_status)->mt_fileno += 1;
+ }
+ }
+
i = flush_buffer(inode, file, mtc.mt_op == MTSEEK ||
mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
if (st_int_ioctl(inode, file, MTLOCK, 0)) {
- printk("st%d: Could not relock door after bus reset.\n", dev);
+ printk(KERN_NOTICE "st%d: Could not relock door after bus reset.\n",
+ dev);
STp->door_locked = ST_UNLOCKED;
}
}
return (-EIO);
#if DEBUG
if (debugging)
- printk("st%d: get tape position.\n", dev);
+ printk(ST_DEB_MSG "st%d: get tape position.\n", dev);
#endif
if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
return (-EINVAL);
mt_pos.mt_blkno = (-1);
#if DEBUG
if (debugging)
- printk("st%d: Can't read tape position.\n", dev);
+ printk(ST_DEB_MSG "st%d: Can't read tape position.\n", dev);
#endif
result = (-EIO);
}
}
}
if (!tb) {
- printk("st: Can't allocate new tape buffer (nbr %d).\n", st_nbr_buffers);
+ printk(KERN_NOTICE "st: Can't allocate new tape buffer (nbr %d).\n",
+ st_nbr_buffers);
return NULL;
}
#if DEBUG
if (debugging)
- printk("st: Allocated tape buffer %d (%d bytes).\n", st_nbr_buffers,
- a_size);
+ printk(ST_DEB_MSG "st: Allocated tape buffer %d (%d bytes).\n",
+ st_nbr_buffers, a_size);
#endif
tb->in_use = 0;
tb->buffer_size = a_size;
#if DEBUG
if (debugging)
- printk("st: Buffer enlarged to %d bytes.\n", a_size);
+ printk(ST_DEB_MSG "st: Buffer enlarged to %d bytes.\n", a_size);
#endif
STbuffer->orig_b_data = STbuffer->b_data;
#if DEBUG
if (debugging)
- printk("st: Buffer normalized to %d bytes.\n", STbuffer->buffer_size);
+ printk(ST_DEB_MSG "st: Buffer normalized to %d bytes.\n",
+ STbuffer->buffer_size);
#endif
}
/* Set the boot options. Syntax: st=xxx,yyy
- where xxx is buffer size in 512 byte blocks and yyy is write threshold
- in 512 byte blocks. */
+ where xxx is buffer size in 1024 byte blocks and yyy is write threshold
+ in 1024 byte blocks. */
void
st_setup(char *str, int *ints)
{
{
if(SDp->type != TYPE_TAPE) return 0;
- printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
+ printk(KERN_NOTICE "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
st_template.dev_noticed++,
SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
if(!st_registered) {
if (register_chrdev(SCSI_TAPE_MAJOR,"st",&st_fops)) {
- printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR);
+ printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",MAJOR_NR);
return 1;
}
st_registered++;
(Scsi_Tape *) scsi_init_malloc(st_template.dev_max * sizeof(Scsi_Tape),
GFP_ATOMIC);
if (scsi_tapes == NULL) {
- printk("Unable to allocate descriptors for SCSI tapes.\n");
+ printk(KERN_ERR "Unable to allocate descriptors for SCSI tapes.\n");
unregister_chrdev(SCSI_TAPE_MAJOR, "st");
return 1;
}
#if DEBUG
- printk("st: Buffer size %d bytes, write threshold %d bytes.\n",
+ printk(ST_DEB_MSG "st: Buffer size %d bytes, write threshold %d bytes.\n",
st_buffer_size, st_write_threshold);
#endif
(ST_buffer **) scsi_init_malloc(st_template.dev_max * sizeof(ST_buffer *),
GFP_ATOMIC);
if (st_buffers == NULL) {
- printk("Unable to allocate tape buffer pointers.\n");
+ printk(KERN_ERR "Unable to allocate tape buffer pointers.\n");
unregister_chrdev(SCSI_TAPE_MAJOR, "st");
scsi_init_free((char *) scsi_tapes,
st_template.dev_max * sizeof(Scsi_Tape));
for (i=st_nbr_buffers=0; i < target_nbr; i++) {
if (!new_tape_buffer(TRUE)) {
if (i == 0) {
- printk("Can't continue without at least one tape buffer.\n");
+ printk(KERN_ERR "Can't continue without at least one tape buffer.\n");
unregister_chrdev(SCSI_TAPE_MAJOR, "st");
scsi_init_free((char *) st_buffers,
st_template.dev_max * sizeof(ST_buffer *));
st_template.dev_max * sizeof(Scsi_Tape));
return 1;
}
- printk("Number of tape buffers adjusted.\n");
+ printk(KERN_INFO "Number of tape buffers adjusted.\n");
break;
}
}
unsigned char fast_mteom;
unsigned char density;
unsigned char door_locked;
+ unsigned char rew_at_close;
ST_buffer * buffer;
struct semaphore sem;
int block_size;
Copyright 1995 Kai Makisara.
- Last modified: Sun Sep 24 11:46:15 1995 by root@kai.makisara.fi
+ Last modified: Thu Dec 14 21:51:27 1995 by root@kai.makisara.fi
*/
#ifndef _ST_OPTIONS_H
}
#include "NCR5380.c"
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = TRANTOR_T128;
+
+#include "scsi_module.c"
+#endif
* macros when this is being used solely for the host stub.
*/
-#ifdef HOSTS_C
+#if defined(HOSTS_C) || defined(MODULE)
#define TRANTOR_T128 {NULL, NULL, NULL, NULL, \
"Trantor T128/T128F/T228", t128_detect, NULL, \
/* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
/* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
-#else
+#endif
+
+#ifndef(HOSTS_C)
#define NCR5380_implementation_fields \
volatile unsigned char *base
continue;
}
- if (bh->b_count || bh->b_size != size)
+ if (bh->b_count || buffer_protected(bh) || bh->b_size != size)
continue;
/* Buffers are written in the order they are placed
panic("Busy buffer in candidate list\n");
if (mem_map[MAP_NR((unsigned long) bh->b_data)].count != 1)
panic("Shared buffer in candidate list\n");
+ if (buffer_protected(bh))
+ panic("Protected buffer in candidate list\n");
if (BADNESS(bh)) panic("Buffer in candidate list with BADNESS != 0\n");
if(bh->b_dev == B_FREE)
}
if (buffer_dirty(buf))
dispose = BUF_DIRTY;
- else if (mem_map[MAP_NR((unsigned long) buf->b_data)].count > 1)
+ else if ((mem_map[MAP_NR((unsigned long) buf->b_data)].count > 1) || buffer_protected(buf))
dispose = BUF_SHARED;
else if (buffer_locked(buf))
dispose = BUF_LOCKED;
printk("Aieee... bforget(): shared buffer\n");
return;
}
+ if (buffer_protected(buf)) {
+ printk("Aieee... bforget(): protected buffer\n");
+ return;
+ }
mark_buffer_clean(buf);
buf->b_count = 0;
remove_from_queues(buf);
do {
if (!tmp)
return 0;
- if (tmp->b_count || buffer_dirty(tmp) || buffer_locked(tmp) || tmp->b_wait)
+ if (tmp->b_count || buffer_protected(tmp) ||
+ buffer_dirty(tmp) || buffer_locked(tmp) || tmp->b_wait)
return 0;
if (priority && buffer_touched(tmp))
return 0;
bh = free_list[isize];
if(!bh) continue;
for (i=0 ; !i || bh != free_list[isize]; bh = bh->b_next_free, i++) {
- if (bh->b_count || !bh->b_this_page)
+ if (bh->b_count || buffer_protected(bh) ||
+ !bh->b_this_page)
continue;
if (!age_of((unsigned long) bh->b_data) &&
try_to_free(bh, &bh, 6))
/* We may have stalled while waiting for I/O
to complete. */
if(bh->b_list != nlist) goto repeat1;
- if (bh->b_count || !bh->b_this_page)
+ if (bh->b_count || buffer_protected(bh) ||
+ !bh->b_this_page)
continue;
if(size && bh->b_size != size) continue;
if (buffer_locked(bh))
{
struct buffer_head * bh;
int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
+ int protected = 0;
int shared;
int nlist, isize;
printk("Buffer blocks: %6d\n",nr_buffers);
for(nlist = 0; nlist < NR_LIST; nlist++) {
- shared = found = locked = dirty = used = lastused = 0;
+ shared = found = locked = dirty = used = lastused = protected = 0;
bh = lru_list[nlist];
if(!bh) continue;
do {
found++;
if (buffer_locked(bh))
locked++;
+ if (buffer_protected(bh))
+ protected++;
if (buffer_dirty(bh))
dirty++;
if(mem_map[MAP_NR(((unsigned long) bh->b_data))].count !=1) shared++;
used++, lastused = found;
bh = bh->b_next_free;
} while (bh != lru_list[nlist]);
- printk("Buffer[%d] mem: %d buffers, %d used (last=%d), %d locked, %d dirty %d shrd\n",
- nlist, found, used, lastused, locked, dirty, shared);
+ printk("Buffer[%d] mem: %d buffers, %d used (last=%d), %d locked, "
+ "%d protected, %d dirty %d shrd\n",
+ nlist, found, used, lastused, locked, protected, dirty, shared);
};
- printk("Size [LAV] Free Clean Unshar Lck Lck1 Dirty Shared\n");
+ printk("Size [LAV] Free Clean Unshar Lck Lck1 Dirty Shared \n");
for(isize = 0; isize<NR_SIZES; isize++){
printk("%5d [%5d]: %7d ", bufferindex_size[isize],
buffers_lav[isize], nr_free[isize]);
if (!tmp)
return 0;
- if (tmp->b_count || buffer_dirty(tmp) || buffer_locked(tmp))
+ if (tmp->b_count || buffer_protected(tmp) ||
+ buffer_dirty(tmp) || buffer_locked(tmp))
return 0;
tmp = tmp->b_this_page;
} while (tmp != bh);
static void wakeup_bdflush(int wait)
{
- if(!bdflush_running){
- printk("Warning - bdflush not running\n");
+ extern int rd_loading;
+
+ if (!bdflush_running){
+ if (!rd_loading)
+ printk("Warning - bdflush not running\n");
sync_buffers(0,0);
return;
};
/* forwards */
static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv);
+ int *lowercase, int *conv, int *nocheck);
static int check_warn(int not_ok,
const char *p1, const char *p2, const char *p3);
static int zerop(void *addr, unsigned len);
int lowercase;
int conv;
int dubious;
+ int nocheck;
MOD_INC_USE_COUNT;
* Get the mount options
*/
- if (!parse_opts(options, &uid, &gid, &umask, &lowercase, &conv)) {
+ if (!parse_opts(options, &uid, &gid, &umask, &lowercase, &conv,
+ &nocheck)) {
printk("HPFS: syntax error in mount options. Not mounted.\n");
s->s_dev = 0;
MOD_DEC_USE_COUNT;
* so don't
*/
- if (dubious)
+ if (dubious && !nocheck)
goto bail2;
dubious |= check_warn((spareblock->n_dnode_spares !=
*/
static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask,
- int *lowercase, int *conv)
+ int *lowercase, int *conv, int *nocheck)
{
char *p, *rhs;
*umask = current->fs->umask;
*lowercase = 1;
*conv = CONV_BINARY;
+ *nocheck = 0;
if (!opts)
return 1;
else
return 0;
}
+ else if (!strcmp(p,"nocheck"))
+ *nocheck=1;
else
return 1;
}
wait_on_inode(inode);
if (IS_WRITABLE(inode)) {
- if (inode->i_sb->dq_op)
+ if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->drop(inode);
}
remove_inode_hash(inode);
inode->i_count--;
if (IS_WRITABLE(inode)) {
- if (inode->i_sb->dq_op)
+ if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->drop(inode);
}
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
inode->i_ino = nr;
+ inode->i_flags = sb->s_flags;
put_last_free(inode);
insert_inode_hash(inode);
read_inode(inode);
printk("msdos_file_write: mode = %07o\n",inode->i_mode);
return -EINVAL;
}
- /* Must not harm system files */
- if (MSDOS_I(inode)->i_attrs & ATTR_SYS) return -EPERM;
+ /* system files are immutable */
+ if (IS_IMMUTABLE(inode)) return -EPERM;
/*
* ok, append may not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
{
int cluster;
- /* Must not harm system files */
/* Why no return value? Surely the disk could fail... */
- if (MSDOS_I(inode)->i_attrs & ATTR_SYS) return /* -EPERM */;
+ if (IS_IMMUTABLE(inode)) return /* -EPERM */;
cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
*check = 'n';
*conversion = 'b';
- *dotsOK =0;
+ /* Please leave dotsOK as 1, and contact Albert Cahalan if */
+ /* it causes any problems for you. <albert@ccs.neu.edu> */
+ *dotsOK =1; /* see note above, and report problems */
*uid = current->uid;
*gid = current->gid;
*umask = current->fs->umask;
inode->i_nlink = 1;
inode->i_size = CF_LE_L(raw_entry->size);
}
+ if(raw_entry->attr & ATTR_SYS)
+ inode->i_flags |= S_IMMUTABLE;
MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion,
raw_entry->ext);
MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED;
res = -EPERM;
goto unlink_done;
}
- if (MSDOS_I(inode)->i_attrs & ATTR_SYS){
+ if (IS_IMMUTABLE(inode)){
res = -EPERM;
goto unlink_done;
}
error = -EROFS;
else {
dir->i_count++; /* create eats the dir */
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
error = dir->i_op->create(dir, basename, namelen, mode, res_inode);
up(&dir->i_sem);
iput(inode);
return error;
}
- if (inode->i_sb->dq_op)
+ if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
newattrs.ia_size = 0;
newattrs.ia_valid = ATTR_SIZE;
put_write_access(inode);
} else
if (flag & FMODE_WRITE)
- if (inode->i_sb->dq_op)
+ if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
*res_inode = inode;
return 0;
return -EPERM;
}
dir->i_count++;
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
return -EPERM;
}
dir->i_count++;
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
error = dir->i_op->mkdir(dir, basename, namelen, mode & 0777 & ~current->fs->umask);
iput(dir);
return -EPERM;
}
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
return dir->i_op->rmdir(dir,basename,namelen);
}
iput(dir);
return -EPERM;
}
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
return dir->i_op->unlink(dir,basename,namelen);
}
return -EPERM;
}
dir->i_count++;
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
error = dir->i_op->symlink(dir,basename,namelen,oldname);
return -EPERM;
}
dir->i_count++;
- if (dir->i_sb->dq_op)
+ if (dir->i_sb && dir->i_sb->dq_op)
dir->i_sb->dq_op->initialize(dir, -1);
down(&dir->i_sem);
error = dir->i_op->link(oldinode, dir, basename, namelen);
return -EPERM;
}
new_dir->i_count++;
- if (new_dir->i_sb->dq_op)
+ if (new_dir->i_sb && new_dir->i_sb->dq_op)
new_dir->i_sb->dq_op->initialize(new_dir, -1);
down(&new_dir->i_sem);
error = old_dir->i_op->rename(old_dir, old_base, old_len,
struct inode * inode;
struct file * file;
struct iattr newattrs;
+ int error;
if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
return -EBADF;
newattrs.ia_valid |= ATTR_MODE;
}
inode->i_dirt = 1;
- return notify_change(inode, &newattrs);
+ if (inode->i_sb->dq_op) {
+ inode->i_sb->dq_op->initialize(inode, -1);
+ if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
+ return -EDQUOT;
+ error = notify_change(inode, &newattrs);
+ if (error)
+ inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
+ } else
+ error = notify_change(inode, &newattrs);
+ return error;
}
asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
newattrs.ia_valid |= ATTR_MODE;
}
inode->i_dirt = 1;
- error = notify_change(inode, &newattrs);
+ if (inode->i_sb->dq_op) {
+ inode->i_sb->dq_op->initialize(inode, -1);
+ if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
+ return -EDQUOT;
+ 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);
}
printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
,UMSDOS_VERSION,UMSDOS_RELEASE);
if (sb != NULL){
+ MSDOS_SB(sb)->dotsOK = 0; /* disable hidden==dotfile */
sb->s_op = &umsdos_sops;
PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
umsdos_setup_dir_inode (sb->s_mounted);
* in <asm/page.h> (currently 8192).
*/
-#define invalidate_all() \
-__asm__ __volatile__( \
- "lda $16,-2($31)\n\t" \
- ".long 51" \
- : : :"$1", "$16", "$17", "$22","$23","$24","$25")
-
-#define invalidate() \
-__asm__ __volatile__( \
- "lda $16,-1($31)\n\t" \
- ".long 51" \
- : : :"$1", "$16", "$17", "$22","$23","$24","$25")
+extern void tbi(long type, ...);
+
+#define tbisi(x) tbi(1,(x))
+#define tbisd(x) tbi(2,(x))
+#define tbis(x) tbi(3,(x))
+#define tbiap() tbi(-1)
+#define tbia() tbi(-2)
+
+/*
+ * Invalidate current user mapping.
+ */
+static inline void invalidate(void)
+{
+ tbiap();
+}
+
+/*
+ * Invalidate everything (kernel mapping may also have
+ * changed due to vmalloc/vfree)
+ */
+static inline void invalidate_all(void)
+{
+ tbia();
+}
+
+/*
+ * Invalidate a specified user mapping
+ */
+static inline void invalidate_mm(struct mm_struct *mm)
+{
+ tbiap();
+}
+
+/*
+ * Page-granular invalidate.
+ *
+ * do a tbisd (type = 2) normally, and a tbis (type = 3)
+ * if it is an executable mapping. We want to avoid the
+ * itlb invalidate, because that potentially also does a
+ * icache invalidate.
+ */
+static inline void invalidate_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ tbi(2 + ((vma->vm_flags & VM_EXEC) != 0), addr);
+}
+
+/*
+ * Invalidate a specified range of user mapping: on the
+ * alpha we invalidate the whole user tlb
+ */
+static inline void invalidate_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ tbiap();
+}
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
extern unsigned long __zero_page(void);
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE 0xfffffc000030A000
/* number of bits that fit into a memory pointer */
#define BITS_PER_PTR (8*sizeof(unsigned long))
0, 0, 0, \
}
+#define alloc_kernel_stack() get_free_page(GFP_KERNEL)
+#define free_kernel_stack(page) free_page((page))
+
#include <asm/ptrace.h>
/*
#define TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
printk("Ok.\n");
}
+static void check_tlb(void)
+{
+ /*
+ * The 386 chips don't support TLB finegrained invalidation.
+ * They will fault when they hit a invlpg instruction.
+ */
+ if (x86 == 3) {
+#if defined(CONFIG_M486) || defined(CONFIG_M586)
+ printk("CPU is a 386 and this kernel was compiled for 486 or better.\n");
+ printk("Giving up.\n");
+ for (;;) ;
+#endif
+ return;
+ }
+}
+
static void check_bugs(void)
{
+ check_tlb();
check_fpu();
check_hlt();
system_utsname.machine[1] = '0' + x86;
#ifndef _I386_PGTABLE_H
#define _I386_PGTABLE_H
+#include <linux/config.h>
+
/*
* Define USE_PENTIUM_MM if you want the 4MB page table optimizations.
* This works only on a intel Pentium.
#define __invalidate() \
__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
-#ifdef __i486__
+#ifdef CONFIG_M486
#define __invalidate_one(addr) \
__asm__ __volatile__("invlpg %0": :"m" (*(char *) addr))
#else
__invalidate();
}
-static inline void invalidate_page(struct mm_struct *mm,
+static inline void invalidate_page(struct vm_area_struct *vma,
unsigned long addr)
{
- if (mm == current->mm)
+ if (vma->vm_mm == current->mm)
__invalidate_one(addr);
}
invalidate();
}
-static inline void invalidate_page(struct mm_struct *mm,
+static inline void invalidate_page(struct vm_area_struct *vma,
unsigned long addr)
{
invalidate();
NULL, 0, 0, 0, 0 /* vm86_info */ \
}
+#define alloc_kernel_stack() get_free_page(GFP_KERNEL)
+#define free_kernel_stack(page) free_page((page))
+
static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
{
regs->cs = USER_CS;
#define TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+
/* Used for packet mode */
#define TIOCPKT_DATA 0
#define TIOCPKT_FLUSHREAD 1
--- /dev/null
+#ifndef __ASM_MIPS_A_OUT_H
+#define __ASM_MIPS_A_OUT_H
+
+struct exec
+{
+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a) ((a).a_trsize)
+#define N_DRSIZE(a) ((a).a_drsize)
+#define N_SYMSIZE(a) ((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP TASK_SIZE
+
+#endif
+
+#endif /* __ASM_MIPS_A_OUT_H */
--- /dev/null
+/*
+ * include/asm-mips/asm.h
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ *
+ * Some usefull macros for MIPS assembler code
+ *
+ * Some of the routines below contain useless nops that will be optimized
+ * away by gas in -O mode. These nops are however required to fill delay
+ * slots in noreorder mode.
+ */
+#ifndef __ASM_ASM_H
+#define __ASM_ASM_H
+
+#include <linux/config.h>
+#include <asm/regdef.h>
+#include <asm/fpregdef.h>
+
+#ifndef CAT
+#ifdef __STDC__
+#define __CAT(str1,str2) str1##str2
+#else
+#define __CAT(str1,str2) str1/**/str2
+#endif
+#define CAT(str1,str2) __CAT(str1,str2)
+#endif
+
+/*
+ * Macros to handle different pointer sizes for 32/64-bit code
+ */
+#if __mips == 3
+#define PTR .quad
+#define PTRSIZE 8
+#define PTRLOG 3
+#define lp ld
+#else
+#define PTR .word
+#define PTRSIZE 4
+#define PTRLOG 2
+#define lp lw
+#endif
+
+/*
+ * ELF specific declarations
+ */
+#ifdef __ELF__
+#define TYPE(symbol,_type) \
+ .type symbol,@_type
+#define SIZE(symbol,_size) \
+ .size symbol,_size
+#else
+#define TYPE(symbol,type)
+#define SIZE(symbol,size)
+#endif
+
+/*
+ * PIC specific declarations
+ * Not used for the kernel but here seems to be the right place.
+ */
+#ifdef __PIC__
+#define CPRESTORE(register) \
+ .cprestore register
+#define CPADD(register) \
+ .cpadd register
+#define CPLOAD(register) \
+ .cpload register
+#else
+#define CPRESTORE(register)
+#define CPADD(register)
+#define CPLOAD(register)
+#endif
+
+/*
+ * LEAF - declare leaf routine
+ */
+#define LEAF(symbol) \
+ .globl symbol; \
+ .align 2; \
+ TYPE(symbol,function); \
+ .ent symbol,0; \
+symbol: .frame sp,0,ra
+
+/*
+ * NESTED - declare nested routine entry point
+ */
+#define NESTED(symbol, framesize, rpc) \
+ .globl symbol; \
+ .align 2; \
+ TYPE(symbol,function); \
+ .ent symbol,0; \
+symbol: .frame sp, framesize, rpc
+
+/*
+ * END - mark end of function
+ */
+#define END(function) \
+ .end function; \
+ SIZE(function,.-function)
+
+/*
+ * EXPORT - export definition of symbol
+ */
+#define EXPORT(symbol) \
+ .globl symbol; \
+symbol:
+
+/*
+ * ABS - export absolute symbol
+ */
+#define ABS(symbol,value) \
+ .globl symbol; \
+symbol = value
+
+#define PANIC(msg) \
+ la a0,8f; \
+ jal panic; \
+ nop; \
+9: b 9b; \
+ nop; \
+ TEXT(msg)
+
+/*
+ * Print formated string
+ */
+#define PRINT(string) \
+ la a0,8f; \
+ jal printk; \
+ nop; \
+ TEXT(string)
+
+#define TEXT(msg) \
+ .data; \
+8: .asciiz msg; \
+ .text
+
+/*
+ * Build text tables
+ */
+#define TTABLE(string) \
+ .text; \
+ .word 1f; \
+ .data; \
+1: .asciz string; \
+ .text;
+
+/*
+ * Move to kernel mode and disable interrupts
+ * Set cp0 enable bit as sign that we're running on the kernel stack
+ * Use with .set noat!
+ * Note that the mtc0 will be effective on R4000 pipeline stage 7. This
+ * means that another three instructions will be executed with interrupts
+ * disabled.
+ */
+#define CLI \
+ mfc0 AT,CP0_STATUS; \
+ li t0,ST0_CU0|0x1f; \
+ or AT,t0; \
+ xori AT,0x1f; \
+ mtc0 AT,CP0_STATUS; \
+
+/*
+ * Move to kernel mode and enable interrupts
+ * Set cp0 enable bit as sign that we're running on the kernel stack
+ * Use with .set noat!
+ * Note that the mtc0 will be effective on R4000 pipeline stage 7. This
+ * means that another three instructions will be executed with interrupts
+ * disabled. Arch/mips/kernel/r4xx0.S makes use of this fact.
+ */
+#define STI \
+ mfc0 AT,CP0_STATUS; \
+ li t0,ST0_CU0|0x1f; \
+ or AT,t0; \
+ xori AT,0x1e; \
+ mtc0 AT,CP0_STATUS; \
+
+/*
+ * Special nop to fill load delay slots
+ */
+#ifndef __R4000__
+#define NOP nop
+#else
+#define NOP
+#endif
+
+/*
+ * Return from exception
+ */
+#if defined (CONFIG_CPU_R3000)
+#define ERET rfe
+#elif defined (CONFIG_CPU_R4X00) || defined (CONFIG_CPU_R4600)
+#define ERET \
+ .set mips3; \
+ eret; \
+ .set mips0
+#else
+#error "Implement ERET macro!"
+#endif
+
+/*
+ * R8000/R10000 (MIPS ISA IV) pref instruction.
+ * Use with .set noreorder only!
+ */
+#if defined (CONFIG_CPU_R8000) || defined(CONFIG_CPU_R10000)
+#define PREF(hint,addr) \
+ pref hint,addr
+#define PREFX(hint,addr) \
+ prefx hint,addr
+#else
+#define PREF
+#define PREFX
+#endif
+
+/*
+ * R8000/R10000 (MIPS ISA IV) movn/movz instructions and
+ * equivalents for old CPUs. Use with .set noreorder only!
+ */
+#if defined (CONFIG_CPU_R8000) || defined (CONFIG_CPU_R10000)
+#define MOVN(rd,rs,rt) \
+ movn rd,rs,rt
+#define MOVZ(rd,rs,rt) \
+ movz rd,rs,rt
+#elif defined (CONFIG_CPU_R4000) || defined (CONFIG_CPU_R6000)
+#define MOVN(rd,rs,rt) \
+ bnezl rt,9f \
+ move rd,rs \
+9:
+#define MOVZ(rd,rs,rt) \
+ beqzl rt,9f \
+ movz rd,rt \
+9:
+#else /* R2000, R3000 */
+#define MOVN(rd,rs,rt) \
+ beqz rt,9f \
+ nop \
+ move rd,rs \
+9:
+#define MOVZ(rd,rs,rt) \
+ bneqz rt,9f \
+ nop \
+ movz rd,rt \
+9:
+#endif
+
+#endif /* __ASM_ASM_H */
#ifndef __ASM_MIPS_BITOPS_H
#define __ASM_MIPS_BITOPS_H
-#ifdef __R4000__
+#if __mips > 1
+/*
+ * These functions for MIPS ISA >= 2 are interrupt and SMP proof and
+ * interrupt friendly
+ */
#include <asm/mipsregs.h>
/*
return retval;
}
-#else /* !defined(__R4000__) */
+#else /* __mips <= 1 */
+/*
+ * These functions are only used for MIPS ISA 1 CPUs. Since I don't
+ * believe that someone ever will run Linux/SMP on such a beast I don't
+ * worry about making them SMP proof.
+ */
#include <asm/system.h>
#ifdef __KERNEL__
/*
- * Only disable interrupt for kernelmode stuff to keep some
- * usermode stuff alive
+ * Only disable interrupt for kernel mode stuff to keep usermode stuff
+ * that dares to use kernel include files alive.
*/
#define __flags unsigned long flags
#define __cli() cli()
#undef __save_flags(x)
#undef __restore_flags(x)
-#endif /* !defined(__R4000__) */
+#endif /* __mips <= 1 */
extern __inline__ int test_bit(int nr, const void *addr)
{
- int mask;
- unsigned long *a;
-
- a = addr;
- addr += nr >> 5;
- mask = 1 << (nr & 0x1f);
- return ((mask & *a) != 0);
+ return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31));
}
extern __inline__ int find_first_zero_bit (void *addr, unsigned size)
__asm__ __volatile__ (
".set\tnoreorder\n\t"
".set\tnoat\n\t"
- "li\t%2,1\n"
+ "move\t%0,$0\n"
"1:\tand\t$1,%2,%1\n\t"
- "beq\t$0,$1,2f\n\t"
- "sll\t%2,%2,1\n\t"
- "bne\t$0,%2,1b\n\t"
- "add\t%0,%0,1\n\t"
+ "beqz\t$1,2f\n\t"
+ "sll\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder\n"
"2:\n\t"
- : "=r" (__res), "=r" (word), "=r" (mask)
- : "1" (~(word)),
- "2" (mask),
- "0" (0)
+ : "=r" (__res), "=r" (mask)
+ : "r" (word), "1" (mask)
: "$1");
return __res;
* License. See the file README.legal in the main directory of this archive
* for more details.
*/
-
#ifndef __ASM_MIPS_BOOTINFO_H
#define __ASM_MIPS_BOOTINFO_H
/*
- * Valid values for machtype field
+ * Valid machtype values
*/
-#define MACH_UNKNOWN 0 /* whatever... */
-#define MACH_DESKSTATION_TYNE 1 /* Deskstation Tyne */
-#define MACH_ACER_PICA_61 2 /* Acer PICA-61 (PICA1) */
-#define MACH_MIPS_MAGNUM_4000 3 /* Mips Magnum 4000 (aka RC4030) */
+#define MACH_UNKNOWN 0 /* whatever... */
+#define MACH_DESKSTATION_RPC44 1 /* Deskstation rPC44 */
+#define MACH_DESKSTATION_TYNE 2 /* Deskstation Tyne */
+#define MACH_ACER_PICA_61 3 /* Acer PICA-61 (PICA1) */
+#define MACH_MIPS_MAGNUM_4000 4 /* Mips Magnum 4000 "RC4030" */
+#define MACH_OLIVETTI_M700 5 /* Olivetti M700 */
+#define MACH_LAST 5
+
+#define MACH_NAMES { "unknown", "Deskstation rPC44", "Deskstation Tyne", \
+ "Acer PICA 61", "Mips Magnum 4000", "Olivetti M700" }
/*
- * Valid values for cputype field
+ * Valid cputype values
*/
#define CPU_UNKNOWN 0
#define CPU_R2000 1
#define CPU_R6000A 18
#define CPU_R8000 19
#define CPU_R10000 20
+#define CPU_LAST 20
-#define CPU_NAMES { "UNKNOWN", "R2000", "R3000", "R3000A", "R3041", "R3051", \
+#define CPU_NAMES { "unknown", "R2000", "R3000", "R3000A", "R3041", "R3051", \
"R3052", "R3081", "R3081E", "R4000PC", "R4000SC", "R4000MC", \
"R4200", "R4400PC", "R4400SC", "R4400MC", "R4600", "R6000", \
"R6000A", "R8000", "R10000" }
#define CL_SIZE (80)
-#ifndef __ASSEMBLY__
+#ifndef __LANGUAGE_ASSEMBLY__
/*
* Some machine parameters passed by MILO. Note that bootinfo
};
struct bootinfo {
- unsigned long machtype; /* machine type */
- unsigned long cputype; /* system CPU & FPU */
+ /*
+ * machine type
+ */
+ unsigned long machtype;
+
+ /*
+ * system CPU & FPU
+ */
+ unsigned long cputype;
/*
* Installed RAM
/*
* Ramdisk Info
*/
- unsigned long ramdisk_size; /* ramdisk size in 1024 byte blocks */
+ unsigned long ramdisk_flags; /* ramdisk flags */
unsigned long ramdisk_base; /* address of the ram disk in mem */
/*
};
+#if 0
+/*
+ * New style bootinfo
+ *
+ * Add new tags only at the end of the enum; *never* remove any tags
+ * or you'll break compatibility!
+ */
+enum bi_tag {
+ /*
+ * not a real tag
+ */
+ dummy,
+
+ /*
+ * machine type
+ */
+ machtype,
+
+ /*
+ * system CPU & FPU
+ */
+ cputype,
+
+ /*
+ * Installed RAM
+ */
+ memlower,
+ memupper,
+
+ /*
+ * Cache Sizes (0xffffffff = unknown)
+ */
+ icache_size,
+ icache_linesize,
+ dcache_size,
+ dcache_linesize,
+ scache_size,
+ scache_linesize,
+
+ /*
+ * TLB Info
+ */
+ tlb_entries,
+
+ /*
+ * DMA buffer size (Deskstation only)
+ */
+ dma_cache_size,
+ dma_cache_base,
+
+ /*
+ * Ramdisk Info
+ */
+ ramdisk_size, /* ramdisk size in 1024 byte blocks */
+ ramdisk_base, /* address of the ram disk in mem */
+
+ /*
+ * Boot flags for the kernel
+ */
+ mount_root_rdonly,
+ drive_info,
+
+ /*
+ * Video ram info (not in tty.h)
+ */
+ vram_base, /* video ram base address */
+
+ command_line /* kernel command line parameters */
+
+};
+
+typedef struct {
+ bi_tag tag;
+ unsigned long size;
+} tag;
+#endif
+
extern struct bootinfo boot_info;
/*
* are in the .data segment since the .bss segment is
* cleared during startup.
*/
-#define BOOT_INFO { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"" }
+#define BOOT_INFO { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, {{0,}}, 0, "" }
+#define SCREEN_INFO {0, 0, {0, }, 52, 3, 80, 4626, 3, 9, 50}
-#else /* !__ASSEMBLY__ */
+#else /* !__LANGUAGE_ASSEMBLY__ */
/*
* Same structure, but as offsets for usage within assembler source.
#define OFFSET_BOOTINFO_DMA_CACHE_BASE 48
#define OFFSET_BOOTINFO_RAMDISK_SIZE 52
#define OFFSET_BOOTINFO_RAMDISK_BASE 56
-#define OFFSET_BOOTINFO_VRAM_BASE 60
-#define OFFSET_BOOTINFO_COMMAND_LINE 64
+#define OFFSET_BOOTINFO_MOUNT_RD_ONLY 60
+#define OFFSET_BOOTINFO_DRIVE_INFO 64
+#define OFFSET_BOOTINFO_VRAM_BASE 96
+#define OFFSET_BOOTINFO_COMMAND_LINE 100
-#endif /* __ASSEMBLY__ */
+#endif /* __LANGUAGE_ASSEMBLY__ */
#endif /* __ASM_MIPS_BOOTINFO_H */
#ifndef __ASM_MIPS_BYTEORDER_H
#define __ASM_MIPS_BYTEORDER_H
+/*
+ * FIXME: Add big endian support
+ */
#undef ntohl
#undef ntohs
#undef htonl
#undef htons
-#ifdef MIPSEL
+#if defined (__MIPSEL__)
#define __LITTLE_ENDIAN
#define __LITTLE_ENDIAN_BITFIELD
-#elif MIPSEB
+#elif defined (__MIPSEB__)
#define __BIG_ENDIAN
#define __BIG_ENDIAN_BITFIELD
#else
-#error "MIPS but neither MIPSEL nor MIPSEB?"
+#error "MIPS but neither __MIPSEL__ nor __MIPSEB__?"
#endif
extern unsigned long int ntohl(unsigned long int);
extern unsigned long int htonl(unsigned long int);
extern unsigned short int htons(unsigned short int);
-extern unsigned long int __ntohl(unsigned long int);
-extern unsigned short int __ntohs(unsigned short int);
-extern unsigned long int __constant_ntohl(unsigned long int);
-extern unsigned short int __constant_ntohs(unsigned short int);
+extern __inline__ unsigned long int __ntohl(unsigned long int);
+extern __inline__ unsigned short int __ntohs(unsigned short int);
+extern __inline__ unsigned long int __constant_ntohl(unsigned long int);
+extern __inline__ unsigned short int __constant_ntohs(unsigned short int);
/*
* The constant and non-constant versions here are the same.
* Maybe I'll come up with an mips-optimized routine for the
* non-constant ones (the constant ones don't need it: gcc
- * will optimize it to the correct constant)
+ * will optimize it to the correct constant). Oh, and the
+ * big endian routines that are still missing will be fairly
+ * easy to write :-)
*/
extern __inline__ unsigned long int
((x & 0xff000000U) >> 24));
}
-extern __inline__ unsigned long int
-__constant_ntohl(unsigned long int x)
-{
- return (((x & 0x000000ffU) << 24) |
- ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) |
- ((x & 0xff000000U) >> 24));
-}
+#define __constant_ntohl(x) \
+ ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
+ (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
+ (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
+ (((unsigned long int)(x) & 0xff000000U) >> 24)))
extern __inline__ unsigned short int
__ntohs(unsigned short int x)
((x & 0xff00) >> 8));
}
-extern __inline__ unsigned short int
-__constant_ntohs(unsigned short int x)
-{
- return (((x & 0x00ff) << 8) |
- ((x & 0xff00) >> 8));
-}
+#define __constant_ntohs(x) \
+ ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
+ (((unsigned short int)(x) & 0xff00) >> 8))) \
#define __htonl(x) __ntohl(x)
#define __htons(x) __ntohs(x)
*
* Written by Ralf Baechle,
* Copyright (C) 1994 by Waldorf GMBH
- *
- * Defines for Risc/OS compatible cacheflush systemcall
*/
#ifndef __ASM_MIPS_CACHECTL
#define __ASM_MIPS_CACHECTL
#define DCACHE (1<<1) /* writeback and flush data cache */
#define BCACHE (ICACHE|DCACHE) /* flush both caches */
-#define CACHELINES 512 /* number of cachelines */
-
#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
+#define CACHELINES 512 /* number of cachelines (kludgy) */
+
+/*
+ * Cache Operations - for use by assembler code
+ */
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+#define Index_Load_Tag_D 0x05
+
+#ifndef __LANGUAGE_ASSEMBLY__
extern int sys_cacheflush(void *addr, int nbytes, int cache);
-#endif
-#endif
+#endif /* !__LANGUAGE_ASSEMBLY__ */
+#endif /* __KERNEL__ */
#endif /* __ASM_MIPS_CACHECTL */
--- /dev/null
+/*
+ * include/asm-mips/checksum.h
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_CHECKSUM_H
+#define __ASM_MIPS_CHECKSUM_H
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum);
+
+/*
+ * the same as csum_partial, but copies from user space (but on the alpha
+ * we have just one address space, so this is identical to the above)
+ */
+#define csum_partial_copy_fromuser csum_partial_copy
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ *
+ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
+ * Arnt Gulbrandsen.
+ */
+static inline unsigned short ip_fast_csum(unsigned char * iph,
+ unsigned int ihl)
+{
+ unsigned short int sum;
+ unsigned long dummy1, dummy2;
+
+ /*
+ * This is optimized for 32-bit MIPS processors.
+ * I tried it in plain C but the generated code looks to bad to
+ * use with old first generation MIPS CPUs.
+ * Using 64-bit code could even further improve these routines.
+ */
+ __asm__("
+ .set noreorder
+ .set noat
+ lw %0,(%3)
+ subu %1,4
+ blez %1,2f
+ sll %1,%4,2 # delay slot
+ lw %2,4(%3)
+ addu %1,%3 # delay slot
+ addu %0,%2
+ sltu $1,%0,%2
+ lw %2,8(%3)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+ lw %2,12(%3)
+ addu %0,$1
+ addu %0,%2
+ sltu $1,%0,%2
+ addu %0,$1
+1: lw %2,16(%3)
+ addu %1,4
+ addu %0,%2
+ sltu $1,%0,%2
+ bne %1,%3,1b
+ addu %0,$1 # delay slot
+ srl $1,%0,16
+ addu %0,$1
+ sltu $1,%0,$1
+ addu %0,$1
+ nor %0,$0,%0
+ andi %0,0xffff
+2: .set at
+ .set reorder"
+ : "=r" (sum), "=r" (dummy1), "=r" (dummy2)
+ : "r" (iph), "r"(ihl)
+ : "$1");
+
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ __asm__("
+ .set noat
+ addu %0,%2
+ sltu $1,%0,%2
+ addu %0,$1
+ addu %0,%3
+ sltu $1,%0,%3
+ addu %0,$1
+ addu %0,%4
+ sltu $1,%0,%4
+ addu %0,$1
+ srl $1,%0,16
+ addu %0,$1
+ sltu $1,%0,$1
+ addu %0,$1
+ nor %0,$0,%0
+ andi %0,0xffff
+ .set at"
+ : "=r" (sum)
+ : "0" (daddr), "r"(saddr), "r"((ntohs(len)<<16)+proto*256), "r"(sum)
+ : "$1");
+
+ return (unsigned short)sum;
+}
+
+/*
+ * Fold a partial checksum without adding pseudo headers
+ */
+static inline unsigned short int csum_fold(unsigned int sum)
+{
+ __asm__("
+ .set noat
+ srl $1,%0,16
+ addu %0,$1
+ sltu $1,%0,$1
+ nor %0,$0,%0
+ andi %0,0xffff
+ .set at"
+ : "=r"(sum)
+ : "0" (sum)
+ : "$1");
+
+ return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len) {
+ unsigned short int sum;
+
+ __asm__("
+ .set noat
+ srl $1,%0,16
+ addu %0,$1
+ sltu $1,%0,$1
+ nor %0,$0,%0
+ andi %0,0xffff
+ .set at"
+ : "=r"(sum)
+ : "r" (csum_partial(buff, len, 0))
+ : "$1");
+
+ return sum;
+}
+
+#endif /* __ASM_MIPS_CHECKSUM_H */
extern __inline__ void udelay(unsigned long usecs)
{
usecs *= 0x000010c6; /* 2**32 / 1000000 */
- __asm__("mul\t%0,%0,%1"
+ __asm__("multu\t%0,%1\n\t"
+ "mfhi\t%0"
:"=r" (usecs)
:"0" (usecs),"r" (loops_per_sec));
__delay(usecs);
}
/*
- * 64-bit integers means we don't have to worry about overflow as
- * on some other architectures..
+ * The different variants for 32/64 bit are pure paranoia. The typical
+ * range of numbers that apprears for MIPS machines avoids overflows.
*/
extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
{
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
* and John Boyd, Nov. 1992.
+ *
+ * NOTE: all this is true *only* for ISA/EISA expansions on Mips boards
+ * and can only be used for expansion cards. Onboard DMA controller, such
+ * as the R4030 on Jazz boards behave totally different!
*/
#ifndef __ASM_MIPS_DMA_H
#define MAX_DMA_CHANNELS 8
-/* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS 0x1000000
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
+/*
+ * The maximum address that we can perform a DMA transfer to on this platform
+ * This discribes only the PC style part of the DMA logic like on Deskstations
+ * or Acer PICA but not the much more versatile DMA logic used for the
+ * local devices on Acer PICA or Mangnums.
+ */
#define MAX_DMA_ADDRESS 0x1000000
/* 8237 DMA controllers */
extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
+/*
+ * DMA memory allocation - formerly in include/linux/mm.h
+ */
+#define __get_dma_pages(priority, order) __get_free_pages((priority),(order), \
+ 0x80000000 + MAX_DMA_ADDRESS)
#endif /* __ASM_MIPS_DMA_H */
--- /dev/null
+#ifndef __ASM_MIPS_ELF_H
+#define __ASM_MIPS_ELF_H
+
+/*
+ * ELF register definitions
+ * This is "make it compile" stuff!
+ */
+#define ELF_NGREG 32
+#define ELF_NFPREG 32
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#endif /* __ASM_MIPS_ELF_H */
--- /dev/null
+/*
+ * include/asm-mips/errno.h
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_ERRNO_H
+#define __ASM_MIPS_ERRNO_H
+
+/*
+ * These error numbers are intended to be MIPS ABI compatible
+ */
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Arg list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+#define ENOMSG 35 /* No message of desired type */
+#define EIDRM 36 /* Identifier removed */
+#define ECHRNG 37 /* Channel number out of range */
+#define EL2NSYNC 38 /* Level 2 not synchronized */
+#define EL3HLT 39 /* Level 3 halted */
+#define EL3RST 40 /* Level 3 reset */
+#define ELNRNG 41 /* Link number out of range */
+#define EUNATCH 42 /* Protocol driver not attached */
+#define ENOCSI 43 /* No CSI structure available */
+#define EL2HLT 44 /* Level 2 halted */
+#define EDEADLK 45 /* Resource deadlock would occur */
+#define ENOLCK 46 /* No record locks available */
+#define EBADE 50 /* Invalid exchange */
+#define EBADR 51 /* Invalid request descriptor */
+#define EXFULL 52 /* Exchange full */
+#define ENOANO 53 /* No anode */
+#define EBADRQC 54 /* Invalid request code */
+#define EBADSLT 55 /* Invalid slot */
+#define EDEADLOCK 56 /* File locking deadlock error */
+#define EBFONT 59 /* Bad font file format */
+#define ENOSTR 60 /* Device not a stream */
+#define ENODATA 61 /* No data available */
+#define ETIME 62 /* Timer expired */
+#define ENOSR 63 /* Out of streams resources */
+#define ENONET 64 /* Machine is not on the network */
+#define ENOPKG 65 /* Package not installed */
+#define EREMOTE 66 /* Object is remote */
+#define ENOLINK 67 /* Link has been severed */
+#define EADV 68 /* Advertise error */
+#define ESRMNT 69 /* Srmount error */
+#define ECOMM 70 /* Communication error on send */
+#define EPROTO 71 /* Protocol error */
+#define EDOTDOT 73 /* RFS specific error */
+#define EMULTIHOP 74 /* Multihop attempted */
+#define EBADMSG 77 /* Not a data message */
+#define ENAMETOOLONG 78 /* File name too long */
+#define EOVERFLOW 79 /* Value too large for defined data type */
+#define ENOTUNIQ 80 /* Name not unique on network */
+#define EBADFD 81 /* File descriptor in bad state */
+#define EREMCHG 82 /* Remote address changed */
+#define ELIBACC 83 /* Can not access a needed shared library */
+#define ELIBBAD 84 /* Accessing a corrupted shared library */
+#define ELIBSCN 85 /* .lib section in a.out corrupted */
+#define ELIBMAX 86 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 87 /* Cannot exec a shared library directly */
+#define EILSEQ 88 /* Illegal byte sequence */
+#define ENOSYS 89 /* Function not implemented */
+#define ELOOP 90 /* Too many symbolic links encountered */
+#define ERESTART 91 /* Interrupted system call should be restarted */
+#define ESTRPIPE 92 /* Streams pipe error */
+#define ENOTEMPTY 93 /* Directory not empty */
+#define EUSERS 94 /* Too many users */
+#define ENOTSOCK 95 /* Socket operation on non-socket */
+#define EDESTADDRREQ 96 /* Destination address required */
+#define EMSGSIZE 97 /* Message too long */
+#define EPROTOTYPE 98 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 99 /* Protocol not available */
+#define EPROTONOSUPPORT 120 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 121 /* Socket type not supported */
+#define EOPNOTSUPP 122 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 123 /* Protocol family not supported */
+#define EAFNOSUPPORT 124 /* Address family not supported by protocol */
+#define EADDRINUSE 125 /* Address already in use */
+#define EADDRNOTAVAIL 126 /* Cannot assign requested address */
+#define ENETDOWN 127 /* Network is down */
+#define ENETUNREACH 128 /* Network is unreachable */
+#define ENETRESET 129 /* Network dropped connection because of reset */
+#define ECONNABORTED 130 /* Software caused connection abort */
+#define ECONNRESET 131 /* Connection reset by peer */
+#define ENOBUFS 132 /* No buffer space available */
+#define EISCONN 133 /* Transport endpoint is already connected */
+#define ENOTCONN 134 /* Transport endpoint is not connected */
+#define EUCLEAN 135 /* Structure needs cleaning */
+#define ENOTNAM 137 /* Not a XENIX named type file */
+#define ENAVAIL 138 /* No XENIX semaphores available */
+#define EISNAM 139 /* Is a named type file */
+#define EREMOTEIO 140 /* Remote I/O error */
+#define EINIT 141 /* Reserved */
+#define EREMDEV 142 /* Error 142 */
+#define ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 144 /* Too many references: cannot splice */
+#define ETIMEDOUT 145 /* Connection timed out */
+#define ECONNREFUSED 146 /* Connection refused */
+#define EHOSTDOWN 147 /* Host is down */
+#define EHOSTUNREACH 148 /* No route to host */
+#define EWOULDBLOCK EAGAIN /* Operation would block */
+#define EALREADY 149 /* Operation already in progress */
+#define EINPROGRESS 150 /* Operation now in progress */
+#define ESTALE 151 /* Stale NFS file handle */
+#define ECANCELED 158 /* AIO operation canceled */
+#define EDQUOT 1133 /* Quota exceeded */
+#define ENFSREMOTE 1134 /* ??? */
+
+#endif /* __ASM_MIPS_ERRNO_H */
--- /dev/null
+#ifndef __ASM_MIPS_FCNTL_H
+#define __ASM_MIPS_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+ located on an ext2 file system */
+#define O_ACCMODE 0x0003
+#define O_RDONLY 0x0000
+#define O_WRONLY 0x0001
+#define O_RDWR 0x0002
+#define O_APPEND 0x0008
+#define O_SYNC 0x0010
+#define O_NONBLOCK 0x0080
+#define O_CREAT 0x0100 /* not fcntl */
+#define O_TRUNC 0x0200 /* not fcntl */
+#define O_EXCL 0x0400 /* not fcntl */
+#define O_NOCTTY 0x0800 /* not fcntl */
+#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
+
+#define O_NDELAY O_NONBLOCK
+
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get f_flags */
+#define F_SETFD 2 /* set f_flags */
+#define F_GETFL 3 /* more flags (cloexec) */
+#define F_SETFL 4
+#define F_GETLK 14
+#define F_SETLK 6
+#define F_SETLKW 7
+
+#define F_SETOWN 24 /* for sockets. */
+#define F_GETOWN 23 /* for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK 4 /* or 3 */
+#define F_SHLCK 8 /* or 4 */
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* or'd with one of the above to prevent XXXXXXXXXXXXXXXXXX
+ blocking */
+#define LOCK_UN 8 /* remove lock */
+
+#ifdef __KERNEL__
+#define F_POSIX 1
+#define F_FLOCK 2
+#endif /* __KERNEL__ */
+
+typedef struct flock {
+ short l_type;
+ short l_whence;
+ off_t l_start;
+ off_t l_len;
+ long l_sysid; /* XXXXXXXXXXXXXXXXXXXXXXXXX */
+ pid_t l_pid;
+ long pad[4]; /* ZZZZZZZZZZZZZZZZZZZZZZZZZZ */
+} flock_t;
+
+#endif /* __ASM_MIPS_FCNTL_H */
#include <asm/vector.h>
#define fd_inb(port) feature->fd_inb(port)
-#define fd_outb(port,value) feature->fd_outb(port,value)
+#define fd_outb(value,port) feature->fd_outb(value,port)
#define fd_enable_dma() feature->fd_enable_dma()
#define fd_disable_dma() feature->fd_disable_dma()
"floppy")
#define fd_free_irq() free_irq(FLOPPY_IRQ);
+#define MAX_BUFFER_SECTORS 24
#define virtual_dma_init() \
if (boot_info.machtype == MACH_ACER_PICA_61 || \
boot_info.machtype == MACH_MIPS_MAGNUM_4000 || \
--- /dev/null
+/*
+ * Definitions for the FPU register names
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_FPREGDEF_H
+#define __ASM_MIPS_FPREGDEF_H
+
+/*
+ * These definitions only cover the R3000-ish 16/32 register model.
+ * But we're trying to be R3000 friendly anyway ...
+ */
+#define fv0 $f0 /* return value */
+#define fv0f $f1
+#define fv1 $f2
+#define fv1f $f3
+#define fa0 $f12 /* argument registers */
+#define fa0f $f13
+#define fa1 $f14
+#define fa1f $f15
+#define ft0 $f4 /* caller saved */
+#define ft0f $f5
+#define ft1 $f6
+#define ft1f $f7
+#define ft2 $f8
+#define ft2f $f9
+#define ft3 $f10
+#define ft3f $f11
+#define ft4 $f16
+#define ft4f $f17
+#define ft5 $f18
+#define ft5f $f19
+#define fs0 $f20 /* callee saved */
+#define fs0f $f21
+#define fs1 $f22
+#define fs1f $f23
+#define fs2 $f24
+#define fs2f $f25
+#define fs3 $f26
+#define fs3f $f27
+#define fs4 $f28
+#define fs4f $f29
+#define fs5 $f30
+#define fs5f $f31
+
+#define fcr31 $31 /* FPU status register */
+
+#endif /* !defined (__ASM_MIPS_FPREGDEF_H) */
--- /dev/null
+/*
+ * include/asm-mips/gdb-stub.h
+ *
+ * Copyright (C) 1995 Andreas Busse
+ */
+
+#ifndef __ASM_MIPS_GDB_STUB_H
+#define __ASM_MIPS_GDB_STUB_H
+
+
+/*
+ * important register numbers
+ */
+
+#define REG_EPC 37
+#define REG_FP 72
+#define REG_SP 29
+
+/*
+ * Stack layout for the GDB exception handler
+ * Derived from the stack layout described in asm-mips/stackframe.h
+ *
+ * The first PTRSIZE*5 bytes are argument save space for C subroutines.
+ */
+#define NUMREGS 90
+
+#define GDB_FR_REG0 (PTRSIZE*5) /* 0 */
+#define GDB_FR_REG1 ((GDB_FR_REG0) + 4) /* 1 */
+#define GDB_FR_REG2 ((GDB_FR_REG1) + 4) /* 2 */
+#define GDB_FR_REG3 ((GDB_FR_REG2) + 4) /* 3 */
+#define GDB_FR_REG4 ((GDB_FR_REG3) + 4) /* 4 */
+#define GDB_FR_REG5 ((GDB_FR_REG4) + 4) /* 5 */
+#define GDB_FR_REG6 ((GDB_FR_REG5) + 4) /* 6 */
+#define GDB_FR_REG7 ((GDB_FR_REG6) + 4) /* 7 */
+#define GDB_FR_REG8 ((GDB_FR_REG7) + 4) /* 8 */
+#define GDB_FR_REG9 ((GDB_FR_REG8) + 4) /* 9 */
+#define GDB_FR_REG10 ((GDB_FR_REG9) + 4) /* 10 */
+#define GDB_FR_REG11 ((GDB_FR_REG10) + 4) /* 11 */
+#define GDB_FR_REG12 ((GDB_FR_REG11) + 4) /* 12 */
+#define GDB_FR_REG13 ((GDB_FR_REG12) + 4) /* 13 */
+#define GDB_FR_REG14 ((GDB_FR_REG13) + 4) /* 14 */
+#define GDB_FR_REG15 ((GDB_FR_REG14) + 4) /* 15 */
+#define GDB_FR_REG16 ((GDB_FR_REG15) + 4) /* 16 */
+#define GDB_FR_REG17 ((GDB_FR_REG16) + 4) /* 17 */
+#define GDB_FR_REG18 ((GDB_FR_REG17) + 4) /* 18 */
+#define GDB_FR_REG19 ((GDB_FR_REG18) + 4) /* 19 */
+#define GDB_FR_REG20 ((GDB_FR_REG19) + 4) /* 20 */
+#define GDB_FR_REG21 ((GDB_FR_REG20) + 4) /* 21 */
+#define GDB_FR_REG22 ((GDB_FR_REG21) + 4) /* 22 */
+#define GDB_FR_REG23 ((GDB_FR_REG22) + 4) /* 23 */
+#define GDB_FR_REG24 ((GDB_FR_REG23) + 4) /* 24 */
+#define GDB_FR_REG25 ((GDB_FR_REG24) + 4) /* 25 */
+#define GDB_FR_REG26 ((GDB_FR_REG25) + 4) /* 26 */
+#define GDB_FR_REG27 ((GDB_FR_REG26) + 4) /* 27 */
+#define GDB_FR_REG28 ((GDB_FR_REG27) + 4) /* 28 */
+#define GDB_FR_REG29 ((GDB_FR_REG28) + 4) /* 29 */
+#define GDB_FR_REG30 ((GDB_FR_REG29) + 4) /* 30 */
+#define GDB_FR_REG31 ((GDB_FR_REG30) + 4) /* 31 */
+
+/*
+ * Saved special registers
+ */
+#define GDB_FR_STATUS ((GDB_FR_REG31) + 4) /* 32 */
+#define GDB_FR_LO ((GDB_FR_STATUS) + 4) /* 33 */
+#define GDB_FR_HI ((GDB_FR_LO) + 4) /* 34 */
+#define GDB_FR_BADVADDR ((GDB_FR_HI) + 4) /* 35 */
+#define GDB_FR_CAUSE ((GDB_FR_BADVADDR) + 4) /* 36 */
+#define GDB_FR_EPC ((GDB_FR_CAUSE) + 4) /* 37 */
+
+/*
+ * Saved floating point registers
+ */
+#define GDB_FR_FPR0 ((GDB_FR_EPC) + 4) /* 38 */
+#define GDB_FR_FPR1 ((GDB_FR_FPR0) + 4) /* 39 */
+#define GDB_FR_FPR2 ((GDB_FR_FPR1) + 4) /* 40 */
+#define GDB_FR_FPR3 ((GDB_FR_FPR2) + 4) /* 41 */
+#define GDB_FR_FPR4 ((GDB_FR_FPR3) + 4) /* 42 */
+#define GDB_FR_FPR5 ((GDB_FR_FPR4) + 4) /* 43 */
+#define GDB_FR_FPR6 ((GDB_FR_FPR5) + 4) /* 44 */
+#define GDB_FR_FPR7 ((GDB_FR_FPR6) + 4) /* 45 */
+#define GDB_FR_FPR8 ((GDB_FR_FPR7) + 4) /* 46 */
+#define GDB_FR_FPR9 ((GDB_FR_FPR8) + 4) /* 47 */
+#define GDB_FR_FPR10 ((GDB_FR_FPR9) + 4) /* 48 */
+#define GDB_FR_FPR11 ((GDB_FR_FPR10) + 4) /* 49 */
+#define GDB_FR_FPR12 ((GDB_FR_FPR11) + 4) /* 50 */
+#define GDB_FR_FPR13 ((GDB_FR_FPR12) + 4) /* 51 */
+#define GDB_FR_FPR14 ((GDB_FR_FPR13) + 4) /* 52 */
+#define GDB_FR_FPR15 ((GDB_FR_FPR14) + 4) /* 53 */
+#define GDB_FR_FPR16 ((GDB_FR_FPR15) + 4) /* 54 */
+#define GDB_FR_FPR17 ((GDB_FR_FPR16) + 4) /* 55 */
+#define GDB_FR_FPR18 ((GDB_FR_FPR17) + 4) /* 56 */
+#define GDB_FR_FPR19 ((GDB_FR_FPR18) + 4) /* 57 */
+#define GDB_FR_FPR20 ((GDB_FR_FPR19) + 4) /* 58 */
+#define GDB_FR_FPR21 ((GDB_FR_FPR20) + 4) /* 59 */
+#define GDB_FR_FPR22 ((GDB_FR_FPR21) + 4) /* 60 */
+#define GDB_FR_FPR23 ((GDB_FR_FPR22) + 4) /* 61 */
+#define GDB_FR_FPR24 ((GDB_FR_FPR23) + 4) /* 62 */
+#define GDB_FR_FPR25 ((GDB_FR_FPR24) + 4) /* 63 */
+#define GDB_FR_FPR26 ((GDB_FR_FPR25) + 4) /* 64 */
+#define GDB_FR_FPR27 ((GDB_FR_FPR26) + 4) /* 65 */
+#define GDB_FR_FPR28 ((GDB_FR_FPR27) + 4) /* 66 */
+#define GDB_FR_FPR29 ((GDB_FR_FPR28) + 4) /* 67 */
+#define GDB_FR_FPR30 ((GDB_FR_FPR29) + 4) /* 68 */
+#define GDB_FR_FPR31 ((GDB_FR_FPR30) + 4) /* 69 */
+
+#define GDB_FR_FSR ((GDB_FR_FPR31) + 4) /* 70 */
+#define GDB_FR_FIR ((GDB_FR_FSR) + 4) /* 71 */
+#define GDB_FR_FRP ((GDB_FR_FIR) + 4) /* 72 */
+
+#define GDB_FR_DUMMY ((GDB_FR_FRP) + 4) /* 73, unused ??? */
+
+/*
+ * Again, CP0 registers
+ */
+#define GDB_FR_CP0_INDEX ((GDB_FR_DUMMY) + 4) /* 74 */
+#define GDB_FR_CP0_RANDOM ((GDB_FR_CP0_INDEX) + 4) /* 75 */
+#define GDB_FR_CP0_ENTRYLO0 ((GDB_FR_CP0_RANDOM) + 4) /* 76 */
+#define GDB_FR_CP0_ENTRYLO1 ((GDB_FR_CP0_ENTRYLO0) + 4) /* 77 */
+#define GDB_FR_CP0_REG4 ((GDB_FR_CP0_ENTRYLO1) + 4) /* 78 */
+#define GDB_FR_CP0_PAGEMASK ((GDB_FR_CP0_REG4) + 4) /* 79 */
+#define GDB_FR_CP0_WIRED ((GDB_FR_CP0_PAGEMASK) + 4) /* 80 */
+#define GDB_FR_CP0_REG7 ((GDB_FR_CP0_WIRED) + 4) /* 81 */
+#define GDB_FR_CP0_REG8 ((GDB_FR_CP0_REG7) + 4) /* 82 */
+#define GDB_FR_CP0_REG9 ((GDB_FR_CP0_REG8) + 4) /* 83 */
+#define GDB_FR_CP0_ENTRYHI ((GDB_FR_CP0_REG9) + 4) /* 84 */
+#define GDB_FR_CP0_REG11 ((GDB_FR_CP0_ENTRYHI) + 4) /* 85 */
+#define GDB_FR_CP0_REG12 ((GDB_FR_CP0_REG11) + 4) /* 86 */
+#define GDB_FR_CP0_REG13 ((GDB_FR_CP0_REG12) + 4) /* 87 */
+#define GDB_FR_CP0_REG14 ((GDB_FR_CP0_REG13) + 4) /* 88 */
+#define GDB_FR_CP0_PRID ((GDB_FR_CP0_REG14) + 4) /* 89 */
+
+#define GDB_FR_SIZE ((((GDB_FR_CP0_PRID) + 4) + (PTRSIZE-1)) & ~(PTRSIZE-1))
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+/*
+ * This is the same as above, but for the high-level
+ * part of the GDB stub.
+ */
+
+struct gdb_regs {
+ /*
+ * Pad bytes for argument save space on the stack
+ * 20/40 Bytes for 32/64 bit code
+ */
+ unsigned long pad0[5];
+
+ /*
+ * saved main processor registers
+ */
+ long reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7;
+ long reg8, reg9, reg10, reg11, reg12, reg13, reg14, reg15;
+ long reg16, reg17, reg18, reg19, reg20, reg21, reg22, reg23;
+ long reg24, reg25, reg26, reg27, reg28, reg29, reg30, reg31;
+
+ /*
+ * Saved special registers
+ */
+ long cp0_status;
+ long lo;
+ long hi;
+ long cp0_badvaddr;
+ long cp0_cause;
+ long cp0_epc;
+
+ /*
+ * Saved floating point registers
+ */
+ long fpr0, fpr1, fpr2, fpr3, fpr4, fpr5, fpr6, fpr7;
+ long fpr8, fpr9, fpr10, fpr11, fpr12, fpr13, fpr14, fpr15;
+ long fpr16, fpr17, fpr18, fpr19, fpr20, fpr21, fpr22, fpr23;
+ long fpr24, fpr25, fpr26, fpr27, fpr28, fpr29, fpr30, fpr31;
+
+ long cp1_fsr;
+ long cp1_fir;
+
+ /*
+ * Frame pointer
+ */
+ long frame_ptr;
+ long dummy; /* unused */
+
+ /*
+ * saved cp0 registers
+ */
+ long cp0_index;
+ long cp0_random;
+ long cp0_entrylo0;
+ long cp0_entrylo1;
+ long cp0_reg4;
+ long cp0_pagemask;
+ long cp0_wired;
+ long cp0_reg7;
+ long cp0_reg8;
+ long cp0_reg9;
+ long cp0_entryhi;
+ long cp0_reg11;
+ long cp0_reg12;
+ long cp0_reg13;
+ long cp0_reg14;
+ long cp0_prid;
+};
+
+/*
+ * Prototypes
+ */
+
+void set_debug_traps(void);
+
+#endif /* __LANGUAGE_ASSEMBLY */
+#endif /* __ASM_MIPS_GDB_STUB_H */
#ifndef __ASM_MIPS_IO_H
#define __ASM_MIPS_IO_H
-#include <asm/mipsregs.h>
#include <asm/mipsconfig.h>
+#include <asm/segment.h>
/*
* This file contains the definitions for the MIPS counterpart of the
#define SLOW_DOWN_IO __SLOW_DOWN_IO
#endif
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/MIPS mapping
+ */
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+ return (unsigned long) address - KSEG0;
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+ return (void *) address + KSEG0;
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ * FIXME: This assumption is wrong for the Deskstation Tyne
+ */
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the x86 architecture, we just read/write the
+ * memory location directly.
+ */
+#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))
+
+#define memset_io(a,b,c) memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+
+/*
+ * Again, MIPS does not require mem IO specific function.
+ */
+
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
+
/*
* Talk about misusing macros..
*/
#define __OUT(m,s) \
__OUT1(s) __OUT2(m) : : "r" (value), "i" (0), "r" (PORT_BASE+port)); } \
-__OUT1(s##c) __OUT2(m) : : "r" (value), "i" (port), "r" (PORT_BASE)); } \
+__OUT1(s##c) __OUT2(m) : : "r" (value), "ir" (port), "r" (PORT_BASE)); } \
__OUT1(s##_p) __OUT2(m) : : "r" (value), "i" (0), "r" (PORT_BASE+port)); \
SLOW_DOWN_IO; } \
-__OUT1(s##c_p) __OUT2(m) : : "r" (value), "i" (port), "r" (PORT_BASE)); \
+__OUT1(s##c_p) __OUT2(m) : : "r" (value), "ir" (port), "r" (PORT_BASE)); \
SLOW_DOWN_IO; }
-#define __IN1(s) \
-extern inline unsigned int __in##s(unsigned int port) { unsigned int _v;
+#define __IN1(t,s) \
+extern __inline__ t __in##s(unsigned int port) { t _v;
+/*
+ * Useless nops will be removed by the assembler
+ */
#define __IN2(m) \
-__asm__ __volatile__ ("l" #m "u\t%0,%1(%2)\n\t"
+__asm__ __volatile__ ("l" #m "u\t%0,%1(%2)\n\tnop"
-#define __IN(m,s) \
-__IN1(s) __IN2(m) STR(FILL_LDS) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); return _v; } \
-__IN1(s##c) __IN2(m) STR(FILL_LDS) : "=r" (_v) : "i" (port), "r" (PORT_BASE)); return _v; } \
-__IN1(s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); SLOW_DOWN_IO; return _v; } \
-__IN1(s##c_p) __IN2(m) : "=r" (_v) : "i" (port), "r" (PORT_BASE)); SLOW_DOWN_IO; return _v; }
+#define __IN(t,m,s) \
+__IN1(t,s) __IN2(m) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); return _v; } \
+__IN1(t,s##c) __IN2(m) : "=r" (_v) : "ir" (port), "r" (PORT_BASE)); return _v; } \
+__IN1(t,s##_p) __IN2(m) : "=r" (_v) : "i" (0), "r" (PORT_BASE+port)); SLOW_DOWN_IO; return _v; } \
+__IN1(t,s##c_p) __IN2(m) : "=r" (_v) : "ir" (port), "r" (PORT_BASE)); SLOW_DOWN_IO; return _v; }
#define __INS1(s) \
extern inline void __ins##s(unsigned int port, void * addr, unsigned long count) {
".set\tnoreorder\n\t" \
".set\tnoat\n" \
"1:\tl" #m "u\t$1,%4(%5)\n\t" \
- "subu\t%1,%1,1\n\t" \
+ "subu\t%1,1\n\t" \
"s" #m "\t$1,(%0)\n\t" \
"bne\t$0,%1,1b\n\t" \
- "addiu\t%0,%0,%6\n\t" \
+ "addiu\t%0,%6\n\t" \
".set\tat\n\t" \
".set\treorder"
: "$1");} \
__INS1(s##c) __INS2(m) \
: "=r" (addr), "=r" (count) \
- : "0" (addr), "1" (count), "i" (port), "r" (PORT_BASE), "I" (i) \
+ : "0" (addr), "1" (count), "ir" (port), "r" (PORT_BASE), "I" (i) \
: "$1");}
#define __OUTS1(s) \
: "$1");} \
__OUTS1(s##c) __OUTS2(m) \
: "=r" (addr), "=r" (count) \
- : "0" (addr), "1" (count), "i" (port), "r" (PORT_BASE), "I" (i) \
+ : "0" (addr), "1" (count), "ir" (port), "r" (PORT_BASE), "I" (i) \
: "$1");}
-__IN(b,b)
-__IN(h,w)
-__IN(w,l)
+__IN(unsigned char,b,b)
+__IN(unsigned short,h,w)
+__IN(unsigned int,w,l)
__OUT(b,b)
__OUT(h,w)
--- /dev/null
+#ifndef __ASM_MIPS_IOCTL_H
+#define __ASM_MIPS_IOCTL_H
+
+/*
+ * The original linux ioctl numbering scheme was just a general
+ * "anything goes" setup, where more or less random numbers were
+ * assigned. Sorry, I was clueless when I started out on this.
+ *
+ * On the alpha, we'll try to clean it up a bit, using a more sane
+ * ioctl numbering, and also trying to be compatible with OSF/1 in
+ * the process. I'd like to clean it up for the i386 as well, but
+ * it's so painful recognizing both the new and the old numbers..
+ *
+ * The same applies for for the MIPS ABI; in fact even the macros
+ * from Linux/Alpha fit almost perfectly.
+ */
+
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#define _IOC_SIZEBITS 13
+#define _IOC_DIRBITS 3
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * We to additionally limit parameters to a maximum 255 bytes.
+ */
+#define _IOC_SLMASK 0xff
+
+/*
+ * Direction bits _IOC_NONE could be 0, but OSF/1 gives it a bit.
+ * And this turns out useful to catch old ioctl numbers in header
+ * files for us.
+ */
+#define _IOC_NONE 1U
+#define _IOC_READ 2U
+#define _IOC_WRITE 4U
+
+/*
+ * The following are included for compatibility
+ */
+#define _IOC_VOID 0x20000000
+#define _IOC_OUT 0x40000000
+#define _IOC_IN 0x80000000
+#define _IOC_INOUT (IOC_IN|IOC_OUT)
+
+#define _IOC(dir,type,nr,size) \
+ (((dir) << _IOC_DIRSHIFT) | \
+ ((type) << _IOC_TYPESHIFT) | \
+ ((nr) << _IOC_NRSHIFT) | \
+ (((size) & _IOC_SLMASK) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode them.. */
+#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+
+#endif /* __ASM_MIPS_IOCTL_H */
--- /dev/null
+#ifndef __ASM_MIPS_IOCTLS_H
+#define __ASM_MIPS_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+#define TCGETA 0x5401
+#define TCSETA 0x5402
+#define TCSETAW 0x5403
+#define TCSETAF 0x5404
+
+#define TCSBRK 0x5405
+#define TCXONC 0x5406
+#define TCFLSH 0x5407
+
+#define TCGETS 0x540d
+#define TCSETS 0x540e
+#define TCSETSW 0x540f
+#define TCSETSF 0x5410
+
+#define TIOCEXCL 0x740d /* set exclusive use of tty */
+#define TIOCNXCL 0x740e /* reset exclusive use of tty */
+#define TIOCOUTQ 0x7472 /* output queue size */
+#define TIOCSTI 0x5472 /* simulate terminal input */
+#define TIOCMGET 0x741d /* get all modem bits */
+#define TIOCMBIS 0x741b /* bis modem bits */
+#define TIOCMBIC 0x741c /* bic modem bits */
+#define TIOCMSET 0x741a /* set all modem bits */
+#define TIOCPKT 0x5470 /* pty: set/clear packet mode */
+#define TIOCPKT_DATA 0x00 /* data packet */
+#define TIOCPKT_FLUSHREAD 0x01 /* flush packet */
+#define TIOCPKT_FLUSHWRITE 0x02 /* flush packet */
+#define TIOCPKT_STOP 0x04 /* stop output */
+#define TIOCPKT_START 0x08 /* start output */
+#define TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */
+#define TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */
+#if 0
+#define TIOCPKT_IOCTL 0x40 /* state change of pty driver */
+#endif
+#define TIOCSWINSZ _IOW('t', 103, struct winsize) /* set window size */
+#define TIOCGWINSZ _IOR('t', 104, struct winsize) /* get window size */
+#define TIOCNOTTY 0x5471 /* void tty association */
+#define TIOCSETD 0x7401
+#define TIOCGETD 0x7400
+
+#define FIOCLEX 0x6601
+#define FIONCLEX 0x6602 /* these numbers need to be adjusted. */
+#define FIOASYNC 0x667d
+#define FIONBIO 0x667e
+
+ /* 116-117 compat */
+#define TIOCSPGRP _IOW('t', 118, int) /* set pgrp of tty */
+#define TIOCGPGRP _IOR('t', 119, int) /* get pgrp of tty */
+#define TIOCCONS _IOW('t', 120, int) /* become virtual console */
+
+#define FIONREAD 0x467f
+#define TIOCINQ FIONREAD
+
+#if 0
+#define TIOCSETA _IOW('t', 20, struct termios) /* set termios struct */
+#define TIOCSETAW _IOW('t', 21, struct termios) /* drain output, set */
+#define TIOCSETAF _IOW('t', 22, struct termios) /* drn out, fls in, set */
+#define TIOCGETD _IOR('t', 26, int) /* get line discipline */
+#define TIOCSETD _IOW('t', 27, int) /* set line discipline */
+ /* 127-124 compat */
+#endif
+
+/* I hope the range from 0x5480 on is free ... */
+#define TIOCSCTTY 0x5480 /* become controlling tty */
+#define TIOCGSOFTCAR 0x5481
+#define TIOCSSOFTCAR 0x5482
+#define TIOCLINUX 0x5483
+#define TIOCGSERIAL 0x5484
+#define TIOCSSERIAL 0x5485
+
+#define TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT 0x5487 /* For debugging only */
+
+#define TIOCSERCONFIG 0x5488
+#define TIOCSERGWILD 0x5489
+#define TIOCSERSWILD 0x548a
+#define TIOCGLCKTRMIOS 0x548b
+#define TIOCSLCKTRMIOS 0x548c
+#define TIOCSERGSTRUCT 0x548d /* For debugging only */
+#define TIOCSERGETLSR 0x548e /* Get line status register */
+#define TIOCSERGETMULTI 0x548f /* Get multiport config */
+#define TIOCSERSETMULTI 0x5490 /* Set multiport config */
+
+/* ----------------------------------------------------------------------- */
+
+/* c_cc characters */
+#define VINTR 0 /* Interrupt character [ISIG]. */
+#define VQUIT 1 /* Quit character [ISIG]. */
+#define VERASE 2 /* Erase character [ICANON]. */
+#define VKILL 3 /* Kill-line character [ICANON]. */
+#define VEOF 4 /* End-of-file character [ICANON]. */
+#define VMIN VEOF /* Minimum number of bytes read at once [!ICANON]. */
+#define VEOL 5 /* End-of-line character [ICANON]. */
+#define VTIME VEOL /* Time-out value (tenths of a second) [!ICANON]. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define VEOL2 6 /* Second EOL character [ICANON]. */
+/* The next two are guesses ... */
+#define VSWTC 7 /* ??? */
+#endif
+#define VSWTCH VSWTC
+#define VSTART 8 /* Start (X-ON) character [IXON, IXOFF]. */
+#define VSTOP 9 /* Stop (X-OFF) character [IXON, IXOFF]. */
+#define VSUSP 10 /* Suspend character [ISIG]. */
+#if 0
+/*
+ * VDSUSP is not supported
+ */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define VDSUSP 11 /* Delayed suspend character [ISIG]. */
+#endif
+#endif
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define VREPRINT 12 /* Reprint-line character [ICANON]. */
+#endif
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define VDISCARD 13 /* Discard character [IEXTEN]. */
+#define VWERASE 14 /* Word-erase character [ICANON]. */
+#define VLNEXT 15 /* Literal-next character [IEXTEN]. */
+#endif
+/*
+ * 17 - 19 are reserved
+ */
+
+#ifdef __KERNEL__
+/*
+ * intr=^C quit=^| erase=del kill=^U
+ * eof=^D eol=time=\0 eol2=\0 swtc=\0
+ * start=^Q stop=^S susp=^Z vdsusp=
+ * reprint=^R discard=^U werase=^W lnext=^V
+ */
+#define INIT_C_CC "\003\034\177\025\004\0\0\0\021\023\032\0\022\017\027\026"
+#endif
+
+/* c_iflag bits */
+#define IGNBRK 0000001 /* Ignore break condition. */
+#define BRKINT 0000002 /* Signal interrupt on break. */
+#define IGNPAR 0000004 /* Ignore characters with parity errors. */
+#define PARMRK 0000010 /* Mark parity and framing errors. */
+#define INPCK 0000020 /* Enable input parity check. */
+#define ISTRIP 0000040 /* Strip 8th bit off characters. */
+#define INLCR 0000100 /* Map NL to CR on input. */
+#define IGNCR 0000200 /* Ignore CR. */
+#define ICRNL 0000400 /* Map CR to NL on input. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define IUCLC 0001000 /* Map upper case to lower case on input. */
+#endif
+#define IXON 0002000 /* Enable start/stop output control. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define IXANY 0004000 /* Any character will restart after stop. */
+#endif
+#define IXOFF 0010000 /* Enable start/stop input control. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define IMAXBEL 0020000 /* Ring bell when input queue is full. */
+#endif
+
+/* c_oflag bits */
+#define OPOST 0000001 /* Perform output processing. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define OLCUC 0000002 /* Map lower case to upper case on output. */
+#define ONLCR 0000004 /* Map NL to CR-NL on output. */
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0100000
+#define FF0 0000000
+#define FF1 0100000
+/*
+#define PAGEOUT ???
+#define WRAP ???
+ */
+#endif
+
+/* c_cflag bit meaning */
+#define CBAUD 0010017
+#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 CSIZE 0000060 /* Number of bits per byte (mask). */
+#define CS5 0000000 /* 5 bits per byte. */
+#define CS6 0000020 /* 6 bits per byte. */
+#define CS7 0000040 /* 7 bits per byte. */
+#define CS8 0000060 /* 8 bits per byte. */
+#define CSTOPB 0000100 /* Two stop bits instead of one. */
+#define CREAD 0000200 /* Enable receiver. */
+#define PARENB 0000400 /* Parity enable. */
+#define PARODD 0001000 /* Odd parity instead of even. */
+#define HUPCL 0002000 /* Hang up on last close. */
+#define CLOCAL 0004000 /* Ignore modem status lines. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define CBAUDEX 0010000
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CRTSCTS 020000000000 /* flow control */
+#endif
+
+/* c_lflag bits */
+#define ISIG 0000001 /* Enable signals. */
+#define ICANON 0000002 /* Do erase and kill processing. */
+#define XCASE 0000004
+#define ECHO 0000010 /* Enable echo. */
+#define ECHOE 0000020 /* Visual erase for ERASE. */
+#define ECHOK 0000040 /* Echo NL after KILL. */
+#define ECHONL 0000100 /* Echo NL even if ECHO is off. */
+#define NOFLSH 0000200 /* Disable flush after interrupt. */
+#define IEXTEN 0000400 /* Enable DISCARD and LNEXT. */
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define ECHOCTL 0001000 /* Echo control characters as ^X. */
+#define ECHOPRT 0002000 /* Hardcopy visual erase. */
+#define ECHOKE 0004000 /* Visual erase for KILL. */
+#endif
+#define FLUSHO 0020000
+#if defined (__USE_BSD) || defined (__KERNEL__)
+#define PENDIN 0040000 /* Retype pending input (state). */
+#endif
+#define TOSTOP 0100000 /* Send SIGTTOU for background output. */
+#define ITOSTOP TOSTOP
+
+/* modem lines */
+#define TIOCM_LE 0x001 /* line enable */
+#define TIOCM_DTR 0x002 /* data terminal ready */
+#define TIOCM_RTS 0x004 /* request to send */
+#define TIOCM_ST 0x010 /* secondary transmit */
+#define TIOCM_SR 0x020 /* secondary receive */
+#define TIOCM_CTS 0x040 /* clear to send */
+#define TIOCM_CAR 0x100 /* carrier detect */
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RNG 0x200 /* ring */
+#define TIOCM_RI TIOCM_RNG
+#define TIOCM_DSR 0x400 /* data set ready */
+
+/* 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 /* Suspend output. */
+#define TCOON 1 /* Restart suspended output. */
+#define TCIOFF 2 /* Send a STOP character. */
+#define TCION 3 /* Send a START character. */
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0 /* Discard data received but not yet read. */
+#define TCOFLUSH 1 /* Discard data written but not yet sent. */
+#define TCIOFLUSH 2 /* Discard all pending data. */
+
+/* tcsetattr uses these */
+#define TCSANOW TCSETS /* Change immediately. */
+#define TCSADRAIN TCSETSW /* Change when pending output is written. */
+#define TCSAFLUSH TCSETSF /* Flush pending input before changing. */
+
+/* line disciplines */
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+#define N_PPP 3
+
+#endif /* __ASM_MIPS_IOCTLS_H */
#ifndef __ASM_MIPS_IRQ_H
#define __ASM_MIPS_IRQ_H
+/*
+ * Actually this is a lie but we hide the local device's interrupts ...
+ */
+#define NR_IRQS 16
+
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
--- /dev/null
+/*
+ * Hardware info about Mips JAZZ and similar systems
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Andreas Busse and Ralf Baechle
+ *
+ * This file is a mess. It really needs some reorganisation!
+ */
+
+#ifndef __ASM_MIPS_JAZZ_H
+#define __ASM_MIPS_JAZZ_H
+
+/*
+ * The addresses below are virtual address. The mappings are
+ * created on startup via wired entries in the tlb. The Mips
+ * Magnum R3000 and R4000 machines are similar in many aspects,
+ * but many hardware register are accessible at 0xb9000000 in
+ * instead of 0xe0000000.
+ */
+
+#define JAZZ_LOCAL_IO_SPACE 0xe0000000
+
+/*
+ * Revision numbers in PICA_ASIC_REVISION
+ *
+ * 0xf0000000 - Rev1
+ * 0xf0000001 - Rev2
+ * 0xf0000002 - Rev3
+ */
+#define PICA_ASIC_REVISION 0xe0000008
+
+/*
+ * The segments of the seven segment LED are mapped
+ * to the control bits as follows:
+ *
+ * (7)
+ * ---------
+ * | |
+ * (2) | | (6)
+ * | (1) |
+ * ---------
+ * | |
+ * (3) | | (5)
+ * | (4) |
+ * --------- . (0)
+ */
+#define PICA_LED 0xe000f000
+
+/*
+ * Some characters for the LED control registers
+ * The original Mips machines seem to have a LED display
+ * with integrated decoder while the Acer machines can
+ * control each of the seven segments and the dot independend.
+ * It's only a toy, anyway...
+ */
+#define LED_DOT 0x01
+#define LED_SPACE 0x00
+#define LED_0 0xfc
+#define LED_1 0x60
+#define LED_2 0xda
+#define LED_3 0xf2
+#define LED_4 0x66
+#define LED_5 0xb6
+#define LED_6 0xbe
+#define LED_7 0xe0
+#define LED_8 0xfe
+#define LED_9 0xf6
+#define LED_A 0xee
+#define LED_b 0x3e
+#define LED_C 0x9c
+#define LED_d 0x7a
+#define LED_E 0x9e
+#define LED_F 0x8e
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+extern __inline__ void pica_set_led(unsigned int bits)
+{
+ volatile unsigned int *led_register = (unsigned int *) PICA_LED;
+
+ *led_register = bits;
+}
+
+#endif
+
+/*
+ * i8042 keyboard controller for JAZZ and PICA chipsets.
+ * This address is just a guess and seems to differ from
+ * other mips machines such as RC3xxx...
+ */
+#define JAZZ_KEYBOARD_ADDRESS 0xe0005000
+#define JAZZ_KEYBOARD_DATA 0xe0005000
+#define JAZZ_KEYBOARD_COMMAND 0xe0005001
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+typedef struct {
+ unsigned char data;
+ unsigned char command;
+} jazz_keyboard_hardware;
+
+typedef struct {
+ unsigned char pad0[3];
+ unsigned char data;
+ unsigned char pad1[3];
+ unsigned char command;
+} mips_keyboard_hardware;
+
+/*
+ * For now. Needs to be changed for RC3xxx support. See below.
+ */
+#define keyboard_hardware jazz_keyboard_hardware
+
+#endif
+
+/*
+ * i8042 keyboard controller for most other Mips machines.
+ */
+#define MIPS_KEYBOARD_ADDRESS 0xb9005000
+#define MIPS_KEYBOARD_DATA 0xb9005003
+#define MIPS_KEYBOARD_COMMAND 0xb9005007
+
+/*
+ * Serial and parallel ports (WD 16C552) on the Mips JAZZ
+ */
+#define JAZZ_SERIAL1_BASE (unsigned int)0xe0006000
+#define JAZZ_SERIAL2_BASE (unsigned int)0xe0007000
+#define JAZZ_PARALLEL_BASE (unsigned int)0xe0008000
+
+/*
+ * Dummy Device Address. Used in jazzdma.c
+ */
+#define JAZZ_DUMMY_DEVICE 0xe000d000
+
+/*
+ * JAZZ timer registers and interrupt no.
+ * Note that the hardware timer interrupt is actually on
+ * cpu level 6, but to keep compatibility with PC stuff
+ * it is remapped to vector 0. See arch/mips/kernel/entry.S.
+ */
+#define JAZZ_TIMER_INTERVAL 0xe0000228
+#define JAZZ_TIMER_REGISTER 0xe0000230
+
+/*
+ * DRAM configuration register
+ */
+#ifndef __LANGUAGE_ASSEMBLY__
+#ifdef __MIPSEL__
+typedef struct {
+ unsigned int bank2 : 3;
+ unsigned int bank1 : 3;
+ unsigned int mem_bus_width : 1;
+ unsigned int reserved2 : 1;
+ unsigned int page_mode : 1;
+ unsigned int reserved1 : 23;
+} dram_configuration;
+#else /* defined (__MIPSEB__) */
+typedef struct {
+ unsigned int reserved1 : 23;
+ unsigned int page_mode : 1;
+ unsigned int reserved2 : 1;
+ unsigned int mem_bus_width : 1;
+ unsigned int bank1 : 3;
+ unsigned int bank2 : 3;
+} dram_configuration;
+#endif
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#define PICA_DRAM_CONFIG 0xe00fffe0
+
+/*
+ * JAZZ interrupt control registers
+ */
+#define JAZZ_IO_IRQ_SOURCE 0xe0100000
+#define JAZZ_IO_IRQ_ENABLE 0xe0100002
+
+/*
+ * JAZZ interrupt enable bits
+ */
+#define JAZZ_IE_PARALLEL (1 << 0)
+#define JAZZ_IE_FLOPPY (1 << 1)
+#define JAZZ_IE_SOUND (1 << 2)
+#define JAZZ_IE_VIDEO (1 << 3)
+#define JAZZ_IE_ETHERNET (1 << 4)
+#define JAZZ_IE_SCSI (1 << 5)
+#define JAZZ_IE_KEYBOARD (1 << 6)
+#define JAZZ_IE_MOUSE (1 << 7)
+#define JAZZ_IE_SERIAL1 (1 << 8)
+#define JAZZ_IE_SERIAL2 (1 << 9)
+
+/*
+ * JAZZ Interrupt Level definitions
+ */
+#define JAZZ_TIMER_IRQ 0
+#define JAZZ_KEYBOARD_IRQ 1
+#define JAZZ_ETHERNET_IRQ 2 /* 15 */
+#define JAZZ_SERIAL1_IRQ 3
+#define JAZZ_SERIAL2_IRQ 4
+#define JAZZ_PARALLEL_IRQ 5
+#define JAZZ_FLOPPY_IRQ 6 /* needs to be consistent with floppy driver! */
+
+
+/*
+ * JAZZ DMA Channels
+ * Note: Channels 4...7 are not used with respect to the Acer PICA-61
+ * chipset which does not provide these DMA channels.
+ */
+#define JAZZ_SCSI_DMA 0 /* SCSI */
+#define JAZZ_FLOPPY_DMA 1 /* FLOPPY */
+#define JAZZ_AUDIOL_DMA 2 /* AUDIO L */
+#define JAZZ_AUDIOR_DMA 3 /* AUDIO R */
+
+/*
+ * JAZZ R4030 MCT_ADR chip (DMA controller)
+ * Note: Virtual Addresses !
+ */
+#define JAZZ_R4030_CONFIG 0xE0000000 /* R4030 config register */
+#define JAZZ_R4030_REVISION 0xE0000008 /* same as PICA_ASIC_REVISION */
+#define JAZZ_R4030_INV_ADDR 0xE0000010 /* Invalid Address register */
+
+#define JAZZ_R4030_TRSTBL_BASE 0xE0000018 /* Translation Table Base */
+#define JAZZ_R4030_TRSTBL_LIM 0xE0000020 /* Translation Table Limit */
+#define JAZZ_R4030_TRSTBL_INV 0xE0000028 /* Translation Table Invalidate */
+
+#define JAZZ_R4030_CACHE_MTNC 0xE0000030 /* Cache Maintenance */
+#define JAZZ_R4030_R_FAIL_ADDR 0xE0000038 /* Remote Failed Address */
+#define JAZZ_R4030_M_FAIL_ADDR 0xE0000040 /* Memory Failed Adresss */
+
+#define JAZZ_R4030_CACHE_PTAG 0xE0000048 /* I/O Cache Physical Tag */
+#define JAZZ_R4030_CACHE_LTAG 0xE0000050 /* I/O Cache Logical Tag */
+#define JAZZ_R4030_CACHE_BMASK 0xE0000058 /* I/O Cache Byte Mask */
+#define JAZZ_R4030_CACHE_BWIN 0xE0000060 /* I/O Cache Buffer Window */
+
+/*
+ * Remote Speed Registers.
+ *
+ * 0: free, 1: Ethernet, 2: SCSI, 3: Floppy,
+ * 4: RTC, 5: Kb./Mouse 6: serial 1, 7: serial 2,
+ * 8: parallel, 9: NVRAM, 10: CPU, 11: PROM,
+ * 12: reserved, 13: free, 14: 7seg LED, 15: ???
+ */
+#define JAZZ_R4030_REM_SPEED 0xE0000070 /* 16 Remote Speed Registers */
+ /* 0xE0000070,78,80... 0xE00000E8 */
+#define JAZZ_R4030_IRQ_ENABLE 0xE00000E8 /* Internal Interrupt Enable */
+
+#define JAZZ_R4030_IRQ_SOURCE 0xE0000200 /* Interrupt Source Reg */
+#define JAZZ_R4030_I386_ERROR 0xE0000208 /* i386/EISA Bus Error */
+
+
+/*
+ * Access the R4030 DMA and I/O Controller
+ */
+#ifndef __LANGUAGE_ASSEMBLY__
+
+extern inline unsigned short r4030_read_reg16(unsigned addr) {
+ unsigned short ret = *((volatile unsigned short *)addr);
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set\treorder");
+ return ret;
+}
+
+extern inline unsigned int r4030_read_reg32(unsigned addr) {
+ unsigned int ret = *((volatile unsigned int *)addr);
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set\treorder");
+ return ret;
+}
+
+extern inline void r4030_write_reg16(unsigned addr, unsigned val) {
+ *((volatile unsigned short *)addr) = val;
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set\treorder");
+}
+
+extern inline unsigned int r4030_write_reg32(unsigned addr, unsigned val) {
+ *((volatile unsigned int *)addr) = val;
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".set\treorder");
+}
+
+#endif /* !LANGUAGE_ASSEMBLY__ */
+
+#define JAZZ_FDC_BASE 0xe0003000
+
+#define JAZZ_RTC_BASE 0xe0004000
+
+#endif /* __ASM_MIPS_JAZZ_H */
--- /dev/null
+/*
+ * Helpfile for jazzdma.c -- Mips Jazz R4030 DMA controller support
+ */
+
+#ifndef __ASM_JAZZDMA_H
+#define __ASM_JAZZDMA_H
+
+/*
+ * Prototypes and macros
+ */
+
+unsigned long vdma_init(unsigned long memory_start, unsigned long memory_end);
+unsigned long vdma_alloc(unsigned long paddr, unsigned long size);
+int vdma_free(unsigned long laddr);
+int vdma_remap(unsigned long laddr, unsigned long paddr, unsigned long size);
+unsigned long vdma_phys2log(unsigned long paddr);
+unsigned long vdma_log2phys(unsigned long laddr);
+void vdma_stats(void); /* for debugging only */
+
+void vdma_enable(int channel);
+void vdma_disable(int channel);
+void vdma_set_mode(int channel, int mode);
+void vdma_set_addr(int channel, long addr);
+void vdma_set_count(int channel, int count);
+int vdma_get_residue(int channel);
+
+/*
+ * some definitions used by the driver functions
+ */
+#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
+
+/*
+ * Macros to get page no. and offset of a given address
+ * Note that VDMA_PAGE() works for physical addresses only
+ */
+#define VDMA_PAGE(a) ((unsigned int)(a) >> 12)
+#define VDMA_OFFSET(a) ((unsigned int)(a) & (VDMA_PAGESIZE-1))
+
+/*
+ * error code returned by vdma_alloc()
+ * (See also arch/mips/kernel/jazzdma.c)
+ */
+#define VDMA_ERROR 0xffffffff
+
+/*
+ * VDMA pagetable entry description
+ */
+typedef volatile struct VDMA_PGTBL_ENTRY
+{
+ unsigned int frame; /* physical frame no. */
+ unsigned int owner; /* owner of this entry (0=free) */
+} VDMA_PGTBL_ENTRY;
+
+
+/*
+ * DMA channel control registers
+ * in the R4030 MCT_ADR chip
+ */
+#define JAZZ_R4030_CHNL_MODE 0xE0000100 /* 8 DMA Channel Mode Registers, */
+ /* 0xE0000100,120,140... */
+#define JAZZ_R4030_CHNL_ENABLE 0xE0000108 /* 8 DMA Channel Enable Regs, */
+ /* 0xE0000108,128,148... */
+#define JAZZ_R4030_CHNL_COUNT 0xE0000110 /* 8 DMA Channel Byte Cnt Regs, */
+ /* 0xE0000110,130,150... */
+#define JAZZ_R4030_CHNL_ADDR 0xE0000118 /* 8 DMA Channel Address Regs, */
+ /* 0xE0000118,138,158... */
+
+/* channel enable register bits */
+
+#define R4030_CHNL_ENABLE (1<<0)
+#define R4030_CHNL_WRITE (1<<1)
+#define R4030_TC_INTR (1<<8)
+#define R4030_MEM_INTR (1<<9)
+#define R4030_ADDR_INTR (1<<10)
+
+/* channel mode register bits */
+
+#define R4030_MODE_ATIME_40 (0) /* device access time on remote bus */
+#define R4030_MODE_ATIME_80 (1)
+#define R4030_MODE_ATIME_120 (2)
+#define R4030_MODE_ATIME_160 (3)
+#define R4030_MODE_ATIME_200 (4)
+#define R4030_MODE_ATIME_240 (5)
+#define R4030_MODE_ATIME_280 (6)
+#define R4030_MODE_ATIME_320 (7)
+#define R4030_MODE_WIDTH_8 (1<<3) /* device data bus width */
+#define R4030_MODE_WIDTH_16 (2<<3)
+#define R4030_MODE_WIDTH_32 (3<<3)
+#define R4030_MODE_INTR_EN (1<<5)
+#define R4030_MODE_BURST (1<<6) /* Rev. 2 only */
+#define R4030_MODE_FAST_ACK (1<<7) /* Rev. 2 only */
+
+#endif /* __ASM_JAZZDMA_H */
--- /dev/null
+/*
+ * Machine dependend access functions for RTC registers.
+ */
+#ifndef __ASM_MIPS_MC146818RTC_H
+#define __ASM_MIPS_MC146818RTC_H
+
+#include <asm/io.h>
+#include <asm/vector.h>
+
+#ifndef RTC_PORT
+#define RTC_PORT(x) (0x70 + (x))
+#define RTC_ALWAYS_BCD 1
+#endif
+
+/*
+ * The yet supported machines all access the RTC index register via
+ * an ISA port access but the way to access the date register differs ...
+ */
+#define CMOS_READ(addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+feature->rtc_read_data(); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p((addr),RTC_PORT(0)); \
+feature->rtc_write_data(val); \
+})
+
+#endif /* __ASM_MIPS_MC146818RTC_H */
/*
- * linux/include/asm-mips/mipsconfig.h
+ * include/asm-mips/mipsconfig.h
*
* 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.
*
- * Copyright (C) 1994, 1995 by Waldorf Electronics
- * written by Ralf Baechle
- *
+ * Copyright (C) 1994, 1995 by Ralf Baechle
*/
-#ifndef __ASM_MIPS_MIPS_CONFIG_H
-#define __ASM_MIPS_MIPS_CONFIG_H
+#ifndef __ASM_MIPS_MIPSCONFIG_H
+#define __ASM_MIPS_MIPSCONFIG_H
/*
* This is the virtual address to which all ports are being mapped.
* Must be a value that can be load with a lui instruction.
*/
-#define PORT_BASE 0xe0000000
-
-/* #define NUMBER_OF_TLB_ENTRIES 48 */ /* see bootinfo.h -- Andy */
-#define NUMBER_OF_TLB_ENTRIES 48
+#ifndef PORT_BASE
+#define PORT_BASE 0xe2000000
+#endif
/*
- * Pagetables are 4MB mapped at 0xe3000000
- * Must be a value that can be load with a lui instruction.
+ * Pagetables are 4MB mapped at 0xe4000000
+ * Must be a value that can be loaded with a single instruction.
*/
#define TLBMAP 0xe4000000
* The virtual address where we'll map the pagetables
* For a base address of 0xe3000000 this is 0xe338c000
* For a base address of 0xe4000000 this is 0xe4390000
- * FIXME: Gas miscomputes the following expression!
+ * FIXME: Gas computes the following expression with signed
+ * shift and therefore false
#define TLB_ROOT (TLBMAP + (TLBMAP >> (12-2)))
*/
#define TLB_ROOT 0xe4390000
/*
- * This ASID is reserved for the swapper
+ * Use this to activate extra TLB error checking
+ */
+#define CONF_DEBUG_TLB
+
+/*
+ * Use this to activate extra TLB profiling code
+ * (currently not implemented)
+ */
+#undef CONF_PROFILE_TLB
+
+/*
+ * Disable all caching. Usefull to find trouble with caches in drivers.
+ */
+#undef CONF_DISABLE_KSEG0_CACHING
+
+/*
+ * Set this to one to enable additional vdma debug code.
*/
-#define SWAPPER_ASID 0
+#define CONF_DEBUG_VDMA 0
-#endif /* __ASM_MIPS_MIPS_CONFIG_H */
+#endif /* __ASM_MIPS_MIPSCONFIG_H */
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1994 by Ralf Baechle
+ * Copyright (C) 1994, 1995 by Ralf Baechle
*/
#ifndef __ASM_MIPS_MIPSREGS_H
/*
* On the R2000/3000 load instructions are not interlocked -
* we therefore sometimes need to fill load delay slots with a nop
- * which are useless for >=R4000.
- *
- * FIXME: Don't know about R6000
+ * which would be useless for ISA >= 2.
*/
#if !defined (__R4000__)
#define FILL_LDS nop
#define CP0_WATCHLO $18
#define CP0_WATCHHI $19
#define CP0_XCONTEXT $20
+#define CP0_FRAMEMASK $21
+#define CP0_DIAGNOSTIC $22
+#define CP0_PERFORMANCE $25
#define CP0_ECC $26
#define CP0_CACHEERR $27
#define CP0_TAGLO $28
#define CP0_TAGHI $29
#define CP0_ERROREPC $30
+/*
+ * Coprocessor 1 (FPU) register names
+ */
+#define CP1_REVISION $0
+#define CP1_STATUS $31
+
/*
* Values for PageMask register
*/
#define PL_4M 22
#define PL_16M 24
-/*
- * Compute a vpn/pfn entry for EntryHi register
- */
-#define VPN(addr,pagesizeshift) ((addr) & ~((1 << (pagesizeshift))-1))
-#define PFN(addr,pagesizeshift) (((addr) & ((1 << (pagesizeshift))-1)) << 6)
-
/*
* Macros to access the system control coprocessor
*/
-#define read_32bit_cp0_register(source) \
-({ int __res; \
- __asm__ __volatile__( \
- "mfc0\t%0,"STR(source) \
- : "=r" (__res)); \
+#define read_32bit_cp0_register(source) \
+({ int __res; \
+ __asm__ __volatile__( \
+ "mfc0\t%0,"STR(source) \
+ : "=r" (__res)); \
__res;})
-#define read_64bit_cp0_register(source) \
-({ int __res; \
- __asm__ __volatile__( \
- "dmfc0\t%0,"STR(source) \
- : "=r" (__res)); \
+#define read_64bit_cp0_register(source) \
+({ int __res; \
+ __asm__ __volatile__( \
+ ".set\tmips3\n\t" \
+ "dmfc0\t%0,"STR(source)"\n\t" \
+ ".set\tmips0" \
+ : "=r" (__res)); \
__res;})
-#define write_32bit_cp0_register(register,value) \
- __asm__ __volatile__( \
- "mtc0\t%0,"STR(register) \
+#define write_32bit_cp0_register(register,value) \
+ __asm__ __volatile__( \
+ "mtc0\t%0,"STR(register) \
: : "r" (value));
+#define write_64bit_cp0_register(register,value) \
+ __asm__ __volatile__( \
+ ".set\tmips3\n\t" \
+ "dmtc0\t%0,"STR(register)"\n\t" \
+ ".set\tmips0" \
+ : : "r" (value))
+/*
+ * R4x00 interrupt enable / cause bits
+ */
+#define IE_SW0 (1<< 8)
+#define IE_SW1 (1<< 9)
+#define IE_IRQ0 (1<<10)
+#define IE_IRQ1 (1<<11)
+#define IE_IRQ2 (1<<12)
+#define IE_IRQ3 (1<<13)
+#define IE_IRQ4 (1<<14)
+#define IE_IRQ5 (1<<15)
+
+/*
+ * R4x00 interrupt cause bits
+ */
+#define C_SW0 (1<< 8)
+#define C_SW1 (1<< 9)
+#define C_IRQ0 (1<<10)
+#define C_IRQ1 (1<<11)
+#define C_IRQ2 (1<<12)
+#define C_IRQ3 (1<<13)
+#define C_IRQ4 (1<<14)
+#define C_IRQ5 (1<<15)
+
+#ifndef __LANGUAGE_ASSEMBLY__
+/*
+ * Manipulate the status register.
+ * Mostly used to access the interrupt bits.
+ */
+#define BUILD_SET_CP0(name,register) \
+extern __inline__ unsigned int \
+set_cp0_##name(unsigned int change, unsigned int new) \
+{ \
+ unsigned int res; \
+ \
+ res = read_32bit_cp0_register(register); \
+ res &= ~change; \
+ res |= (new & change); \
+ if(change) \
+ write_32bit_cp0_register(register, res); \
+ \
+ return res; \
+}
+
+BUILD_SET_CP0(status,CP0_STATUS)
+BUILD_SET_CP0(cause,CP0_CAUSE)
+
+#endif /* defined (__LANGUAGE_ASSEMBLY__) */
+
/*
* Inline code for use of the ll and sc instructions
*
* Since these operations are only being used for atomic operations
* the easiest workaround for the R[23]00 is to disable interrupts.
*/
-#define load_linked(addr) \
-({ \
- unsigned int __res; \
- \
- __asm__ __volatile__( \
- "ll\t%0,(%1)" \
- : "=r" (__res) \
- : "r" ((unsigned int) (addr))); \
- \
- __res; \
+#define load_linked(addr) \
+({ \
+ unsigned int __res; \
+ \
+ __asm__ __volatile__( \
+ "ll\t%0,(%1)" \
+ : "=r" (__res) \
+ : "r" ((unsigned int) (addr))); \
+ \
+ __res; \
})
-#define store_conditional(addr,value) \
-({ \
- int __res; \
- \
- __asm__ __volatile__( \
- "sc\t%0,(%2)" \
- : "=r" (__res) \
- : "0" (value), "r" (addr)); \
- \
- __res; \
+#define store_conditional(addr,value) \
+({ \
+ int __res; \
+ \
+ __asm__ __volatile__( \
+ "sc\t%0,(%2)" \
+ : "=r" (__res) \
+ : "0" (value), "r" (addr)); \
+ \
+ __res; \
})
/*
* Bitfields in the cp0 status register
*
- * Refer to MIPS R4600 manual, page 5-4 for explanation
+ * Refer to the MIPS R4xx0 manuals, chapter 5 for explanation.
+ * FIXME: This doesn't cover all R4xx0 processors.
+ */
+#define ST0_IE (1 << 0)
+#define ST0_EXL (1 << 1)
+#define ST0_ERL (1 << 2)
+#define ST0_KSU (3 << 3)
+# define KSU_USER (2 << 3)
+# define KSU_SUPERVISOR (1 << 3)
+# define KSU_KERNEL (0 << 3)
+#define ST0_UX (1 << 5)
+#define ST0_SX (1 << 6)
+#define ST0_KX (1 << 7)
+#define ST0_IM (255 << 8)
+#define ST0_DE (1 << 16)
+#define ST0_CE (1 << 17)
+#define ST0_CH (1 << 18)
+#define ST0_SR (1 << 20)
+#define ST0_BEV (1 << 22)
+#define ST0_RE (1 << 25)
+#define ST0_FR (1 << 26)
+#define ST0_CU (15 << 28)
+#define ST0_CU0 (1 << 28)
+#define ST0_CU1 (1 << 29)
+#define ST0_CU2 (1 << 30)
+#define ST0_CU3 (1 << 31)
+#define ST0_XX (1 << 31) /* R8000/R10000 naming */
+
+/*
+ * Bitfields and bit numbers in the coprocessor 0 cause register.
+ *
+ * Refer to to your MIPS R4xx0 manual, chapter 5 for explanation.
*/
-#define ST0_IE (1 << 0)
-#define ST0_EXL (1 << 1)
-#define ST0_ERL (1 << 2)
-#define ST0_KSU (3 << 3)
-#define ST0_UX (1 << 5)
-#define ST0_SX (1 << 6)
-#define ST0_KX (1 << 7)
-#define ST0_IM (255 << 8)
-#define ST0_DE (1 << 16)
-#define ST0_CE (1 << 17)
-#define ST0_CH (1 << 18)
-#define ST0_SR (1 << 20)
-#define ST0_BEV (1 << 22)
-#define ST0_RE (1 << 25)
-#define ST0_FR (1 << 26)
-#define ST0_CU (15 << 28)
-#define ST0_CU0 (1 << 28)
-#define ST0_CU1 (1 << 29)
-#define ST0_CU2 (1 << 30)
-#define ST0_CU3 (1 << 31)
+#define CAUSEB_EXCCODE 2
+#define CAUSEF_EXCCODE (31 << 2)
+#define CAUSEB_IP 8
+#define CAUSEF_IP (255 << 8)
+#define CAUSEB_IP0 8
+#define CAUSEF_IP0 (1 << 8)
+#define CAUSEB_IP1 9
+#define CAUSEF_IP1 (1 << 9)
+#define CAUSEB_IP2 10
+#define CAUSEF_IP2 (1 << 10)
+#define CAUSEB_IP3 11
+#define CAUSEF_IP3 (1 << 11)
+#define CAUSEB_IP4 12
+#define CAUSEF_IP4 (1 << 12)
+#define CAUSEB_IP5 13
+#define CAUSEF_IP5 (1 << 13)
+#define CAUSEB_IP6 14
+#define CAUSEF_IP6 (1 << 14)
+#define CAUSEB_IP7 15
+#define CAUSEF_IP7 (1 << 15)
+#define CAUSEB_CE 28
+#define CAUSEF_CE (3 << 28)
+#define CAUSEB_BD 31
+#define CAUSEF_BD (1 << 31)
#endif /* __ASM_MIPS_MIPSREGS_H */
--- /dev/null
+/*
+ * Linux/MIPS memory manager definitions
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_MMAN_H
+#define __ASM_MIPS_MMAN_H
+
+/*
+ * Protections are chosen from these bits, OR'd together. The
+ * implementation does not necessarily support PROT_EXEC or PROT_WRITE
+ * without PROT_READ. The only guarantees are that no writing will be
+ * allowed without PROT_WRITE and no access will be allowed for PROT_NONE.
+ */
+#define PROT_NONE 0x0 /* page can not be accessed */
+#define PROT_READ 0x1 /* page can be read */
+#define PROT_WRITE 0x2 /* page can be written */
+#define PROT_EXEC 0x4 /* page can be executed */
+
+/*
+ * Flags for mmap
+ */
+#define MAP_SHARED 0x001 /* Share changes */
+#define MAP_PRIVATE 0x002 /* Changes are private */
+#define MAP_TYPE 0x00f /* Mask for type of mapping */
+#define MAP_FIXED 0x010 /* Interpret addr exactly */
+
+/* not used by linux, but here to make sure we don't clash with ABI defines */
+#define MAP_RENAME 0x020 /* Assign page to file */
+#define MAP_AUTOGROW 0x040 /* File may grow by writing */
+#define MAP_LOCAL 0x080 /* Copy on fork/sproc */
+#define MAP_AUTORSRV 0x100 /* Logical swap reserved on demand */
+
+/* These are linux-specific */
+#define MAP_ANONYMOUS 0x0800 /* don't use a file */
+#define MAP_GROWSDOWN 0x1000 /* stack-like segment */
+#define MAP_DENYWRITE 0x2000 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x4000 /* mark it as a executable */
+#define MAP_LOCKED 0x8000 /* pages are locked */
+
+/*
+ * Flags for msync
+ */
+#define MS_SYNC 0 /* synchronous memory sync */
+#define MS_ASYNC 1 /* sync memory asynchronously */
+#define MS_INVALIDATE 2 /* invalidate mappings & caches */
+
+/*
+ * Flags for mlockall
+ */
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
+/* compatibility flags */
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FILE 0
+
+#endif /* __ASM_MIPS_MMAN_H */
#ifndef __ASM_MIPS_PAGE_H
#define __ASM_MIPS_PAGE_H
-#define STRICT_MM_TYPECHECKS
-
-#ifndef __ASSEMBLY__
-
-#include <linux/linkage.h>
+/* PAGE_SHIFT determines the page size */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
-#define invalidate() tlbflush();
-extern asmlinkage void tlbflush(void);
+#ifdef __KERNEL__
-/* 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))
+#define STRICT_MM_TYPECHECKS
-typedef unsigned short mem_map_t;
+#ifndef __LANGUAGE_ASSEMBLY__
#ifdef STRICT_MM_TYPECHECKS
/*
* These are used to make use of C type-checking..
*/
typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) ((x).pte)
+#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
+#define __pme(x) ((pme_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
* .. while these make it easier on the compiler
*/
typedef unsigned long pte_t;
+typedef unsigned long pmd_t;
typedef unsigned long pgd_t;
typedef unsigned long pgprot_t;
#define pte_val(x) (x)
+#define pmd_val(x) (x)
#define pgd_val(x) (x)
#define pgprot_val(x) (x)
#define __pte(x) (x)
+#define __pmd(x) (x)
#define __pgd(x) (x)
#define __pgprot(x) (x)
#endif /* !defined (STRICT_MM_TYPECHECKS) */
-#endif /* __ASSEMBLY__ */
-
-/*
- * Note that we shift the lower 32bits of each EntryLo[01] entry
- * 6 bits to the left. That way we can convert the PFN into the
- * physical address by a single 'and' operation and gain 6 additional
- * bits for storing information which isn't present in a normal
- * MIPS page table.
- */
-#define _PAGE_PRESENT (1<<0) /* implemented in software */
-#define _PAGE_COW (1<<1) /* implemented in software */
-#define _PAGE_DIRTY (1<<2) /* implemented in software */
-#define _PAGE_USER (1<<3)
-#define _PAGE_UNUSED1 (1<<4)
-#define _PAGE_UNUSED2 (1<<5)
-#define _PAGE_GLOBAL (1<<6)
-#define _PAGE_ACCESSED (1<<7) /* The MIPS valid bit */
-#define _PAGE_RW (1<<8) /* The MIPS dirty bit */
-#define _CACHE_CACHABLE_NO_WA (0<<9)
-#define _CACHE_CACHABLE_WA (1<<9)
-#define _CACHE_UNCACHED (2<<9)
-#define _CACHE_CACHABLE_NONCOHERENT (3<<9)
-#define _CACHE_CACHABLE_CE (4<<9)
-#define _CACHE_CACHABLE_COW (5<<9)
-#define _CACHE_CACHABLE_CUW (6<<9)
-#define _CACHE_MASK (7<<9)
-
-#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY | \
- _CACHE_CACHABLE_NO_WA)
-
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _CACHE_MASK)
-
-#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _CACHE_CACHABLE_NO_WA)
-#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW | _CACHE_CACHABLE_NO_WA)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _CACHE_CACHABLE_NO_WA)
-#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
/*
- * MIPS can't do page protection for execute, and considers that the same like
- * read. Also, write permissions imply read permissions. This is the closest
- * we can get by reasonable means..
+ * We need a special version of copy_page that can handle virtual caches.
+ * While we're at tweaking with caches we can use that to make it even
+ * faster. The R10000 accelerated caching mode will further accelerate it.
*/
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY
-#define __P101 PAGE_READONLY
-#define __P110 PAGE_COPY
-#define __P111 PAGE_COPY
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY
-#define __S101 PAGE_READONLY
-#define __S110 PAGE_SHARED
-#define __S111 PAGE_SHARED
-
-/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT 12
-#define PGDIR_SHIFT 22
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
-
-#ifdef __KERNEL__
+extern void __copy_page(unsigned long from, unsigned long to);
+#define copy_page(from,to) __copy_page((unsigned long)from, (unsigned long)to)
-#define PAGE_OFFSET KERNELBASE
-#define MAP_NR(addr) (((addr) - PAGE_OFFSET) >> PAGE_SHIFT)
-#define MAP_PAGE_RESERVED (1<<15)
-
-#if !defined (__ASSEMBLY__)
-
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-
-/*
- * BAD_PAGETABLE is used when we need a bogus page-table, while
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern pte_t * __bad_pagetable(void);
-
-extern unsigned long __zero_page(void);
-
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
-
-/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR (8*sizeof(unsigned long))
-
-/* to mask away the intra-page address bits */
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-/* to mask away the intra-page address bits */
-#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#endif /* __LANGUAGE_ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware! SRB. */
-#define SIZEOF_PTR_LOG2 2
-
-/* to find an entry in a page-table-directory */
-#define PAGE_DIR_OFFSET(tsk,address) \
-((((unsigned long)(address)) >> PGDIR_SHIFT) + (pgd_t *) (tsk)->tss.pg_dir)
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* the no. of pointers that fit on a page */
-#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*))
-
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
- (tsk)->tss.pg_dir = (unsigned long) (pgdir); \
- if ((tsk) == current) \
- invalidate(); \
-} while (0)
-
-extern unsigned long high_memory;
-
-extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
-extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
-extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
-
-extern inline int pgd_none(pgd_t pgd) { return !pgd_val(pgd); }
-extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE || pgd_val(pgd) > high_memory; }
-extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) & _PAGE_PRESENT; }
-extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; }
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+/* This handles the memory map */
+#if __mips == 3
/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
+ * We handle pages at XKPHYS + 0x1800000000000000 (cachable, noncoherent)
+ * Pagetables are at XKPHYS + 0x1000000000000000 (uncached)
*/
-extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
-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; }
-
+#define PAGE_OFFSET 0x9800000000000000UL
+#define PT_OFFSET 0x9000000000000000UL
+#define MAP_MASK 0x07ffffffffffffffUL
+#else
/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * We handle pages at KSEG0 (cachable, noncoherent)
+ * Pagetables are at KSEG1 (uncached)
*/
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+#define PAGE_OFFSET 0x80000000
+#define PT_OFFSET 0xa0000000
+#define MAP_MASK 0x1fffffff
+#endif
+
+#define MAP_NR(addr) ((((unsigned long)(addr)) & MAP_MASK) >> PAGE_SHIFT)
-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; }
+#ifndef __LANGUAGE_ASSEMBLY__
-extern inline unsigned long pte_page(pte_t pte) { return pte_val(pte) & PAGE_MASK; }
-extern inline unsigned long pgd_page(pgd_t pgd) { return pgd_val(pgd) & PAGE_MASK; }
+extern unsigned long page_colour_mask;
-extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
-{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+extern inline unsigned long
+page_colour(unsigned long page)
+{
+ return page & page_colour_mask;
+}
-#endif /* !defined (__ASSEMBLY__) */
+#endif /* defined (__LANGUAGE_ASSEMBLY__) */
#endif /* defined (__KERNEL__) */
#endif /* __ASM_MIPS_PAGE_H */
--- /dev/null
+#ifndef __ASM_MIPS_PGTABLE_H
+#define __ASM_MIPS_PGTABLE_H
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <asm/cachectl.h>
+
+/*
+ * The Linux memory management assumes a three-level page table setup. In
+ * 32 bit mode we use that, but "fold" the mid level into the top-level page
+ * table, so that we physically have the same two-level page table as the
+ * i386 mmu expects. The 64 bit version uses a three level setup.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the MIPS page table tree. Note the frequent conversion between addresses
+ * in KSEG0 and KSEG1.
+ *
+ * This is required due to the cache aliasing problem of the R4xx0 series.
+ * Sometimes doing uncached accesses also to improve the cache performance
+ * slightly. The R10000 caching mode "uncached accelerated" will help even
+ * further.
+ */
+
+/*
+ * TLB invalidation:
+ *
+ * - invalidate() invalidates the current mm struct TLBs
+ * - invalidate_all() invalidates all processes TLBs
+ * - invalidate_mm(mm) invalidates the specified mm context TLB's
+ * - invalidate_page(mm, vmaddr) invalidates one page
+ * - invalidate_range(mm, start, end) invalidates a range of pages
+ *
+ * FIXME: MIPS has full control of all TLB activity in the CPU. Though
+ * we just stick with complete flushing of TLBs for now.
+ */
+extern asmlinkage void tlbflush(void);
+#define invalidate() ({sys_cacheflush(0, ~0, BCACHE);tlbflush();})
+
+#define invalidate_all() invalidate()
+#define invalidate_mm(mm_struct) \
+do { if ((mm_struct) == current->mm) invalidate(); } while (0)
+#define invalidate_page(mm_struct,addr) \
+do { if ((mm_struct) == current->mm) invalidate(); } while (0)
+#define invalidate_range(mm_struct,start,end) \
+do { if ((mm_struct) == current->mm) invalidate(); } while (0)
+
+/*
+ * We need a special version of copy_page that can handle virtual caches.
+ * While we're at tweaking with caches we can use that to make it faster.
+ * The R10000's accelerated caching mode will further accelerate it.
+ */
+extern void __copy_page(unsigned long from, unsigned long to);
+#define copy_page(from,to) __copy_page((unsigned long)from, (unsigned long)to)
+
+/* 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))
+
+#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
+
+/* PMD_SHIFT determines the size of the area a second-level page table can map */
+#define PMD_SHIFT 22
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+
+/* PGDIR_SHIFT determines what a third-level page table entry can map */
+#define PGDIR_SHIFT 22
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: we use two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE 1024
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 1024
+
+#define VMALLOC_START KSEG2
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+
+/*
+ * Note that we shift the lower 32bits of each EntryLo[01] entry
+ * 6 bits to the left. That way we can convert the PFN into the
+ * physical address by a single 'and' operation and gain 6 additional
+ * bits for storing information which isn't present in a normal
+ * MIPS page table.
+ * Since the Mips has choosen some quite missleading names for the
+ * valid and dirty bits they're defined here but only their synonyms
+ * will be used.
+ */
+#define _PAGE_PRESENT (1<<0) /* implemented in software */
+#define _PAGE_COW (1<<1) /* implemented in software */
+#define _PAGE_READ (1<<2) /* implemented in software */
+#define _PAGE_WRITE (1<<3) /* implemented in software */
+#define _PAGE_ACCESSED (1<<4) /* implemented in software */
+#define _PAGE_MODIFIED (1<<5) /* implemented in software */
+#define _PAGE_GLOBAL (1<<6)
+#define _PAGE_VALID (1<<7)
+#define _PAGE_SILENT_READ (1<<7) /* synonym */
+#define _PAGE_DIRTY (1<<8) /* The MIPS dirty bit */
+#define _PAGE_SILENT_WRITE (1<<8)
+#define _CACHE_CACHABLE_NO_WA (0<<9) /* R4600 only */
+#define _CACHE_CACHABLE_WA (1<<9) /* R4600 only */
+#define _CACHE_UNCACHED (2<<9) /* R4[0246]00 */
+#define _CACHE_CACHABLE_NONCOHERENT (3<<9) /* R4[0246]00 */
+#define _CACHE_CACHABLE_CE (4<<9) /* R4[04]00 only */
+#define _CACHE_CACHABLE_COW (5<<9) /* R4[04]00 only */
+#define _CACHE_CACHABLE_CUW (6<<9) /* R4[04]00 only */
+#define _CACHE_CACHABLE_ACCELERATED (7<<9) /* R10000 only */
+#define _CACHE_MASK (7<<9)
+
+#define __READABLE (_PAGE_READ|_PAGE_SILENT_READ|_PAGE_ACCESSED)
+#define __WRITEABLE (_PAGE_WRITE|_PAGE_SILENT_WRITE|_PAGE_MODIFIED)
+
+#define _PAGE_TABLE (_PAGE_PRESENT | __READABLE | __WRITEABLE | \
+ _PAGE_DIRTY | _CACHE_UNCACHED)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _CACHE_MASK)
+
+#define PAGE_NONE __pgprot(_PAGE_PRESENT | __READABLE | _CACHE_UNCACHED)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_WRITE | \
+ _PAGE_ACCESSED | _CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_COW | \
+ _CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | __READABLE | \
+ _CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
+ _CACHE_CACHABLE_NONCOHERENT)
+
+/*
+ * MIPS can't do page protection for execute, and considers that the same like
+ * read. Also, write permissions imply read permissions. This is the closest
+ * we can get by reasonable means..
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED
+
+#if !defined (__LANGUAGE_ASSEMBLY__)
+
+/* page table for 0-4MB for everybody */
+extern unsigned long pg0[1024];
+
+/*
+ * BAD_PAGETABLE is used when we need a bogus page-table, while
+ * BAD_PAGE is used for a bogus page.
+ *
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
+extern unsigned long __zero_page(void);
+
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE __zero_page()
+
+/* number of bits that fit into a memory pointer */
+#define BITS_PER_PTR (8*sizeof(unsigned long))
+
+/* to align the pointer to a pointer address */
+#define PTR_MASK (~(sizeof(void*)-1))
+
+/*
+ * sizeof(void*)==1<<SIZEOF_PTR_LOG2
+ */
+#if __mips == 3
+#define SIZEOF_PTR_LOG2 3
+#else
+#define SIZEOF_PTR_LOG2 2
+#endif
+
+/* to find an entry in a page-table */
+#define PAGE_PTR(address) \
+((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+
+/* to set the page-dir */
+#define SET_PAGE_DIR(tsk,pgdir) \
+do { \
+ (tsk)->tss.pg_dir = ((unsigned long) (pgdir)) - PT_OFFSET; \
+ if ((tsk) == current) \
+ { \
+ void load_pgd(unsigned long pg_dir); \
+ \
+ load_pgd((tsk)->tss.pg_dir); \
+ } \
+} while (0)
+
+extern unsigned long high_memory;
+extern pmd_t invalid_pte_table[PAGE_SIZE/sizeof(pmd_t)];
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline unsigned long pte_page(pte_t pte)
+{ return PAGE_OFFSET + (pte_val(pte) & PAGE_MASK); }
+
+extern inline unsigned long pmd_page(pmd_t pmd)
+{ return PAGE_OFFSET + (pmd_val(pmd) & PAGE_MASK); }
+
+extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
+{ pmd_val(*pmdp) = _PAGE_TABLE | ((unsigned long) ptep - PT_OFFSET); }
+
+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 int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
+extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
+extern inline void pte_reuse(pte_t * ptep)
+{
+ if (!mem_map[MAP_NR(ptep)].reserved)
+ mem_map[MAP_NR(ptep)].count++;
+}
+
+/*
+ * Empty pgd/pmd entries point to the invalid_pte_table.
+ */
+extern inline int pmd_none(pmd_t pmd) { return (pmd_val(pmd) & PAGE_MASK) == ((unsigned long) invalid_pte_table - PAGE_OFFSET); }
+
+extern inline int pmd_bad(pmd_t pmd)
+{
+ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE ||
+ pmd_page(pmd) > high_memory ||
+ pmd_page(pmd) < PAGE_OFFSET;
+}
+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 void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = ((unsigned long) invalid_pte_table - PAGE_OFFSET); }
+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
+ * into the pgd entry)
+ */
+extern inline int pgd_none(pgd_t pgd) { return 0; }
+extern inline int pgd_bad(pgd_t pgd) { return 0; }
+extern inline int pgd_present(pgd_t pgd) { return 1; }
+extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)].reserved; }
+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_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; }
+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_WRITE | _PAGE_SILENT_WRITE);
+ return pte;
+}
+extern inline pte_t pte_rdprotect(pte_t pte)
+{
+ pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte;
+}
+extern inline pte_t pte_exprotect(pte_t pte)
+{
+ pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte;
+}
+extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(_PAGE_MODIFIED|_PAGE_SILENT_WRITE); return pte; }
+extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ|_PAGE_SILENT_WRITE); return pte; }
+extern inline pte_t pte_uncow(pte_t pte) { pte_val(pte) &= ~_PAGE_COW; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_WRITE;
+ if (pte_val(pte) & _PAGE_MODIFIED)
+ pte_val(pte) |= _PAGE_SILENT_WRITE;
+ return pte;
+}
+extern inline pte_t pte_mkread(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_READ;
+ if (pte_val(pte) & _PAGE_ACCESSED)
+ pte_val(pte) |= _PAGE_SILENT_READ;
+ return pte;
+}
+extern inline pte_t pte_mkexec(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_READ;
+ if (pte_val(pte) & _PAGE_ACCESSED)
+ pte_val(pte) |= _PAGE_SILENT_READ;
+ return pte;
+}
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_MODIFIED;
+ if (pte_val(pte) & _PAGE_WRITE)
+ pte_val(pte) |= _PAGE_SILENT_WRITE;
+ return pte;
+}
+extern inline pte_t pte_mkyoung(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_ACCESSED;
+ if (pte_val(pte) & _PAGE_READ)
+ {
+ pte_val(pte) |= _PAGE_SILENT_READ;
+ if ((pte_val(pte) & (_PAGE_WRITE|_PAGE_MODIFIED)) == (_PAGE_WRITE|_PAGE_MODIFIED))
+ pte_val(pte) |= _PAGE_SILENT_WRITE;
+ }
+ return pte;
+}
+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 pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = (page - PAGE_OFFSET) | 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; }
+
+/* to find an entry in a page-table-directory */
+extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
+{
+ return mm->pgd + (address >> PGDIR_SHIFT);
+}
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+{
+ return (pmd_t *) dir;
+}
+
+/* Find an entry in the third-level page table.. */
+extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
+{
+ return (pte_t *) (pmd_page(*dir) + (PT_OFFSET - PAGE_OFFSET)) +
+ ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+}
+
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any, and marks the page tables reserved.
+ */
+extern inline void pte_free_kernel(pte_t * pte)
+{
+ unsigned long page = (unsigned long) pte;
+
+ mem_map[MAP_NR(pte)].reserved = 0;
+ if(!page)
+ return;
+ page -= (PT_OFFSET - PAGE_OFFSET);
+ free_page(page);
+}
+
+extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ unsigned long page = __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (page) {
+ mem_map[MAP_NR(page)].reserved = 1;
+ memset((void *) page, 0, PAGE_SIZE);
+ sys_cacheflush((void *)page, PAGE_SIZE, DCACHE);
+ sync_mem();
+ page += (PT_OFFSET - PAGE_OFFSET);
+ pmd_set(pmd, (pte_t *)page);
+ return ((pte_t *)page) + address;
+ }
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page(page);
+ }
+ if (pmd_bad(*pmd)) {
+ printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ return NULL;
+ }
+ return (pte_t *) (pmd_page(*pmd) + (PT_OFFSET - PAGE_OFFSET)) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free_kernel(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t * pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+extern inline void pte_free(pte_t * pte)
+{
+ unsigned long page = (unsigned long) pte;
+
+ if(!page)
+ return;
+ page -= (PT_OFFSET - PAGE_OFFSET);
+ free_page(page);
+}
+
+extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
+{
+ address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+ if (pmd_none(*pmd)) {
+ unsigned long page = __get_free_page(GFP_KERNEL);
+ if (pmd_none(*pmd)) {
+ if (page) {
+ memset((void *) page, 0, PAGE_SIZE);
+ sys_cacheflush((void *)page, PAGE_SIZE, DCACHE);
+ sync_mem();
+ page += (PT_OFFSET - PAGE_OFFSET);
+ pmd_set(pmd, (pte_t *)page);
+ return ((pte_t *)page) + address;
+ }
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ return NULL;
+ }
+ free_page(page);
+ }
+ if (pmd_bad(*pmd)) {
+ printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+ pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+ return NULL;
+ }
+ return (pte_t *) (pmd_page(*pmd) + (PT_OFFSET - PAGE_OFFSET)) + address;
+}
+
+/*
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+extern inline void pmd_free(pmd_t * pmd)
+{
+}
+
+extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
+{
+ return (pmd_t *) pgd;
+}
+
+extern inline void pgd_free(pgd_t * pgd)
+{
+ unsigned long page = (unsigned long) pgd;
+
+ if(!page)
+ return;
+ page -= (PT_OFFSET - PAGE_OFFSET);
+ free_page(page);
+}
+
+/*
+ * Initialize new page directory with pointers to invalid ptes
+ */
+extern inline void pgd_init(unsigned long page)
+{
+ unsigned long dummy1, dummy2;
+
+ page += (PT_OFFSET - PAGE_OFFSET);
+#if __mips >= 3
+ /*
+ * Ich will Spass - ich geb Gas ich geb Gas...
+ */
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ ".set\tmips3\n\t"
+ "dsll32\t$1,%2,0\n\t"
+ "dsrl32\t%2,$1,0\n\t"
+ "or\t%2,$1\n"
+ "1:\tsd\t%2,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,8\n\t"
+ ".set\tmips0\n\t"
+ ".set\tat\n\t"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) |
+ _PAGE_TABLE),
+ "0" (page),
+ "1" (PAGE_SIZE/(sizeof(pmd_t)*2))
+ :"$1");
+#else
+ __asm__ __volatile__(
+ ".set\tnoreorder\n"
+ "1:\tsw\t%2,(%0)\n\t"
+ "subu\t%1,1\n\t"
+ "bnez\t%1,1b\n\t"
+ "addiu\t%0,4\n\t"
+ ".set\treorder"
+ :"=r" (dummy1),
+ "=r" (dummy2)
+ :"r" (((unsigned long) invalid_pte_table - PAGE_OFFSET) |
+ _PAGE_TABLE),
+ "0" (page),
+ "1" (PAGE_SIZE/sizeof(pmd_t)));
+#endif
+}
+
+extern inline pgd_t * pgd_alloc(void)
+{
+ unsigned long page;
+
+ if(!(page = __get_free_page(GFP_KERNEL)))
+ return NULL;
+
+ sys_cacheflush((void *)page, PAGE_SIZE, DCACHE);
+ sync_mem();
+ pgd_init(page);
+
+ return (pgd_t *) (page + (PT_OFFSET - PAGE_OFFSET));
+}
+
+extern pgd_t swapper_pg_dir[1024];
+
+/*
+ * MIPS doesn't need any external MMU info: the kernel page tables contain
+ * all the necessary information. We use this hook though to load the
+ * TLB as early as possible with uptodate information avoiding unecessary
+ * exceptions.
+ */
+extern void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address, pte_t pte);
+
+#if __mips >= 3
+
+#define SWP_TYPE(entry) (((entry) >> 32) & 0xff)
+#define SWP_OFFSET(entry) ((entry) >> 40)
+#define SWP_ENTRY(type,offset) pte_val(mk_swap_pte((type),(offset)))
+
+#else
+
+#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
+#define SWP_OFFSET(entry) ((entry) >> 8)
+#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
+
+#endif
+
+#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
+
+#endif /* __ASM_MIPS_PGTABLE_H */
--- /dev/null
+/*
+ * Hardware info about Acer PICA 61 and similar
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Andreas Busse and Ralf Baechle
+ */
+#ifndef __ASM_MIPS_PICA_H
+#define __ASM_MIPS_PICA_H
+
+/*
+ * The addresses below are virtual address. The mappings are
+ * created on startup via wired entries in the tlb. The Mips
+ * Magnum R3000 and R4000 machines are similar in many aspects,
+ * but many hardware register are accessible at 0xb9000000 in
+ * instead of 0xe0000000.
+ */
+
+/*
+ * Revision numbers in PICA_ASIC_REVISION
+ *
+ * 0xf0000000 - Rev1
+ * 0xf0000001 - Rev2
+ * 0xf0000002 - Rev3
+ */
+#define PICA_ASIC_REVISION 0xe0000008
+
+/*
+ * The segments of the seven segment LED are mapped
+ * to the control bits as follows:
+ *
+ * (7)
+ * ---------
+ * | |
+ * (2) | | (6)
+ * | (1) |
+ * ---------
+ * | |
+ * (3) | | (5)
+ * | (4) |
+ * --------- . (0)
+ */
+#define PICA_LED 0xe000f000
+
+/*
+ * Some characters for the LED control registers
+ * The original Mips machines seem to have a LED display
+ * with integrated decoder while the Acer machines can
+ * control each of the seven segments and the dot independend.
+ * It only a toy, anyway...
+ */
+#define LED_DOT 0x01
+#define LED_SPACE 0x00
+#define LED_0 0xfc
+#define LED_1 0x60
+#define LED_2 0xda
+#define LED_3 0xf2
+#define LED_4 0x66
+#define LED_5 0xb6
+#define LED_6 0xbe
+#define LED_7 0xe0
+#define LED_8 0xfe
+#define LED_9 0xf6
+#define LED_A 0xee
+#define LED_b 0x3e
+#define LED_C 0x9c
+#define LED_d 0x7a
+#define LED_E 0x9e
+#define LED_F 0x8e
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+extern __inline__ void pica_set_led(unsigned int bits)
+{
+ volatile unsigned int *led_register = (unsigned int *) PICA_LED;
+
+ *led_register = bits;
+}
+
+#endif
+
+/*
+ * i8042 keyboard controller for PICA chipset.
+ * This address is just a guess and seems to differ
+ * from the other mips machines...
+ */
+#define PICA_KEYBOARD_ADDRESS 0xe0005000
+#define PICA_KEYBOARD_DATA 0xe0005000
+#define PICA_KEYBOARD_COMMAND 0xe0005001
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+typedef struct {
+ unsigned char data;
+ unsigned char command;
+} pica_keyboard_hardware;
+
+typedef struct {
+ unsigned char pad0[3];
+ unsigned char data;
+ unsigned char pad1[3];
+ unsigned char command;
+} mips_keyboard_hardware;
+
+/*
+ * For now
+ */
+#define keyboard_hardware pica_keyboard_hardware
+
+#endif
+
+/*
+ * i8042 keyboard controller for most other Mips machines.
+ */
+#define MIPS_KEYBOARD_ADDRESS 0xb9005000
+#define MIPS_KEYBOARD_DATA 0xb9005003
+#define MIPS_KEYBOARD_COMMAND 0xb9005007
+
+#ifndef __LANGUAGE_ASSEMBLY__
+
+#endif
+
+/*
+ * PICA timer registers and interrupt no.
+ * Note that the hardware timer interrupt is actually on
+ * cpu level 6, but to keep compatibility with PC stuff
+ * it is remapped to vector 0. See arch/mips/kernel/entry.S.
+ */
+#define PICA_TIMER_INTERVAL 0xe0000228
+#define PICA_TIMER_REGISTER 0xe0000230
+
+/*
+ * DRAM configuration register
+ */
+#ifndef __LANGUAGE_ASSEMBLY__
+#ifdef __MIPSEL__
+typedef struct {
+ unsigned int bank2 : 3;
+ unsigned int bank1 : 3;
+ unsigned int mem_bus_width : 1;
+ unsigned int reserved2 : 1;
+ unsigned int page_mode : 1;
+ unsigned int reserved1 : 23;
+} dram_configuration;
+#else /* defined (__MIPSEB__) */
+typedef struct {
+ unsigned int reserved1 : 23;
+ unsigned int page_mode : 1;
+ unsigned int reserved2 : 1;
+ unsigned int mem_bus_width : 1;
+ unsigned int bank1 : 3;
+ unsigned int bank2 : 3;
+} dram_configuration;
+#endif
+#endif /* __LANGUAGE_ASSEMBLY__ */
+
+#define PICA_DRAM_CONFIG 0xe00fffe0
+
+/*
+ * PICA interrupt control registers
+ */
+#define PICA_IO_IRQ_SOURCE 0xe0100000
+#define PICA_IO_IRQ_ENABLE 0xe0100002
+
+/*
+ * Pica interrupt enable bits
+ */
+#define PIE_PARALLEL (1<<0)
+#define PIE_FLOPPY (1<<1)
+#define PIE_SOUND (1<<2)
+#define PIE_VIDEO (1<<3)
+#define PIE_ETHERNET (1<<4)
+#define PIE_SCSI (1<<5)
+#define PIE_KEYBOARD (1<<6)
+#define PIE_MOUSE (1<<7)
+#define PIE_SERIAL1 (1<<8)
+#define PIE_SERIAL2 (1<<9)
+
+#endif /* __ASM_MIPS_PICA_H */
#ifndef __ASM_MIPS_PROCESSOR_H
#define __ASM_MIPS_PROCESSOR_H
-#if !defined (__ASSEMBLY__)
+#if !defined (__LANGUAGE_ASSEMBLY__)
+#include <asm/cachectl.h>
+#include <asm/mipsregs.h>
+#include <asm/reg.h>
#include <asm/system.h>
/*
extern unsigned long intr_count;
extern unsigned long event;
-#if defined (__R4000__)
-
-#define start_bh_atomic() \
-__asm__ __volatile__( \
- ".set\tnoreorder\n\t" \
- ".set\tnoat\n\t" \
- "ll\t$1,(%0)\n" \
- "1:\taddiu\t$1,$1,1\n\t" \
- "sc\t$1,(%0)\n\t" \
- "beqzl\t$1,1b\n\t" \
- "ll\t$1,(%0)\n\t" \
- ".set\tat\n\t" \
- ".set\treorder" \
- : /* no outputs */ \
- : "r" (&intr_count));
-
-#define end_bh_atomic() \
-__asm__ __volatile__( \
- ".set\tnoreorder\n\t" \
- ".set\tnoat\n\t" \
- "ll\t$1,(%0)\n" \
- "1:\tsubu\t$1,$1,1\n\t" \
- "sc\t$1,(%0)\n\t" \
- "beqzl\t$1,1b\n\t" \
- "ll\t$1,(%0)\n\t" \
- ".set\tat\n\t" \
- ".set\treorder" \
- : /* no outputs */ \
- : "r" (&intr_count));
-
-#else /* !defined (__R4000__) */
-
-#define start_bh_atomic() \
-{int flags; save_flags(flags); cli(); intr_count++; restore_flags(flags)}
-
-#define end_bh_atomic() \
-{int flags; save_flags(flags); cli(); intr_count--; restore_flags(flags)}
-
-#endif
-
/*
* Bus types (default is ISA, but people can check others with these..)
* MCA_bus hardcoded to 0 for now.
};
#define INIT_FPU { \
- 0, \
+ {{0,},} \
}
/*
*/
union mips_fpu_union fpu;
/*
- * Other stuff associated with the process
+ * Other stuff associated with the thread
*/
unsigned long cp0_badvaddr;
unsigned long error_code;
unsigned long trap_no;
unsigned long ksp; /* Top of kernel stack */
- unsigned long fs; /* "Segment" pointer */
unsigned long pg_dir; /* L1 page table pointer */
+#define MF_FIXADE 1
+ unsigned long mflags;
};
-#endif /* !defined (__ASSEMBLY__) */
+#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
/*
* If you change the #defines remember to change thread_struct above too!
#define TOFF_ERROR_CODE (TOFF_CP0_BADVADDR+4)
#define TOFF_TRAP_NO (TOFF_ERROR_CODE+4)
#define TOFF_KSP (TOFF_TRAP_NO+4)
-#define TOFF_FS (TOFF_KSP+4)
-#define TOFF_PG_DIR (TOFF_FS+4)
+#define TOFF_PG_DIR (TOFF_KSP+4)
+#define TOFF_MFLAGS (TOFF_PG_DIR+4)
-#if !defined (__ASSEMBLY__)
+#if !defined (__LANGUAGE_ASSEMBLY__)
+
+#define INIT_MMAP { &init_mm, KSEG0, KSEG1, PAGE_SHARED, \
+ VM_READ | VM_WRITE | VM_EXEC }
#define INIT_TSS { \
/* \
/* \
* Other stuff associated with the process\
*/ \
- 0, 0, 0, (((unsigned long)init_kernel_stack)+4096-8), \
- KERNEL_DS, (unsigned long) swapper_pg_dir \
+ 0, 0, 0, sizeof(init_kernel_stack) + (unsigned long)init_kernel_stack - 8, \
+ (unsigned long) swapper_pg_dir - PT_OFFSET, 0 \
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+{
+ return ((unsigned long *)t->reg29)[EF_CP0_EPC];
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ */
+static __inline__
+void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+{
+ /*
+ * Pure paranoia; probably not needed.
+ */
+ sys_cacheflush(0, ~0, BCACHE);
+ sync_mem();
+ regs->cp0_epc = pc;
+ /*
+ * New thread looses kernel priviledges.
+ */
+ regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU)) | KSU_USER;
+ /*
+ * Reserve argument save space for registers a0 - a3.
+ regs->reg29 = sp - 4 * sizeof(unsigned long);
+ */
+ regs->reg29 = sp;
}
#ifdef __KERNEL__
#else /* !defined (__R4000__) */
-#error "#define USES_USER_TIME(regs)!"
+#define USES_USER_TIME(regs) (!((regs)->cp0_status & 0x4))
#endif /* !defined (__R4000__) */
#endif /* __KERNEL__ */
-#endif /* !defined (__ASSEMBLY__) */
+#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
+
+/*
+ * ELF support
+ *
+ * Using EM_MIPS is actually wrong - this one is reserved for big endian
+ * machines only
+ */
+#define INCOMPATIBLE_MACHINE(m) ((m) != EM_MIPS && (m) != EM_MIPS_RS4_BE)
+#define ELF_EM_CPU EM_MIPS
#endif /* __ASM_MIPS_PROCESSOR_H */
/*
* linux/include/asm-mips/ptrace.h
*
- * machine dependent structs and defines to help the user use
+ * 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.
+ *
+ * Copyright (C) 1994, 1995 by Waldorf GMBH
+ * written by Ralf Baechle
+ *
+ * Machine dependent structs and defines to help the user use
* the ptrace system call.
*/
#ifndef __ASM_MIPS_PTRACE_H
#define __ASM_MIPS_PTRACE_H
/*
- * use ptrace (3 or 6, pid, PT_EXCL, data); to read or write
- * the processes registers.
- *
- * This defines/structures correspond to the register layout on stack -
- * if the order here is changed, it needs to be updated in
- * arch/mips/fork.c:copy_process, asm/mips/signal.c:do_signal,
- * asm-mips/ptrace.c, include/asm-mips/ptrace.h.
- */
-
-#include <asm/stackframe.h>
-
-/*
- * This struct defines the way the registers are stored on the
- * stack during a system call/exception. As usual the registers
- * k0/k1 aren't being saved.
+ * This struct defines the way the registers are stored on the stack during a
+ * system call/exception. As usual the registers k0/k1 aren't being saved.
*/
struct pt_regs {
/*
* Pad bytes for argument save space on the stack
+ * 20/40 Bytes for 32/64 bit code
*/
- unsigned long pad0[FR_REG1/sizeof(unsigned long)];
+ unsigned long pad0[5];
/*
* saved main processor registers
*/
unsigned long interrupt;
long orig_reg2;
+ long pad1;
};
+#ifdef __KERNEL__
+
/*
* Does the process account for user or for system time?
*/
#if defined (__R4000__)
-#define user_mode(regs) (!((regs)->cp0_status & 0x18))
+#define user_mode(regs) ((regs)->cp0_status & 0x10)
#else /* !defined (__R4000__) */
-#error "#define user_mode(regs) for R3000!"
+#define user_mode(regs) (!((regs)->cp0_status & 0x8))
#endif /* !defined (__R4000__) */
+#define instruction_pointer(regs) ((regs)->cp0_epc)
+extern void show_regs(struct pt_regs *);
+#endif
+
#endif /* __ASM_MIPS_PTRACE_H */
--- /dev/null
+/*
+ * Makefile for MIPS Linux main source directory
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_REG_H
+#define __ASM_MIPS_REG_H
+
+/*
+ * This defines/structures correspond to the register layout on stack -
+ * if the order here is changed, it needs to be updated in
+ * include/asm-mips/stackframe.h
+ */
+#define EF_REG1 5
+#define EF_REG2 6
+#define EF_REG3 7
+#define EF_REG4 8
+#define EF_REG5 9
+#define EF_REG6 10
+#define EF_REG7 11
+#define EF_REG8 12
+#define EF_REG9 13
+#define EF_REG10 14
+#define EF_REG11 15
+#define EF_REG12 16
+#define EF_REG13 17
+#define EF_REG14 18
+#define EF_REG15 19
+#define EF_REG16 20
+#define EF_REG17 21
+#define EF_REG18 22
+#define EF_REG19 23
+#define EF_REG20 24
+#define EF_REG21 25
+#define EF_REG22 26
+#define EF_REG23 27
+#define EF_REG24 28
+#define EF_REG25 29
+/*
+ * k0/k1 unsaved
+ */
+#define EF_REG28 30
+#define EF_REG29 31
+#define EF_REG30 32
+#define EF_REG31 33
+
+/*
+ * Saved special registers
+ */
+#define EF_LO 34
+#define EF_HI 35
+
+/*
+ * saved cp0 registers
+ */
+#define EF_CP0_STATUS 36
+#define EF_CP0_EPC 37
+#define EF_CP0_CAUSE 38
+
+/*
+ * Some goodies
+ */
+#define EF_INTERRUPT 39
+#define EF_ORIG_REG2 40
+
+#define EF_SIZE (41*4)
+
+/*
+ * Map register number into core file offset.
+ */
+#define CORE_REG(reg, ubase) \
+ (((unsigned long *)((unsigned long)(ubase)))[reg])
+
+#endif /* __ASM_MIPS_REG_H */
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1994 by Ralf Baechle
+ * Copyright (C) 1994, 1995 by Ralf Baechle
*/
-#ifndef __ASM_MIPS_REGSDEFS_H
-#define __ASM_MIPS_REGSDEFS_H
+#ifndef __ASM_MIPS_REGDEF_H
+#define __ASM_MIPS_REGDEF_H
/*
- * Symbolic register names
+ * Symbolic register names for 32 bit ABI
*/
#define zero $0 /* wired zero */
-#define AT $1 /* assembler temp (uprcase, because ".set at") */
+#define AT $1 /* assembler temp - uppercase because of ".set at" */
#define v0 $2 /* return value */
#define v1 $3
#define a0 $4 /* argument registers */
#define s7 $23
#define t8 $24 /* caller saved */
#define t9 $25
+#define jp $25 /* PIC jump register */
#define k0 $26 /* kernel scratch */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define fp $30 /* frame pointer */
+#define s8 $30 /* same like fp! */
#define ra $31 /* return address */
-#endif /* __ASM_MIPS_REGSDEFS_H */
+#endif /* __ASM_MIPS_REGDEF_H */
--- /dev/null
+/*
+ * Process resource limits
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_RESOURCE_H
+#define __ASM_MIPS_RESOURCE_H
+
+/*
+ * Resource limits
+ */
+#define RLIMIT_CPU 0 /* CPU time in ms */
+#define RLIMIT_FSIZE 1 /* Maximum filesize */
+#define RLIMIT_DATA 2 /* max data size */
+#define RLIMIT_STACK 3 /* max stack size */
+#define RLIMIT_CORE 4 /* max core file size */
+#define RLIMIT_NOFILE 5 /* max number of open files */
+#define RLIMIT_VMEM 6 /* mapped memory */
+#define RLIMIT_AS RLIMIT_VMEM
+#define RLIMIT_RSS 7 /* max resident set size */
+#define RLIMIT_NPROC 8 /* max number of processes */
+#define RLIMIT_MEMLOCK 9 /* max locked-in-memory address space*/
+
+#define RLIM_NLIMITS 10
+
+#ifdef __KERNEL__
+
+#define INIT_RLIMITS \
+{ \
+ {LONG_MAX, LONG_MAX}, \
+ {LONG_MAX, LONG_MAX}, \
+ {LONG_MAX, LONG_MAX}, \
+ {_STK_LIM, _STK_LIM}, \
+ { 0, LONG_MAX}, \
+ {NR_OPEN, NR_OPEN}, \
+ {LONG_MAX, LONG_MAX}, \
+ {LONG_MAX, LONG_MAX}, \
+ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, \
+ { LONG_MAX, LONG_MAX }, \
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_MIPS_RESOURCE_H */
*
* Copyright (C) 1994, 1995 by Ralf Baechle
*
+ * Note that the quad functions are only being used for the 64 bit kernel and
+ * therefore it isn't really important that they will be misscompiled for
+ * 32-bit kernels.
*/
#ifndef __ASM_MIPS_SEGMENT_H
#define __ASM_MIPS_SEGMENT_H
+#ifndef __LANGUAGE_ASSEMBLY__
/*
- * Memory segments (32bit kernel mode addresses)
+ * For memcpy()
*/
-#define KUSEG 0x00000000
-#define KSEG0 0x80000000
-#define KSEG1 0xa0000000
-#define KSEG2 0xc0000000
-#define KSEG3 0xe0000000
+#include <linux/string.h>
/*
- * returns the kernel segment base of a given address
+ * This is a gcc optimization barrier, which essentially
+ * inserts a sequence point in the gcc RTL tree that gcc
+ * can't move code around. This is needed when we enter
+ * or exit a critical region (in this case around user-level
+ * accesses that may sleep, and we can't let gcc optimize
+ * global state around them).
*/
-#define KSEGX(a) (a & 0xe0000000)
-
-#ifndef __ASSEMBLY__
+#define __gcc_barrier() __asm__ __volatile__("": : :"memory")
/*
- * Beware: the xxx_fs_word functions work on 16bit words!
+ * Uh, these should become the main single-value transfer routines..
+ * They automatically use the right size if we just have the right
+ * pointer type..
*/
-#define get_fs_byte(addr) get_user_byte((char *)(addr))
-static inline unsigned char get_user_byte(const char *addr)
-{
- return *addr;
-}
+#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
+#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
-#define get_fs_word(addr) get_user_word((short *)(addr))
-static inline unsigned short get_user_word(const short *addr)
-{
- return *addr;
-}
+/*
+ * This is a silly but good way to make sure that
+ * the __put_user function is indeed always optimized,
+ * and that we use the correct sizes..
+ */
+extern int bad_user_access_length(void);
-#define get_fs_long(addr) get_user_long((int *)(addr))
-static inline unsigned long get_user_long(const int *addr)
+/* I should make this use unaligned transfers etc.. */
+static inline void __put_user(unsigned long x, void * y, int size)
{
- return *addr;
+ __gcc_barrier();
+ switch (size) {
+ case 1:
+ *(char *) y = x;
+ break;
+ case 2:
+ *(short *) y = x;
+ break;
+ case 4:
+ *(int *) y = x;
+ break;
+ case 8:
+ *(long *) y = x;
+ break;
+ default:
+ bad_user_access_length();
+ }
+ __gcc_barrier();
}
-#define get_fs_dlong(addr) get_user_dlong((long long *)(addr))
-static inline unsigned long get_user_dlong(const long long *addr)
+/* I should make this use unaligned transfers etc.. */
+static inline unsigned long __get_user(const void * y, int size)
{
- return *addr;
+ unsigned long result;
+
+ __gcc_barrier();
+ switch (size) {
+ case 1:
+ result = *(unsigned char *) y;
+ break;
+ case 2:
+ result = *(unsigned short *) y;
+ break;
+ case 4:
+ result = *(unsigned int *) y;
+ break;
+ case 8:
+ result = *(unsigned long *) y;
+ break;
+ default:
+ result = bad_user_access_length();
+ break;
+ }
+ __gcc_barrier();
+
+ return result;
}
-#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr))
-static inline void put_user_byte(char val,char *addr)
-{
- *addr = val;
-}
+#define get_fs_byte(addr) get_user((unsigned char *)(addr))
+#define get_fs_word(addr) get_user((unsigned short *)(addr))
+#define get_fs_long(addr) get_user((unsigned int *)(addr))
+#define get_fs_quad(addr) get_user((unsigned long *)(addr))
-#define put_fs_word(x,addr) put_user_word((x),(short *)(addr))
-static inline void put_user_word(short val,short * addr)
-{
- *addr = val;
-}
+#define put_fs_byte(x,addr) put_user((x),(char *)(addr))
+#define put_fs_word(x,addr) put_user((x),(short *)(addr))
+#define put_fs_long(x,addr) put_user((x),(int *)(addr))
+#define put_fs_quad(x,addr) put_user((x),(long *)(addr))
-#define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
-static inline void put_user_long(unsigned long val,int * addr)
+static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
- *addr = val;
+ __gcc_barrier();
+ memcpy(to, from, n);
+ __gcc_barrier();
}
-#define put_fs_dlong(x,addr) put_user_dlong((x),(int *)(addr))
-static inline void put_user_dlong(unsigned long val,long long * addr)
+static inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
- *addr = val;
+ __gcc_barrier();
+ memcpy(to, from, n);
+ __gcc_barrier();
}
-#define memcpy_fromfs(to, from, n) memcpy((to),(from),(n))
-
-#define memcpy_tofs(to, from, n) memcpy((to),(from),(n))
-
/*
* For segmented architectures, these are used to specify which segment
* to use for the above functions.
static inline unsigned long get_fs(void)
{
- return 0;
+ return USER_DS;
}
static inline unsigned long get_ds(void)
{
- return 0;
+ return KERNEL_DS;
}
static inline void set_fs(unsigned long val)
{
}
-#endif /* !__ASSEMBLY__ */
+#endif /* !__LANGUAGE_ASSEMBLY__ */
+
+/*
+ * Memory segments (32bit kernel mode addresses)
+ */
+#define KUSEG 0x00000000
+#define KSEG0 0x80000000
+#define KSEG1 0xa0000000
+#define KSEG2 0xc0000000
+#define KSEG3 0xe0000000
+
+/*
+ * Returns the kernel segment base of a given address
+ */
+#define KSEGX(a) (((unsigned long)(a)) & 0xe0000000)
+
+/*
+ * Returns the physical address of a KSEG0/KSEG1 address
+ */
+#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
+
+/*
+ * Map an address to a certain kernel segment
+ */
+#define KSEG0ADDR(a) ((((unsigned long)(a)) & 0x1fffffff) | KSEG0)
+#define KSEG1ADDR(a) ((((unsigned long)(a)) & 0x1fffffff) | KSEG1)
+#define KSEG2ADDR(a) ((((unsigned long)(a)) & 0x1fffffff) | KSEG2)
+#define KSEG3ADDR(a) ((((unsigned long)(a)) & 0x1fffffff) | KSEG3)
+
+/*
+ * Memory segments (64bit kernel mode addresses)
+ */
+#define XKUSEG 0x0000 0000 0000 0000
+#define XKSSEG 0x4000 0000 0000 0000
+#define XKPHYS 0x8000 0000 0000 0000
+#define XKSEG 0xc000 0000 0000 0000
+#define CKSEG0 0xffff ffff 8000 0000
+#define CKSEG1 0xffff ffff a000 0000
+#define CKSSEG 0xffff ffff c000 0000
+#define CKSEG3 0xffff ffff e000 0000
#endif /* __ASM_MIPS_SEGMENT_H */
--- /dev/null
+#ifndef __ASM_MIPS_SHMPARAM_H
+#define __ASM_MIPS_SHMPARAM_H
+
+/* address range for shared memory attaches if no address passed to shmat() */
+#define SHM_RANGE_START 0x50000000
+#define SHM_RANGE_END 0x60000000
+
+/*
+ * Format of a swap-entry for shared memory pages currently out in
+ * swap space (see also mm/swap.c).
+ *
+ * SWP_TYPE = SHM_SWP_TYPE
+ * SWP_OFFSET is used as follows:
+ *
+ * bits 0..6 : id of shared memory segment page belongs to (SHM_ID)
+ * bits 7..21: index of page within shared memory segment (SHM_IDX)
+ * (actually fewer bits get used since SHMMAX is so low)
+ */
+
+/*
+ * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
+ * there is a static array of size SHMMNI.
+ */
+#define _SHM_ID_BITS 7
+#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1)
+
+#define SHM_IDX_SHIFT (_SHM_ID_BITS)
+#define _SHM_IDX_BITS 15
+#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1)
+
+/*
+ * _SHM_ID_BITS + _SHM_IDX_BITS must be <= 24 on the i386 and
+ * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
+ */
+
+#define SHMMAX 0x1000000 /* max shared seg size (bytes) */
+#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */
+#define SHMMNI (1<<_SHM_ID_BITS) /* max num of segs system wide */
+#define SHMALL /* max shm system wide (pages) */ \
+ (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
+/*
+ * This constant is very large but the ABI in it's wisdom says ...
+ */
+#define SHMLBA 0x40000 /* attach addr a multiple of this */
+#define SHMSEG SHMMNI /* max shared segs per process */
+
+#endif /* __ASM_MIPS_SHMPARAM_H */
--- /dev/null
+#ifndef __ASM_MIPS_SIGCONTEXT_H
+#define __ASM_MIPS_SIGCONTEXT_H
+
+/*
+ * This struct isn't in the ABI, so we continue to use the old
+ * pre 1.3 definition. Needs to be changed for 64 bit kernels,
+ * but it's 4am ...
+ */
+struct sigcontext_struct {
+ unsigned long sc_at, sc_v0, sc_v1, sc_a0, sc_a1, sc_a2, sc_a3;
+ unsigned long sc_t0, sc_t1, sc_t2, sc_t3, sc_t4, sc_t5, sc_t6, sc_t7;
+ unsigned long sc_s0, sc_s1, sc_s2, sc_s3, sc_s4, sc_s5, sc_s6, sc_s7;
+ unsigned long sc_t8, sc_t9, sc_gp, sc_sp, sc_fp, sc_ra;
+
+ unsigned long sc_epc;
+ unsigned long sc_cause;
+
+ unsigned long sc_oldmask;
+};
+
+#endif /* __ASM_MIPS_SIGCONTEXT_H */
#ifndef __ASM_MIPS_SIGNAL_H
#define __ASM_MIPS_SIGNAL_H
-struct sigcontext_struct {
- unsigned long sc_at, sc_v0, sc_v1, sc_a0, sc_a1, sc_a2, sc_a3;
- unsigned long sc_t0, sc_t1, sc_t2, sc_t3, sc_t4, sc_t5, sc_t6, sc_t7;
- unsigned long sc_s0, sc_s1, sc_s2, sc_s3, sc_s4, sc_s5, sc_s6, sc_s7;
- unsigned long sc_t8, sc_t9, sc_gp, sc_sp, sc_fp, sc_ra;
+/*
+ * For now ...
+ */
+#include <linux/types.h>
+typedef __u64 sigset_t;
- unsigned long sc_epc;
- unsigned long sc_cause;
+#if 0
+/*
+ * This is what we should really use but the kernel can't handle
+ * a non-scalar type yet. Since we use 64 signals only anyway we
+ * just use __u64 and pad another 64 bits in the kernel for now ...
+ */
+typedef struct {
+ unsigned int sigbits[4];
+} sigset_t;
+#endif
- unsigned long oldmask;
+#define _NSIG 65
+#define NSIG _NSIG
+
+/*
+ * For 1.3.0 Linux/MIPS changed the signal numbers to be compatible the ABI.
+ */
+#define SIGHUP 1 /* Hangup (POSIX). */
+#define SIGINT 2 /* Interrupt (ANSI). */
+#define SIGQUIT 3 /* Quit (POSIX). */
+#define SIGILL 4 /* Illegal instruction (ANSI). */
+#define SIGTRAP 5 /* Trace trap (POSIX). */
+#define SIGIOT 6 /* IOT trap (4.2 BSD). */
+#define SIGABRT SIGIOT /* Abort (ANSI). */
+#define SIGEMT 7
+#define SIGFPE 8 /* Floating-point exception (ANSI). */
+#define SIGKILL 9 /* Kill, unblockable (POSIX). */
+#define SIGBUS 10 /* BUS error (4.2 BSD). */
+#define SIGSEGV 11 /* Segmentation violation (ANSI). */
+#define SIGSYS 12
+#define SIGPIPE 13 /* Broken pipe (POSIX). */
+#define SIGALRM 14 /* Alarm clock (POSIX). */
+#define SIGTERM 15 /* Termination (ANSI). */
+#define SIGUSR1 16 /* User-defined signal 1 (POSIX). */
+#define SIGUSR2 17 /* User-defined signal 2 (POSIX). */
+#define SIGCHLD 18 /* Child status has changed (POSIX). */
+#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
+#define SIGPWR 19 /* Power failure restart (System V). */
+#define SIGWINCH 20 /* Window size change (4.3 BSD, Sun). */
+#define SIGURG 21 /* Urgent condition on socket (4.2 BSD). */
+#define SIGIO 22 /* I/O now possible (4.2 BSD). */
+#define SIGPOLL SIGIO /* Pollable event occured (System V). */
+#define SIGSTOP 23 /* Stop, unblockable (POSIX). */
+#define SIGTSTP 24 /* Keyboard stop (POSIX). */
+#define SIGCONT 25 /* Continue (POSIX). */
+#define SIGTTIN 26 /* Background read from tty (POSIX). */
+#define SIGTTOU 27 /* Background write to tty (POSIX). */
+#define SIGVTALRM 28 /* Virtual alarm clock (4.2 BSD). */
+#define SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */
+#define SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */
+#define SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */
+
+/*
+ * sa_flags values: SA_STACK is not currently supported, but will allow the
+ * usage of signal stacks by using the (now obsolete) sa_restorer field in
+ * the sigaction structure as a stack pointer. This is now possible due to
+ * the changes in signal handling. LBT 010493.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ */
+#define SA_STACK 0x1
+#define SA_ONSTACK SA_STACK
+#define SA_RESTART 0x4
+#define SA_NOCLDSTOP 0x20000
+/* Non ABI signals */
+#define SA_INTERRUPT 0x01000000
+#define SA_NOMASK 0x02000000
+#define SA_ONESHOT 0x04000000
+
+#ifdef __KERNEL__
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ */
+#define SA_PROBE SA_ONESHOT
+#define SA_SAMPLE_RANDOM SA_RESTART
+#endif
+
+#define SIG_BLOCK 1 /* for blocking signals */
+#define SIG_UNBLOCK 2 /* for unblocking signals */
+#define SIG_SETMASK 3 /* for setting the signal mask */
+
+/* Type of a signal handler. */
+typedef void (*__sighandler_t)(int);
+
+/* Fake signal functions */
+#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
+#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
+#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
+
+struct sigaction {
+ unsigned int sa_flags;
+ __sighandler_t sa_handler;
+ sigset_t sa_mask;
+ /*
+ * To keep the ABI structure size we have to fill a little gap ...
+ */
+ unsigned int sa_mask_pad[2];
+
+ /* Abi says here follows reserved int[2] */
+ void (*sa_restorer)(void);
+#if __mips < 3
+ /*
+ * For 32 bit code we have to pad struct sigaction to get
+ * constant size for the ABI
+ */
+ int pad0[1]; /* reserved */
+#endif
};
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+#endif
+
#endif /* __ASM_MIPS_SIGNAL_H */
--- /dev/null
+#ifndef __ASM_MIPS_SOCKET_H
+#define __ASM_MIPS_SOCKET_H
+
+#include <linux/types.h>
+#include <asm/ioctl.h>
+
+/* Socket-level I/O control calls. */
+#define FIOGETOWN _IOR('f', 123, int)
+#define FIOSETOWN _IOW('f', 124, int)
+
+#define SIOCATMARK _IOR('s', 7, int)
+#define SIOCSPGRP _IOW('s', 8, pid_t)
+#define SIOCGPGRP _IOR('s', 9, pid_t)
+
+#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */
+
+/*
+ * For setsockoptions(2)
+ *
+ * This defines are ABI conformant as far as Linux supports these ...
+ */
+#define SOL_SOCKET 0xffff
+
+#define SO_DEBUG 0x0001
+#define SO_REUSEADDR 0x0004
+#define SO_KEEPALIVE 0x0008
+#define SO_DONTROUTE 0x0010
+#define SO_BROADCAST 0x0020
+#define SO_LINGER 0x0080
+#define SO_OOBINLINE 0x0100
+/* To add: #define SO_REUSEPORT 0x0200 */
+
+#define SO_TYPE 0x1008
+#define SO_ERROR 0x1007
+#define SO_SNDBUF 0x1001
+#define SO_RCVBUF 0x1002
+
+/* linux-specific, might as well be the same as on i386 */
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_BSDCOMPAT 14
+
+/*
+ * Wierd. There are two ABIs; in the old one SOCK_STREAM and SOCK_DGRAM
+ * have swapped values. I choose to be compatible with the new one.
+ */
+#define SOCK_DGRAM 1 /* datagram (conn.less) socket */
+#define SOCK_STREAM 2 /* stream (connection) socket */
+#define SOCK_RAW 3 /* raw socket */
+#define SOCK_RDM 4 /* reliably-delivered message */
+#define SOCK_SEQPACKET 5 /* sequential packet socket */
+#define SOCK_PACKET 10 /* linux specific way of */
+ /* getting packets at the dev */
+ /* level. For writing rarp and */
+ /* other similar things on the */
+ /* user level. */
+
+#endif /* __ASM_MIPS_SOCKET_H */
/*
* Stack layout for all exceptions:
*
- * ptrace needs to have all regs on the stack.
- * if the order here is changed, it needs to be
- * updated in asm/mips/fork.c:copy_process, asm/mips/signal.c:do_signal,
- * asm-mips/ptrace.c, include/asm-mips/ptrace.h
- * and asm-mips/ptrace
- */
-
-/*
- * Offsets into the Interrupt stackframe.
- * The first 20 bytes are reserved for the usual MIPS calling sequence
+ * ptrace needs to have all regs on the stack. If the order here is changed,
+ * it needs to be updated in include/asm-mips/ptrace.h
+ *
+ * The first PTRSIZE*5 bytes are argument save space for C subroutines.
*/
-#define FR_REG1 20
+#define FR_REG1 (PTRSIZE*5)
#define FR_REG2 ((FR_REG1) + 4)
#define FR_REG3 ((FR_REG2) + 4)
#define FR_REG4 ((FR_REG3) + 4)
*/
#define FR_INTERRUPT ((FR_CAUSE) + 4)
#define FR_ORIG_REG2 ((FR_INTERRUPT) + 4)
+#define FR_PAD1 ((FR_ORIG_REG2) + 4)
/*
- * Size of stack frame
+ * Size of stack frame, word/double word alignment
*/
-#define FR_SIZE ((FR_ORIG_REG2) + 4)
+#define FR_SIZE ((((FR_PAD1) + 4) + (PTRSIZE-1)) & ~(PTRSIZE-1))
-#define SAVE_ALL \
- mfc0 k0,CP0_STATUS; \
- andi k0,0x18; /* extract KSU bits */ \
- beqz k0,1f; \
- move k1,sp; \
- /* \
- * Called from user mode, new stack \
- */ \
- lui k1,%hi(_kernelsp); \
- lw k1,%lo(_kernelsp)(k1); \
-1: move k0,sp; \
- subu sp,k1,FR_SIZE; \
- sw k0,FR_REG29(sp); \
- sw $2,FR_REG2(sp); \
- sw $2,FR_ORIG_REG2(sp); \
- mfc0 v0,CP0_STATUS; \
- sw v0,FR_STATUS(sp); \
- mfc0 v0,CP0_CAUSE; \
- sw v0,FR_CAUSE(sp); \
- mfc0 v0,CP0_EPC; \
- sw v0,FR_EPC(sp); \
- mfhi v0; \
- sw v0,FR_HI(sp); \
- mflo v0; \
- sw v0,FR_LO(sp); \
- sw $1,FR_REG1(sp); \
- sw $3,FR_REG3(sp); \
- sw $4,FR_REG4(sp); \
- sw $5,FR_REG5(sp); \
- sw $6,FR_REG6(sp); \
- sw $7,FR_REG7(sp); \
- sw $8,FR_REG8(sp); \
- sw $9,FR_REG9(sp); \
- sw $10,FR_REG10(sp); \
- sw $11,FR_REG11(sp); \
- sw $12,FR_REG12(sp); \
- sw $13,FR_REG13(sp); \
- sw $14,FR_REG14(sp); \
- sw $15,FR_REG15(sp); \
- sw $16,FR_REG16(sp); \
- sw $17,FR_REG17(sp); \
- sw $18,FR_REG18(sp); \
- sw $19,FR_REG19(sp); \
- sw $20,FR_REG20(sp); \
- sw $21,FR_REG21(sp); \
- sw $22,FR_REG22(sp); \
- sw $23,FR_REG23(sp); \
- sw $24,FR_REG24(sp); \
- sw $25,FR_REG25(sp); \
- sw $28,FR_REG28(sp); \
- sw $30,FR_REG30(sp); \
- sw $31,FR_REG31(sp)
+#ifdef __R4000__
-#define RESTORE_ALL \
- lw v1,FR_EPC(sp); \
- lw v0,FR_HI(sp); \
- mtc0 v1,CP0_EPC; \
- lw v1,FR_LO(sp); \
- mthi v0; \
- lw v0,FR_STATUS(sp); \
- mtlo v1; \
- mtc0 v0,CP0_STATUS; \
- lw $31,FR_REG31(sp); \
- lw $30,FR_REG30(sp); \
- lw $28,FR_REG28(sp); \
- lw $25,FR_REG25(sp); \
- lw $24,FR_REG24(sp); \
- lw $23,FR_REG23(sp); \
- lw $22,FR_REG22(sp); \
- lw $21,FR_REG21(sp); \
- lw $20,FR_REG20(sp); \
- lw $19,FR_REG19(sp); \
- lw $18,FR_REG18(sp); \
- lw $17,FR_REG17(sp); \
- lw $16,FR_REG16(sp); \
- lw $15,FR_REG15(sp); \
- lw $14,FR_REG14(sp); \
- lw $13,FR_REG13(sp); \
- lw $12,FR_REG12(sp); \
- lw $11,FR_REG11(sp); \
- lw $10,FR_REG10(sp); \
- lw $9,FR_REG9(sp); \
- lw $8,FR_REG8(sp); \
- lw $7,FR_REG7(sp); \
- lw $6,FR_REG6(sp); \
- lw $5,FR_REG5(sp); \
- lw $4,FR_REG4(sp); \
- lw $3,FR_REG3(sp); \
- lw $2,FR_REG2(sp); \
- lw $1,FR_REG1(sp); \
- lw sp,FR_REG29(sp); /* Deallocate stack */ \
- eret
+#define SAVE_ALL \
+ mfc0 k0,CP0_STATUS; \
+ sll k0,3; /* extract cu0 bit */ \
+ bltz k0,8f; \
+ move k1,sp; \
+ /* \
+ * Called from user mode, new stack \
+ */ \
+ lui k1,%hi(kernelsp); \
+ lw k1,%lo(kernelsp)(k1); \
+8: move k0,sp; \
+ subu sp,k1,FR_SIZE; \
+ sw k0,FR_REG29(sp); \
+ sw $2,FR_REG2(sp); \
+ sw $2,FR_ORIG_REG2(sp); \
+ mfc0 v0,CP0_STATUS; \
+ sw v0,FR_STATUS(sp); \
+ mfc0 v0,CP0_CAUSE; \
+ sw v0,FR_CAUSE(sp); \
+ mfc0 v0,CP0_EPC; \
+ sw v0,FR_EPC(sp); \
+ mfhi v0; \
+ sw v0,FR_HI(sp); \
+ mflo v0; \
+ sw v0,FR_LO(sp); \
+ sw $1,FR_REG1(sp); \
+ sw $3,FR_REG3(sp); \
+ sw $4,FR_REG4(sp); \
+ sw $5,FR_REG5(sp); \
+ sw $6,FR_REG6(sp); \
+ sw $7,FR_REG7(sp); \
+ sw $8,FR_REG8(sp); \
+ sw $9,FR_REG9(sp); \
+ sw $10,FR_REG10(sp); \
+ sw $11,FR_REG11(sp); \
+ sw $12,FR_REG12(sp); \
+ sw $13,FR_REG13(sp); \
+ sw $14,FR_REG14(sp); \
+ sw $15,FR_REG15(sp); \
+ sw $16,FR_REG16(sp); \
+ sw $17,FR_REG17(sp); \
+ sw $18,FR_REG18(sp); \
+ sw $19,FR_REG19(sp); \
+ sw $20,FR_REG20(sp); \
+ sw $21,FR_REG21(sp); \
+ sw $22,FR_REG22(sp); \
+ sw $23,FR_REG23(sp); \
+ sw $24,FR_REG24(sp); \
+ sw $25,FR_REG25(sp); \
+ sw $28,FR_REG28(sp); \
+ sw $30,FR_REG30(sp); \
+ sw $31,FR_REG31(sp)
/*
- * Move to kernel mode and disable interrupts
+ * Note that we restore the IE flags from stack. This means
+ * that a modified IE mask will be nullified.
*/
-#define CLI \
- mfc0 k0,CP0_STATUS; \
- ori k0,k0,0x1f; \
- xori k0,k0,0x1f; \
- mtc0 k0,CP0_STATUS
+#define RESTORE_ALL \
+ .set mips3; \
+ mfc0 t0,CP0_STATUS; \
+ ori t0,0x1f; \
+ xori t0,0x1f; \
+ mtc0 t0,CP0_STATUS; \
+ \
+ lw v0,FR_STATUS(sp); \
+ lw v1,FR_LO(sp); \
+ mtc0 v0,CP0_STATUS; \
+ mtlo v1; \
+ lw v0,FR_HI(sp); \
+ lw v1,FR_EPC(sp); \
+ mthi v0; \
+ mtc0 v1,CP0_EPC; \
+ lw $31,FR_REG31(sp); \
+ lw $30,FR_REG30(sp); \
+ lw $28,FR_REG28(sp); \
+ lw $25,FR_REG25(sp); \
+ lw $24,FR_REG24(sp); \
+ lw $23,FR_REG23(sp); \
+ lw $22,FR_REG22(sp); \
+ lw $21,FR_REG21(sp); \
+ lw $20,FR_REG20(sp); \
+ lw $19,FR_REG19(sp); \
+ lw $18,FR_REG18(sp); \
+ lw $17,FR_REG17(sp); \
+ lw $16,FR_REG16(sp); \
+ lw $15,FR_REG15(sp); \
+ lw $14,FR_REG14(sp); \
+ lw $13,FR_REG13(sp); \
+ lw $12,FR_REG12(sp); \
+ lw $11,FR_REG11(sp); \
+ lw $10,FR_REG10(sp); \
+ lw $9,FR_REG9(sp); \
+ lw $8,FR_REG8(sp); \
+ lw $7,FR_REG7(sp); \
+ lw $6,FR_REG6(sp); \
+ lw $5,FR_REG5(sp); \
+ lw $4,FR_REG4(sp); \
+ lw $3,FR_REG3(sp); \
+ lw $2,FR_REG2(sp); \
+ lw $1,FR_REG1(sp); \
+ lw sp,FR_REG29(sp); /* Deallocate stack */ \
+ .set mips0
-/*
- * Move to kernel mode and enable interrupts
- */
-#define STI \
- mfc0 k0,CP0_STATUS; \
- ori k0,k0,0x1f; \
- xori k0,k0,0x1e; \
- mtc0 k0,CP0_STATUS
+#else /* !defined (__R4000__) */
+
+#error "Implement SAVE_ALL and RESTORE_ALL!"
+
+#endif /* !defined (__R4000__) */
#endif /* __ASM_MIPS_STACKFRAME_H */
--- /dev/null
+#ifndef __ASM_MIPS_STAT_H
+#define __ASM_MIPS_STAT_H
+
+#include <linux/types.h>
+
+struct old_stat {
+ unsigned int st_dev;
+ unsigned int st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_rdev;
+ long st_size;
+ unsigned int st_atime, st_res1;
+ unsigned int st_mtime, st_res2;
+ unsigned int st_ctime, st_res3;
+ unsigned int st_blkize;
+ int st_blocks;
+ unsigned int st_flags;
+ unsigned int st_gen;
+};
+
+struct new_stat {
+ dev_t st_dev;
+ long st_pad1[3]; /* Reserved for network id */
+ ino_t st_ino;
+ mode_t st_mode;
+ nlink_t st_nlink;
+ uid_t st_uid;
+ gid_t st_gid;
+ dev_t st_rdev;
+ long st_pad2[2];
+ off_t st_size;
+ long st_pad3;
+ /*
+ * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+ * but we don't have it under Linux.
+ */
+ time_t st_atime;
+ long reserved0;
+ time_t st_mtime;
+ long reserved1;
+ time_t st_ctime;
+ long reserved2;
+ long st_blksize;
+ long st_blocks;
+ char st_fstype[16]; /* Filesystem type name */
+ long st_pad4[8];
+ /* Linux specific fields */
+ unsigned int st_flags;
+ unsigned int st_gen;
+};
+
+#endif /* __ASM_MIPS_STAT_H */
--- /dev/null
+#ifndef __ASM_MIPS_STATFS_H
+#define __ASM_MIPS_STATFS_H
+
+typedef struct {
+ long val[2];
+} fsid_t;
+
+struct statfs {
+ long f_type;
+#define f_fstyp f_type
+ long f_bsize;
+ long f_frsize; /* Fragment size - unsupported */
+ long f_blocks;
+ long f_bfree;
+ long f_files;
+ long f_ffree;
+
+ /* Linux specials */
+ long f_bavail;
+ fsid_t f_fsid;
+ long f_namelen;
+ long f_spare[6];
+};
+
+#endif /* __ASM_MIPS_STATFS_H */
* Copyright (c) 1994, 1995 Waldorf Electronics
* written by Ralf Baechle
*/
-
#ifndef __ASM_MIPS_STRING_H
#define __ASM_MIPS_STRING_H
-#include <asm/mipsregs.h>
-
+#define __HAVE_ARCH_STRCPY
extern __inline__ char * strcpy(char * dest, const char *src)
{
char *xdest = dest;
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlbu\t$1,(%1)\n\t"
- "addiu\t%1,%1,1\n\t"
+ "addiu\t%1,1\n\t"
"sb\t$1,(%0)\n\t"
"bnez\t$1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (dest), "=r" (src)
return xdest;
}
+#define __HAVE_ARCH_STRNCPY
extern __inline__ char * strncpy(char *dest, const char *src, size_t n)
{
char *xdest = dest;
return dest;
}
+#define __HAVE_ARCH_STRCMP
extern __inline__ int strcmp(const char * cs, const char * ct)
{
int __res;
".set\tnoat\n\t"
"lbu\t%2,(%0)\n"
"1:\tlbu\t$1,(%1)\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
"bne\t$1,%2,2f\n\t"
- "addiu\t%1,%1,1\n\t"
+ "addiu\t%1,1\n\t"
"bnez\t%2,1b\n\t"
"lbu\t%2,(%0)\n\t"
- STR(FILL_LDS) "\n\t"
+#ifndef __R4000__
+ "nop\n\t"
+#endif
"move\t%2,$1\n"
- "2:\tsub\t%2,%2,$1\n"
+ "2:\tsubu\t%2,$1\n"
"3:\t.set\tat\n\t"
- ".set\treorder\n\t"
+ ".set\treorder"
: "=d" (cs), "=d" (ct), "=d" (__res)
: "0" (cs), "1" (ct)
: "$1");
return __res;
}
+#define __HAVE_ARCH_STRNCMP
extern __inline__ int strncmp(const char * cs, const char * ct, size_t count)
{
char __res;
"1:\tlbu\t%3,(%0)\n\t"
"beqz\t%2,2f\n\t"
"lbu\t$1,(%1)\n\t"
- "addiu\t%2,%2,-1\n\t"
+ "subu\t%2,1\n\t"
"bne\t$1,%3,3f\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
"bnez\t%3,1b\n\t"
- "addiu\t%1,%1,1\n"
+ "addiu\t%1,1\n"
"2:\tmove\t%3,$1\n"
- "3:\tsub\t%3,%3,$1\n\t"
+ "3:\tsubu\t%3,$1\n\t"
".set\tat\n\t"
".set\treorder"
: "=d" (cs), "=d" (ct), "=d" (count), "=d" (__res)
return __res;
}
+#define __HAVE_ARCH_MEMSET
extern __inline__ void * memset(void * s, int c, size_t count)
{
void *xs = s;
return xs;
}
+#define __HAVE_ARCH_MEMCPY
extern __inline__ void * memcpy(void * to, const void * from, size_t n)
{
void *xto = to;
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlbu\t$1,(%1)\n\t"
- "addiu\t%1,%1,1\n\t"
+ "addiu\t%1,1\n\t"
"sb\t$1,(%0)\n\t"
- "subu\t%2,%2,1\n\t"
+ "subu\t%2,1\n\t"
"bnez\t%2,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (to), "=r" (from), "=r" (n)
return xto;
}
+#define __HAVE_ARCH_MEMMOVE
extern __inline__ void * memmove(void * dest,const void * src, size_t n)
{
void *xdest = dest;
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlbu\t$1,(%1)\n\t"
- "addiu\t%1,%1,1\n\t"
+ "addiu\t%1,1\n\t"
"sb\t$1,(%0)\n\t"
- "subu\t%2,%2,1\n\t"
+ "subu\t%2,1\n\t"
"bnez\t%2,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (dest), "=r" (src), "=r" (n)
".set\tnoreorder\n\t"
".set\tnoat\n"
"1:\tlbu\t$1,-1(%1)\n\t"
- "subu\t%1,%1,1\n\t"
+ "subu\t%1,1\n\t"
"sb\t$1,-1(%0)\n\t"
- "subu\t%2,%2,1\n\t"
+ "subu\t%2,1\n\t"
"bnez\t%2,1b\n\t"
- "subu\t%0,%0,1\n\t"
+ "subu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (dest), "=r" (src), "=r" (n)
return xdest;
}
+#define __HAVE_ARCH_MEMSCAN
extern __inline__ void * memscan(void * addr, int c, size_t size)
{
if (!size)
return addr;
__asm__(".set\tnoreorder\n\t"
".set\tnoat\n"
- "1:\tbeq\t$0,%1,2f\n\t"
+ "1:\tbeqz\t%1,2f\n\t"
"lbu\t$1,(%0)\n\t"
- "subu\t%1,%1,1\n\t"
+ "subu\t%1,1\n\t"
"bnez\t%1,1b\n\t"
- "addiu\t%0,%0,1\n\t"
+ "addiu\t%0,1\n\t"
".set\tat\n\t"
".set\treorder\n"
"2:"
--- /dev/null
+/*
+ * Definitions for the MIPS sysmips(2) call
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_SYSMIPS_H
+#define __ASM_MIPS_SYSMIPS_H
+
+/*
+ * Commands for the sysmips(2) call
+ *
+ * sysmips(2) is deprecated - though some existing software uses it.
+ * We only support the following commands.
+ */
+#define SETNAME 1 /* set hostname */
+#define FLUSH_CACHE 3 /* writeback and invalide caches */
+#define MIPS_FIXADE 7 /* control address error fixing */
+#define MIPS_ATOMIC_SET 2001 /* atomically set variable */
+
+#endif /* __ASM_MIPS_SYSMIPS_H */
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1994 by Ralf Baechle
+ * Copyright (C) 1994, 1995 by Ralf Baechle
*/
-
#ifndef __ASM_MIPS_SYSTEM_H
#define __ASM_MIPS_SYSTEM_H
-#include <linux/types.h>
-#include <asm/segment.h>
-#include <asm/mipsregs.h>
-#include <asm/mipsconfig.h>
+#include <linux/kernel.h>
-/*
- * (Currently empty to support debugging)
- */
-#define move_to_user_mode() \
-__asm__ __volatile__ ( \
+#if defined (__R4000__)
+#define sti() \
+__asm__ __volatile__( \
".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
- "la\t$1,1f\n\t" \
- "subu\t$1,$1,%0\n\t" \
- "jr\t$1\n\t" \
"mfc0\t$1,$12\n\t" \
- "1:ori\t$1,0x00\n\t" \
+ "ori\t$1,0x1f\n\t" \
+ "xori\t$1,0x1e\n\t" \
"mtc0\t$1,$12\n\t" \
- "subu\t$29,%0\n\t" \
".set\tat\n\t" \
".set\treorder" \
: /* no outputs */ \
- : "r" (KERNELBASE));
+ : /* no inputs */ \
+ : "$1")
-#if defined (__R4000__)
-#define sti() \
+#define cli() \
__asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
- "mfc0\t$1,"STR(CP0_STATUS)"\n\t" \
- "ori\t$1,$1,0x1f\n\t" \
- "xori\t$1,$1,0x1e\n\t" \
- "mtc0\t$1,"STR(CP0_STATUS)"\n\t" \
- ".set\tat" \
+ "mfc0\t$1,$12\n\t" \
+ "ori\t$1,1\n\t" \
+ "xori\t$1,1\n\t" \
+ "mtc0\t$1,$12\n\t" \
+ "nop\n\t" \
+ "nop\n\t" \
+ "nop\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
: /* no outputs */ \
: /* no inputs */ \
: "$1")
-#define cli() \
+#else /* !defined (__R4000__) */
+/*
+ * Untested goodies for the R3000 based DECstation et al.
+ */
+#define sti() \
__asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
".set\tnoat\n\t" \
- "mfc0\t$1,"STR(CP0_STATUS)"\n\t" \
- "ori\t$1,$1,1\n\t" \
- "xori\t$1,$1,1\n\t" \
- "mtc0\t$1,"STR(CP0_STATUS)"\n\t" \
- ".set\tat" \
+ "mfc0\t$1,$12\n\t" \
+ "ori\t$1,0x01\n\t" \
+ "mtc0\t$1,$12\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
+ : /* no outputs */ \
+ : /* no inputs */ \
+ : "$1")
+
+#define cli() \
+__asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ ".set\tnoat\n\t" \
+ "mfc0\t$1,$12\n\t" \
+ "ori\t$1,1\n\t" \
+ "xori\t$1,1\n\t" \
+ "mtc0\t$1,$12\n\t" \
+ ".set\tat\n\t" \
+ ".set\treorder" \
: /* no outputs */ \
: /* no inputs */ \
: "$1")
-#else /* !defined (__R4000__) */
-/*
- * Cheese - I don't have a R3000 manual
- */
-#error "Yikes - write cli()/sti() macros for R3000!"
#endif /* !defined (__R4000__) */
#define nop() __asm__ __volatile__ ("nop")
#define save_flags(x) \
__asm__ __volatile__( \
- "mfc0\t%0,$12" \
+ ".set\tnoreorder\n\t" \
+ "mfc0\t%0,$12\n\t" \
+ ".set\treorder" \
: "=r" (x)) \
#define restore_flags(x) \
__asm__ __volatile__( \
- "mtc0\t%0,$12" \
+ ".set\tnoreorder\n\t" \
+ "mtc0\t%0,$12\n\t" \
+ "nop\n\t" \
+ "nop\n\t" \
+ "nop\n\t" \
+ ".set\treorder" \
: /* no output */ \
: "r" (x)) \
-extern inline unsigned long xchg_u8(char * m, unsigned long val)
+#define sync_mem() \
+__asm__ __volatile__( \
+ ".set\tnoreorder\n\t" \
+ "sync\n\t" \
+ ".set\treorder") \
+
+/*
+ * The 8 and 16 bit variants have to disable interrupts temporarily.
+ * Both are currently unused.
+ */
+extern inline unsigned long xchg_u8(volatile char * m, unsigned long val)
{
unsigned long flags, retval;
return retval;
}
-extern inline unsigned long xchg_u16(short * m, unsigned long val)
+extern inline unsigned long xchg_u16(volatile short * m, unsigned long val)
{
unsigned long flags, retval;
/*
* For 32 and 64 bit operands we can take advantage of ll and sc.
- * The later isn't currently being used.
+ * FIXME: This doesn't work for R3000 machines.
*/
-extern inline unsigned long xchg_u32(int * m, unsigned long val)
+extern inline unsigned long xchg_u32(volatile int * m, unsigned long val)
{
unsigned long dummy;
"ll\t%0,(%1)\n"
"1:\tmove\t$1,%2\n\t"
"sc\t$1,(%1)\n\t"
- "beqzl\t%3,1b\n\t"
+ "beqzl\t$1,1b\n\t"
"ll\t%0,(%1)\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (val), "=r" (m), "=r" (dummy)
- : "1" (*m), "2" (val));
+ : "1" (m), "2" (val));
return val;
}
-extern inline unsigned long xchg_u64(long * m, unsigned long val)
+/*
+ * Only used for 64 bit kernel.
+ */
+extern inline unsigned long xchg_u64(volatile long * m, unsigned long val)
{
unsigned long dummy;
"lld\t%0,(%1)\n"
"1:\tmove\t$1,%2\n\t"
"scd\t$1,(%1)\n\t"
- "beqzl\t%3,1b\n\t"
+ "beqzl\t$1,1b\n\t"
"ll\t%0,(%1)\n\t"
".set\tat\n\t"
".set\treorder"
: "=r" (val), "=r" (m), "=r" (dummy)
- : "1" (*m), "2" (val));
+ : "1" (m), "2" (val));
return val;
}
-#if 0
-extern inline int tas(char * m)
-{
- return xchg_u8(m,1);
-}
-#endif
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define tas(ptr) (xchg((ptr),1))
+
+/*
+ * This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid xchg().
+ *
+ * This only works if the compiler isn't horribly bad at optimizing.
+ * gcc-2.5.8 reportedly can't handle this, but I define that one to
+ * be dead anyway.
+ */
+extern void __xchg_called_with_bad_pointer(void);
-extern inline void * xchg_ptr(void * m, void * val)
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
- return (void *) xchg_u32(m, (unsigned long) val);
+ switch (size) {
+ case 1:
+ return xchg_u8(ptr, x);
+ case 2:
+ return xchg_u16(ptr, x);
+ case 4:
+ return xchg_u32(ptr, x);
+ case 8:
+ return xchg_u64(ptr, x);
+ }
+ __xchg_called_with_bad_pointer();
+ return x;
}
-extern ulong IRQ_vectors[256];
-extern ulong exception_handlers[256];
+extern unsigned long IRQ_vectors[16];
+extern unsigned long exception_handlers[32];
-#define set_intr_gate(n,addr) \
- IRQ_vectors[n] = (ulong) (addr)
+#define set_int_vector(n,addr) \
+ IRQ_vectors[n] = (unsigned long) (addr)
#define set_except_vector(n,addr) \
- exception_handlers[n] = (ulong) (addr)
-
-/*
- * atomic exchange of one word
- */
-#if defined (__R4000__)
-#define atomic_exchange(m,r) \
- __asm__ __volatile__( \
- ".set\tnoreorder\n\t" \
- "ll\t%0,(%2)\n" \
- "1:\tmove\t$8,%1\n\t" \
- "sc\t$8,(%2)\n\t" \
- "beql\t$0,$8,1b\n\t" \
- "ll\t%0,(%2)\n\t" \
- ".set\treorder" \
- : "=r" (r) \
- : "r" (r), "r" (&(m)) \
- : "$8","memory")
-#else
-#define atomic_exchange(m,r) \
- { \
- unsigned long flags; \
- unsigned long tmp; \
- save_flags(flags); \
- cli(); \
- tmp = (m); \
- (m) = (r); \
- (r) = tmp; \
- restore_flags(flags); \
- }
-#endif
+ exception_handlers[n] = (unsigned long) (addr)
#endif /* __ASM_MIPS_SYSTEM_H */
--- /dev/null
+#ifndef __ASM_MIPS_TERMBITS_H
+#define __ASM_MIPS_TERMBITS_H
+
+#include <asm/ioctl.h>
+#include <asm/ioctls.h>
+
+/*
+ * The ABI says nothing about NCC but seems to use NCCS as
+ * replacement for it in struct termio
+ */
+#define NCC 8
+#define NCCS 23
+
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ char c_line; /* line discipline */
+ unsigned char c_cc[NCCS]; /* control characters */
+};
+
+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 */
+ /*
+ * Seems nonexistant in the ABI, but Linux assumes existence ...
+ */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+#endif /* __ASM_MIPS_TERMBITS_H */
--- /dev/null
+#ifndef __ASM_MIPS_TERMIOS_H
+#define __ASM_MIPS_TERMIOS_H
+
+#include <linux/types.h>
+#include <asm/termbits.h>
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+/* ----------------------------------------------------------------------- */
+
+#ifdef __KERNEL__
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+extern inline void trans_from_termio(struct termio * termio,
+ struct termios * termios)
+{
+#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
+ SET_LOW_BITS(termios->c_iflag, termio->c_iflag);
+ SET_LOW_BITS(termios->c_oflag, termio->c_oflag);
+ SET_LOW_BITS(termios->c_cflag, termio->c_cflag);
+ SET_LOW_BITS(termios->c_lflag, termio->c_lflag);
+#undef SET_LOW_BITS
+ memcpy(termios->c_cc, termio->c_cc, NCC);
+}
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+extern inline void trans_to_termio(struct termios * termios,
+ struct termio * termio)
+{
+ termio->c_iflag = termios->c_iflag;
+ termio->c_oflag = termios->c_oflag;
+ termio->c_cflag = termios->c_cflag;
+ termio->c_lflag = termios->c_lflag;
+ termio->c_line = termios->c_line;
+ memcpy(termio->c_cc, termios->c_cc, NCC);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASM_MIPS_TERMIOS_H */
+/*
+ * include/asm-mips/types.h
+ *
+ * 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.
+ *
+ * Copyright (C) 1994, 1995 by Waldorf GMBH
+ * written by Ralf Baechle
+ */
#ifndef __ASM_MIPS_TYPES_H
#define __ASM_MIPS_TYPES_H
#ifndef _SIZE_T
#define _SIZE_T
-typedef unsigned long size_t;
+typedef __SIZE_TYPE__ size_t;
#endif
#ifndef _SSIZE_T
#define _SSIZE_T
-typedef long ssize_t;
+typedef __SSIZE_TYPE__ ssize_t;
#endif
#ifndef _PTRDIFF_T
#define _PTRDIFF_T
-typedef long ptrdiff_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+#endif
+
+#ifndef _TIME_T
+#define _TIME_T
+typedef long time_t;
+#endif
+
+#ifndef _CLOCK_T
+#define _CLOCK_T
+typedef long clock_t;
#endif
/*
typedef __signed short s16;
typedef unsigned short u16;
-typedef __signed long s32;
-typedef unsigned long u32;
+typedef __signed int s32;
+typedef unsigned int u32;
#if ((~0UL) == 0xffffffff)
#endif /* __KERNEL__ */
+typedef __s32 pid_t;
+typedef __s32 uid_t;
+typedef __s32 gid_t;
+typedef __u32 dev_t;
+typedef __u32 ino_t;
+typedef __u32 mode_t;
+typedef __u32 umode_t;
+typedef __u32 nlink_t;
+typedef long daddr_t;
+typedef long off_t;
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, fd_set *fdsetp)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, fd_set *fdsetp)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, fd_set *p)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
/*
- * These definitions double the definitions from <gnu/types.h>.
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
*/
-#undef __FDELT
-#define __FDELT(d) ((d) / __NFDBITS)
-#undef __FDMASK
-#define __FDMASK(d) (1 << ((d) % __NFDBITS))
-#undef __FD_SET
-#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
-#undef __FD_CLR
-#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
-#undef __FD_ISSET
-#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
-#undef __FD_ZERO
-#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(fd_set *p)
+{
+ unsigned int *tmp = p->fds_bits;
+ int i;
+
+ if (__builtin_constant_p(__FDSET_INTS)) {
+ switch (__FDSET_INTS) {
+ case 8:
+ tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
+ tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
+ return;
+ }
+ }
+ i = __FDSET_INTS;
+ while (i) {
+ i--;
+ *tmp = 0;
+ tmp++;
+ }
+}
#endif /* __ASM_MIPS_TYPES_H */
+/*
+ * This file contains the system call numbers.
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
#ifndef __ASM_MIPS_UNISTD_H
#define __ASM_MIPS_UNISTD_H
-#ifdef __KERNEL__
+/*
+ * The syscalls 0 - 3999 are reserved for a down to the root syscall
+ * compatibility with Risc/OS and IRIX. None of these syscalls has yet been
+ * implemented. We'll see how to deal with the various "real" BSD variants
+ * like Ultrix, NetBSD ...
+ */
+
+/*
+ * SVR4 syscalls are in the range from 1 to 999
+ */
+#define __NR_SVR4 0
+#define __NR_SVR4_syscall (__NR_SVR4 + 0)
+#define __NR_SVR4_exit (__NR_SVR4 + 1)
+#define __NR_SVR4_fork (__NR_SVR4 + 2)
+#define __NR_SVR4_read (__NR_SVR4 + 3)
+#define __NR_SVR4_write (__NR_SVR4 + 4)
+#define __NR_SVR4_open (__NR_SVR4 + 5)
+#define __NR_SVR4_close (__NR_SVR4 + 6)
+#define __NR_SVR4_wait (__NR_SVR4 + 7)
+#define __NR_SVR4_creat (__NR_SVR4 + 8)
+#define __NR_SVR4_link (__NR_SVR4 + 9)
+#define __NR_SVR4_unlink (__NR_SVR4 + 10)
+#define __NR_SVR4_exec (__NR_SVR4 + 11)
+#define __NR_SVR4_chdir (__NR_SVR4 + 12)
+#define __NR_SVR4_gtime (__NR_SVR4 + 13)
+#define __NR_SVR4_mknod (__NR_SVR4 + 14)
+#define __NR_SVR4_chmod (__NR_SVR4 + 15)
+#define __NR_SVR4_chown (__NR_SVR4 + 16)
+#define __NR_SVR4_sbreak (__NR_SVR4 + 17)
+#define __NR_SVR4_stat (__NR_SVR4 + 18)
+#define __NR_SVR4_lseek (__NR_SVR4 + 19)
+#define __NR_SVR4_getpid (__NR_SVR4 + 20)
+#define __NR_SVR4_mount (__NR_SVR4 + 21)
+#define __NR_SVR4_umount (__NR_SVR4 + 22)
+#define __NR_SVR4_setuid (__NR_SVR4 + 23)
+#define __NR_SVR4_getuid (__NR_SVR4 + 24)
+#define __NR_SVR4_stime (__NR_SVR4 + 25)
+#define __NR_SVR4_ptrace (__NR_SVR4 + 26)
+#define __NR_SVR4_alarm (__NR_SVR4 + 27)
+#define __NR_SVR4_fstat (__NR_SVR4 + 28)
+#define __NR_SVR4_pause (__NR_SVR4 + 29)
+#define __NR_SVR4_utime (__NR_SVR4 + 30)
+#define __NR_SVR4_stty (__NR_SVR4 + 31)
+#define __NR_SVR4_gtty (__NR_SVR4 + 32)
+#define __NR_SVR4_access (__NR_SVR4 + 33)
+#define __NR_SVR4_nice (__NR_SVR4 + 34)
+#define __NR_SVR4_statfs (__NR_SVR4 + 35)
+#define __NR_SVR4_sync (__NR_SVR4 + 36)
+#define __NR_SVR4_kill (__NR_SVR4 + 37)
+#define __NR_SVR4_fstatfs (__NR_SVR4 + 38)
+#define __NR_SVR4_setpgrp (__NR_SVR4 + 39)
+#define __NR_SVR4_cxenix (__NR_SVR4 + 40)
+#define __NR_SVR4_dup (__NR_SVR4 + 41)
+#define __NR_SVR4_pipe (__NR_SVR4 + 42)
+#define __NR_SVR4_times (__NR_SVR4 + 43)
+#define __NR_SVR4_profil (__NR_SVR4 + 44)
+#define __NR_SVR4_plock (__NR_SVR4 + 45)
+#define __NR_SVR4_setgid (__NR_SVR4 + 46)
+#define __NR_SVR4_getgid (__NR_SVR4 + 47)
+#define __NR_SVR4_sig (__NR_SVR4 + 48)
+#define __NR_SVR4_msgsys (__NR_SVR4 + 49)
+#define __NR_SVR4_sysmips (__NR_SVR4 + 50)
+#define __NR_SVR4_sysacct (__NR_SVR4 + 51)
+#define __NR_SVR4_shmsys (__NR_SVR4 + 52)
+#define __NR_SVR4_semsys (__NR_SVR4 + 53)
+#define __NR_SVR4_ioctl (__NR_SVR4 + 54)
+#define __NR_SVR4_uadmin (__NR_SVR4 + 55)
+#define __NR_SVR4_exch (__NR_SVR4 + 56)
+#define __NR_SVR4_utssys (__NR_SVR4 + 57)
+#define __NR_SVR4_fsync (__NR_SVR4 + 58)
+#define __NR_SVR4_exece (__NR_SVR4 + 59)
+#define __NR_SVR4_umask (__NR_SVR4 + 60)
+#define __NR_SVR4_chroot (__NR_SVR4 + 61)
+#define __NR_SVR4_fcntl (__NR_SVR4 + 62)
+#define __NR_SVR4_ulimit (__NR_SVR4 + 63)
+#define __NR_SVR4_reserved1 (__NR_SVR4 + 64)
+#define __NR_SVR4_reserved2 (__NR_SVR4 + 65)
+#define __NR_SVR4_reserved3 (__NR_SVR4 + 66)
+#define __NR_SVR4_reserved4 (__NR_SVR4 + 67)
+#define __NR_SVR4_reserved5 (__NR_SVR4 + 68)
+#define __NR_SVR4_reserved6 (__NR_SVR4 + 69)
+#define __NR_SVR4_advfs (__NR_SVR4 + 70)
+#define __NR_SVR4_unadvfs (__NR_SVR4 + 71)
+#define __NR_SVR4_unused1 (__NR_SVR4 + 72)
+#define __NR_SVR4_unused2 (__NR_SVR4 + 73)
+#define __NR_SVR4_rfstart (__NR_SVR4 + 74)
+#define __NR_SVR4_unused3 (__NR_SVR4 + 75)
+#define __NR_SVR4_rdebug (__NR_SVR4 + 76)
+#define __NR_SVR4_rfstop (__NR_SVR4 + 77)
+#define __NR_SVR4_rfsys (__NR_SVR4 + 78)
+#define __NR_SVR4_rmdir (__NR_SVR4 + 79)
+#define __NR_SVR4_mkdir (__NR_SVR4 + 80)
+#define __NR_SVR4_getdents (__NR_SVR4 + 81)
+#define __NR_SVR4_libattach (__NR_SVR4 + 82)
+#define __NR_SVR4_libdetach (__NR_SVR4 + 83)
+#define __NR_SVR4_sysfs (__NR_SVR4 + 84)
+#define __NR_SVR4_getmsg (__NR_SVR4 + 85)
+#define __NR_SVR4_putmsg (__NR_SVR4 + 86)
+#define __NR_SVR4_poll (__NR_SVR4 + 87)
+#define __NR_SVR4_lstat (__NR_SVR4 + 88)
+#define __NR_SVR4_symlink (__NR_SVR4 + 89)
+#define __NR_SVR4_readlink (__NR_SVR4 + 90)
+#define __NR_SVR4_setgroups (__NR_SVR4 + 91)
+#define __NR_SVR4_getgroups (__NR_SVR4 + 92)
+#define __NR_SVR4_fchmod (__NR_SVR4 + 93)
+#define __NR_SVR4_fchown (__NR_SVR4 + 94)
+#define __NR_SVR4_sigprocmask (__NR_SVR4 + 95)
+#define __NR_SVR4_sigsuspend (__NR_SVR4 + 96)
+#define __NR_SVR4_sigaltstack (__NR_SVR4 + 97)
+#define __NR_SVR4_sigaction (__NR_SVR4 + 98)
+#define __NR_SVR4_sigpending (__NR_SVR4 + 99)
+#define __NR_SVR4_setcontext (__NR_SVR4 + 100)
+#define __NR_SVR4_evsys (__NR_SVR4 + 101)
+#define __NR_SVR4_evtrapret (__NR_SVR4 + 102)
+#define __NR_SVR4_statvfs (__NR_SVR4 + 103)
+#define __NR_SVR4_fstatvfs (__NR_SVR4 + 104)
+#define __NR_SVR4_reserved7 (__NR_SVR4 + 105)
+#define __NR_SVR4_nfssys (__NR_SVR4 + 106)
+#define __NR_SVR4_waitid (__NR_SVR4 + 107)
+#define __NR_SVR4_sigsendset (__NR_SVR4 + 108)
+#define __NR_SVR4_hrtsys (__NR_SVR4 + 109)
+#define __NR_SVR4_acancel (__NR_SVR4 + 110)
+#define __NR_SVR4_async (__NR_SVR4 + 111)
+#define __NR_SVR4_priocntlset (__NR_SVR4 + 112)
+#define __NR_SVR4_pathconf (__NR_SVR4 + 113)
+#define __NR_SVR4_mincore (__NR_SVR4 + 114)
+#define __NR_SVR4_mmap (__NR_SVR4 + 115)
+#define __NR_SVR4_mprotect (__NR_SVR4 + 116)
+#define __NR_SVR4_munmap (__NR_SVR4 + 117)
+#define __NR_SVR4_fpathconf (__NR_SVR4 + 118)
+#define __NR_SVR4_vfork (__NR_SVR4 + 119)
+#define __NR_SVR4_fchdir (__NR_SVR4 + 120)
+#define __NR_SVR4_readv (__NR_SVR4 + 121)
+#define __NR_SVR4_writev (__NR_SVR4 + 122)
+#define __NR_SVR4_xstat (__NR_SVR4 + 123)
+#define __NR_SVR4_lxstat (__NR_SVR4 + 124)
+#define __NR_SVR4_fxstat (__NR_SVR4 + 125)
+#define __NR_SVR4_xmknod (__NR_SVR4 + 126)
+#define __NR_SVR4_clocal (__NR_SVR4 + 127)
+#define __NR_SVR4_setrlimit (__NR_SVR4 + 128)
+#define __NR_SVR4_getrlimit (__NR_SVR4 + 129)
+#define __NR_SVR4_lchown (__NR_SVR4 + 130)
+#define __NR_SVR4_memcntl (__NR_SVR4 + 131)
+#define __NR_SVR4_getpmsg (__NR_SVR4 + 132)
+#define __NR_SVR4_putpmsg (__NR_SVR4 + 133)
+#define __NR_SVR4_rename (__NR_SVR4 + 134)
+#define __NR_SVR4_nuname (__NR_SVR4 + 135)
+#define __NR_SVR4_setegid (__NR_SVR4 + 136)
+#define __NR_SVR4_sysconf (__NR_SVR4 + 137)
+#define __NR_SVR4_adjtime (__NR_SVR4 + 138)
+#define __NR_SVR4_sysinfo (__NR_SVR4 + 139)
+#define __NR_SVR4_reserved8 (__NR_SVR4 + 140)
+#define __NR_SVR4_seteuid (__NR_SVR4 + 141)
+#define __NR_SVR4_PYRAMID_statis (__NR_SVR4 + 142)
+#define __NR_SVR4_PYRAMID_tuning (__NR_SVR4 + 143)
+#define __NR_SVR4_PYRAMID_forcerr (__NR_SVR4 + 144)
+#define __NR_SVR4_PYRAMID_mpcntl (__NR_SVR4 + 145)
+#define __NR_SVR4_reserved9 (__NR_SVR4 + 146)
+#define __NR_SVR4_reserved10 (__NR_SVR4 + 147)
+#define __NR_SVR4_reserved11 (__NR_SVR4 + 148)
+#define __NR_SVR4_reserved12 (__NR_SVR4 + 149)
+#define __NR_SVR4_reserved13 (__NR_SVR4 + 150)
+#define __NR_SVR4_reserved14 (__NR_SVR4 + 151)
+#define __NR_SVR4_reserved15 (__NR_SVR4 + 152)
+#define __NR_SVR4_reserved16 (__NR_SVR4 + 153)
+#define __NR_SVR4_reserved17 (__NR_SVR4 + 154)
+#define __NR_SVR4_reserved18 (__NR_SVR4 + 155)
+#define __NR_SVR4_reserved19 (__NR_SVR4 + 156)
+#define __NR_SVR4_reserved20 (__NR_SVR4 + 157)
+#define __NR_SVR4_reserved21 (__NR_SVR4 + 158)
+#define __NR_SVR4_reserved22 (__NR_SVR4 + 159)
+#define __NR_SVR4_reserved23 (__NR_SVR4 + 160)
+#define __NR_SVR4_reserved24 (__NR_SVR4 + 161)
+#define __NR_SVR4_reserved25 (__NR_SVR4 + 162)
+#define __NR_SVR4_reserved26 (__NR_SVR4 + 163)
+#define __NR_SVR4_reserved27 (__NR_SVR4 + 164)
+#define __NR_SVR4_reserved28 (__NR_SVR4 + 165)
+#define __NR_SVR4_reserved29 (__NR_SVR4 + 166)
+#define __NR_SVR4_reserved30 (__NR_SVR4 + 167)
+#define __NR_SVR4_reserved31 (__NR_SVR4 + 168)
+#define __NR_SVR4_reserved32 (__NR_SVR4 + 169)
+#define __NR_SVR4_reserved33 (__NR_SVR4 + 170)
+#define __NR_SVR4_reserved34 (__NR_SVR4 + 171)
+#define __NR_SVR4_reserved35 (__NR_SVR4 + 172)
+#define __NR_SVR4_reserved36 (__NR_SVR4 + 173)
+#define __NR_SVR4_reserved37 (__NR_SVR4 + 174)
+#define __NR_SVR4_reserved38 (__NR_SVR4 + 175)
+#define __NR_SVR4_reserved39 (__NR_SVR4 + 176)
+#define __NR_SVR4_reserved40 (__NR_SVR4 + 177)
+#define __NR_SVR4_reserved41 (__NR_SVR4 + 178)
+#define __NR_SVR4_reserved42 (__NR_SVR4 + 179)
+#define __NR_SVR4_reserved43 (__NR_SVR4 + 180)
+#define __NR_SVR4_reserved44 (__NR_SVR4 + 181)
+#define __NR_SVR4_reserved45 (__NR_SVR4 + 182)
+#define __NR_SVR4_reserved46 (__NR_SVR4 + 183)
+#define __NR_SVR4_reserved47 (__NR_SVR4 + 184)
+#define __NR_SVR4_reserved48 (__NR_SVR4 + 185)
+#define __NR_SVR4_reserved49 (__NR_SVR4 + 186)
+#define __NR_SVR4_reserved50 (__NR_SVR4 + 187)
+#define __NR_SVR4_reserved51 (__NR_SVR4 + 188)
+#define __NR_SVR4_reserved52 (__NR_SVR4 + 189)
+#define __NR_SVR4_reserved53 (__NR_SVR4 + 190)
+#define __NR_SVR4_reserved54 (__NR_SVR4 + 191)
+#define __NR_SVR4_reserved55 (__NR_SVR4 + 192)
+#define __NR_SVR4_reserved56 (__NR_SVR4 + 193)
+#define __NR_SVR4_reserved57 (__NR_SVR4 + 194)
+#define __NR_SVR4_reserved58 (__NR_SVR4 + 195)
+#define __NR_SVR4_reserved59 (__NR_SVR4 + 196)
+#define __NR_SVR4_reserved60 (__NR_SVR4 + 197)
+#define __NR_SVR4_reserved61 (__NR_SVR4 + 198)
+#define __NR_SVR4_reserved62 (__NR_SVR4 + 199)
+#define __NR_SVR4_reserved63 (__NR_SVR4 + 200)
+#define __NR_SVR4_aread (__NR_SVR4 + 201)
+#define __NR_SVR4_awrite (__NR_SVR4 + 202)
+#define __NR_SVR4_listio (__NR_SVR4 + 203)
+#define __NR_SVR4_mips_acancel (__NR_SVR4 + 204)
+#define __NR_SVR4_astatus (__NR_SVR4 + 205)
+#define __NR_SVR4_await (__NR_SVR4 + 206)
+#define __NR_SVR4_areadv (__NR_SVR4 + 207)
+#define __NR_SVR4_awritev (__NR_SVR4 + 208)
+#define __NR_SVR4_MIPS_reserved1 (__NR_SVR4 + 209)
+#define __NR_SVR4_MIPS_reserved2 (__NR_SVR4 + 210)
+#define __NR_SVR4_MIPS_reserved3 (__NR_SVR4 + 211)
+#define __NR_SVR4_MIPS_reserved4 (__NR_SVR4 + 212)
+#define __NR_SVR4_MIPS_reserved5 (__NR_SVR4 + 213)
+#define __NR_SVR4_MIPS_reserved6 (__NR_SVR4 + 214)
+#define __NR_SVR4_MIPS_reserved7 (__NR_SVR4 + 215)
+#define __NR_SVR4_MIPS_reserved8 (__NR_SVR4 + 216)
+#define __NR_SVR4_MIPS_reserved9 (__NR_SVR4 + 217)
+#define __NR_SVR4_MIPS_reserved10 (__NR_SVR4 + 218)
+#define __NR_SVR4_MIPS_reserved11 (__NR_SVR4 + 219)
+#define __NR_SVR4_MIPS_reserved12 (__NR_SVR4 + 220)
+#define __NR_SVR4_CDC_reserved1 (__NR_SVR4 + 221)
+#define __NR_SVR4_CDC_reserved2 (__NR_SVR4 + 222)
+#define __NR_SVR4_CDC_reserved3 (__NR_SVR4 + 223)
+#define __NR_SVR4_CDC_reserved4 (__NR_SVR4 + 224)
+#define __NR_SVR4_CDC_reserved5 (__NR_SVR4 + 225)
+#define __NR_SVR4_CDC_reserved6 (__NR_SVR4 + 226)
+#define __NR_SVR4_CDC_reserved7 (__NR_SVR4 + 227)
+#define __NR_SVR4_CDC_reserved8 (__NR_SVR4 + 228)
+#define __NR_SVR4_CDC_reserved9 (__NR_SVR4 + 229)
+#define __NR_SVR4_CDC_reserved10 (__NR_SVR4 + 230)
+#define __NR_SVR4_CDC_reserved11 (__NR_SVR4 + 231)
+#define __NR_SVR4_CDC_reserved12 (__NR_SVR4 + 232)
+#define __NR_SVR4_CDC_reserved13 (__NR_SVR4 + 233)
+#define __NR_SVR4_CDC_reserved14 (__NR_SVR4 + 234)
+#define __NR_SVR4_CDC_reserved15 (__NR_SVR4 + 235)
+#define __NR_SVR4_CDC_reserved16 (__NR_SVR4 + 236)
+#define __NR_SVR4_CDC_reserved17 (__NR_SVR4 + 237)
+#define __NR_SVR4_CDC_reserved18 (__NR_SVR4 + 238)
+#define __NR_SVR4_CDC_reserved19 (__NR_SVR4 + 239)
+#define __NR_SVR4_CDC_reserved20 (__NR_SVR4 + 240)
+
+/*
+ * SYS V syscalls are in the range from 1000 to 1999
+ */
+#define __NR_SYSV 1000
+#define __NR_SYSV_syscall (__NR_SYSV + 0)
+#define __NR_SYSV_exit (__NR_SYSV + 1)
+#define __NR_SYSV_fork (__NR_SYSV + 2)
+#define __NR_SYSV_read (__NR_SYSV + 3)
+#define __NR_SYSV_write (__NR_SYSV + 4)
+#define __NR_SYSV_open (__NR_SYSV + 5)
+#define __NR_SYSV_close (__NR_SYSV + 6)
+#define __NR_SYSV_wait (__NR_SYSV + 7)
+#define __NR_SYSV_creat (__NR_SYSV + 8)
+#define __NR_SYSV_link (__NR_SYSV + 9)
+#define __NR_SYSV_unlink (__NR_SYSV + 10)
+#define __NR_SYSV_execv (__NR_SYSV + 11)
+#define __NR_SYSV_chdir (__NR_SYSV + 12)
+#define __NR_SYSV_time (__NR_SYSV + 13)
+#define __NR_SYSV_mknod (__NR_SYSV + 14)
+#define __NR_SYSV_chmod (__NR_SYSV + 15)
+#define __NR_SYSV_chown (__NR_SYSV + 16)
+#define __NR_SYSV_brk (__NR_SYSV + 17)
+#define __NR_SYSV_stat (__NR_SYSV + 18)
+#define __NR_SYSV_lseek (__NR_SYSV + 19)
+#define __NR_SYSV_getpid (__NR_SYSV + 20)
+#define __NR_SYSV_mount (__NR_SYSV + 21)
+#define __NR_SYSV_umount (__NR_SYSV + 22)
+#define __NR_SYSV_setuid (__NR_SYSV + 23)
+#define __NR_SYSV_getuid (__NR_SYSV + 24)
+#define __NR_SYSV_stime (__NR_SYSV + 25)
+#define __NR_SYSV_ptrace (__NR_SYSV + 26)
+#define __NR_SYSV_alarm (__NR_SYSV + 27)
+#define __NR_SYSV_fstat (__NR_SYSV + 28)
+#define __NR_SYSV_pause (__NR_SYSV + 29)
+#define __NR_SYSV_utime (__NR_SYSV + 30)
+#define __NR_SYSV_stty (__NR_SYSV + 31)
+#define __NR_SYSV_gtty (__NR_SYSV + 32)
+#define __NR_SYSV_access (__NR_SYSV + 33)
+#define __NR_SYSV_nice (__NR_SYSV + 34)
+#define __NR_SYSV_statfs (__NR_SYSV + 35)
+#define __NR_SYSV_sync (__NR_SYSV + 36)
+#define __NR_SYSV_kill (__NR_SYSV + 37)
+#define __NR_SYSV_fstatfs (__NR_SYSV + 38)
+#define __NR_SYSV_setpgrp (__NR_SYSV + 39)
+#define __NR_SYSV_syssgi (__NR_SYSV + 40)
+#define __NR_SYSV_dup (__NR_SYSV + 41)
+#define __NR_SYSV_pipe (__NR_SYSV + 42)
+#define __NR_SYSV_times (__NR_SYSV + 43)
+#define __NR_SYSV_profil (__NR_SYSV + 44)
+#define __NR_SYSV_plock (__NR_SYSV + 45)
+#define __NR_SYSV_setgid (__NR_SYSV + 46)
+#define __NR_SYSV_getgid (__NR_SYSV + 47)
+#define __NR_SYSV_sig (__NR_SYSV + 48)
+#define __NR_SYSV_msgsys (__NR_SYSV + 49)
+#define __NR_SYSV_sysmips (__NR_SYSV + 50)
+#define __NR_SYSV_acct (__NR_SYSV + 51)
+#define __NR_SYSV_shmsys (__NR_SYSV + 52)
+#define __NR_SYSV_semsys (__NR_SYSV + 53)
+#define __NR_SYSV_ioctl (__NR_SYSV + 54)
+#define __NR_SYSV_uadmin (__NR_SYSV + 55)
+#define __NR_SYSV_sysmp (__NR_SYSV + 56)
+#define __NR_SYSV_utssys (__NR_SYSV + 57)
+#define __NR_SYSV_USG_reserved1 (__NR_SYSV + 58)
+#define __NR_SYSV_execve (__NR_SYSV + 59)
+#define __NR_SYSV_umask (__NR_SYSV + 60)
+#define __NR_SYSV_chroot (__NR_SYSV + 61)
+#define __NR_SYSV_fcntl (__NR_SYSV + 62)
+#define __NR_SYSV_ulimit (__NR_SYSV + 63)
+#define __NR_SYSV_SAFARI4_reserved1 (__NR_SYSV + 64)
+#define __NR_SYSV_SAFARI4_reserved2 (__NR_SYSV + 65)
+#define __NR_SYSV_SAFARI4_reserved3 (__NR_SYSV + 66)
+#define __NR_SYSV_SAFARI4_reserved4 (__NR_SYSV + 67)
+#define __NR_SYSV_SAFARI4_reserved5 (__NR_SYSV + 68)
+#define __NR_SYSV_SAFARI4_reserved6 (__NR_SYSV + 69)
+#define __NR_SYSV_advfs (__NR_SYSV + 70)
+#define __NR_SYSV_unadvfs (__NR_SYSV + 71)
+#define __NR_SYSV_rmount (__NR_SYSV + 72)
+#define __NR_SYSV_rumount (__NR_SYSV + 73)
+#define __NR_SYSV_rfstart (__NR_SYSV + 74)
+#define __NR_SYSV_getrlimit64 (__NR_SYSV + 75)
+#define __NR_SYSV_setrlimit64 (__NR_SYSV + 76)
+#define __NR_SYSV_nanosleep (__NR_SYSV + 77)
+#define __NR_SYSV_lseek64 (__NR_SYSV + 78)
+#define __NR_SYSV_rmdir (__NR_SYSV + 79)
+#define __NR_SYSV_mkdir (__NR_SYSV + 80)
+#define __NR_SYSV_getdents (__NR_SYSV + 81)
+#define __NR_SYSV_sginap (__NR_SYSV + 82)
+#define __NR_SYSV_sgikopt (__NR_SYSV + 83)
+#define __NR_SYSV_sysfs (__NR_SYSV + 84)
+#define __NR_SYSV_getmsg (__NR_SYSV + 85)
+#define __NR_SYSV_putmsg (__NR_SYSV + 86)
+#define __NR_SYSV_poll (__NR_SYSV + 87)
+#define __NR_SYSV_sigreturn (__NR_SYSV + 88)
+#define __NR_SYSV_accept (__NR_SYSV + 89)
+#define __NR_SYSV_bind (__NR_SYSV + 90)
+#define __NR_SYSV_connect (__NR_SYSV + 91)
+#define __NR_SYSV_gethostid (__NR_SYSV + 92)
+#define __NR_SYSV_getpeername (__NR_SYSV + 93)
+#define __NR_SYSV_getsockname (__NR_SYSV + 94)
+#define __NR_SYSV_getsockopt (__NR_SYSV + 95)
+#define __NR_SYSV_listen (__NR_SYSV + 96)
+#define __NR_SYSV_recv (__NR_SYSV + 97)
+#define __NR_SYSV_recvfrom (__NR_SYSV + 98)
+#define __NR_SYSV_recvmsg (__NR_SYSV + 99)
+#define __NR_SYSV_select (__NR_SYSV + 100)
+#define __NR_SYSV_send (__NR_SYSV + 101)
+#define __NR_SYSV_sendmsg (__NR_SYSV + 102)
+#define __NR_SYSV_sendto (__NR_SYSV + 103)
+#define __NR_SYSV_sethostid (__NR_SYSV + 104)
+#define __NR_SYSV_setsockopt (__NR_SYSV + 105)
+#define __NR_SYSV_shutdown (__NR_SYSV + 106)
+#define __NR_SYSV_socket (__NR_SYSV + 107)
+#define __NR_SYSV_gethostname (__NR_SYSV + 108)
+#define __NR_SYSV_sethostname (__NR_SYSV + 109)
+#define __NR_SYSV_getdomainname (__NR_SYSV + 110)
+#define __NR_SYSV_setdomainname (__NR_SYSV + 111)
+#define __NR_SYSV_truncate (__NR_SYSV + 112)
+#define __NR_SYSV_ftruncate (__NR_SYSV + 113)
+#define __NR_SYSV_rename (__NR_SYSV + 114)
+#define __NR_SYSV_symlink (__NR_SYSV + 115)
+#define __NR_SYSV_readlink (__NR_SYSV + 116)
+#define __NR_SYSV_lstat (__NR_SYSV + 117)
+#define __NR_SYSV_nfsmount (__NR_SYSV + 118)
+#define __NR_SYSV_nfssvc (__NR_SYSV + 119)
+#define __NR_SYSV_getfh (__NR_SYSV + 120)
+#define __NR_SYSV_async_daemon (__NR_SYSV + 121)
+#define __NR_SYSV_exportfs (__NR_SYSV + 122)
+#define __NR_SYSV_setregid (__NR_SYSV + 123)
+#define __NR_SYSV_setreuid (__NR_SYSV + 124)
+#define __NR_SYSV_getitimer (__NR_SYSV + 125)
+#define __NR_SYSV_setitimer (__NR_SYSV + 126)
+#define __NR_SYSV_adjtime (__NR_SYSV + 127)
+#define __NR_SYSV_BSD_getime (__NR_SYSV + 128)
+#define __NR_SYSV_sproc (__NR_SYSV + 129)
+#define __NR_SYSV_prctl (__NR_SYSV + 130)
+#define __NR_SYSV_procblk (__NR_SYSV + 131)
+#define __NR_SYSV_sprocsp (__NR_SYSV + 132)
+#define __NR_SYSV_sgigsc (__NR_SYSV + 133)
+#define __NR_SYSV_mmap (__NR_SYSV + 134)
+#define __NR_SYSV_munmap (__NR_SYSV + 135)
+#define __NR_SYSV_mprotect (__NR_SYSV + 136)
+#define __NR_SYSV_msync (__NR_SYSV + 137)
+#define __NR_SYSV_madvise (__NR_SYSV + 138)
+#define __NR_SYSV_pagelock (__NR_SYSV + 139)
+#define __NR_SYSV_getpagesize (__NR_SYSV + 140)
+#define __NR_SYSV_quotactl (__NR_SYSV + 141)
+#define __NR_SYSV_libdetach (__NR_SYSV + 142)
+#define __NR_SYSV_BSDgetpgrp (__NR_SYSV + 143)
+#define __NR_SYSV_BSDsetpgrp (__NR_SYSV + 144)
+#define __NR_SYSV_vhangup (__NR_SYSV + 145)
+#define __NR_SYSV_fsync (__NR_SYSV + 146)
+#define __NR_SYSV_fchdir (__NR_SYSV + 147)
+#define __NR_SYSV_getrlimit (__NR_SYSV + 148)
+#define __NR_SYSV_setrlimit (__NR_SYSV + 149)
+#define __NR_SYSV_cacheflush (__NR_SYSV + 150)
+#define __NR_SYSV_cachectl (__NR_SYSV + 151)
+#define __NR_SYSV_fchown (__NR_SYSV + 152)
+#define __NR_SYSV_fchmod (__NR_SYSV + 153)
+#define __NR_SYSV_wait3 (__NR_SYSV + 154)
+#define __NR_SYSV_socketpair (__NR_SYSV + 155)
+#define __NR_SYSV_sysinfo (__NR_SYSV + 156)
+#define __NR_SYSV_nuname (__NR_SYSV + 157)
+#define __NR_SYSV_xstat (__NR_SYSV + 158)
+#define __NR_SYSV_lxstat (__NR_SYSV + 159)
+#define __NR_SYSV_fxstat (__NR_SYSV + 160)
+#define __NR_SYSV_xmknod (__NR_SYSV + 161)
+#define __NR_SYSV_ksigaction (__NR_SYSV + 162)
+#define __NR_SYSV_sigpending (__NR_SYSV + 163)
+#define __NR_SYSV_sigprocmask (__NR_SYSV + 164)
+#define __NR_SYSV_sigsuspend (__NR_SYSV + 165)
+#define __NR_SYSV_sigpoll (__NR_SYSV + 166)
+#define __NR_SYSV_swapctl (__NR_SYSV + 167)
+#define __NR_SYSV_getcontext (__NR_SYSV + 168)
+#define __NR_SYSV_setcontext (__NR_SYSV + 169)
+#define __NR_SYSV_waitsys (__NR_SYSV + 170)
+#define __NR_SYSV_sigstack (__NR_SYSV + 171)
+#define __NR_SYSV_sigaltstack (__NR_SYSV + 172)
+#define __NR_SYSV_sigsendset (__NR_SYSV + 173)
+#define __NR_SYSV_statvfs (__NR_SYSV + 174)
+#define __NR_SYSV_fstatvfs (__NR_SYSV + 175)
+#define __NR_SYSV_getpmsg (__NR_SYSV + 176)
+#define __NR_SYSV_putpmsg (__NR_SYSV + 177)
+#define __NR_SYSV_lchown (__NR_SYSV + 178)
+#define __NR_SYSV_priocntl (__NR_SYSV + 179)
+#define __NR_SYSV_ksigqueue (__NR_SYSV + 180)
+#define __NR_SYSV_readv (__NR_SYSV + 181)
+#define __NR_SYSV_writev (__NR_SYSV + 182)
+#define __NR_SYSV_truncate64 (__NR_SYSV + 183)
+#define __NR_SYSV_ftruncate64 (__NR_SYSV + 184)
+#define __NR_SYSV_mmap64 (__NR_SYSV + 185)
+#define __NR_SYSV_dmi (__NR_SYSV + 186)
+#define __NR_SYSV_pread (__NR_SYSV + 187)
+#define __NR_SYSV_pwrite (__NR_SYSV + 188)
+
+/*
+ * BSD 4.3 syscalls are in the range from 2000 to 2999
+ */
+#define __NR_BSD43 2000
+#define __NR_BSD43_syscall (__NR_BSD43 + 0)
+#define __NR_BSD43_exit (__NR_BSD43 + 1)
+#define __NR_BSD43_fork (__NR_BSD43 + 2)
+#define __NR_BSD43_read (__NR_BSD43 + 3)
+#define __NR_BSD43_write (__NR_BSD43 + 4)
+#define __NR_BSD43_open (__NR_BSD43 + 5)
+#define __NR_BSD43_close (__NR_BSD43 + 6)
+#define __NR_BSD43_wait (__NR_BSD43 + 7)
+#define __NR_BSD43_creat (__NR_BSD43 + 8)
+#define __NR_BSD43_link (__NR_BSD43 + 9)
+#define __NR_BSD43_unlink (__NR_BSD43 + 10)
+#define __NR_BSD43_exec (__NR_BSD43 + 11)
+#define __NR_BSD43_chdir (__NR_BSD43 + 12)
+#define __NR_BSD43_time (__NR_BSD43 + 13)
+#define __NR_BSD43_mknod (__NR_BSD43 + 14)
+#define __NR_BSD43_chmod (__NR_BSD43 + 15)
+#define __NR_BSD43_chown (__NR_BSD43 + 16)
+#define __NR_BSD43_sbreak (__NR_BSD43 + 17)
+#define __NR_BSD43_oldstat (__NR_BSD43 + 18)
+#define __NR_BSD43_lseek (__NR_BSD43 + 19)
+#define __NR_BSD43_getpid (__NR_BSD43 + 20)
+#define __NR_BSD43_oldmount (__NR_BSD43 + 21)
+#define __NR_BSD43_umount (__NR_BSD43 + 22)
+#define __NR_BSD43_setuid (__NR_BSD43 + 23)
+#define __NR_BSD43_getuid (__NR_BSD43 + 24)
+#define __NR_BSD43_stime (__NR_BSD43 + 25)
+#define __NR_BSD43_ptrace (__NR_BSD43 + 26)
+#define __NR_BSD43_alarm (__NR_BSD43 + 27)
+#define __NR_BSD43_oldfstat (__NR_BSD43 + 28)
+#define __NR_BSD43_pause (__NR_BSD43 + 29)
+#define __NR_BSD43_utime (__NR_BSD43 + 30)
+#define __NR_BSD43_stty (__NR_BSD43 + 31)
+#define __NR_BSD43_gtty (__NR_BSD43 + 32)
+#define __NR_BSD43_access (__NR_BSD43 + 33)
+#define __NR_BSD43_nice (__NR_BSD43 + 34)
+#define __NR_BSD43_ftime (__NR_BSD43 + 35)
+#define __NR_BSD43_sync (__NR_BSD43 + 36)
+#define __NR_BSD43_kill (__NR_BSD43 + 37)
+#define __NR_BSD43_stat (__NR_BSD43 + 38)
+#define __NR_BSD43_oldsetpgrp (__NR_BSD43 + 39)
+#define __NR_BSD43_lstat (__NR_BSD43 + 40)
+#define __NR_BSD43_dup (__NR_BSD43 + 41)
+#define __NR_BSD43_pipe (__NR_BSD43 + 42)
+#define __NR_BSD43_times (__NR_BSD43 + 43)
+#define __NR_BSD43_profil (__NR_BSD43 + 44)
+#define __NR_BSD43_msgsys (__NR_BSD43 + 45)
+#define __NR_BSD43_setgid (__NR_BSD43 + 46)
+#define __NR_BSD43_getgid (__NR_BSD43 + 47)
+#define __NR_BSD43_ssig (__NR_BSD43 + 48)
+#define __NR_BSD43_reserved1 (__NR_BSD43 + 49)
+#define __NR_BSD43_reserved2 (__NR_BSD43 + 50)
+#define __NR_BSD43_sysacct (__NR_BSD43 + 51)
+#define __NR_BSD43_phys (__NR_BSD43 + 52)
+#define __NR_BSD43_lock (__NR_BSD43 + 53)
+#define __NR_BSD43_ioctl (__NR_BSD43 + 54)
+#define __NR_BSD43_reboot (__NR_BSD43 + 55)
+#define __NR_BSD43_mpxchan (__NR_BSD43 + 56)
+#define __NR_BSD43_symlink (__NR_BSD43 + 57)
+#define __NR_BSD43_readlink (__NR_BSD43 + 58)
+#define __NR_BSD43_execve (__NR_BSD43 + 59)
+#define __NR_BSD43_umask (__NR_BSD43 + 60)
+#define __NR_BSD43_chroot (__NR_BSD43 + 61)
+#define __NR_BSD43_fstat (__NR_BSD43 + 62)
+#define __NR_BSD43_reserved3 (__NR_BSD43 + 63)
+#define __NR_BSD43_getpagesize (__NR_BSD43 + 64)
+#define __NR_BSD43_mremap (__NR_BSD43 + 65)
+#define __NR_BSD43_vfork (__NR_BSD43 + 66)
+#define __NR_BSD43_vread (__NR_BSD43 + 67)
+#define __NR_BSD43_vwrite (__NR_BSD43 + 68)
+#define __NR_BSD43_sbrk (__NR_BSD43 + 69)
+#define __NR_BSD43_sstk (__NR_BSD43 + 70)
+#define __NR_BSD43_mmap (__NR_BSD43 + 71)
+#define __NR_BSD43_vadvise (__NR_BSD43 + 72)
+#define __NR_BSD43_munmap (__NR_BSD43 + 73)
+#define __NR_BSD43_mprotect (__NR_BSD43 + 74)
+#define __NR_BSD43_madvise (__NR_BSD43 + 75)
+#define __NR_BSD43_vhangup (__NR_BSD43 + 76)
+#define __NR_BSD43_vlimit (__NR_BSD43 + 77)
+#define __NR_BSD43_mincore (__NR_BSD43 + 78)
+#define __NR_BSD43_getgroups (__NR_BSD43 + 79)
+#define __NR_BSD43_setgroups (__NR_BSD43 + 80)
+#define __NR_BSD43_getpgrp (__NR_BSD43 + 81)
+#define __NR_BSD43_setpgrp (__NR_BSD43 + 82)
+#define __NR_BSD43_setitimer (__NR_BSD43 + 83)
+#define __NR_BSD43_wait3 (__NR_BSD43 + 84)
+#define __NR_BSD43_swapon (__NR_BSD43 + 85)
+#define __NR_BSD43_getitimer (__NR_BSD43 + 86)
+#define __NR_BSD43_gethostname (__NR_BSD43 + 87)
+#define __NR_BSD43_sethostname (__NR_BSD43 + 88)
+#define __NR_BSD43_getdtablesize (__NR_BSD43 + 89)
+#define __NR_BSD43_dup2 (__NR_BSD43 + 90)
+#define __NR_BSD43_getdopt (__NR_BSD43 + 91)
+#define __NR_BSD43_fcntl (__NR_BSD43 + 92)
+#define __NR_BSD43_select (__NR_BSD43 + 93)
+#define __NR_BSD43_setdopt (__NR_BSD43 + 94)
+#define __NR_BSD43_fsync (__NR_BSD43 + 95)
+#define __NR_BSD43_setpriority (__NR_BSD43 + 96)
+#define __NR_BSD43_socket (__NR_BSD43 + 97)
+#define __NR_BSD43_connect (__NR_BSD43 + 98)
+#define __NR_BSD43_oldaccept (__NR_BSD43 + 99)
+#define __NR_BSD43_getpriority (__NR_BSD43 + 100)
+#define __NR_BSD43_send (__NR_BSD43 + 101)
+#define __NR_BSD43_recv (__NR_BSD43 + 102)
+#define __NR_BSD43_sigreturn (__NR_BSD43 + 103)
+#define __NR_BSD43_bind (__NR_BSD43 + 104)
+#define __NR_BSD43_setsockopt (__NR_BSD43 + 105)
+#define __NR_BSD43_listen (__NR_BSD43 + 106)
+#define __NR_BSD43_vtimes (__NR_BSD43 + 107)
+#define __NR_BSD43_sigvec (__NR_BSD43 + 108)
+#define __NR_BSD43_sigblock (__NR_BSD43 + 109)
+#define __NR_BSD43_sigsetmask (__NR_BSD43 + 110)
+#define __NR_BSD43_sigpause (__NR_BSD43 + 111)
+#define __NR_BSD43_sigstack (__NR_BSD43 + 112)
+#define __NR_BSD43_oldrecvmsg (__NR_BSD43 + 113)
+#define __NR_BSD43_oldsendmsg (__NR_BSD43 + 114)
+#define __NR_BSD43_vtrace (__NR_BSD43 + 115)
+#define __NR_BSD43_gettimeofday (__NR_BSD43 + 116)
+#define __NR_BSD43_getrusage (__NR_BSD43 + 117)
+#define __NR_BSD43_getsockopt (__NR_BSD43 + 118)
+#define __NR_BSD43_reserved4 (__NR_BSD43 + 119)
+#define __NR_BSD43_readv (__NR_BSD43 + 120)
+#define __NR_BSD43_writev (__NR_BSD43 + 121)
+#define __NR_BSD43_settimeofday (__NR_BSD43 + 122)
+#define __NR_BSD43_fchown (__NR_BSD43 + 123)
+#define __NR_BSD43_fchmod (__NR_BSD43 + 124)
+#define __NR_BSD43_oldrecvfrom (__NR_BSD43 + 125)
+#define __NR_BSD43_setreuid (__NR_BSD43 + 126)
+#define __NR_BSD43_setregid (__NR_BSD43 + 127)
+#define __NR_BSD43_rename (__NR_BSD43 + 128)
+#define __NR_BSD43_truncate (__NR_BSD43 + 129)
+#define __NR_BSD43_ftruncate (__NR_BSD43 + 130)
+#define __NR_BSD43_flock (__NR_BSD43 + 131)
+#define __NR_BSD43_semsys (__NR_BSD43 + 132)
+#define __NR_BSD43_sendto (__NR_BSD43 + 133)
+#define __NR_BSD43_shutdown (__NR_BSD43 + 134)
+#define __NR_BSD43_socketpair (__NR_BSD43 + 135)
+#define __NR_BSD43_mkdir (__NR_BSD43 + 136)
+#define __NR_BSD43_rmdir (__NR_BSD43 + 137)
+#define __NR_BSD43_utimes (__NR_BSD43 + 138)
+#define __NR_BSD43_sigcleanup (__NR_BSD43 + 139)
+#define __NR_BSD43_adjtime (__NR_BSD43 + 140)
+#define __NR_BSD43_oldgetpeername (__NR_BSD43 + 141)
+#define __NR_BSD43_gethostid (__NR_BSD43 + 142)
+#define __NR_BSD43_sethostid (__NR_BSD43 + 143)
+#define __NR_BSD43_getrlimit (__NR_BSD43 + 144)
+#define __NR_BSD43_setrlimit (__NR_BSD43 + 145)
+#define __NR_BSD43_killpg (__NR_BSD43 + 146)
+#define __NR_BSD43_shmsys (__NR_BSD43 + 147)
+#define __NR_BSD43_quota (__NR_BSD43 + 148)
+#define __NR_BSD43_qquota (__NR_BSD43 + 149)
+#define __NR_BSD43_oldgetsockname (__NR_BSD43 + 150)
+#define __NR_BSD43_sysmips (__NR_BSD43 + 151)
+#define __NR_BSD43_cacheflush (__NR_BSD43 + 152)
+#define __NR_BSD43_cachectl (__NR_BSD43 + 153)
+#define __NR_BSD43_debug (__NR_BSD43 + 154)
+#define __NR_BSD43_reserved5 (__NR_BSD43 + 155)
+#define __NR_BSD43_reserved6 (__NR_BSD43 + 156)
+#define __NR_BSD43_nfs_mount (__NR_BSD43 + 157)
+#define __NR_BSD43_nfs_svc (__NR_BSD43 + 158)
+#define __NR_BSD43_getdirentries (__NR_BSD43 + 159)
+#define __NR_BSD43_statfs (__NR_BSD43 + 160)
+#define __NR_BSD43_fstatfs (__NR_BSD43 + 161)
+#define __NR_BSD43_unmount (__NR_BSD43 + 162)
+#define __NR_BSD43_async_daemon (__NR_BSD43 + 163)
+#define __NR_BSD43_nfs_getfh (__NR_BSD43 + 164)
+#define __NR_BSD43_getdomainname (__NR_BSD43 + 165)
+#define __NR_BSD43_setdomainname (__NR_BSD43 + 166)
+#define __NR_BSD43_pcfs_mount (__NR_BSD43 + 167)
+#define __NR_BSD43_quotactl (__NR_BSD43 + 168)
+#define __NR_BSD43_oldexportfs (__NR_BSD43 + 169)
+#define __NR_BSD43_smount (__NR_BSD43 + 170)
+#define __NR_BSD43_mipshwconf (__NR_BSD43 + 171)
+#define __NR_BSD43_exportfs (__NR_BSD43 + 172)
+#define __NR_BSD43_nfsfh_open (__NR_BSD43 + 173)
+#define __NR_BSD43_libattach (__NR_BSD43 + 174)
+#define __NR_BSD43_libdetach (__NR_BSD43 + 175)
+#define __NR_BSD43_accept (__NR_BSD43 + 176)
+#define __NR_BSD43_reserved7 (__NR_BSD43 + 177)
+#define __NR_BSD43_reserved8 (__NR_BSD43 + 178)
+#define __NR_BSD43_recvmsg (__NR_BSD43 + 179)
+#define __NR_BSD43_recvfrom (__NR_BSD43 + 180)
+#define __NR_BSD43_sendmsg (__NR_BSD43 + 181)
+#define __NR_BSD43_getpeername (__NR_BSD43 + 182)
+#define __NR_BSD43_getsockname (__NR_BSD43 + 183)
+#define __NR_BSD43_aread (__NR_BSD43 + 184)
+#define __NR_BSD43_awrite (__NR_BSD43 + 185)
+#define __NR_BSD43_listio (__NR_BSD43 + 186)
+#define __NR_BSD43_acancel (__NR_BSD43 + 187)
+#define __NR_BSD43_astatus (__NR_BSD43 + 188)
+#define __NR_BSD43_await (__NR_BSD43 + 189)
+#define __NR_BSD43_areadv (__NR_BSD43 + 190)
+#define __NR_BSD43_awritev (__NR_BSD43 + 191)
+
+/*
+ * POSIX syscalls are in the range from 3000 to 3999
+ */
+#define __NR_POSIX 3000
+#define __NR_POSIX_syscall (__NR_POSIX + 0)
+#define __NR_POSIX_exit (__NR_POSIX + 1)
+#define __NR_POSIX_fork (__NR_POSIX + 2)
+#define __NR_POSIX_read (__NR_POSIX + 3)
+#define __NR_POSIX_write (__NR_POSIX + 4)
+#define __NR_POSIX_open (__NR_POSIX + 5)
+#define __NR_POSIX_close (__NR_POSIX + 6)
+#define __NR_POSIX_wait (__NR_POSIX + 7)
+#define __NR_POSIX_creat (__NR_POSIX + 8)
+#define __NR_POSIX_link (__NR_POSIX + 9)
+#define __NR_POSIX_unlink (__NR_POSIX + 10)
+#define __NR_POSIX_exec (__NR_POSIX + 11)
+#define __NR_POSIX_chdir (__NR_POSIX + 12)
+#define __NR_POSIX_gtime (__NR_POSIX + 13)
+#define __NR_POSIX_mknod (__NR_POSIX + 14)
+#define __NR_POSIX_chmod (__NR_POSIX + 15)
+#define __NR_POSIX_chown (__NR_POSIX + 16)
+#define __NR_POSIX_sbreak (__NR_POSIX + 17)
+#define __NR_POSIX_stat (__NR_POSIX + 18)
+#define __NR_POSIX_lseek (__NR_POSIX + 19)
+#define __NR_POSIX_getpid (__NR_POSIX + 20)
+#define __NR_POSIX_mount (__NR_POSIX + 21)
+#define __NR_POSIX_umount (__NR_POSIX + 22)
+#define __NR_POSIX_setuid (__NR_POSIX + 23)
+#define __NR_POSIX_getuid (__NR_POSIX + 24)
+#define __NR_POSIX_stime (__NR_POSIX + 25)
+#define __NR_POSIX_ptrace (__NR_POSIX + 26)
+#define __NR_POSIX_alarm (__NR_POSIX + 27)
+#define __NR_POSIX_fstat (__NR_POSIX + 28)
+#define __NR_POSIX_pause (__NR_POSIX + 29)
+#define __NR_POSIX_utime (__NR_POSIX + 30)
+#define __NR_POSIX_stty (__NR_POSIX + 31)
+#define __NR_POSIX_gtty (__NR_POSIX + 32)
+#define __NR_POSIX_access (__NR_POSIX + 33)
+#define __NR_POSIX_nice (__NR_POSIX + 34)
+#define __NR_POSIX_statfs (__NR_POSIX + 35)
+#define __NR_POSIX_sync (__NR_POSIX + 36)
+#define __NR_POSIX_kill (__NR_POSIX + 37)
+#define __NR_POSIX_fstatfs (__NR_POSIX + 38)
+#define __NR_POSIX_getpgrp (__NR_POSIX + 39)
+#define __NR_POSIX_syssgi (__NR_POSIX + 40)
+#define __NR_POSIX_dup (__NR_POSIX + 41)
+#define __NR_POSIX_pipe (__NR_POSIX + 42)
+#define __NR_POSIX_times (__NR_POSIX + 43)
+#define __NR_POSIX_profil (__NR_POSIX + 44)
+#define __NR_POSIX_lock (__NR_POSIX + 45)
+#define __NR_POSIX_setgid (__NR_POSIX + 46)
+#define __NR_POSIX_getgid (__NR_POSIX + 47)
+#define __NR_POSIX_sig (__NR_POSIX + 48)
+#define __NR_POSIX_msgsys (__NR_POSIX + 49)
+#define __NR_POSIX_sysmips (__NR_POSIX + 50)
+#define __NR_POSIX_sysacct (__NR_POSIX + 51)
+#define __NR_POSIX_shmsys (__NR_POSIX + 52)
+#define __NR_POSIX_semsys (__NR_POSIX + 53)
+#define __NR_POSIX_ioctl (__NR_POSIX + 54)
+#define __NR_POSIX_uadmin (__NR_POSIX + 55)
+#define __NR_POSIX_exch (__NR_POSIX + 56)
+#define __NR_POSIX_utssys (__NR_POSIX + 57)
+#define __NR_POSIX_USG_reserved1 (__NR_POSIX + 58)
+#define __NR_POSIX_exece (__NR_POSIX + 59)
+#define __NR_POSIX_umask (__NR_POSIX + 60)
+#define __NR_POSIX_chroot (__NR_POSIX + 61)
+#define __NR_POSIX_fcntl (__NR_POSIX + 62)
+#define __NR_POSIX_ulimit (__NR_POSIX + 63)
+#define __NR_POSIX_SAFARI4_reserved1 (__NR_POSIX + 64)
+#define __NR_POSIX_SAFARI4_reserved2 (__NR_POSIX + 65)
+#define __NR_POSIX_SAFARI4_reserved3 (__NR_POSIX + 66)
+#define __NR_POSIX_SAFARI4_reserved4 (__NR_POSIX + 67)
+#define __NR_POSIX_SAFARI4_reserved5 (__NR_POSIX + 68)
+#define __NR_POSIX_SAFARI4_reserved6 (__NR_POSIX + 69)
+#define __NR_POSIX_advfs (__NR_POSIX + 70)
+#define __NR_POSIX_unadvfs (__NR_POSIX + 71)
+#define __NR_POSIX_rmount (__NR_POSIX + 72)
+#define __NR_POSIX_rumount (__NR_POSIX + 73)
+#define __NR_POSIX_rfstart (__NR_POSIX + 74)
+#define __NR_POSIX_reserved1 (__NR_POSIX + 75)
+#define __NR_POSIX_rdebug (__NR_POSIX + 76)
+#define __NR_POSIX_rfstop (__NR_POSIX + 77)
+#define __NR_POSIX_rfsys (__NR_POSIX + 78)
+#define __NR_POSIX_rmdir (__NR_POSIX + 79)
+#define __NR_POSIX_mkdir (__NR_POSIX + 80)
+#define __NR_POSIX_getdents (__NR_POSIX + 81)
+#define __NR_POSIX_sginap (__NR_POSIX + 82)
+#define __NR_POSIX_sgikopt (__NR_POSIX + 83)
+#define __NR_POSIX_sysfs (__NR_POSIX + 84)
+#define __NR_POSIX_getmsg (__NR_POSIX + 85)
+#define __NR_POSIX_putmsg (__NR_POSIX + 86)
+#define __NR_POSIX_poll (__NR_POSIX + 87)
+#define __NR_POSIX_sigreturn (__NR_POSIX + 88)
+#define __NR_POSIX_accept (__NR_POSIX + 89)
+#define __NR_POSIX_bind (__NR_POSIX + 90)
+#define __NR_POSIX_connect (__NR_POSIX + 91)
+#define __NR_POSIX_gethostid (__NR_POSIX + 92)
+#define __NR_POSIX_getpeername (__NR_POSIX + 93)
+#define __NR_POSIX_getsockname (__NR_POSIX + 94)
+#define __NR_POSIX_getsockopt (__NR_POSIX + 95)
+#define __NR_POSIX_listen (__NR_POSIX + 96)
+#define __NR_POSIX_recv (__NR_POSIX + 97)
+#define __NR_POSIX_recvfrom (__NR_POSIX + 98)
+#define __NR_POSIX_recvmsg (__NR_POSIX + 99)
+#define __NR_POSIX_select (__NR_POSIX + 100)
+#define __NR_POSIX_send (__NR_POSIX + 101)
+#define __NR_POSIX_sendmsg (__NR_POSIX + 102)
+#define __NR_POSIX_sendto (__NR_POSIX + 103)
+#define __NR_POSIX_sethostid (__NR_POSIX + 104)
+#define __NR_POSIX_setsockopt (__NR_POSIX + 105)
+#define __NR_POSIX_shutdown (__NR_POSIX + 106)
+#define __NR_POSIX_socket (__NR_POSIX + 107)
+#define __NR_POSIX_gethostname (__NR_POSIX + 108)
+#define __NR_POSIX_sethostname (__NR_POSIX + 109)
+#define __NR_POSIX_getdomainname (__NR_POSIX + 110)
+#define __NR_POSIX_setdomainname (__NR_POSIX + 111)
+#define __NR_POSIX_truncate (__NR_POSIX + 112)
+#define __NR_POSIX_ftruncate (__NR_POSIX + 113)
+#define __NR_POSIX_rename (__NR_POSIX + 114)
+#define __NR_POSIX_symlink (__NR_POSIX + 115)
+#define __NR_POSIX_readlink (__NR_POSIX + 116)
+#define __NR_POSIX_lstat (__NR_POSIX + 117)
+#define __NR_POSIX_nfs_mount (__NR_POSIX + 118)
+#define __NR_POSIX_nfs_svc (__NR_POSIX + 119)
+#define __NR_POSIX_nfs_getfh (__NR_POSIX + 120)
+#define __NR_POSIX_async_daemon (__NR_POSIX + 121)
+#define __NR_POSIX_exportfs (__NR_POSIX + 122)
+#define __NR_POSIX_SGI_setregid (__NR_POSIX + 123)
+#define __NR_POSIX_SGI_setreuid (__NR_POSIX + 124)
+#define __NR_POSIX_getitimer (__NR_POSIX + 125)
+#define __NR_POSIX_setitimer (__NR_POSIX + 126)
+#define __NR_POSIX_adjtime (__NR_POSIX + 127)
+#define __NR_POSIX_SGI_bsdgettime (__NR_POSIX + 128)
+#define __NR_POSIX_SGI_sproc (__NR_POSIX + 129)
+#define __NR_POSIX_SGI_prctl (__NR_POSIX + 130)
+#define __NR_POSIX_SGI_blkproc (__NR_POSIX + 131)
+#define __NR_POSIX_SGI_reserved1 (__NR_POSIX + 132)
+#define __NR_POSIX_SGI_sgigsc (__NR_POSIX + 133)
+#define __NR_POSIX_SGI_mmap (__NR_POSIX + 134)
+#define __NR_POSIX_SGI_munmap (__NR_POSIX + 135)
+#define __NR_POSIX_SGI_mprotect (__NR_POSIX + 136)
+#define __NR_POSIX_SGI_msync (__NR_POSIX + 137)
+#define __NR_POSIX_SGI_madvise (__NR_POSIX + 138)
+#define __NR_POSIX_SGI_mpin (__NR_POSIX + 139)
+#define __NR_POSIX_SGI_getpagesize (__NR_POSIX + 140)
+#define __NR_POSIX_SGI_libattach (__NR_POSIX + 141)
+#define __NR_POSIX_SGI_libdetach (__NR_POSIX + 142)
+#define __NR_POSIX_SGI_getpgrp (__NR_POSIX + 143)
+#define __NR_POSIX_SGI_setpgrp (__NR_POSIX + 144)
+#define __NR_POSIX_SGI_reserved2 (__NR_POSIX + 145)
+#define __NR_POSIX_SGI_reserved3 (__NR_POSIX + 146)
+#define __NR_POSIX_SGI_reserved4 (__NR_POSIX + 147)
+#define __NR_POSIX_SGI_reserved5 (__NR_POSIX + 148)
+#define __NR_POSIX_SGI_reserved6 (__NR_POSIX + 149)
+#define __NR_POSIX_cacheflush (__NR_POSIX + 150)
+#define __NR_POSIX_cachectl (__NR_POSIX + 151)
+#define __NR_POSIX_fchown (__NR_POSIX + 152)
+#define __NR_POSIX_fchmod (__NR_POSIX + 153)
+#define __NR_POSIX_wait3 (__NR_POSIX + 154)
+#define __NR_POSIX_mmap (__NR_POSIX + 155)
+#define __NR_POSIX_munmap (__NR_POSIX + 156)
+#define __NR_POSIX_madvise (__NR_POSIX + 157)
+#define __NR_POSIX_BSD_getpagesize (__NR_POSIX + 158)
+#define __NR_POSIX_setreuid (__NR_POSIX + 159)
+#define __NR_POSIX_setregid (__NR_POSIX + 160)
+#define __NR_POSIX_setpgid (__NR_POSIX + 161)
+#define __NR_POSIX_getgroups (__NR_POSIX + 162)
+#define __NR_POSIX_setgroups (__NR_POSIX + 163)
+#define __NR_POSIX_gettimeofday (__NR_POSIX + 164)
+#define __NR_POSIX_getrusage (__NR_POSIX + 165)
+#define __NR_POSIX_getrlimit (__NR_POSIX + 166)
+#define __NR_POSIX_setrlimit (__NR_POSIX + 167)
+#define __NR_POSIX_waitpid (__NR_POSIX + 168)
+#define __NR_POSIX_dup2 (__NR_POSIX + 169)
+#define __NR_POSIX_reserved2 (__NR_POSIX + 170)
+#define __NR_POSIX_reserved3 (__NR_POSIX + 171)
+#define __NR_POSIX_reserved4 (__NR_POSIX + 172)
+#define __NR_POSIX_reserved5 (__NR_POSIX + 173)
+#define __NR_POSIX_reserved6 (__NR_POSIX + 174)
+#define __NR_POSIX_reserved7 (__NR_POSIX + 175)
+#define __NR_POSIX_reserved8 (__NR_POSIX + 176)
+#define __NR_POSIX_reserved9 (__NR_POSIX + 177)
+#define __NR_POSIX_reserved10 (__NR_POSIX + 178)
+#define __NR_POSIX_reserved11 (__NR_POSIX + 179)
+#define __NR_POSIX_reserved12 (__NR_POSIX + 180)
+#define __NR_POSIX_reserved13 (__NR_POSIX + 181)
+#define __NR_POSIX_reserved14 (__NR_POSIX + 182)
+#define __NR_POSIX_reserved15 (__NR_POSIX + 183)
+#define __NR_POSIX_reserved16 (__NR_POSIX + 184)
+#define __NR_POSIX_reserved17 (__NR_POSIX + 185)
+#define __NR_POSIX_reserved18 (__NR_POSIX + 186)
+#define __NR_POSIX_reserved19 (__NR_POSIX + 187)
+#define __NR_POSIX_reserved20 (__NR_POSIX + 188)
+#define __NR_POSIX_reserved21 (__NR_POSIX + 189)
+#define __NR_POSIX_reserved22 (__NR_POSIX + 190)
+#define __NR_POSIX_reserved23 (__NR_POSIX + 191)
+#define __NR_POSIX_reserved24 (__NR_POSIX + 192)
+#define __NR_POSIX_reserved25 (__NR_POSIX + 193)
+#define __NR_POSIX_reserved26 (__NR_POSIX + 194)
+#define __NR_POSIX_reserved27 (__NR_POSIX + 195)
+#define __NR_POSIX_reserved28 (__NR_POSIX + 196)
+#define __NR_POSIX_reserved29 (__NR_POSIX + 197)
+#define __NR_POSIX_reserved30 (__NR_POSIX + 198)
+#define __NR_POSIX_reserved31 (__NR_POSIX + 199)
+#define __NR_POSIX_reserved32 (__NR_POSIX + 200)
+#define __NR_POSIX_reserved33 (__NR_POSIX + 201)
+#define __NR_POSIX_reserved34 (__NR_POSIX + 202)
+#define __NR_POSIX_reserved35 (__NR_POSIX + 203)
+#define __NR_POSIX_reserved36 (__NR_POSIX + 204)
+#define __NR_POSIX_reserved37 (__NR_POSIX + 205)
+#define __NR_POSIX_reserved38 (__NR_POSIX + 206)
+#define __NR_POSIX_reserved39 (__NR_POSIX + 207)
+#define __NR_POSIX_reserved40 (__NR_POSIX + 208)
+#define __NR_POSIX_reserved41 (__NR_POSIX + 209)
+#define __NR_POSIX_reserved42 (__NR_POSIX + 210)
+#define __NR_POSIX_reserved43 (__NR_POSIX + 211)
+#define __NR_POSIX_reserved44 (__NR_POSIX + 212)
+#define __NR_POSIX_reserved45 (__NR_POSIX + 213)
+#define __NR_POSIX_reserved46 (__NR_POSIX + 214)
+#define __NR_POSIX_reserved47 (__NR_POSIX + 215)
+#define __NR_POSIX_reserved48 (__NR_POSIX + 216)
+#define __NR_POSIX_reserved49 (__NR_POSIX + 217)
+#define __NR_POSIX_reserved50 (__NR_POSIX + 218)
+#define __NR_POSIX_reserved51 (__NR_POSIX + 219)
+#define __NR_POSIX_reserved52 (__NR_POSIX + 220)
+#define __NR_POSIX_reserved53 (__NR_POSIX + 221)
+#define __NR_POSIX_reserved54 (__NR_POSIX + 222)
+#define __NR_POSIX_reserved55 (__NR_POSIX + 223)
+#define __NR_POSIX_reserved56 (__NR_POSIX + 224)
+#define __NR_POSIX_reserved57 (__NR_POSIX + 225)
+#define __NR_POSIX_reserved58 (__NR_POSIX + 226)
+#define __NR_POSIX_reserved59 (__NR_POSIX + 227)
+#define __NR_POSIX_reserved60 (__NR_POSIX + 228)
+#define __NR_POSIX_reserved61 (__NR_POSIX + 229)
+#define __NR_POSIX_reserved62 (__NR_POSIX + 230)
+#define __NR_POSIX_reserved63 (__NR_POSIX + 231)
+#define __NR_POSIX_reserved64 (__NR_POSIX + 232)
+#define __NR_POSIX_reserved65 (__NR_POSIX + 233)
+#define __NR_POSIX_reserved66 (__NR_POSIX + 234)
+#define __NR_POSIX_reserved67 (__NR_POSIX + 235)
+#define __NR_POSIX_reserved68 (__NR_POSIX + 236)
+#define __NR_POSIX_reserved69 (__NR_POSIX + 237)
+#define __NR_POSIX_reserved70 (__NR_POSIX + 238)
+#define __NR_POSIX_reserved71 (__NR_POSIX + 239)
+#define __NR_POSIX_reserved72 (__NR_POSIX + 240)
+#define __NR_POSIX_reserved73 (__NR_POSIX + 241)
+#define __NR_POSIX_reserved74 (__NR_POSIX + 242)
+#define __NR_POSIX_reserved75 (__NR_POSIX + 243)
+#define __NR_POSIX_reserved76 (__NR_POSIX + 244)
+#define __NR_POSIX_reserved77 (__NR_POSIX + 245)
+#define __NR_POSIX_reserved78 (__NR_POSIX + 246)
+#define __NR_POSIX_reserved79 (__NR_POSIX + 247)
+#define __NR_POSIX_reserved80 (__NR_POSIX + 248)
+#define __NR_POSIX_reserved81 (__NR_POSIX + 249)
+#define __NR_POSIX_reserved82 (__NR_POSIX + 250)
+#define __NR_POSIX_reserved83 (__NR_POSIX + 251)
+#define __NR_POSIX_reserved84 (__NR_POSIX + 252)
+#define __NR_POSIX_reserved85 (__NR_POSIX + 253)
+#define __NR_POSIX_reserved86 (__NR_POSIX + 254)
+#define __NR_POSIX_reserved87 (__NR_POSIX + 255)
+#define __NR_POSIX_reserved88 (__NR_POSIX + 256)
+#define __NR_POSIX_reserved89 (__NR_POSIX + 257)
+#define __NR_POSIX_reserved90 (__NR_POSIX + 258)
+#define __NR_POSIX_reserved91 (__NR_POSIX + 259)
+#define __NR_POSIX_netboot (__NR_POSIX + 260)
+#define __NR_POSIX_netunboot (__NR_POSIX + 261)
+#define __NR_POSIX_rdump (__NR_POSIX + 262)
+#define __NR_POSIX_setsid (__NR_POSIX + 263)
+#define __NR_POSIX_getmaxsig (__NR_POSIX + 264)
+#define __NR_POSIX_sigpending (__NR_POSIX + 265)
+#define __NR_POSIX_sigprocmask (__NR_POSIX + 266)
+#define __NR_POSIX_sigsuspend (__NR_POSIX + 267)
+#define __NR_POSIX_sigaction (__NR_POSIX + 268)
+#define __NR_POSIX_MIPS_reserved1 (__NR_POSIX + 269)
+#define __NR_POSIX_MIPS_reserved2 (__NR_POSIX + 270)
+#define __NR_POSIX_MIPS_reserved3 (__NR_POSIX + 271)
+#define __NR_POSIX_MIPS_reserved4 (__NR_POSIX + 272)
+#define __NR_POSIX_MIPS_reserved5 (__NR_POSIX + 273)
+#define __NR_POSIX_MIPS_reserved6 (__NR_POSIX + 274)
+#define __NR_POSIX_MIPS_reserved7 (__NR_POSIX + 275)
+#define __NR_POSIX_MIPS_reserved8 (__NR_POSIX + 276)
+#define __NR_POSIX_MIPS_reserved9 (__NR_POSIX + 277)
+#define __NR_POSIX_MIPS_reserved10 (__NR_POSIX + 278)
+#define __NR_POSIX_MIPS_reserved11 (__NR_POSIX + 279)
+#define __NR_POSIX_TANDEM_reserved1 (__NR_POSIX + 280)
+#define __NR_POSIX_TANDEM_reserved2 (__NR_POSIX + 281)
+#define __NR_POSIX_TANDEM_reserved3 (__NR_POSIX + 282)
+#define __NR_POSIX_TANDEM_reserved4 (__NR_POSIX + 283)
+#define __NR_POSIX_TANDEM_reserved5 (__NR_POSIX + 284)
+#define __NR_POSIX_TANDEM_reserved6 (__NR_POSIX + 285)
+#define __NR_POSIX_TANDEM_reserved7 (__NR_POSIX + 286)
+#define __NR_POSIX_TANDEM_reserved8 (__NR_POSIX + 287)
+#define __NR_POSIX_TANDEM_reserved9 (__NR_POSIX + 288)
+#define __NR_POSIX_TANDEM_reserved10 (__NR_POSIX + 289)
+#define __NR_POSIX_TANDEM_reserved11 (__NR_POSIX + 290)
+#define __NR_POSIX_TANDEM_reserved12 (__NR_POSIX + 291)
+#define __NR_POSIX_TANDEM_reserved13 (__NR_POSIX + 292)
+#define __NR_POSIX_TANDEM_reserved14 (__NR_POSIX + 293)
+#define __NR_POSIX_TANDEM_reserved15 (__NR_POSIX + 294)
+#define __NR_POSIX_TANDEM_reserved16 (__NR_POSIX + 295)
+#define __NR_POSIX_TANDEM_reserved17 (__NR_POSIX + 296)
+#define __NR_POSIX_TANDEM_reserved18 (__NR_POSIX + 297)
+#define __NR_POSIX_TANDEM_reserved19 (__NR_POSIX + 298)
+#define __NR_POSIX_TANDEM_reserved20 (__NR_POSIX + 299)
+#define __NR_POSIX_SGI_reserved7 (__NR_POSIX + 300)
+#define __NR_POSIX_SGI_reserved8 (__NR_POSIX + 301)
+#define __NR_POSIX_SGI_reserved9 (__NR_POSIX + 302)
+#define __NR_POSIX_SGI_reserved10 (__NR_POSIX + 303)
+#define __NR_POSIX_SGI_reserved11 (__NR_POSIX + 304)
+#define __NR_POSIX_SGI_reserved12 (__NR_POSIX + 305)
+#define __NR_POSIX_SGI_reserved13 (__NR_POSIX + 306)
+#define __NR_POSIX_SGI_reserved14 (__NR_POSIX + 307)
+#define __NR_POSIX_SGI_reserved15 (__NR_POSIX + 308)
+#define __NR_POSIX_SGI_reserved16 (__NR_POSIX + 309)
+#define __NR_POSIX_SGI_reserved17 (__NR_POSIX + 310)
+#define __NR_POSIX_SGI_reserved18 (__NR_POSIX + 311)
+#define __NR_POSIX_SGI_reserved19 (__NR_POSIX + 312)
+#define __NR_POSIX_SGI_reserved20 (__NR_POSIX + 313)
+#define __NR_POSIX_SGI_reserved21 (__NR_POSIX + 314)
+#define __NR_POSIX_SGI_reserved22 (__NR_POSIX + 315)
+#define __NR_POSIX_SGI_reserved23 (__NR_POSIX + 316)
+#define __NR_POSIX_SGI_reserved24 (__NR_POSIX + 317)
+#define __NR_POSIX_SGI_reserved25 (__NR_POSIX + 318)
+#define __NR_POSIX_SGI_reserved26 (__NR_POSIX + 319)
+
+/*
+ * Linux syscalls are in the range from 4000 to 4999
+ * Hopefully these syscall numbers are unused ... If not everyone using
+ * statically linked binaries is pretty upsh*t. You've been warned.
+ */
+#define __NR_Linux 4000
+#define __NR_syscall (__NR_Linux + 0)
+#define __NR_exit (__NR_Linux + 1)
+#define __NR_fork (__NR_Linux + 2)
+#define __NR_read (__NR_Linux + 3)
+#define __NR_write (__NR_Linux + 4)
+#define __NR_open (__NR_Linux + 5)
+#define __NR_close (__NR_Linux + 6)
+#define __NR_waitpid (__NR_Linux + 7)
+#define __NR_creat (__NR_Linux + 8)
+#define __NR_link (__NR_Linux + 9)
+#define __NR_unlink (__NR_Linux + 10)
+#define __NR_execve (__NR_Linux + 11)
+#define __NR_chdir (__NR_Linux + 12)
+#define __NR_time (__NR_Linux + 13)
+#define __NR_mknod (__NR_Linux + 14)
+#define __NR_chmod (__NR_Linux + 15)
+#define __NR_chown (__NR_Linux + 16)
+#define __NR_break (__NR_Linux + 17)
+#define __NR_oldstat (__NR_Linux + 18)
+#define __NR_lseek (__NR_Linux + 19)
+#define __NR_getpid (__NR_Linux + 20)
+#define __NR_mount (__NR_Linux + 21)
+#define __NR_umount (__NR_Linux + 22)
+#define __NR_setuid (__NR_Linux + 23)
+#define __NR_getuid (__NR_Linux + 24)
+#define __NR_stime (__NR_Linux + 25)
+#define __NR_ptrace (__NR_Linux + 26)
+#define __NR_alarm (__NR_Linux + 27)
+#define __NR_oldfstat (__NR_Linux + 28)
+#define __NR_pause (__NR_Linux + 29)
+#define __NR_utime (__NR_Linux + 30)
+#define __NR_stty (__NR_Linux + 31)
+#define __NR_gtty (__NR_Linux + 32)
+#define __NR_access (__NR_Linux + 33)
+#define __NR_nice (__NR_Linux + 34)
+#define __NR_ftime (__NR_Linux + 35)
+#define __NR_sync (__NR_Linux + 36)
+#define __NR_kill (__NR_Linux + 37)
+#define __NR_rename (__NR_Linux + 38)
+#define __NR_mkdir (__NR_Linux + 39)
+#define __NR_rmdir (__NR_Linux + 40)
+#define __NR_dup (__NR_Linux + 41)
+#define __NR_pipe (__NR_Linux + 42)
+#define __NR_times (__NR_Linux + 43)
+#define __NR_prof (__NR_Linux + 44)
+#define __NR_brk (__NR_Linux + 45)
+#define __NR_setgid (__NR_Linux + 46)
+#define __NR_getgid (__NR_Linux + 47)
+#define __NR_signal (__NR_Linux + 48)
+#define __NR_geteuid (__NR_Linux + 49)
+#define __NR_getegid (__NR_Linux + 50)
+#define __NR_acct (__NR_Linux + 51)
+#define __NR_phys (__NR_Linux + 52)
+#define __NR_lock (__NR_Linux + 53)
+#define __NR_ioctl (__NR_Linux + 54)
+#define __NR_fcntl (__NR_Linux + 55)
+#define __NR_mpx (__NR_Linux + 56)
+#define __NR_setpgid (__NR_Linux + 57)
+#define __NR_ulimit (__NR_Linux + 58)
+#define __NR_oldolduname (__NR_Linux + 59)
+#define __NR_umask (__NR_Linux + 60)
+#define __NR_chroot (__NR_Linux + 61)
+#define __NR_ustat (__NR_Linux + 62)
+#define __NR_dup2 (__NR_Linux + 63)
+#define __NR_getppid (__NR_Linux + 64)
+#define __NR_getpgrp (__NR_Linux + 65)
+#define __NR_setsid (__NR_Linux + 66)
+#define __NR_sigaction (__NR_Linux + 67)
+#define __NR_sgetmask (__NR_Linux + 68)
+#define __NR_ssetmask (__NR_Linux + 69)
+#define __NR_setreuid (__NR_Linux + 70)
+#define __NR_setregid (__NR_Linux + 71)
+#define __NR_sigsuspend (__NR_Linux + 72)
+#define __NR_sigpending (__NR_Linux + 73)
+#define __NR_sethostname (__NR_Linux + 74)
+#define __NR_setrlimit (__NR_Linux + 75)
+#define __NR_getrlimit (__NR_Linux + 76)
+#define __NR_getrusage (__NR_Linux + 77)
+#define __NR_gettimeofday (__NR_Linux + 78)
+#define __NR_settimeofday (__NR_Linux + 79)
+#define __NR_getgroups (__NR_Linux + 80)
+#define __NR_setgroups (__NR_Linux + 81)
+#define __NR_select (__NR_Linux + 82)
+#define __NR_symlink (__NR_Linux + 83)
+#define __NR_oldlstat (__NR_Linux + 84)
+#define __NR_readlink (__NR_Linux + 85)
+#define __NR_uselib (__NR_Linux + 86)
+#define __NR_swapon (__NR_Linux + 87)
+#define __NR_reboot (__NR_Linux + 88)
+#define __NR_readdir (__NR_Linux + 89)
+#define __NR_mmap (__NR_Linux + 90)
+#define __NR_munmap (__NR_Linux + 91)
+#define __NR_truncate (__NR_Linux + 92)
+#define __NR_ftruncate (__NR_Linux + 93)
+#define __NR_fchmod (__NR_Linux + 94)
+#define __NR_fchown (__NR_Linux + 95)
+#define __NR_getpriority (__NR_Linux + 96)
+#define __NR_setpriority (__NR_Linux + 97)
+#define __NR_profil (__NR_Linux + 98)
+#define __NR_statfs (__NR_Linux + 99)
+#define __NR_fstatfs (__NR_Linux + 100)
+#define __NR_ioperm (__NR_Linux + 101)
+#define __NR_socketcall (__NR_Linux + 102)
+#define __NR_syslog (__NR_Linux + 103)
+#define __NR_setitimer (__NR_Linux + 104)
+#define __NR_getitimer (__NR_Linux + 105)
+#define __NR_stat (__NR_Linux + 106)
+#define __NR_lstat (__NR_Linux + 107)
+#define __NR_fstat (__NR_Linux + 108)
+#define __NR_olduname (__NR_Linux + 109)
+#define __NR_iopl (__NR_Linux + 110)
+#define __NR_vhangup (__NR_Linux + 111)
+#define __NR_idle (__NR_Linux + 112)
+#define __NR_vm86 (__NR_Linux + 113)
+#define __NR_wait4 (__NR_Linux + 114)
+#define __NR_swapoff (__NR_Linux + 115)
+#define __NR_sysinfo (__NR_Linux + 116)
+#define __NR_ipc (__NR_Linux + 117)
+#define __NR_fsync (__NR_Linux + 118)
+#define __NR_sigreturn (__NR_Linux + 119)
+#define __NR_clone (__NR_Linux + 120)
+#define __NR_setdomainname (__NR_Linux + 121)
+#define __NR_uname (__NR_Linux + 122)
+#define __NR_modify_ldt (__NR_Linux + 123)
+#define __NR_adjtimex (__NR_Linux + 124)
+#define __NR_mprotect (__NR_Linux + 125)
+#define __NR_sigprocmask (__NR_Linux + 126)
+#define __NR_create_module (__NR_Linux + 127)
+#define __NR_init_module (__NR_Linux + 128)
+#define __NR_delete_module (__NR_Linux + 129)
+#define __NR_get_kernel_syms (__NR_Linux + 130)
+#define __NR_quotactl (__NR_Linux + 131)
+#define __NR_getpgid (__NR_Linux + 132)
+#define __NR_fchdir (__NR_Linux + 133)
+#define __NR_bdflush (__NR_Linux + 134)
+#define __NR_sysfs (__NR_Linux + 135)
+#define __NR_personality (__NR_Linux + 136)
+#define __NR_afs_syscall (__NR_Linux + 137) /* Syscall for Andrew File System */
+#define __NR_setfsuid (__NR_Linux + 138)
+#define __NR_setfsgid (__NR_Linux + 139)
+#define __NR__llseek (__NR_Linux + 140)
+#define __NR_getdents (__NR_Linux + 141)
+#define __NR__newselect (__NR_Linux + 142)
+#define __NR_flock (__NR_Linux + 143)
+#define __NR_msync (__NR_Linux + 144)
+#define __NR_readv (__NR_Linux + 145)
+#define __NR_writev (__NR_Linux + 146)
+#define __NR_cacheflush (__NR_Linux + 147)
+#define __NR_cachectl (__NR_Linux + 148)
+#define __NR_sysmips (__NR_Linux + 149)
+#define __NR_setup (__NR_Linux + 150) /* used only by init, to get system going */
+#define __NR_getsid (__NR_Linux + 151)
+#define __NR_reserved1 (__NR_Linux + 152)
+#define __NR_reserved2 (__NR_Linux + 153)
+#define __NR_mlock (__NR_Linux + 154)
+#define __NR_munlock (__NR_Linux + 155)
+#define __NR_mlockall (__NR_Linux + 156)
+#define __NR_munlockall (__NR_Linux + 157)
+
-#include <asm/mipsconfig.h>
/*
- * Ugly kludge to enforce 32bit mode proof code.
- * Access errno via USEG, not KSEGx for internal kernel syscalls
+ * Offset of the last Linux flavoured syscall
*/
-#define errno (*(int *)((unsigned long)&errno - KERNELBASE))
+#define __NR_Linux_syscalls 157
-#endif /* __KERNEL__ */
+#ifndef __LANGUAGE_ASSEMBLY__
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
type name(void) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile ("syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name)); \
-if (__res >= 0) \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("li\t$2,%2\n\t" \
+ "syscall" \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name)); \
+if (__err == 0) \
return (type) __res; \
-errno = -__res; \
+errno = __res; \
return -1; \
}
+/*
+ * DANGER: This macro isn't usable for the pipe(2) call
+ * which has a unusual return convention.
+ */
#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile ("move\t$4,%2\n\t" \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("move\t$4,%3\n\t" \
+ "li\t$2,%2\n\t" \
"syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name),"r" ((long)(a)) \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name),"r" ((long)(a)) \
: "$4"); \
-if (__res >= 0) \
+if (__err == 0) \
return (type) __res; \
-errno = -__res; \
+errno = __res; \
return -1; \
}
type name(atype a,btype b) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile ("move\t$4,%2\n\t" \
- "move\t$5,%3\n\t" \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("move\t$4,%3\n\t" \
+ "move\t$5,%4\n\t" \
+ "li\t$2,%2\n\t" \
"syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name),"r" ((long)(a)), \
- "r" ((long)(b))); \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name),"r" ((long)(a)), \
+ "r" ((long)(b)) \
: "$4","$5"); \
-if (__res >= 0) \
+if (__err == 0) \
return (type) __res; \
-errno = -__res; \
+errno = __res; \
return -1; \
}
type name (atype a, btype b, ctype c) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile ("move\t$4,%2\n\t" \
- "move\t$5,%3\n\t" \
- "move\t$6,%4\n\t" \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("move\t$4,%3\n\t" \
+ "move\t$5,%4\n\t" \
+ "move\t$6,%5\n\t" \
+ "li\t$2,%2\n\t" \
"syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name),"r" ((long)(a)), \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name),"r" ((long)(a)), \
"r" ((long)(b)), \
"r" ((long)(c)) \
: "$4","$5","$6"); \
-if (__res>=0) \
+if (__err == 0) \
return (type) __res; \
-errno=-__res; \
+errno = __res; \
return -1; \
}
type name (atype a, btype b, ctype c, dtype d) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile (".set\tnoat\n\t" \
- "move\t$4,%2\n\t" \
- "move\t$5,%3\n\t" \
- "move\t$6,%4\n\t" \
- "move\t$7,%5\n\t" \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("move\t$4,%3\n\t" \
+ "move\t$5,%4\n\t" \
+ "move\t$6,%5\n\t" \
+ "move\t$7,%6\n\t" \
+ "li\t$2,%2\n\t" \
"syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name),"r" ((long)(a)), \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name),"r" ((long)(a)), \
"r" ((long)(b)), \
"r" ((long)(c)), \
"r" ((long)(d)) \
- : "$4","$5","$6","$7"); \
-if (__res>=0) \
+ : "$4","$5","$6"); \
+if (__err == 0) \
return (type) __res; \
-errno=-__res; \
+errno = __res; \
return -1; \
}
type name (atype a,btype b,ctype c,dtype d,etype e) \
{ \
register long __res __asm__ ("$2"); \
-__asm__ volatile (".set\tnoat\n\t" \
- "move\t$4,%2\n\t" \
- "move\t$5,%3\n\t" \
- "move\t$6,%4\n\t" \
- "move\t$7,%5\n\t" \
- "move\t$3,%6\n\t" \
+register long __err __asm__ ("$7"); \
+__asm__ volatile ("move\t$4,%3\n\t" \
+ "move\t$5,%4\n\t" \
+ "move\t$6,%5\n\t" \
+ "move\t$7,%6\n\t" \
+ "move\t$3,%7\n\t" \
+ "li\t$2,%2\n\t" \
"syscall" \
- : "=r" (__res) \
- : "0" (__NR_##name),"r" ((long)(a)), \
+ : "=r" (__res), "=r" (__err) \
+ : "i" (__NR_##name),"r" ((long)(a)), \
"r" ((long)(b)), \
"r" ((long)(c)), \
"r" ((long)(d)), \
"r" ((long)(e)) \
- : "$3","$4","$5","$6","$7"); \
-if (__res>=0) \
+ : "$3","$4","$5","$6"); \
+if (__err == 0) \
return (type) __res; \
-errno=-__res; \
+errno = __res; \
return -1; \
}
+#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.
+ */
+#define __NR__exit __NR_exit
+static inline _syscall0(int,idle)
+static inline _syscall0(int,fork)
+static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+static inline _syscall0(int,pause)
+static inline _syscall0(int,setup)
+static inline _syscall0(int,sync)
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
+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 pid_t wait(int * wait_stat)
+{
+ return waitpid(-1,wait_stat,0);
+}
+
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process(ie the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ */
+static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+
+ __asm__ __volatile__(
+ ".set\tnoreorder\n\t"
+ "move\t$8,$sp\n\t"
+ "move\t$4,%5\n\t"
+ "li\t$2,%1\n\t"
+ "syscall\n\t"
+ "beq\t$8,$sp,1f\n\t"
+ "subu\t$sp,16\n\t" /* delay slot */
+ "jalr\t%4\n\t"
+ "move\t$4,%3\n\t" /* delay slot */
+ "move\t$4,$2\n\t"
+ "li\t$2,%2\n\t"
+ "syscall\n"
+ "1:\taddiu\t$sp,16\n\t"
+ "move\t%0,$2\n\t"
+ ".set\treorder"
+ :"=r" (retval)
+ :"i" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "r" (fn),
+ "r" (flags | CLONE_VM)
+ /*
+ * The called subroutine might have destroyed any of the
+ * at, result, argument or temporary registers ...
+ */
+ :"$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+ "$9","$10","$11","$12","$13","$14","$15","$24","$25");
+
+ return retval;
+}
+
+#endif /* !defined (__KERNEL_SYSCALLS__) */
+#endif /* !defined (__LANGUAGE_ASSEMBLY__) */
+
#endif /* __ASM_MIPS_UNISTD_H */
--- /dev/null
+#ifndef __ASM_MIPS_USER_H
+#define __ASM_MIPS_USER_H
+
+#include <linux/ptrace.h>
+
+#include <asm/page.h>
+#include <asm/reg.h>
+
+/*
+ * Core file format: The core file is written in such a way that gdb
+ * can understand it and provide useful information to the user (under
+ * linux we use the `trad-core' bfd, NOT the osf-core). The file contents
+ * are as follows:
+ *
+ * upage: 1 page consisting of a user struct that tells gdb
+ * what is present in the file. Directly after this is a
+ * copy of the task_struct, which is currently not used by gdb,
+ * but it may come in handy at some point. All of the registers
+ * are stored as part of the upage. The upage should always be
+ * only one page long.
+ * data: The data segment follows next. We use current->end_text to
+ * current->brk to pick up all of the user variables, plus any memory
+ * that may have been sbrk'ed. No attempt is made to determine if a
+ * page is demand-zero or if a page is totally unused, we just cover
+ * the entire range. All of the addresses are rounded in such a way
+ * that an integral number of pages is written.
+ * stack: We need the stack information in order to get a meaningful
+ * backtrace. We need to write the data from usp to
+ * current->start_stack, so we round each of these in order to be able
+ * to write an integer number of pages.
+ */
+struct user {
+ unsigned long regs[EF_SIZE/8+32]; /* integer and fp regs */
+ size_t u_tsize; /* text size (pages) */
+ size_t u_dsize; /* data size (pages) */
+ size_t u_ssize; /* stack size (pages) */
+ unsigned long start_code; /* text starting address */
+ unsigned long start_data; /* data starting address */
+ unsigned long start_stack; /* stack starting address */
+ long int signal; /* signal causing core dump */
+ struct regs * u_ar0; /* help gdb find registers */
+ unsigned long magic; /* identifies a core file */
+ char u_comm[32]; /* user command name */
+};
+
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_DATA_START_ADDR (u.start_data)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif /* __ASM_MIPS_USER_H */
--- /dev/null
+/*
+ * include/asm-mips/vector.h
+ *
+ * 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.
+ *
+ * Copyright (C) 1995 by Ralf Baechle
+ */
+#ifndef __ASM_MIPS_VECTOR_H
+#define __ASM_MIPS_VECTOR_H
+
+/*
+ * This structure defines how to access various features of
+ * different machine types and how to access them.
+ *
+ * FIXME: More things need to be accessed via this vector.
+ */
+struct feature {
+ void (*handle_int)(void);
+ /*
+ * How to access the floppy controller's ports.
+ */
+ unsigned char (*fd_inb)(unsigned int port);
+ void (*fd_outb)(unsigned char value, unsigned int port);
+ /*
+ * How to access the floppy DMA functions.
+ */
+ void (*fd_enable_dma)(void);
+ void (*fd_disable_dma)(void);
+ int (*fd_request_dma)(void);
+ void (*fd_free_dma)(void);
+ void (*fd_clear_dma_ff)(void);
+ void (*fd_set_dma_mode)(char mode);
+ void (*fd_set_dma_addr)(unsigned int a);
+ void (*fd_set_dma_count)(unsigned int count);
+ int (*fd_get_dma_residue)(void);
+ void (*fd_enable_irq)(void);
+ void (*fd_disable_irq)(void);
+ void (*fd_cacheflush)(unsigned char *addr, unsigned int size);
+ /*
+ * How to access the RTC register of DS1287
+ */
+ unsigned char (*rtc_read_data)(void);
+ void (*rtc_write_data)(unsigned char);
+};
+
+/*
+ * Similar to the above this is a structure that describes various
+ * CPU dependend features.
+ *
+ * FIXME: This vector isn't being used yet
+ */
+struct cpu {
+ int dummy; /* keep GCC from complaining */
+};
+
+extern struct feature *feature;
+extern struct cpu *cpu;
+
+#endif /* __ASM_MIPS_VECTOR_H */
#endif
/* skip a bunch so we don't run into any of sun's numbers */
M_386 = 100,
+ M_MIPS1 = 151, /* MIPS R3000/R3000 binary */
+ M_MIPS2 = 152, /* MIPS R6000/R4000 binary */
};
#if !defined (N_MAGIC)
#endif
extern void set_device_ro(kdev_t dev,int flag);
+void add_blkdev_randomness(int major);
extern int floppy_init(void);
extern void rd_load(void);
-extern long rd_init(long mem_start, int length);
-extern int ramdisk_size;
+extern int rd_init(void);
+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 */
#define RO_IOCTLS(dev,where) \
case BLKROSET: if (!suser()) return -EACCES; \
#define DEVICE_ON(device) /* nothing */
#define DEVICE_OFF(device) /* nothing */
-#elif (MAJOR_NR == MEM_MAJOR)
+#elif (MAJOR_NR == RAMDISK_MAJOR)
/* ram disk */
#define DEVICE_NAME "ramdisk"
-#define DEVICE_REQUEST do_rd_request
-#define DEVICE_NR(device) (MINOR(device) & 7)
+#define DEVICE_REQUEST rd_request
+#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#define DEVICE_NO_RANDOM
#elif (MAJOR_NR == FLOPPY_MAJOR)
return;
}
}
+#ifndef DEVICE_NO_RANDOM
+ add_blkdev_randomness(MAJOR(req->rq_dev));
+#endif
#ifdef IDE_DRIVER
blk_dev[MAJOR(req->rq_dev)].current_request = req->next;
hwgroup->rq = NULL;
/*--------- LOGITECH BUSMOUSE ITEMS -------------*/
+#define LOGIBM_BASE 0x23c
#define MSE_DATA_PORT 0x23c
#define MSE_SIGNATURE_PORT 0x23d
#define MSE_CONTROL_PORT 0x23e
-#define MSE_INTERRUPT_PORT 0x23e
+#define MSE_INTERRUPT_PORT 0x23e
#define MSE_CONFIG_PORT 0x23f
+#define LOGIBM_EXTENT 0x4
#define MSE_ENABLE_INTERRUPTS 0x00
#define MSE_DISABLE_INTERRUPTS 0x10
/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/
+#define MSBM_BASE 0x23d
#define MS_MSE_DATA_PORT 0x23d
#define MS_MSE_SIGNATURE_PORT 0x23e
#define MS_MSE_CONTROL_PORT 0x23c
#define MS_MSE_CONFIG_PORT 0x23f
+#define MSBM_EXTENT 0x3
#define MS_MSE_ENABLE_INTERRUPTS 0x11
#define MS_MSE_DISABLE_INTERRUPTS 0x10
#include <linux/kdev_t.h>
#include <linux/ioctl.h>
-#include <asm/bitops.h>
-
/*
* It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
* that later. Anyway, now the file code is no longer dependent
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
#ifdef __KERNEL__
+
+#include <asm/bitops.h>
+
extern void buffer_init(void);
extern unsigned long inode_init(unsigned long start, unsigned long end);
extern unsigned long file_table_init(unsigned long start, unsigned long end);
#define BH_Req 3 /* 0 if the buffer has been invalidated */
#define BH_Touched 4 /* 1 if the buffer has been touched (aging) */
#define BH_Has_aged 5 /* 1 if the buffer has been aged (aging) */
+#define BH_Protected 6 /* 1 if the buffer is protected */
struct buffer_head {
char * b_data; /* pointer to data block (1024 bytes) */
return test_bit(BH_Has_aged, &bh->b_state);
}
+static inline int buffer_protected(struct buffer_head * bh)
+{
+ return test_bit(BH_Protected, &bh->b_state);
+}
+
#include <linux/pipe_fs_i.h>
#include <linux/minix_fs_i.h>
#include <linux/ext_fs_i.h>
#define UNNAMED_MAJOR 0
#define MEM_MAJOR 1
+#define RAMDISK_MAJOR 1
#define FLOPPY_MAJOR 2
#define PTY_MASTER_MAJOR 2
#define IDE0_MAJOR 3
struct vfsmount
{
- dev_t mnt_dev; /* Device this applies to */
+ kdev_t mnt_dev; /* Device this applies to */
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
char *mnt_dirname; /* Name of directory mounted on */
unsigned int mnt_flags; /* Flags of this device */
struct vfsmount *mnt_next; /* pointer to next in linkedlist */
};
-struct vfsmount *lookup_vfsmnt(dev_t dev);
+struct vfsmount *lookup_vfsmnt(kdev_t dev);
#endif /* _LINUX_MOUNT_H */
int reserved[32];
};
+/*
+ * Serial input interrupt line counters -- external structure
+ * Four lines can interrupt: CTS, DSR, RI, DCD
+ */
+struct serial_icounter_struct {
+ int cts, dsr, rng, dcd;
+ int reserved[16];
+};
+
+
#ifdef __KERNEL__
/*
* This is our internal structure for each serial port's state.
#include <linux/termios.h>
#include <linux/tqueue.h>
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+struct async_icount {
+ __u32 cts, dsr, rng, dcd;
+};
+
struct async_struct {
int magic;
int baud_base;
struct termios callout_termios;
struct wait_queue *open_wait;
struct wait_queue *close_wait;
+ struct wait_queue *delta_msr_wait;
+ struct async_icount icount; /* kernel counters for the 4 input interrupts */
struct async_struct *next_port; /* For the linked list */
struct async_struct *prev_port;
};
extern long console_init(long, long);
extern long kmalloc_init(long,long);
extern void sock_init(void);
-extern long rd_init(long mem_start, int length);
extern long pci_init(long, long);
extern void swap_setup(char *str, int *ints);
#ifdef CONFIG_SJCD
extern void sjcd_setup(char *str, int *ints);
#endif CONFIG_SJCD
-static void ramdisk_setup(char *str, int *ints);
+static void ramdisk_start_setup(char *str, int *ints);
+static void load_ramdisk(char *str, int *ints);
+static void prompt_ramdisk(char *str, int *ints);
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
int rows, cols;
-int ramdisk_size;
+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 */
int root_mountflags = MS_RDONLY;
char *execute_command = 0;
} bootsetups[] = {
{ "reserve=", reserve_setup },
{ "profile=", profile_setup },
- { "ramdisk=", ramdisk_setup },
+ { "ramdisk_start=", ramdisk_start_setup },
+ { "load_ramdisk", load_ramdisk },
+ { "prompt_ramdisk", prompt_ramdisk },
{ "swap=", swap_setup },
{ "buff=", buff_setup },
#ifdef CONFIG_BUGi386
{ 0, 0 }
};
-static void ramdisk_setup(char *str, int *ints)
+static void ramdisk_start_setup(char *str, int *ints)
{
if (ints[0] > 0 && ints[1] >= 0)
- ramdisk_size = ints[1];
+ rd_image_start = ints[1];
+}
+
+static void load_ramdisk(char *str, int *ints)
+{
+ rd_doload = 1;
+}
+
+static void prompt_ramdisk(char *str, int *ints)
+{
+ rd_prompt = 1;
}
static int checksetup(char *line)
memory_start = inode_init(memory_start,memory_end);
memory_start = file_table_init(memory_start,memory_end);
memory_start = name_cache_init(memory_start,memory_end);
- if (ramdisk_size)
- memory_start += rd_init(memory_start, ramdisk_size*1024);
mem_init(memory_start,memory_end);
buffer_init();
sock_init();
release_thread(p);
if (STACK_MAGIC != *(unsigned long *)p->kernel_stack_page)
printk(KERN_ALERT "release: %s kernel stack corruption. Aiee\n", p->comm);
- free_page(p->kernel_stack_page);
+ free_kernel_stack(p->kernel_stack_page);
current->cmin_flt += p->min_flt + p->cmin_flt;
current->cmaj_flt += p->maj_flt + p->cmaj_flt;
current->cnswap += p->nswap + p->cnswap;
/*
* Check to see if any process groups have become orphaned
* as a result of our exiting, and if they have any stopped
- * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2)
+ * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
*
* Case i: Our father is in a different pgrp than we are
* and we were the only connection outside, so our pgrp
p = (struct task_struct *) kmalloc(sizeof(*p), GFP_KERNEL);
if (!p)
goto bad_fork;
- new_stack = get_free_page(GFP_KERNEL);
+ new_stack = alloc_kernel_stack();
if (!new_stack)
goto bad_fork_free_p;
error = -EAGAIN;
REMOVE_LINKS(p);
nr_tasks--;
bad_fork_free_stack:
- free_page(new_stack);
+ free_kernel_stack(new_stack);
bad_fork_free_p:
kfree(p);
bad_fork:
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
+#include <linux/kernel_stat.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/ptrace.h>
X(do_gettimeofday),
X(loops_per_sec),
X(need_resched),
+ X(kstat),
X(kill_proc),
X(kill_pg),
X(kill_sl),
X(scsi_init_malloc),
X(scsi_init_free),
X(scsi_ioctl),
+ X(scsi_mark_host_bus_reset),
X(print_command),
X(print_msg),
X(print_status),
--- /dev/null
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+ version c10p1, 10 January 1993 */
+
+/*
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3
+ */
+
+/*
+ Inflate deflated (PKZIP's method 8 compressed) data. The compression
+ method searches for as much of the current string of bytes (up to a
+ length of 258) in the previous 32K bytes. If it doesn't find any
+ matches (of at least length 3), it codes the next byte. Otherwise, it
+ codes the length of the matched string and its distance backwards from
+ the current position. There is a single Huffman code that codes both
+ single bytes (called "literals") and match lengths. A second Huffman
+ code codes the distance information, which follows a length code. Each
+ length or distance code actually represents a base value and a number
+ of "extra" (sometimes zero) bits to get to add to the base value. At
+ the end of each deflated block is a special end-of-block (EOB) literal/
+ length code. The decoding process is basically: get a literal/length
+ code; if EOB then done; if a literal, emit the decoded byte; if a
+ length then get the distance and emit the referred-to bytes from the
+ sliding window of previously emitted data.
+
+ There are (currently) three kinds of inflate blocks: stored, fixed, and
+ dynamic. The compressor deals with some chunk of data at a time, and
+ decides which method to use on a chunk-by-chunk basis. A chunk might
+ typically be 32K or 64K. If the chunk is uncompressible, then the
+ "stored" method is used. In this case, the bytes are simply stored as
+ is, eight bits per byte, with none of the above coding. The bytes are
+ preceded by a count, since there is no longer an EOB code.
+
+ If the data is compressible, then either the fixed or dynamic methods
+ are used. In the dynamic method, the compressed data is preceded by
+ an encoding of the literal/length and distance Huffman codes that are
+ to be used to decode this block. The representation is itself Huffman
+ coded, and so is preceded by a description of that code. These code
+ descriptions take up a little space, and so for small blocks, there is
+ a predefined set of codes, called the fixed codes. The fixed method is
+ used if the block codes up smaller that way (usually for quite small
+ chunks), otherwise the dynamic method is used. In the latter case, the
+ codes are customized to the probabilities in the current block, and so
+ can code it much better than the pre-determined fixed codes.
+
+ The Huffman codes themselves are decoded using a mutli-level table
+ lookup, in order to maximize the speed of decoding plus the speed of
+ building the decoding tables. See the comments below that precede the
+ lbits and dbits tuning parameters.
+ */
+
+
+/*
+ Notes beyond the 1.93a appnote.txt:
+
+ 1. Distance pointers never point before the beginning of the output
+ stream.
+ 2. Distance pointers can point back across blocks, up to 32k away.
+ 3. There is an implied maximum of 7 bits for the bit length table and
+ 15 bits for the actual data.
+ 4. If only one code exists, then it is encoded using one bit. (Zero
+ would be more efficient, but perhaps a little confusing.) If two
+ codes exist, they are coded using one bit each (0 and 1).
+ 5. There is no way of sending zero distance codes--a dummy must be
+ sent if there are none. (History: a pre 2.0 version of PKZIP would
+ store blocks with no distance codes, but this was discovered to be
+ too harsh a criterion.) Valid only for 1.93a. 2.04c does allow
+ zero distance codes, which is sent as one code of zero bits in
+ length.
+ 6. There are up to 286 literal/length codes. Code 256 represents the
+ end-of-block. Note however that the static length tree defines
+ 288 codes just to fill out the Huffman codes. Codes 286 and 287
+ cannot be used though, since there is no length base or extra bits
+ defined for them. Similarly, there are up to 30 distance codes.
+ However, static trees define 32 codes (all 5 bits) to fill out the
+ Huffman codes, but the last two had better not show up in the data.
+ 7. Unzip can check dynamic Huffman blocks for complete code sets.
+ The exception is that a single code would not be complete (see #4).
+ 8. The five bits following the block type is really the number of
+ literal codes sent minus 257.
+ 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+ (1+6+6). Therefore, to output three times the length, you output
+ three codes (1+1+1), whereas to output four times the same length,
+ you only need two codes (1+3). Hmm.
+ 10. In the tree reconstruction algorithm, Code = Code + Increment
+ only if BitLength(i) is not zero. (Pretty obvious.)
+ 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19)
+ 12. Note: length code 284 can represent 227-258, but length code 285
+ really is 258. The last length deserves its own, short code
+ since it gets used a lot in very redundant files. The length
+ 258 is special since 258 - 3 (the min match length) is 255.
+ 13. The literal/length and distance code bit lengths are read as a
+ single stream of lengths. It is possible (and advantageous) for
+ a repeat code (16, 17, or 18) to go across the boundary between
+ the two sets of lengths.
+ */
+
+#ifdef RCSID
+static char rcsid[] = "#Id: inflate.c,v 0.14 1993/06/10 13:27:04 jloup Exp #";
+#endif
+
+#ifndef STATIC
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+# include <sys/types.h>
+# include <stdlib.h>
+#endif
+
+#include "gzip.h"
+#define STATIC
+#endif /* !STATIC */
+
+#define slide window
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+ that have 16-bit pointers (e.g. PC's in the small or medium model).
+ Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16
+ means that v is a literal, 16 < e < 32 means that v is a pointer to
+ the next table, which codes e - 16 bits, and lastly e == 99 indicates
+ an unused code. If a code with e == 99 is looked up, this implies an
+ error in the data. */
+struct huft {
+ uch e; /* number of extra bits or operation */
+ uch b; /* number of bits in this code or subcode */
+ union {
+ ush n; /* literal, length base, or distance base */
+ struct huft *t; /* pointer to next level of table */
+ } v;
+};
+
+
+/* Function prototypes */
+STATIC int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+ struct huft **, int *));
+STATIC int huft_free OF((struct huft *));
+STATIC int inflate_codes OF((struct huft *, struct huft *, int, int));
+STATIC int inflate_stored OF((void));
+STATIC int inflate_fixed OF((void));
+STATIC int inflate_dynamic OF((void));
+STATIC int inflate_block OF((int *));
+STATIC int inflate OF((void));
+
+
+/* The inflate algorithm uses a sliding 32K byte window on the uncompressed
+ stream to find repeated byte strings. This is implemented here as a
+ circular buffer. The index is updated simply by incrementing and then
+ and'ing with 0x7fff (32K-1). */
+/* It is left to other modules to supply the 32K area. It is assumed
+ to be usable as if it were declared "uch slide[32768];" or as just
+ "uch *slide;" and then malloc'ed in the latter case. The definition
+ must be in unzip.h, included above. */
+/* unsigned wp; current position in slide */
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = { /* Order of the bit length code lengths */
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = { /* Copy lengths for literal codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = { /* Extra bits for literal codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+static ush cpdext[] = { /* Extra bits for distance codes */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+
+
+/* Macros for inflate() bit peeking and grabbing.
+ The usage is:
+
+ NEEDBITS(j)
+ x = b & mask_bits[j];
+ DUMPBITS(j)
+
+ where NEEDBITS makes sure that b has at least j bits in it, and
+ DUMPBITS removes the bits from b. The macros use the variable k
+ for the number of bits in b. Normally, b and k are register
+ variables for speed, and are initialized at the beginning of a
+ routine that uses these macros from a global bit buffer and count.
+
+ If we assume that EOB will be the longest code, then we will never
+ ask for bits with NEEDBITS that are beyond the end of the stream.
+ So, NEEDBITS should not read any more bytes than are needed to
+ meet the request. Then no bytes need to be "returned" to the buffer
+ at the end of the last block.
+
+ However, this assumption is not true for fixed blocks--the EOB code
+ is 7 bits, but the other literal/length codes can be 8 or 9 bits.
+ (The EOB code is shorter than other codes because fixed blocks are
+ generally short. So, while a block always has an EOB, many other
+ literal/length codes have a significantly lower probability of
+ showing up at all.) However, by making the first table have a
+ lookup of seven bits, the EOB code will be found in that first
+ lookup, and so will not require that too many bits be pulled from
+ the stream.
+ */
+
+STATIC ulg bb; /* bit buffer */
+STATIC unsigned bk; /* bits in bit buffer */
+
+STATIC ush mask_bits[] = {
+ 0x0000,
+ 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+ 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#define NEXTBYTE() (uch)get_byte()
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+
+/*
+ Huffman code decoding is performed using a multi-level table lookup.
+ The fastest way to decode is to simply build a lookup table whose
+ size is determined by the longest code. However, the time it takes
+ to build this table can also be a factor if the data being decoded
+ is not very long. The most common codes are necessarily the
+ shortest codes, so those codes dominate the decoding time, and hence
+ the speed. The idea is you can have a shorter table that decodes the
+ shorter, more probable codes, and then point to subsidiary tables for
+ the longer codes. The time it costs to decode the longer codes is
+ then traded against the time it takes to make longer tables.
+
+ This results of this trade are in the variables lbits and dbits
+ below. lbits is the number of bits the first level table for literal/
+ length codes can decode in one step, and dbits is the same thing for
+ the distance codes. Subsequent tables are also less than or equal to
+ those sizes. These values may be adjusted either when all of the
+ codes are shorter than that, in which case the longest code length in
+ bits is used, or when the shortest code is *longer* than the requested
+ table size, in which case the length of the shortest code in bits is
+ used.
+
+ There are two different values for the two tables, since they code a
+ different number of possibilities each. The literal/length table
+ codes 286 possible values, or in a flat code, a little over eight
+ bits. The distance table codes 30 possible values, or a little less
+ than five bits, flat. The optimum values for speed end up being
+ about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+ The optimum values may differ though from machine to machine, and
+ possibly even between compilers. Your mileage may vary.
+ */
+
+
+STATIC int lbits = 9; /* bits in base literal/length lookup table */
+STATIC int dbits = 6; /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16 /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288 /* maximum number of codes in any set */
+
+
+STATIC unsigned hufts; /* track memory usage */
+
+
+STATIC int huft_build(b, n, s, d, e, t, m)
+unsigned *b; /* code lengths in bits (all assumed <= BMAX) */
+unsigned n; /* number of codes (assumed <= N_MAX) */
+unsigned s; /* number of simple-valued codes (0..s-1) */
+ush *d; /* list of base values for non-simple codes */
+ush *e; /* list of extra bits for non-simple codes */
+struct huft **t; /* result: starting table */
+int *m; /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+ tables to decode that set of codes. Return zero on success, one if
+ the given code set is incomplete (the tables are still built in this
+ case), two if the input is invalid (all zero length codes or an
+ oversubscribed set of lengths), and three if not enough memory. */
+{
+ unsigned a; /* counter for codes of length k */
+ unsigned c[BMAX+1]; /* bit length count table */
+ unsigned f; /* i repeats in table every f entries */
+ int g; /* maximum code length */
+ int h; /* table level */
+ register unsigned i; /* counter, current code */
+ register unsigned j; /* counter */
+ register int k; /* number of bits in current code */
+ int l; /* bits per table (returned in m) */
+ register unsigned *p; /* pointer into c[], b[], or v[] */
+ register struct huft *q; /* points to current table */
+ struct huft r; /* table entry for structure assignment */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ register int w; /* bits before this table == (l * h) */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ unsigned *xp; /* pointer into x */
+ int y; /* number of dummy codes added */
+ unsigned z; /* number of entries in current table */
+
+DEBG("huft1 ");
+
+ /* Generate counts for each bit length */
+ memzero(c, sizeof(c));
+ p = b; i = n;
+ do {
+ Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
+ n-i, *p));
+ c[*p]++; /* assume all entries <= BMAX */
+ p++; /* Can't combine with above line (Solaris bug) */
+ } while (--i);
+ if (c[0] == n) /* null input--all zero length codes */
+ {
+ *t = (struct huft *)NULL;
+ *m = 0;
+ return 0;
+ }
+
+DEBG("huft2 ");
+
+ /* Find minimum and maximum length, bound *m by those */
+ l = *m;
+ for (j = 1; j <= BMAX; j++)
+ if (c[j])
+ break;
+ k = j; /* minimum code length */
+ if ((unsigned)l < j)
+ l = j;
+ for (i = BMAX; i; i--)
+ if (c[i])
+ break;
+ g = i; /* maximum code length */
+ if ((unsigned)l > i)
+ l = i;
+ *m = l;
+
+DEBG("huft3 ");
+
+ /* Adjust last length count to fill out codes, if needed */
+ for (y = 1 << j; j < i; j++, y <<= 1)
+ if ((y -= c[j]) < 0)
+ return 2; /* bad input: more codes than bits */
+ if ((y -= c[i]) < 0)
+ return 2;
+ c[i] += y;
+
+DEBG("huft4 ");
+
+ /* Generate starting offsets into the value table for each length */
+ x[1] = j = 0;
+ p = c + 1; xp = x + 2;
+ while (--i) { /* note that i == g from above */
+ *xp++ = (j += *p++);
+ }
+
+DEBG("huft5 ");
+
+ /* Make a table of values in order of bit lengths */
+ p = b; i = 0;
+ do {
+ if ((j = *p++) != 0)
+ v[x[j]++] = i;
+ } while (++i < n);
+
+DEBG("h6 ");
+
+ /* Generate the Huffman codes and for each, make the table entries */
+ x[0] = i = 0; /* first Huffman code is zero */
+ p = v; /* grab values in bit order */
+ h = -1; /* no tables yet--level -1 */
+ w = -l; /* bits decoded == (l * h) */
+ u[0] = (struct huft *)NULL; /* just to keep compilers happy */
+ q = (struct huft *)NULL; /* ditto */
+ z = 0; /* ditto */
+DEBG("h6a ");
+
+ /* go through the bit lengths (k already is bits in shortest code) */
+ for (; k <= g; k++)
+ {
+DEBG("h6b ");
+ a = c[k];
+ while (a--)
+ {
+DEBG("h6b1 ");
+ /* here i is the Huffman code of length k bits for value *p */
+ /* make tables up to required level */
+ while (k > w + l)
+ {
+DEBG1("1 ");
+ h++;
+ w += l; /* previous table always l bits */
+
+ /* compute minimum size table less than or equal to l bits */
+ z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */
+ if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */
+ { /* too few codes for k-w bit table */
+DEBG1("2 ");
+ f -= a + 1; /* deduct codes from patterns left */
+ xp = c + k;
+ while (++j < z) /* try smaller tables up to z bits */
+ {
+ if ((f <<= 1) <= *++xp)
+ break; /* enough codes to use up j bits */
+ f -= *xp; /* else deduct codes from patterns */
+ }
+ }
+DEBG1("3 ");
+ z = 1 << j; /* table entries for j-bit table */
+
+ /* allocate and link in new table */
+ if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) ==
+ (struct huft *)NULL)
+ {
+ if (h)
+ huft_free(u[0]);
+ return 3; /* not enough memory */
+ }
+DEBG1("4 ");
+ hufts += z + 1; /* track memory usage */
+ *t = q + 1; /* link to list for huft_free() */
+ *(t = &(q->v.t)) = (struct huft *)NULL;
+ u[h] = ++q; /* table starts after link */
+
+DEBG1("5 ");
+ /* connect to last table, if there is one */
+ if (h)
+ {
+ x[h] = i; /* save pattern for backing up */
+ r.b = (uch)l; /* bits to dump before this table */
+ r.e = (uch)(16 + j); /* bits in this table */
+ r.v.t = q; /* pointer to this table */
+ j = i >> (w - l); /* (get around Turbo C bug) */
+ u[h-1][j] = r; /* connect to last table */
+ }
+DEBG1("6 ");
+ }
+DEBG("h6c ");
+
+ /* set up table entry in r */
+ r.b = (uch)(k - w);
+ if (p >= v + n)
+ r.e = 99; /* out of values--invalid code */
+ else if (*p < s)
+ {
+ r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */
+ r.v.n = (ush)(*p); /* simple code is just the value */
+ p++; /* one compiler does not like *p++ */
+ }
+ else
+ {
+ r.e = (uch)e[*p - s]; /* non-simple--look up in lists */
+ r.v.n = d[*p++ - s];
+ }
+DEBG("h6d ");
+
+ /* fill code-like entries with r */
+ f = 1 << (k - w);
+ for (j = i >> w; j < z; j += f)
+ q[j] = r;
+
+ /* backwards increment the k-bit code i */
+ for (j = 1 << (k - 1); i & j; j >>= 1)
+ i ^= j;
+ i ^= j;
+
+ /* backup over finished tables */
+ while ((i & ((1 << w) - 1)) != x[h])
+ {
+ h--; /* don't need to update q */
+ w -= l;
+ }
+DEBG("h6e ");
+ }
+DEBG("h6f ");
+ }
+
+DEBG("huft7 ");
+
+ /* Return true (1) if we were given an incomplete table */
+ return y != 0 && g != 1;
+}
+
+
+
+STATIC int huft_free(t)
+struct huft *t; /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+ list of the tables it made, with the links in a dummy first entry of
+ each table. */
+{
+ register struct huft *p, *q;
+
+
+ /* Go through linked list, freeing from the malloced (t[-1]) address. */
+ p = t;
+ while (p != (struct huft *)NULL)
+ {
+ q = (--p)->v.t;
+ free((char*)p);
+ p = q;
+ }
+ return 0;
+}
+
+
+STATIC int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td; /* literal/length and distance decoder tables */
+int bl, bd; /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+ Return an error code or zero if it all goes ok. */
+{
+ register unsigned e; /* table entry flag/number of extra bits */
+ unsigned n, d; /* length and index for copy */
+ unsigned w; /* current window position */
+ struct huft *t; /* pointer to table entry */
+ unsigned ml, md; /* masks for bl and bd bits */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+ /* inflate the coded data */
+ ml = mask_bits[bl]; /* precompute masks for speed */
+ md = mask_bits[bd];
+ for (;;) /* do until end of block */
+ {
+ NEEDBITS((unsigned)bl)
+ if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ if (e == 16) /* then it's a literal */
+ {
+ slide[w++] = (uch)t->v.n;
+ Tracevv((stderr, "%c", slide[w-1]));
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ }
+ else /* it's an EOB or a length */
+ {
+ /* exit if end of block */
+ if (e == 15)
+ break;
+
+ /* get length of block to copy */
+ NEEDBITS(e)
+ n = t->v.n + ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e);
+
+ /* decode distance of block to copy */
+ NEEDBITS((unsigned)bd)
+ if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+ do {
+ if (e == 99)
+ return 1;
+ DUMPBITS(t->b)
+ e -= 16;
+ NEEDBITS(e)
+ } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+ DUMPBITS(t->b)
+ NEEDBITS(e)
+ d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+ DUMPBITS(e)
+ Tracevv((stderr,"\\[%d,%d]", w-d, n));
+
+ /* do the copy */
+ do {
+ n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+ if (w - d >= e) /* (this test assumes unsigned comparison) */
+ {
+ memcpy(slide + w, slide + d, e);
+ w += e;
+ d += e;
+ }
+ else /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+ do {
+ slide[w++] = slide[d++];
+ Tracevv((stderr, "%c", slide[w-1]));
+ } while (--e);
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ } while (n);
+ }
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ /* done */
+ return 0;
+}
+
+
+
+STATIC int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+ unsigned n; /* number of bytes in block */
+ unsigned w; /* current window position */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+ /* make local copies of globals */
+ b = bb; /* initialize bit buffer */
+ k = bk;
+ w = wp; /* initialize window position */
+
+
+ /* go to byte boundary */
+ n = k & 7;
+ DUMPBITS(n);
+
+
+ /* get the length and its complement */
+ NEEDBITS(16)
+ n = ((unsigned)b & 0xffff);
+ DUMPBITS(16)
+ NEEDBITS(16)
+ if (n != (unsigned)((~b) & 0xffff))
+ return 1; /* error in compressed data */
+ DUMPBITS(16)
+
+
+ /* read and output the compressed data */
+ while (n--)
+ {
+ NEEDBITS(8)
+ slide[w++] = (uch)b;
+ if (w == WSIZE)
+ {
+ flush_output(w);
+ w = 0;
+ }
+ DUMPBITS(8)
+ }
+
+
+ /* restore the globals from the locals */
+ wp = w; /* restore global window pointer */
+ bb = b; /* restore global bit buffer */
+ bk = k;
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+STATIC int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block. We should
+ either replace this with a custom decoder, or at least precompute the
+ Huffman tables. */
+{
+ int i; /* temporary variable */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned l[288]; /* length list for huft_build */
+
+DEBG("<fix");
+
+ /* set up literal table */
+ for (i = 0; i < 144; i++)
+ l[i] = 8;
+ for (; i < 256; i++)
+ l[i] = 9;
+ for (; i < 280; i++)
+ l[i] = 7;
+ for (; i < 288; i++) /* make a complete, but wrong code set */
+ l[i] = 8;
+ bl = 7;
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ return i;
+
+
+ /* set up distance table */
+ for (i = 0; i < 30; i++) /* make an incomplete code set */
+ l[i] = 5;
+ bd = 5;
+ if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+ {
+ huft_free(tl);
+
+ DEBG(">");
+ return i;
+ }
+
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+ return 0;
+}
+
+
+
+STATIC int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+ int i; /* temporary variables */
+ unsigned j;
+ unsigned l; /* last length */
+ unsigned m; /* mask for bit lengths table */
+ unsigned n; /* number of lengths to get */
+ struct huft *tl; /* literal/length code table */
+ struct huft *td; /* distance code table */
+ int bl; /* lookup bits for tl */
+ int bd; /* lookup bits for td */
+ unsigned nb; /* number of bit length codes */
+ unsigned nl; /* number of literal/length codes */
+ unsigned nd; /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+ unsigned ll[288+32]; /* literal/length and distance code lengths */
+#else
+ unsigned ll[286+30]; /* literal/length and distance code lengths */
+#endif
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+DEBG("<dyn");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in table lengths */
+ NEEDBITS(5)
+ nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */
+ DUMPBITS(5)
+ NEEDBITS(5)
+ nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */
+ DUMPBITS(5)
+ NEEDBITS(4)
+ nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */
+ DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+ if (nl > 288 || nd > 32)
+#else
+ if (nl > 286 || nd > 30)
+#endif
+ return 1; /* bad lengths */
+
+DEBG("dyn1 ");
+
+ /* read in bit-length-code lengths */
+ for (j = 0; j < nb; j++)
+ {
+ NEEDBITS(3)
+ ll[border[j]] = (unsigned)b & 7;
+ DUMPBITS(3)
+ }
+ for (; j < 19; j++)
+ ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+ /* build decoding table for trees--single level, 7 bit lookup */
+ bl = 7;
+ if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+ {
+ if (i == 1)
+ huft_free(tl);
+ return i; /* incomplete code set */
+ }
+
+DEBG("dyn3 ");
+
+ /* read in literal and distance code lengths */
+ n = nl + nd;
+ m = mask_bits[bl];
+ i = l = 0;
+ while ((unsigned)i < n)
+ {
+ NEEDBITS((unsigned)bl)
+ j = (td = tl + ((unsigned)b & m))->b;
+ DUMPBITS(j)
+ j = td->v.n;
+ if (j < 16) /* length of code in bits (0..15) */
+ ll[i++] = l = j; /* save last length in l */
+ else if (j == 16) /* repeat last length 3 to 6 times */
+ {
+ NEEDBITS(2)
+ j = 3 + ((unsigned)b & 3);
+ DUMPBITS(2)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = l;
+ }
+ else if (j == 17) /* 3 to 10 zero length codes */
+ {
+ NEEDBITS(3)
+ j = 3 + ((unsigned)b & 7);
+ DUMPBITS(3)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ else /* j == 18: 11 to 138 zero length codes */
+ {
+ NEEDBITS(7)
+ j = 11 + ((unsigned)b & 0x7f);
+ DUMPBITS(7)
+ if ((unsigned)i + j > n)
+ return 1;
+ while (j--)
+ ll[i++] = 0;
+ l = 0;
+ }
+ }
+
+DEBG("dyn4 ");
+
+ /* free decoding table for trees */
+ huft_free(tl);
+
+DEBG("dyn5 ");
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+DEBG("dyn5a ");
+
+ /* build the decoding tables for literal/length and distance codes */
+ bl = lbits;
+ if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+ {
+DEBG("dyn5b ");
+ if (i == 1) {
+ error(" incomplete literal tree\n");
+ huft_free(tl);
+ }
+ return i; /* incomplete code set */
+ }
+DEBG("dyn5c ");
+ bd = dbits;
+ if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+ {
+DEBG("dyn5d ");
+ if (i == 1) {
+ error(" incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+ i = 0;
+ }
+#else
+ huft_free(td);
+ }
+ huft_free(tl);
+ return i; /* incomplete code set */
+#endif
+ }
+
+DEBG("dyn6 ");
+
+ /* decompress until an end-of-block code */
+ if (inflate_codes(tl, td, bl, bd))
+ return 1;
+
+DEBG("dyn7 ");
+
+ /* free the decoding tables, return */
+ huft_free(tl);
+ huft_free(td);
+
+ DEBG(">");
+ return 0;
+}
+
+
+
+STATIC int inflate_block(e)
+int *e; /* last block flag */
+/* decompress an inflated block */
+{
+ unsigned t; /* block type */
+ register ulg b; /* bit buffer */
+ register unsigned k; /* number of bits in bit buffer */
+
+ DEBG("<blk");
+
+ /* make local bit buffer */
+ b = bb;
+ k = bk;
+
+
+ /* read in last block bit */
+ NEEDBITS(1)
+ *e = (int)b & 1;
+ DUMPBITS(1)
+
+
+ /* read in block type */
+ NEEDBITS(2)
+ t = (unsigned)b & 3;
+ DUMPBITS(2)
+
+
+ /* restore the global bit buffer */
+ bb = b;
+ bk = k;
+
+ /* inflate that block type */
+ if (t == 2)
+ return inflate_dynamic();
+ if (t == 0)
+ return inflate_stored();
+ if (t == 1)
+ return inflate_fixed();
+
+ DEBG(">");
+
+ /* bad block type */
+ return 2;
+}
+
+
+
+STATIC int inflate()
+/* decompress an inflated entry */
+{
+ int e; /* last block flag */
+ int r; /* result code */
+ unsigned h; /* maximum struct huft's malloc'ed */
+ void *ptr;
+
+ /* initialize window, bit buffer */
+ wp = 0;
+ bk = 0;
+ bb = 0;
+
+
+ /* decompress until the last block */
+ h = 0;
+ do {
+ hufts = 0;
+ gzip_mark(&ptr);
+ if ((r = inflate_block(&e)) != 0) {
+ gzip_release(&ptr);
+ return r;
+ }
+ gzip_release(&ptr);
+ if (hufts > h)
+ h = hufts;
+ } while (!e);
+
+ /* Undo too much lookahead. The next read will be byte aligned so we
+ * can discard unused bits in the last meaningful byte.
+ */
+ while (bk >= 8) {
+ bk -= 8;
+ inptr--;
+ }
+
+ /* flush out slide */
+ flush_output(wp);
+
+
+ /* return success */
+#ifdef DEBUG
+ fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * The following are support routines for inflate.c
+ *
+ **********************************************************************/
+
+static ulg crc_32_tab[256];
+static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+#define CRC_VALUE (crc ^ 0xffffffffL)
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from
+ * gzip-1.0.3/makecrc.c.
+ */
+
+static void
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler */
+
+ unsigned long c; /* crc shift register */
+ unsigned long e; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* Make exclusive-or pattern from polynomial */
+ e = 0;
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ e |= 1L << (31 - p[i]);
+
+ crc_32_tab[0] = 0;
+
+ for (i = 1; i < 256; i++)
+ {
+ c = 0;
+ for (k = i | 256; k != 1; k >>= 1)
+ {
+ c = c & 1 ? (c >> 1) ^ e : c >> 1;
+ if (k & 1)
+ c ^= e;
+ }
+ crc_32_tab[i] = c;
+ }
+}
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+/*
+ * Do the uncompression!
+ */
+static int gunzip(void)
+{
+ uch flags;
+ unsigned char magic[2]; /* magic header */
+ char method;
+ ulg orig_crc = 0; /* original crc */
+ ulg orig_len = 0; /* original uncompressed length */
+ int res;
+
+ magic[0] = (unsigned char)get_byte();
+ magic[1] = (unsigned char)get_byte();
+ method = (unsigned char)get_byte();
+
+ if (magic[0] != 037 ||
+ ((magic[1] != 0213) && (magic[1] != 0236))) {
+ error("bad gzip magic numbers");
+ return -1;
+ }
+
+ /* We only support method #8, DEFLATED */
+ if (method != 8) {
+ error("internal error, invalid method");
+ return -1;
+ }
+
+ flags = (uch)get_byte();
+ if ((flags & ENCRYPTED) != 0) {
+ error("Input is encrypted\n");
+ return -1;
+ }
+ if ((flags & CONTINUATION) != 0) {
+ error("Multi part input\n");
+ return -1;
+ }
+ if ((flags & RESERVED) != 0) {
+ error("Input has invalid flags\n");
+ return -1;
+ }
+ (ulg)get_byte(); /* Get timestamp */
+ ((ulg)get_byte()) << 8;
+ ((ulg)get_byte()) << 16;
+ ((ulg)get_byte()) << 24;
+
+ (void)get_byte(); /* Ignore extra flags for the moment */
+ (void)get_byte(); /* Ignore OS type for the moment */
+
+ if ((flags & EXTRA_FIELD) != 0) {
+ unsigned len = (unsigned)get_byte();
+ len |= ((unsigned)get_byte())<<8;
+ while (len--) (void)get_byte();
+ }
+
+ /* Get original file name if it was truncated */
+ if ((flags & ORIG_NAME) != 0) {
+ /* Discard the old name */
+ while (get_byte() != 0) /* null */ ;
+ }
+
+ /* Discard file comment if any */
+ if ((flags & COMMENT) != 0) {
+ while (get_byte() != 0) /* null */ ;
+ }
+
+ /* Decompress */
+ if ((res = inflate())) {
+ switch (res) {
+ case 0:
+ break;
+ case 1:
+ error("invalid compressed format (err=1)");
+ break;
+ case 2:
+ error("invalid compressed format (err=2)");
+ break;
+ case 3:
+ error("out of memory");
+ break;
+ default:
+ error("invalid compressed format (other)");
+ }
+ return -1;
+ }
+
+ /* Get the crc and original length */
+ /* crc32 (see algorithm.doc)
+ * uncompressed input size modulo 2^32
+ */
+ orig_crc = (ulg) get_byte();
+ orig_crc |= (ulg) get_byte() << 8;
+ orig_crc |= (ulg) get_byte() << 16;
+ orig_crc |= (ulg) get_byte() << 24;
+
+ orig_len = (ulg) get_byte();
+ orig_len |= (ulg) get_byte() << 8;
+ orig_len |= (ulg) get_byte() << 16;
+ orig_len |= (ulg) get_byte() << 24;
+
+ /* Validate decompression */
+ if (orig_crc != CRC_VALUE) {
+ error("crc error");
+ return -1;
+ }
+ if (orig_len != bytes_out) {
+ error("length error");
+ return -1;
+ }
+ return 0;
+}
+
+
set_pte(page_table, __pte(entry));
/* Yuck, perhaps a slightly modified swapout parameter set? */
- invalidate_page(vma->vm_mm, (offset + vma->vm_start - vma->vm_offset));
+ invalidate_page(vma, (offset + vma->vm_start - vma->vm_offset));
error = filemap_write_page(vma, offset, page);
if (pte_val(*page_table) == entry)
pte_clear(page_table);
if (!pte_dirty(pte))
return 0;
set_pte(ptep, pte_mkclean(pte));
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
page = pte_page(pte);
mem_map[MAP_NR(page)].count++;
} else {
if (pte_none(pte))
return 0;
pte_clear(ptep);
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
if (!pte_present(pte)) {
swap_free(pte_val(pte));
return 0;
struct mem_list free_area_list[NR_MEM_LISTS];
unsigned char * free_area_map[NR_MEM_LISTS];
-#define copy_page(from,to) memcpy((void *) to, (void *) from, PAGE_SIZE)
+/*
+ * We special-case the C-O-W ZERO_PAGE, because it's such
+ * a common occurrence (no need to read the page to know
+ * that it's zero - better for the cache and memory subsystem).
+ */
+static inline void copy_page(unsigned long from, unsigned long to)
+{
+ if (from == ZERO_PAGE) {
+ memset((void *) to, 0, PAGE_SIZE);
+ return;
+ }
+ memcpy((void *) to, (void *) from, PAGE_SIZE);
+}
#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
}
if (!pte_none(*pte)) {
printk("put_dirty_page: page already exists\n");
- pte_clear(pte);
- invalidate_page(tsk->mm, address);
+ free_page(page);
+ return 0;
}
set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY))));
/* no need for invalidate */
copy_page(old_page,new_page);
set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
free_page(old_page);
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
return;
}
set_pte(page_table, BAD_PAGE);
free_page(old_page);
oom(tsk);
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
return;
}
set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
if (new_page)
free_page(new_page);
return;
return 1;
/* ok, need to mark it read-only, so invalidate any possible old TB entry */
set_pte(from_table, pte_wrprotect(from));
- invalidate_page(from_area->vm_mm, from_address);
+ invalidate_page(from_area, from_address);
return 1;
}
return 0;
vma->vm_mm->rss--;
set_pte(page_table, __pte(entry));
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
tsk->nswap++;
write_swap_page(entry, (char *) page);
}
}
vma->vm_mm->rss--;
set_pte(page_table, __pte(entry));
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
free_page(page);
return 1;
}
vma->vm_mm->rss--;
pte_clear(page_table);
- invalidate_page(vma->vm_mm, address);
+ invalidate_page(vma, address);
entry = mem_map[MAP_NR(page)].count;
free_page(page);
return entry;
int netlink_post(int unit, struct sk_buff *skb)
{
unsigned long flags;
- int ret=0;
+ int ret=-EUNATCH;
if(open_map&(1<<unit))
{
save_flags(flags);