]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.84 1.1.84
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:52 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:52 +0000 (15:09 -0500)
63 files changed:
CREDITS
Makefile
arch/alpha/boot/main.c
arch/alpha/mm/fault.c
arch/alpha/mm/init.c
arch/i386/config.in
arch/i386/ibcs/binfmt_elf.c
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/vm86.c
arch/i386/mm/fault.c
arch/i386/mm/init.c
drivers/block/README.aztcd
drivers/block/README.fd [new file with mode: 0644]
drivers/block/README.ide
drivers/block/aztcd.c
drivers/block/floppy.c
drivers/block/ide.c
drivers/char/mem.c
drivers/net/Makefile
drivers/net/at1700.c
drivers/net/atp.c
drivers/net/ewrk3.c
drivers/net/lance.c
drivers/net/net_init.c
drivers/net/smc-ultra.c
drivers/net/tulip.c [new file with mode: 0644]
drivers/scsi/Makefile
drivers/scsi/aha152x.c
drivers/scsi/aha152x.h
drivers/scsi/eata_dma.c
drivers/scsi/eata_dma.h
drivers/scsi/in2000.c
drivers/scsi/qlogic.c
drivers/sound/ad1848.c
drivers/sound/gus_card.c
drivers/sound/sound_calls.h
fs/binfmt_elf.c
fs/exec.c
fs/msdos/mmap.c
fs/namei.c
fs/nfs/mmap.c
fs/proc/array.c
fs/proc/mem.c
fs/umsdos/check.c
include/asm-alpha/page.h
include/asm-i386/page.h
include/linux/aztcd.h
include/linux/head.h
include/linux/mm.h
include/linux/pci.h
include/linux/sched.h
include/linux/timer.h
include/linux/xd.h
ipc/shm.c
lib/string.c
mm/filemap.c
mm/memory.c
mm/mmap.c
mm/mprotect.c
mm/swap.c
mm/vmalloc.c
net/inet/ip.c

diff --git a/CREDITS b/CREDITS
index 1eb2badf35cb49640d1213591d927ae8b38971a5..f392830ac292fd9a14b62e7dc5ad863d522f7357 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -953,6 +953,13 @@ S: 1507 145th Place SE #B5
 S: Bellevue, Washington 98007
 S: USA
 
+N: Werner Zimmermann
+E: zimmerma@rz.fht-esslingen.de
+D: CDROM driver "aztcd" (Aztech/Okano/Orchid/Wearnes)
+S: Flandernstrasse 101
+S: D-73732 Esslingen
+S: Germany
+
 N: Leonard N. Zubkoff
 E: lnz@dandelion.com
 D: XFree86 and BusLogic driver additions
index 156cd71b6486dc530e1d723087f23d004c83c5bd..bfdb0345adcd3ed06de33f459afad3a8a452e3bd 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 83
+SUBLEVEL = 84
 
 ARCH = i386
 
index d407195fc37c0a55fb6f77666047da6debf6c4e2..4b5f5e58a10c91d8945049f4099a00b8c5faa8c6 100644 (file)
@@ -8,11 +8,11 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/version.h>
+#include <linux/mm.h>
 
 #include <asm/system.h>
 #include <asm/console.h>
 #include <asm/hwrpb.h>
-#include <asm/page.h>
 
 #include <stdarg.h>
 
index a14f8981bd05a46545b4f0844305f20bb20bb22c..db6b9e56e82b88638f1a8cd9bedc301d3f3bba58 100644 (file)
@@ -60,11 +60,18 @@ asmlinkage void do_page_fault(unsigned long address, unsigned long mmcsr,
  * we can handle it..
  */
 good_area:
-       if (!(vma->vm_page_prot & PAGE_USER))
-               goto bad_area;
-       if (mmcsr) {
-               if (!(vma->vm_page_prot & (PAGE_RW | PAGE_COW)))
+       if (cause < 0) {
+               if (!(vma->vm_flags & VM_EXEC))
+                       goto bad_area;
+       } else if (!cause) {
+               if (!(vma->vm_flags & VM_READ))
+                       goto bad_area;
+       } else {
+               if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+       }
+
+       if (mmcsr) {
                do_wp_page(vma, address, cause > 0);
                return;
        }
index f04f3dc15a381b881b9a6178a0cec469793de0f1..1ab81cbd3e86fdd054266a806c3272a8a79acc96 100644 (file)
@@ -38,10 +38,10 @@ extern void show_net_buffers(void);
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-unsigned long __bad_pagetable(void)
+struct pte * __bad_pagetable(void)
 {
        memset((void *) EMPTY_PGT, 0, PAGE_SIZE);
-       return EMPTY_PGT;
+       return (struct pte *) EMPTY_PGT;
 }
 
 unsigned long __bad_page(void)
index d2c961108f5fe3412b7b3ce8fdf68cd3f718d818..d52302184a538e648dae7f6c8f858685365c182d 100644 (file)
@@ -9,6 +9,7 @@ bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
 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
index dab9c4bdf0c3d3f0c9afe37fe93eba8a6414fd0e..ab6d36915787ae1e4c3f547eac03759b97e22d85 100644 (file)
@@ -65,7 +65,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
                mpnt->vm_task = current;
                mpnt->vm_start = PAGE_MASK & (unsigned long) p;
                mpnt->vm_end = TASK_SIZE;
-               mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+               mpnt->vm_page_prot = PAGE_COPY;
                mpnt->vm_flags = VM_STACK_FLAGS;
                mpnt->vm_ops = NULL;
                mpnt->vm_inode = NULL;
index 3cb81ee64c8eab6b6a0f5d679a8a874e5c76e265..34e4a4605eef28349970f312735ea5128659c1d9 100644 (file)
@@ -37,7 +37,7 @@ asmlinkage int sys_idle(void)
 
        /* Map out the low memory: it's no longer needed */
        for (i = 0 ; i < 768 ; i++)
-               swapper_pg_dir[i] = 0;
+               pgd_clear(swapper_pg_dir + i);
 
        /* endless idle loop with no priority at all */
        current->counter = -100;
index 0e14bed1974a871b4a0a899280d2460aaf6b5838..00d16e9931a9d7cb22aa5501fb3fbe150ed41cbc 100644 (file)
@@ -84,23 +84,30 @@ static inline int put_stack_long(struct task_struct *task, int offset,
  */
 static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
 {
+       pgd_t * pgdir;
+       pte_t * pgtable;
        unsigned long page;
 
 repeat:
-       page = *PAGE_DIR_OFFSET(vma->vm_task, addr);
-       if (page & PAGE_PRESENT) {
-               page &= PAGE_MASK;
-               page += PAGE_PTR(addr);
-               page = *((unsigned long *) page);
+       pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+       if (pgd_none(*pgdir)) {
+               do_no_page(vma, addr, 0);
+               goto repeat;
+       }
+       if (pgd_bad(*pgdir)) {
+               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               pgd_clear(pgdir);
+               return 0;
        }
-       if (!(page & PAGE_PRESENT)) {
+       pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+       if (!pte_present(*pgtable)) {
                do_no_page(vma, addr, 0);
                goto repeat;
        }
+       page = pte_page(*pgtable);
 /* this is a hack for non-kernel-mapped video buffers and similar */
        if (page >= high_memory)
                return 0;
-       page &= PAGE_MASK;
        page += addr & ~PAGE_MASK;
        return *(unsigned long *) page;
 }
@@ -117,39 +124,40 @@ repeat:
 static void put_long(struct vm_area_struct * vma, unsigned long addr,
        unsigned long data)
 {
-       unsigned long page, pte = 0;
-       int readonly = 0;
+       pgd_t *pgdir;
+       pte_t *pgtable;
+       unsigned long page;
 
 repeat:
-       page = *PAGE_DIR_OFFSET(vma->vm_task, addr);
-       if (page & PAGE_PRESENT) {
-               page &= PAGE_MASK;
-               page += PAGE_PTR(addr);
-               pte = page;
-               page = *((unsigned long *) page);
+       pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
+       if (!pgd_present(*pgdir)) {
+               do_no_page(vma, addr, 1);
+               goto repeat;
        }
-       if (!(page & PAGE_PRESENT)) {
-               do_no_page(vma, addr, 0 /* PAGE_RW */);
+       if (pgd_bad(*pgdir)) {
+               printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+               pgd_clear(pgdir);
+               return;
+       }
+       pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+       if (!pte_present(*pgtable)) {
+               do_no_page(vma, addr, 1);
                goto repeat;
        }
-       if (!(page & PAGE_RW)) {
-               if (!(page & PAGE_COW))
-                       readonly = 1;
-               do_wp_page(vma, addr, PAGE_RW | PAGE_PRESENT);
+       page = pte_page(*pgtable);
+       if (!pte_write(*pgtable)) {
+               do_wp_page(vma, addr, 1);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
-       if (page >= high_memory)
-               return;
+       if (page < high_memory) {
+               page += addr & ~PAGE_MASK;
+               *(unsigned long *) page = data;
+       }
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
-       *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW);
-       page &= PAGE_MASK;
-       page += addr & ~PAGE_MASK;
-       *(unsigned long *) page = data;
-       if (readonly) {
-               *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
-               invalidate();
-       } 
+/* this should also re-instate whatever read-only mode there was before */
+       *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+       invalidate();
 }
 
 static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, unsigned long addr)
index f1c78ecf7614765dc194be1d93530ff82251b80d..2e4bfb830ebe707d77c53ee31d4733963e00df46 100644 (file)
@@ -67,20 +67,24 @@ asmlinkage struct pt_regs * save_v86_state(struct vm86_regs * regs)
 
 static void mark_screen_rdonly(struct task_struct * tsk)
 {
-       unsigned long tmp;
-       unsigned long *pg_table;
-
-       if ((tmp = tsk->tss.cr3) != 0) {
-               tmp = *(unsigned long *) tmp;
-               if (tmp & PAGE_PRESENT) {
-                       tmp &= PAGE_MASK;
-                       pg_table = (0xA0000 >> PAGE_SHIFT) + (unsigned long *) tmp;
-                       tmp = 32;
-                       while (tmp--) {
-                               if (PAGE_PRESENT & *pg_table)
-                                       *pg_table &= ~PAGE_RW;
-                               pg_table++;
-                       }
+       pgd_t *pg_dir;
+
+       pg_dir = PAGE_DIR_OFFSET(tsk, 0);
+       if (!pgd_none(*pg_dir)) {
+               pte_t *pg_table;
+               int i;
+
+               if (pgd_bad(*pg_dir)) {
+                       printk("vm86: bad page table directory entry %08lx\n", pgd_val(*pg_dir));
+                       pgd_clear(pg_dir);
+                       return;
+               }
+               pg_table = (pte_t *) pgd_page(*pg_dir);
+               pg_table += 0xA0000 >> PAGE_SHIFT;
+               for (i = 0 ; i < 32 ; i++) {
+                       if (pte_present(*pg_table))
+                               *pg_table = pte_wrprotect(*pg_table);
+                       pg_table++;
                }
        }
 }
index 11662e7165405d8efe968317962aeb3f10ed2fd1..b56194222720a9a4ff17cb77b7d794029abf316b 100644 (file)
@@ -25,6 +25,11 @@ 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.
+ *
+ * error_code:
+ *     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)
 {
@@ -50,24 +55,36 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
  * we can handle it..
  */
 good_area:
+       /*
+        * was it a write?
+        */
+       if (error_code & 2) {
+               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;
+       }
+       /*
+        * Did it hit the DOS screen memory VA from vm86 mode?
+        */
        if (regs->eflags & VM_MASK) {
                unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
                if (bit < 32)
                        current->tss.screen_bitmap |= 1 << bit;
        }
-       if (!(vma->vm_page_prot & PAGE_USER))
-               goto bad_area;
-       if (error_code & PAGE_PRESENT) {
-               if (!(vma->vm_page_prot & (PAGE_RW | PAGE_COW)))
-                       goto bad_area;
+       if (error_code & 1) {
 #ifdef CONFIG_TEST_VERIFY_AREA
                if (regs->cs == KERNEL_CS)
                        printk("WP fault at %08x\n", regs->eip);
 #endif
-               do_wp_page(vma, address, error_code & PAGE_RW);
+               do_wp_page(vma, address, error_code & 2);
                return;
        }
-       do_no_page(vma, address, error_code & PAGE_RW);
+       do_no_page(vma, address, error_code & 2);
        return;
 
 /*
@@ -75,7 +92,7 @@ good_area:
  * Fix it, but check if it's kernel or user first..
  */
 bad_area:
-       if (error_code & PAGE_USER) {
+       if (error_code & 4) {
                current->tss.cr2 = address;
                current->tss.error_code = error_code;
                current->tss.trap_no = 14;
@@ -85,17 +102,19 @@ bad_area:
 /*
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
+ *
+ * First we check if it was the bootup rw-test, though..
  */
-       if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & PAGE_PRESENT)) {
+       if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
                wp_works_ok = 1;
-               pg0[0] = PAGE_SHARED;
+               pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
                invalidate();
                printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
                return;
        }
        if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-               pg0[0] = PAGE_SHARED;
+               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);
@@ -104,7 +123,7 @@ bad_area:
                current->tss.cr3, page);
        page = ((unsigned long *) page)[address >> 22];
        printk(KERN_ALERT "*pde = %08lx\n", page);
-       if (page & PAGE_PRESENT) {
+       if (page & 1) {
                page &= PAGE_MASK;
                address &= 0x003ff000;
                page = ((unsigned long *) page)[address >> PAGE_SHIFT];
index d3b41d5cf27a25345478cf222d056bece38b3a28..c74bce6f7b324fd829ddda6cc39c51f28188d01f 100644 (file)
@@ -36,19 +36,19 @@ extern void show_net_buffers(void);
  * ZERO_PAGE is a special page that is used for zero-initialized
  * data and COW.
  */
-unsigned long __bad_pagetable(void)
+pte_t * __bad_pagetable(void)
 {
        extern char empty_bad_page_table[PAGE_SIZE];
 
        __asm__ __volatile__("cld ; rep ; stosl":
-               :"a" (BAD_PAGE + PAGE_TABLE),
+               :"a" (pte_val(BAD_PAGE)),
                 "D" ((long) empty_bad_page_table),
                 "c" (PTRS_PER_PAGE)
                :"di","cx");
-       return (unsigned long) empty_bad_page_table;
+       return (pte_t *) empty_bad_page_table;
 }
 
-unsigned long __bad_page(void)
+pte_t __bad_page(void)
 {
        extern char empty_bad_page[PAGE_SIZE];
 
@@ -57,7 +57,7 @@ unsigned long __bad_page(void)
                 "D" ((long) empty_bad_page),
                 "c" (PTRS_PER_PAGE)
                :"di","cx");
-       return (unsigned long) empty_bad_page;
+       return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
 }
 
 unsigned long __zero_page(void)
@@ -111,8 +111,8 @@ extern unsigned long free_area_init(unsigned long, unsigned long);
  */
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
-       unsigned long * pg_dir;
-       unsigned long * pg_table;
+       pgd_t * pg_dir;
+       pte_t * pg_table;
        unsigned long tmp;
        unsigned long address;
 
@@ -129,20 +129,22 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        address = 0;
        pg_dir = swapper_pg_dir;
        while (address < end_mem) {
-               tmp = *(pg_dir + 768);          /* at virtual addr 0xC0000000 */
-               if (!tmp) {
-                       tmp = start_mem | PAGE_TABLE;
-                       *(pg_dir + 768) = tmp;
+               /* map the memory at virtual addr 0xC0000000 */
+               if (pgd_none(pg_dir[768])) {
+                       pgd_set(pg_dir+768, (pte_t *) start_mem);
                        start_mem += PAGE_SIZE;
                }
-               *pg_dir = tmp;                  /* also map it in at 0x0000000 for init */
+               pg_table = (pte_t *) pgd_page(pg_dir[768]);
+
+               /* also map it tempoarily at 0x0000000 for init */
+               pgd_set(pg_dir+768, pg_table);
+               pgd_set(pg_dir, pg_table);
                pg_dir++;
-               pg_table = (unsigned long *) (tmp & PAGE_MASK);
                for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) {
                        if (address < end_mem)
-                               *pg_table = address | PAGE_SHARED;
+                               *pg_table = mk_pte(address, PAGE_SHARED);
                        else
-                               *pg_table = 0;
+                               pte_clear(pg_table);
                        address += PAGE_SIZE;
                }
        }
@@ -208,7 +210,7 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
                datapages << (PAGE_SHIFT-10));
 /* test if the WP bit is honoured in supervisor mode */
        wp_works_ok = -1;
-       pg0[0] = PAGE_READONLY;
+       pg0[0] = pte_val(mk_pte(0, PAGE_READONLY));
        invalidate();
        __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory");
        pg0[0] = 0;
index 5527c9b7105086a44ad28643331cbe7585769684..46eae8ea20df09ec72ee15c1faf83fe6f206beaf 100644 (file)
@@ -45,7 +45,7 @@ old kernel, in order to reboot if something goes wrong!
 2. INSTALLATION
 If you received this software as a standalone package AZTECH.CDROM.Vxx.tgz 
 (xx=version number) and not included in the standard Linux kernel, read the 
-file AZTECH.CDROM.Vxx.README included in that package to install it. The 
+file AZTECH.CDROM.README included in that package to install it. The 
 standalone package's home is 'ftp.gwdg.de : pub/linux/cdrom/drivers/aztech'.
 The driver consists of a header file 'aztcd.h', which normally should reside 
 in /usr/include/linux and the source code 'aztcd.c', which normally resides in
@@ -62,13 +62,12 @@ see the following message while Linux boots:
     Aztech CD-ROM Init: <drive type> detected
     Aztech CD-ROM Init: End
 If the message looks different and you are sure to have a supported drive,
-it may have a different base address. The Aztech driver does have an 'auto-
-detection feature', which looks for the CD-ROM drive at the base address 
-specified in aztcd.h at compile time. This address can be overwritten by boot 
-parameter aztcd=....You should reboot and start Linux with boot parameter 
-aztcd=<base address>, e.g. aztcd=0x320. If you do not know the base address, 
-start your PC with DOS and look at the boot message of your CD-ROM's DOS 
-driver. 
+it may have a different base address. The Aztech driver does look for the 
+CD-ROM drive at the base address specified in aztcd.h at compile time. This 
+address can be overwritten by boot parameter aztcd=....You should reboot and 
+start Linux with boot parameter aztcd=<base address>, e.g. aztcd=0x320. If 
+you do not know the base address, start your PC with DOS and look at the boot 
+message of your CD-ROM's DOS driver. 
 
 If the message looks correct, as user 'root' you should be able to mount the 
 drive by
@@ -146,13 +145,12 @@ Please send detailed bug reports and bug fixes via EMail to
 
         zimmerma@rz.fht-esslingen.de
 
-I also would like to get positive feedback. Please inform me, if you have
-positive test results. Please include a description of your CD-ROM drive
-type and interface card, the exact firmware message during Linux bootup, 
-the version number of the AZTECH-CDROM-driver and the Linux kernel version.
-Also a description of your system's other hardware could be of interest,
-especially microprocessor type, clock frequency, other interface cards such
-as soundcards, ethernet adapter, game cards etc..
+Please include a description of your CD-ROM drive type and interface card, 
+the exact firmware message during Linux bootup, the version number of the 
+AZTECH-CDROM-driver and the Linux kernel version. Also a description of your 
+system's other hardware could be of interest, especially microprocessor type, 
+clock frequency, other interface cards such as soundcards, ethernet adapter, 
+game cards etc..
 
 I will try to collect the reports and make the necessary modifications from 
 time to time. I may also come back to you directly with some bug fixes and 
@@ -172,12 +170,12 @@ snail mail address for such 'stuff' is
 7. OTHER DRIVES
 The following drives ORCHID CDS3110, OKANO CDD110 and WEARNES nearly look 
 the same as AZTECH CDA268-01A, especially they seem to use the same command 
-codes. So it should be simple to make the AZTECH driver work with these drives. 
+codes. So it was quite simple to make the AZTECH driver work with these drives. 
 
-Unfortuntately I do not have any of these drives available, so I can't test
-it. I've got reports, that it works with ORCHID CDS3110 and Game-Wave32
-sound cards and also with WEARNES CDD110 in some different combinations. In 
-some installations, it seems necessary to initialize the drive with the DOS 
+Unfortuntately I do not have any of these drives available, so I couldn't test
+it myself. But I've got reports, that it works with ORCHID CDS3110 and Game-
+Wave32 sound cards and also with WEARNES CDD110 in some different combinations. 
+In some installations, it seems necessary to initialize the drive with the DOS 
 driver before (especially if combined with a sound card) and then do a warm 
 boot (CTRL-ALT-RESET) or start Linux from DOS, e.g. with 'loadlin'.
 
@@ -350,8 +348,8 @@ great job in analyzing the command structure of various CD-ROM drives, this
 work would not have been possible. E.Moenkeberg was also a great help in 
 making the software 'kernel ready' and in answering many of the CDROM-related 
 questions in the newsgroups. He really is *the* Linux CD-ROM guru. Thanks 
-also to  Ruediger Helsch, Unifix, and to all the guys on the Internet, who 
-collected valuable technical information about CDROMs. 
+also to all the guys on the Internet, who collected valuable technical 
+information about CDROMs. 
 
 Joe Nardone (nardone@clark.net) was a patient tester even for my first
 trial, which was more than slow, and made suggestions for code improvement.
@@ -462,7 +460,7 @@ int main(void)
            unsigned char buf[2336];
          } azt;
 
-  printf("\nMini-Audio CD-Player V0.5   (C) 1994  W.Zimmermann\n");
+  printf("\nMini-Audio CD-Player V0.5   (C) 1994,1995  W.Zimmermann\n");
   handle=open("/dev/cdrom",O_RDWR);
   ioctl(handle,CDROMRESUME);
   
@@ -608,7 +606,7 @@ int main(void)
                            { printf("Drive error or invalid adress\n");
                            }
                           break;
-#ifdef AZT_PRIVATE_IOCTLS
+#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
               case 'd':   cmd=CDROMREADMODE1;
                           printf("Adress (min:sec:frame)  ");
                           scanf("%d:%d:%d",&arg1,&arg2,&arg3);
@@ -618,7 +616,7 @@ int main(void)
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt.msf)) 
-                           { printf("Drive error or invalid adress\n");
+                           { printf("Drive error, invalid adress or unsupported command\n");
                            }
                           k=0;
                           getchar();
@@ -651,7 +649,7 @@ int main(void)
                           if (azt.msf.cdmsf_sec0  > 59) azt.msf.cdmsf_sec0  =59;
                           if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
                           if (ioctl(handle,cmd,&azt)) 
-                           { printf("Drive error or invalid adress\n");
+                           { printf("Drive error, invalid adress or unsupported command\n");
                            }
                           k=0;
                           for (i=0;i<146;i++)
diff --git a/drivers/block/README.fd b/drivers/block/README.fd
new file mode 100644 (file)
index 0000000..0d49477
--- /dev/null
@@ -0,0 +1,114 @@
+This Readme file describes the floppy driver.
+
+FAQ list:
+=========
+
+ A FAQ list may be found in the fdutils package (see below), and also
+at ftp.imag.fr:pub/Linux/ZLIBC/floppy/FAQ
+
+
+Lilo config options (Thinkpad users, read this)
+===============================================
+
+ The floppy driver is configured using the 'floppy=' option in
+lilo. This option can be typed at the boot prompt, or entered in the
+lilo configuration file.
+ Example: If your kernel is called linux-72, type the following line
+at the lilo boot prompt (if you have a thinkpad):
+ linux-72 floppy=thinkpad
+You may also enter the following line in /etc/lilo.conf, in the description
+of linux-72:
+ append = "floppy=thinkpad"
+
+ Several floppy related options may be given, example:
+ linux-72 floppy=daring floppy=two_fdc
+ append = "floppy=daring floppy=two_fdc"
+
+ If you give options both in the lilo config file and on the boot
+prompt, the option strings of both places are concatenated, the boot
+prompt options coming last. That's why there are also options to
+restore the default behaviour.
+
+ The floppy related options include:
+
+ floppy=<mask>,allowed_drive_mask         
+       Sets the bitmask of allowed drives to <mask>. By default, only units
+       0 and 1 of each floppy controller are allowed. This is done because
+       certain non-standard hardware (ASUS PCI motherboards) mess up the
+       keyboard when accessing units 2 or 3.
+
+ floppy=two_fdc
+       Tells the floppy driver that you have two floppy controllers. The
+       second floppy controller is assumed to be at io address 0x370.
+
+ floppy=thinkpad
+       Tells the floppy driver that you have a Thinkpad. Thinkpads use an
+       inverted convention for the disk change line.
+
+
+
+Supporting utilities and additional documentation:
+==================================================
+
+ Additional parameters of the floppy driver can be configured at run
+time.  Utilities which do this can be found in the fdutils
+package. This package also contains a new version of mtools which
+allows to access high capacity disks (up to 1992K on a high density 3
+1/2 disk!). It also contains additional documentation about the floppy
+driver. It can be found at:
+ ftp.imag.fr:pub/Linux/ZLIBC/fdutils/fdutils-4.0.src.tar.gz
+ sunsite.unc.edu:/pub/Linux/system/Misc/fdutils-4.0.src.tar.gz
+ tsx-11.mit.edu:/pub/linux/sources/sbin/fdutils-4.0.src.tar.gz
+
+ Alpha patches to these utilities are at:
+ ftp.imag.fr:pub/Linux/ZLIBC/fdutils/ALPHA
+ All patches contained in this directory are directly against the base
+version, i.e. DON'T APPLY THEM ON TOP OF EACH OTHER. Only apply the
+most recent one.
+
+
+Alpha patches for the floppy driver:
+====================================
+
+ You may find ALPHA patches of the driver itself in
+ftp.imag.fr:pub/Linux/ZLIBC/floppy/ALPHA. These patches are named
+fdp<kernel-version>-<day><month>.diff.gz
+ WARNING: These _are_ ALPHA, and may introduce new problems! Some
+problems may only show up on certain hardware, or when trying weirdo
+things. So don't be misled by people claiming they are stable and
+should really be BETA. What works for one person, may not work for
+somebody else at all. This directory contains a RELEASES file
+describing the features of some of these patches.
+
+ If after some testing these patches prove to be sufficiently stable,
+they'll move into ftp.imag.fr:pub/Linux/ZLIBC/floppy/BETA.
+
+ You may find quick&dirty fixes to the driver in
+ftp.imag.fr:pub/Linux/ZLIBC/QDF. These patches are named
+fdp<kernel-version>-<day><month>.diff
+ These patches fix only the most obvious problems, or provide trivial
+enhancements. The main objective is to keep these patches small and
+local, in order to keep the probability of introducing new problems as
+small as possible. However, they may not attack the root of the
+problem but only cure the symptoms. This directory contains a RELEASES
+file describing the features of these patches.
+
+ The ALPHA, BETA and QDF directories are removed, and replaced by a
+README file when they get empty due to integration of the patches into
+the stock kernel. You may still find patches to old kernels in
+ftp.imag.fr:pub/Linux/ZLIBC/obsolete
+
+
+Reporting problems about the floppy driver
+==========================================
+
+ If you have a question or a bug report about the floppy driver, mail
+me at Alain.Knaff@imag.fr. If you post to the news, use preferably one
+of the groups comp.os.linux.help (for questions) or
+comp.os.linux.hardware (for bug reports). As the volume in these
+groups is rather high, be sure to include the word "floppy" (or
+"FLOPPY") in the subject line.
+
+ Be sure to read the FAQ before mailing/posting any bug reports!
+
+ Alain 
index 82bee1100070d4716ac7528a397994966a2d9ab1..febe434489f41b6c207714890ce417e0615a1a04 100644 (file)
@@ -18,7 +18,7 @@ Major features of ide.c & ide-cd.c:
        - optional (compile time) support for 32-bit VLB data transfers
        - support for IDE multiple (block) mode (same as hd.c)
        - support for interrupt unmasking during I/O (better than hd.c)
-       - auto detection/use of multiple (block) mode settings from BIOS
+       - compile flag for auto detection/use of multiple mode setting from BIOS
        - improved handshaking and error detection/recovery
        - can co-exist with hd.c to control only the secondary interface
 
@@ -96,10 +96,54 @@ mlord@bnr.ca
 snyder@fnald0.fnal.gov
 ================================================================================
 
-How To Use *Big* IDE drives with Linux/DOS
+Some Terminology
+----------------
+IDE = Integrated Drive Electonics, meaning that each drive has a built-in
+controller, which is why an "IDE interface card" is not a "controller card".
+
+IDE drives are designed to attach almost directly to the ISA bus of an AT-style
+computer.  The typcial IDE interface card merely provides I/O port address
+decoding and tri-state buffers, although several newer localbus cards go much
+beyond the basics.  When purchasing a localbus IDE interface, avoid cards with
+an onboard BIOS and those which require special drivers.  Instead, look for a
+card which uses hardware switches/jumpers to select the interface timing speed,
+to allow much faster data transfers than the original 8Mhz ISA bus allows.
+
+ATA = AT (the old IBM 286 computer) Attachment Interface, a draft American
+National Standard for connecting hard drives to PCs.  This is the official
+name for "IDE".
+
+The latest standards define some enhancements, known as the ATA-2 spec,
+which grew out of vendor-specific "Enhanced IDE" (EIDE) implementations.
+
+ATAPI = ATA Packet Interface, a new protocol for controlling the drives,
+similar to SCSI protocols, created at the same time as the ATA2 standard.
+ATAPI is currently used for controlling CDROM and TAPE devices, and will
+likely also soon be used for Floppy drives, removeable R/W cartridges,
+and for high capacity hard disk drives.
+
+How To Use *Big* ATA/IDE drives with Linux
 ------------------------------------------
-All IDE drives larger than 504MB ("528Meg") use a "physical" geometry which
-has more than 1024 cylinders.  This presents two problems to most systems:
+The ATA Interface spec for IDE disk drives allows a total of 28 bits
+(8 bits for sector, 16 bits for cylinder, and 4 bits for head) for addressing
+individual disk sectors of 512 bytes each (in "Linear Block Address" (LBA)
+mode, there is still only a total of 28 bits available in the hardware).
+This "limits" the capacity of an IDE drive to no more than 128GB (Giga-bytes).  All current day IDE drives are somewhat smaller than this upper limit, and
+within a few years, ATAPI disk drives will raise the limit considerably.
+
+All IDE disk drives "suffer" from a "16-heads" limitation:  the hardware has
+only a four bit field for head selection, restricting the number of "physical"
+heads to 16 or less.  Since the BIOS usually has a 63 sectors/track limit,
+this means that all IDE drivers larger than 504MB (528Meg) must use a "physical"
+geometry with more than 1024 cylinders.
+
+   (1024cyls * 16heads * 63sects * 512bytes/sector) / (1024 * 1024) == 504MB
+
+(Some BIOSs (and controllers with onboard BIOS) pretend to allow "32" or "64"
+ heads per drive (discussed below), but can only do so by playing games with
+ the real (hidden) geometry, which is always limited to 16 or fewer heads).
+
+This presents two problems to most systems:
 
        1. The INT13 interface to the BIOS only allows 10-bits for cylinder
        addresses, giving a limit of 1024cyls for programs which use it.
@@ -182,6 +226,11 @@ by doing the following after installing slackware (or whatever):
         5. Create a symlink for LILO to use with:  ln -s /dos/boot /boot
         6. Re-run LILO with:  lilo
 
+       A danger with this approach is that whenever an MS-DOS "defragmentation"
+       program is run (like Norton "speeddisk"), it may move the Linux boot
+       files around, confusing LILO and making the (Linux) system unbootable.
+       Be sure to keep a "boot floppy" kernel at hand for such circumstances.
+
 If you "don't do DOS", then partition as you please, but remember to create
 a small partition to hold the /boot directory (and vmlinuz) as described above
 such that they stay within the first 1024 cylinders.
index 1633c9ceb5281683414dc593dc26d2463e452c45..f06b66fe79a39c310f6aba6af250f3a021ca247e 100644 (file)
@@ -1,5 +1,5 @@
-#define AZT_VERSION "V0.72"
-/*      $Id: aztcd.c,v 0.72 1995/01/13 15:21:09 root Exp root $
+#define AZT_VERSION "V0.8"
+/*      $Id: aztcd.c,v 0.80 1995/01/21 19:54:53 root Exp $
        linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
 
        Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
                W.Zimmermann, Jan. 8, 1995
        V0.72   Some more modifications for adaption to the standard kernel.
                W.Zimmermann, Jan. 16, 1995
-                            
+        V0.80   aztcd is now part of the standard kernel since version 1.1.83.
+                Modified the SET_TIMER and CLEAR_TIMER macros to comply with
+                the new timer scheme.
+                W.Zimmermann, Jan. 21, 1995
        NOTE: 
        Points marked with ??? are questionable !
 */
 #include <asm/io.h>
 #include <asm/segment.h>
 
-#ifdef CONFIG_AZTCD
 #define MAJOR_NR AZTECH_CDROM_MAJOR 
-#else
-#define MAJOR_NR MITSUMI_CDROM_MAJOR    /*use Mitsumi major number, if Aztech*/                 
-#endif                                  /*major number is not configured*/
 
 #include "blk.h"
 #include <linux/aztcd.h>
@@ -128,7 +127,6 @@ static int aztPresent = 0;
 #define AZT_TEST4 /* QUICK_LOOP-counter */
 #define AZT_TEST5 /* port(1) state */
 #define AZT_DEBUG
-#define AZT_PRIVATE_IOCTLS /*incompatible ioctls*/
 #endif
 
 #define CURRENT_VALID \
@@ -176,6 +174,7 @@ static char  azt_init_end = 0;
 
 static int AztTimeout, AztTries;
 static struct wait_queue *azt_waitq = NULL; 
+static struct timer_list delay_timer = { NULL, NULL, 0, 0, NULL };
 
 static struct azt_DiskInfo DiskInfo;
 static struct azt_Toc Toc[MAX_TRACKS];
@@ -1208,6 +1207,7 @@ static void aztcd_release(struct inode * inode, struct file * file)
        azt_invalidate_buffers();
        sync_dev(inode->i_rdev);             /*??? isn't it a read only dev?*/
        invalidate_buffers(inode -> i_rdev);
+        CLEAR_TIMER;
   }
   return;
 }
index edf336dcd2fc89fa624cab8d232f14d664f5332a..d1ef1d90622151d023d75a8141f0e25f585eb7b6 100644 (file)
@@ -92,6 +92,8 @@
 
 #include <linux/config.h>
 
+#ifdef CONFIG_BLK_DEV_FD
+
 #ifndef FD_MODULE
 /* the following is the mask of allowed drives. By default units 2 and
  * 3 of both floppy controllers are disabled, because switching on the
@@ -108,7 +110,6 @@ static int FDC2=-1;
 
 #define MODULE_AWARE_DRIVER
 
-#ifdef CONFIG_BLK_DEV_FD
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -989,7 +990,7 @@ static void fdc_specify(void)
                /* TODO: lock this in via LOCK during initialization */
                output_byte(FD_CONFIGURE);
                output_byte(0);
-               output_byte(0x1A);      /* FIFO on, polling off, 10 byte threshold */
+               output_byte(0x2A);      /* FIFO on, polling off, 10 byte threshold */
                output_byte(0);         /* precompensation from track 0 upwards */
                if ( FDCS->reset ){
                        FDCS->has_fifo=0;
@@ -1708,9 +1709,10 @@ static void failure_and_wakeup(void)
 static int next_valid_format(void)
 {
        int probed_format;
+
+       probed_format = DRS->probed_format;
        while(1){
-               probed_format = DRS->probed_format;
-               if ( probed_format > N_DRIVE ||
+               if ( probed_format >= 8 ||
                    ! DP->autodetect[probed_format] ){
                        DRS->probed_format = 0;
                        return 1;
index 8d10c4478362891f426e902ca70123d01b65a261..fe33b5befd9c08d1adf95e108dd36f4f850dff02 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c  Version 3.8  January 12, 1995
+ *  linux/drivers/block/ide.c  Version 3.10  January 21, 1995
  *
  *  Copyright (C) 1994, 1995  Linus Torvalds & authors (see below)
  */
  *  Version 3.8                fixed byte-swapping for confused Mitsumi cdrom drives
  *                     update of ide-cd.c from Scott, allows blocksize=1024
  *                     cdrom probe fixes, inspired by jprang@uni-duisburg.de
+ *  Version 3.9                don't use LBA if lba_capacity looks funny
+ *                     correct the drive capacity calculations
+ *                     fix probing for old Seagates without HD_ALTSTATUS
+ *                     fix byte-ordering for some NEC cdrom drives
+ *  Version 3.10       disable multiple mode by default; was causing trouble
  *
  *  To do:
  *     - special 32-bit controller-type detection & support
  *     - figure out how to support oddball "intelligent" caching cards
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/hdreg.h>
 #include <linux/genhd.h>
-#include <linux/config.h>
 #include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/major.h>
 #include <asm/io.h>
 
 #undef REALLY_FAST_IO                  /* define if ide ports are perfect */
-#undef INITIAL_MULT_COUNT              /* define to override status quo */
-
+#define INITIAL_MULT_COUNT     0       /* undef to use BIOS setting on entry */
+                                       /*   or non-zero to enable block mode */
 #ifndef VLB_32BIT_IDE                  /* 0 for safety, 1 for 32-bit chipset:*/
 #define VLB_32BIT_IDE          0       /*   Winbond 83759F or OPTi 82C621 */
 #endif
@@ -1567,7 +1572,11 @@ static void fixstring (byte *s, int bytecount, int byteswap)
                *p++ = '\0';
 }
 
-static unsigned long fix_lba_capacity (struct hd_driveid *id)
+static int lba_capacity_is_ok (struct hd_driveid *id)
+/*
+ * Returns:    1 if lba_capacity looks sensible
+ *             0 otherwise
+ */
 {
        unsigned long lba_sects   = id->lba_capacity;
        unsigned long chs_sects   = id->cyls * id->heads * id->sectors;
@@ -1575,15 +1584,15 @@ static unsigned long fix_lba_capacity (struct hd_driveid *id)
 
        /* perform a rough sanity check on lba_sects:  within 10% is "okay" */
        if ((lba_sects - chs_sects) < _10_percent)
-               return lba_sects;
+               return 1;       /* lba_capacity is good */
 
        /* some drives have the word order reversed */
        lba_sects = (lba_sects << 16) | (lba_sects >> 16);
-       if ((lba_sects - chs_sects) < _10_percent)
-               return (id->lba_capacity = lba_sects);
-
-       /* play it safe and assume lba capacity is the same as chs capacity */
-       return chs_sects;
+       if ((lba_sects - chs_sects) < _10_percent) {
+               id->lba_capacity = lba_sects;   /* fix it */
+               return 1;       /* lba_capacity is (now) good */
+       }
+       return 0;       /* lba_capacity value is bad */
 }
 
 static unsigned long probe_mem_start;  /* used by drive/irq probing routines */
@@ -1591,6 +1600,7 @@ static unsigned long probe_mem_start;     /* used by drive/irq probing routines */
 static void do_identify (ide_dev_t *dev)
 {
        int bswap;
+       unsigned short model01;
        struct hd_driveid *id;
        unsigned long capacity, check;
 
@@ -1601,16 +1611,23 @@ static void do_identify (ide_dev_t *dev)
 
        /*
         * Non-ATAPI drives seem to always use big-endian string ordering.
-        * Most ATAPI cdrom drives, such as the NEC, Vertos, and some Mitsumi
-        * models, use little-endian.  But other Mitsumi models appear to use
-        * big-endian, confusing the issue.  We try to take all of this into 
-        * consideration, "knowing" that Mitsumi drive names begin with "FX".
+        * Most ATAPI cdrom drives, such as the Vertos, and some NEC and Mitsumi
+        * models, use little-endian.  But some NEC/Mitsumi revisions appear to
+        * use big-endian, confusing the issue.  We try to take all of this
+        * into consideration, "knowing" that Mitsumi drive model names begin
+        * with "FX" and NEC drive model names begin with "NE".
         */
-       bswap = 1;
-       if (id->model[0] != 'X' || id->model[1] != 'F') {
-               if ((id->model[0] == 'F' && id->model[1] == 'X') || (id->config & 0x8000))
-                       bswap = 0;
-       }
+#define PAIR(hi,lo)    ((unsigned short)((hi<<8)|(lo&0xff)))
+       model01 = PAIR(id->model[0],id->model[1]);
+       if (model01 == PAIR('N','E') || model01 == PAIR('F','X'))
+               bswap = 0;      /* little endian NEC or Mitsumi */
+       else if (model01 == PAIR('E','N') || model01 == PAIR('X','F'))
+               bswap = 1;      /* big endian NEC or Mitsumi */
+       else if ((id->config & 0x8000) || dev->type == cdrom)
+               bswap = 0;      /* all other ATAPI drives */
+       else
+               bswap = 1;      /* all other non-ATAPI drives */
+#undef PAIR
        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);
@@ -1636,17 +1653,15 @@ static void do_identify (ide_dev_t *dev)
                return;
        }
 
-       /*
-        * Gather up the geometry info.
-        */
        dev->type = disk;
+       /* Extract geometry if we did not already have one for the drive */
        if (!dev->present) {
                dev->present = 1;
                dev->cyl     = dev->bios_cyl  = id->cyls;
                dev->head    = dev->bios_head = id->heads;
                dev->sect    = dev->bios_sect = id->sectors; 
        }
-       capacity = BIOS_SECTORS(dev);   /* default value */
+       /* Handle logical geometry translation by the drive */
        if ((id->field_valid & 1) && id->cur_cyls && id->cur_heads
         && (id->cur_heads <= 16) && id->cur_sectors)
        {
@@ -1670,22 +1685,23 @@ static void do_identify (ide_dev_t *dev)
                if (check == capacity)          /* was it swapped? */
                        *((int *)&id->cur_capacity0) = capacity; /* fix it */
        }
-       if (id->capability & 2) {       /* use LBA if the drive supports it */
-               capacity  = fix_lba_capacity(id);
-               dev->select.b.lba = 1;
-               if (!dev->head || dev->head > 16) {
-                       dev->cyl  = id->cyls;   /* WIN_SPECIFY needs a valid */
-                       dev->head = id->heads;  /*  geometry or it fails.  */
-                       dev->sect = id->sectors; 
-               }
+       /* Use physical geometry if what we have still makes no sense */
+       if ((!dev->head || dev->head > 16) && id->heads && id->heads <= 16) {
+               dev->cyl  = id->cyls;
+               dev->head = id->heads;
+               dev->sect = id->sectors; 
        }
        /* Correct the number of cyls if the bios value is too small */
        if (dev->sect == dev->bios_sect && dev->head == dev->bios_head) {
-               if (dev->cyl > dev->bios_cyl) {
+               if (dev->cyl > dev->bios_cyl)
                        dev->bios_cyl = dev->cyl;
-                       if (!(id->capability & 2))      /* if NOT using LBA */
-                               capacity = BIOS_SECTORS(dev);
-               }
+       }
+       /* Determine capacity, and use LBA if the drive properly supports it */
+       if ((id->capability & 2) && lba_capacity_is_ok(id)) {
+               dev->select.b.lba = 1;
+               capacity = id->lba_capacity;
+       } else {
+               capacity = dev->cyl * dev->head * dev->sect;
        }
 
        ide_capacity[DEV_HWIF][dev->select.b.drive] = capacity;
@@ -1693,17 +1709,18 @@ static void do_identify (ide_dev_t *dev)
         dev->name, id->model, capacity/2048L, id->buf_size/2,
         dev->select.b.lba ? "LBA, " : "",
         dev->bios_cyl, dev->bios_head, dev->bios_sect);
+
+       /* Keep current multiplemode setting, if any (from DOS/BIOS) */
        if (id->max_multsect) {
-               /*
-                * Keep current multiplemode setting, if any (from DOS/BIOS):
-                */
                if ((id->multsect_valid & 1) && id->multsect)
                        dev->mult_count = id->multsect; /* current setting */
 #ifdef INITIAL_MULT_COUNT
-               if (INITIAL_MULT_COUNT <= id->max_multsect)
-                       dev->mult_req = INITIAL_MULT_COUNT;
-               else
+               dev->mult_req = INITIAL_MULT_COUNT;
+#if INITIAL_MULT_COUNT
+               /* use specified value, or maximum, whichever is less */
+               if (INITIAL_MULT_COUNT > id->max_multsect)
                        dev->mult_req = id->max_multsect;
+#endif
 #else  /* use existing setting from DOS/BIOS: */
                if (dev->mult_count <= id->max_multsect) /* valid? */
                        dev->mult_req = dev->mult_count; /* keep it */
@@ -1729,7 +1746,7 @@ static int try_to_identify (ide_dev_t *dev, byte cmd)
  *             2  device aborted the command (refused to identify itself)
  */
 {
-       int rc;
+       int hd_status, rc;
        unsigned long timeout;
 #if PROBE_FOR_IRQS
        int irqs = 0;
@@ -1744,18 +1761,23 @@ static int try_to_identify (ide_dev_t *dev, byte cmd)
        }
 #endif /* PROBE_FOR_IRQS */
        delay_10ms();                           /* take a deep breath */
+       if (IN_BYTE(HD_ALTSTATUS,DEV_HWIF) == IN_BYTE(HD_STATUS,DEV_HWIF))
+               hd_status = HD_ALTSTATUS;       /* use non-intrusive polling */
+       else
+               hd_status = HD_STATUS;          /* an ancient Seagate drive */
        OUT_BYTE(cmd,HD_COMMAND);               /* ask drive for ID */
-       delay_10ms();                           /* wait for BUSY_STAT */
        timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
-       for (timeout += jiffies; IN_BYTE(HD_ALTSTATUS,DEV_HWIF) & BUSY_STAT;) {
-               if (timeout < jiffies) {
+       timeout += jiffies;
+       do {
+               if (jiffies > timeout) {
 #if PROBE_FOR_IRQS
                        if (!irq_probed[DEV_HWIF])
                                (void) probe_irq_off(irqs);
 #endif /* PROBE_FOR_IRQS */
                        return 1;       /* drive timed-out */
                }
-       }
+               delay_10ms();           /* give drive a breather */
+       } while (IN_BYTE(hd_status,DEV_HWIF) & BUSY_STAT);
        delay_10ms();           /* wait for IRQ and DRQ_STAT */
        if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_RW_STAT)) {
                cli();                  /* some systems need this */
@@ -1821,7 +1843,8 @@ static int do_probe (ide_dev_t *dev, byte cmd)
                if ((rc = try_to_identify(dev, cmd)))  /* send cmd and wait */
                        rc = try_to_identify(dev, cmd); /* failed: try again */
                if (rc == 1)
-                       printk("%s: no response\n", dev->name);
+                       printk("%s: no response (status = 0x%02x)\n",
+                        dev->name, GET_STAT(DEV_HWIF));
                OUT_BYTE(dev->ctl|2,HD_CMD);    /* disable device irq */
                delay_10ms();
                (void) GET_STAT(DEV_HWIF);      /* ensure drive irq is clear */
index e9570354f396d61d78f48c834be4171b7407ae72..d69e051a3709728ea7f814e0654e8a20830e9391 100644 (file)
@@ -87,7 +87,13 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
 {
        if (vma->vm_offset & ~PAGE_MASK)
                return -ENXIO;
-#ifdef __i386__
+#if 0 && defined(__i386__)
+       /*
+        * hmm.. This disables high-memory caching, as the XFree86 team wondered
+        * about that at one time. It doesn't seem to make a difference, though:
+        * the surround logic should disable caching for the high device addresses
+        * anyway.
+        */
        if (x86 > 3 && vma->vm_offset >= high_memory)
                vma->vm_page_prot |= PAGE_PCD;
 #endif
@@ -163,7 +169,7 @@ static int read_zero(struct inode * node,struct file * file,char * buf,int count
 
 static int mmap_zero(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
-       if (vma->vm_page_prot & PAGE_RW)
+       if (vma->vm_flags & VM_SHARED)
                return -EINVAL;
        if (zeromap_page_range(vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot))
                return -EAGAIN;
index 4dad30e06840e613429b8487672885c6b01b89bd..e3ef3e160a6b2580c37656a596fd2c5d5b694add 100644 (file)
@@ -166,6 +166,9 @@ endif
 ifdef CONFIG_APRICOT
 NETDRV_OBJS := $(NETDRV_OBJS) apricot.o
 endif
+ifdef CONFIG_DEC_ELCP
+NETDRV_OBJS := $(NETDRV_OBJS) tulip.o
+endif
 
 ifdef CONFIG_8390
 NETDRV_OBJS := $(NETDRV_OBJS) 8390.o
index 52cd20df59508ff5e89a3616234d885327207721..63059ad0fae8ae552fe0e63f29862d62717afae8 100644 (file)
        straight-forward Fujitsu MB86965 implementation.
 
   Sources:
-    The Fujitsu MB86695 datasheet.
+    The Fujitsu MB86965 datasheet.
 
-       After the initial version of this driver was written Gerry Sockins of
+       After the initial version of this driver was written Gerry Sawkins of
        ATI provided their EEPROM configuration code header file.
     Thanks to NIIBE Yutaka <gniibe@mri.co.jp> for bug fixes.
 
   Bugs:
-       The MB86695 has a design flaw that makes all probes unreliable.  Not
+       The MB86965 has a design flaw that makes all probes unreliable.  Not
        only is it difficult to detect, it also moves around in I/O space in
        response to inb()s from other device probes!
 */
 
 static char *version =
-       "at1700.c:v1.10 9/24/94  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+       "at1700.c:v1.12 1/18/95  Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/config.h>
 
@@ -70,7 +70,6 @@ typedef unsigned char uchar;
 /* Information that need to be kept for each board. */
 struct net_local {
        struct enet_statistics stats;
-       long open_time;                         /* Useless example local info. */
        uint tx_started:1;                      /* Number of packet on the Tx queue. */
        uchar tx_queue;                         /* Number of packet on the Tx queue. */
        ushort tx_queue_len;            /* Current length of the Tx queue. */
@@ -207,7 +206,7 @@ int at1700_probe1(struct device *dev, short ioaddr)
 
        /* Grab the region so that we can find another board if the IRQ request
           fails. */
-       request_region(ioaddr, AT1700_IO_EXTENT,"at1700");
+       request_region(ioaddr, AT1700_IO_EXTENT, "at1700");
 
        printk("%s: AT1700 found at %#3x, IRQ %d, address ", dev->name,
                   ioaddr, irq);
@@ -345,12 +344,14 @@ static int net_open(struct device *dev)
        /* Switch to register bank 2 for the run-time registers. */
        outb(0xe8, ioaddr + CONFIG_1);
 
+       lp->tx_started = 0;
+       lp->tx_queue = 0;
+       lp->tx_queue_len = 0;
+
        /* Turn on Rx interrupts, leave Tx interrupts off until packet Tx. */
        outb(0x00, ioaddr + TX_INTR);
        outb(0x81, ioaddr + RX_INTR);
 
-       lp->open_time = jiffies;
-
        dev->tbusy = 0;
        dev->interrupt = 0;
        dev->start = 1;
@@ -385,6 +386,9 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
                outw(0x8100, ioaddr + TX_INTR);
                dev->tbusy=0;
                dev->trans_start = jiffies;
+               lp->tx_started = 0;
+               lp->tx_queue = 0;
+               lp->tx_queue_len = 0;
        }
 
        /* If some higher layer thinks we've missed an tx-done interrupt
@@ -492,6 +496,7 @@ net_rx(struct device *dev)
 
        while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {
                ushort status = inw(ioaddr + DATAPORT);
+               ushort pkt_len = inw(ioaddr + DATAPORT);
 
                if (net_debug > 4)
                        printk("%s: Rxing packet mode %02x status %04x.\n",
@@ -510,13 +515,14 @@ net_rx(struct device *dev)
                        if (status & 0x02) lp->stats.rx_crc_errors++;
                        if (status & 0x01) lp->stats.rx_over_errors++;
                } else {
-                       ushort pkt_len = inw(ioaddr + DATAPORT);
                        /* Malloc up new buffer. */
                        struct sk_buff *skb;
 
                        if (pkt_len > 1550) {
                                printk("%s: The AT1700 claimed a very large packet, size %d.\n",
                                           dev->name, pkt_len);
+                               /* Prime the FIFO and then flush the packet. */
+                               inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
                                outb(0x05, ioaddr + 14);
                                lp->stats.rx_errors++;
                                break;
@@ -525,6 +531,8 @@ net_rx(struct device *dev)
                        if (skb == NULL) {
                                printk("%s: Memory squeeze, dropping packet (len %d).\n",
                                           dev->name, pkt_len);
+                               /* Prime the FIFO and then flush the packet. */
+                               inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
                                outb(0x05, ioaddr + 14);
                                lp->stats.rx_dropped++;
                                break;
@@ -533,15 +541,6 @@ net_rx(struct device *dev)
                        skb->dev = dev;
 
                        insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1);
-
-                       if (net_debug > 5) {
-                               int i;
-                               printk("%s: Rxed packet of length %d: ", dev->name, pkt_len);
-                               for (i = 0; i < 14; i++)
-                                       printk(" %02x", skb->data[i]);
-                               printk(".\n");
-                       }
-
                        netif_rx(skb);
                        lp->stats.rx_packets++;
                }
@@ -574,8 +573,6 @@ static int net_close(struct device *dev)
        struct net_local *lp = (struct net_local *)dev->priv;
        int ioaddr = dev->base_addr;
 
-       lp->open_time = 0;
-
        dev->tbusy = 1;
        dev->start = 0;
 
index d2ad308d26f464cd3f1cfdb4b78d26a852db6be1..9caf47c29fe828c022ebdbd74bc7db7974ecff37 100644 (file)
@@ -1,23 +1,30 @@
-/* atp.c: Attached (pocket) ethernet adaptor driver for linux. */
+/* atp.c: Attached (pocket) ethernet adapter driver for linux. */
 /*
-       Written 1993 by Donald Becker.
-       Copyright 1993 United States Government as represented by the Director,
-       National Security Agency.  This software may only be used and distributed
-       according to the terms of the GNU Public License as modified by SRC,
-       incorporated herein by reference.
+       This is a driver for a commonly OEMed pocket (parallel port)
+       ethernet adapter.  
 
-       The author may be reached as becker@super.org or
-       C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+       Written 1993,1994,1995 by Donald Becker.
 
+       Copyright 1993 United States Government as represented by the
+       Director, National Security Agency.
+
+       This software may be used and distributed according to the terms
+       of the GNU Public License, incorporated herein by reference.
+
+       The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+       Center of Excellence in Space Data and Information Sciences
+               Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+       The timer-based reset code was written by Bill Carlson, wwc@super.org.
 */
 
 static char *version =
-       "atp.c:v0.04 2/25/94 Donald Becker (becker@super.org)\n";
+       "atp.c:v1.01 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 /*
        This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket
-       ethernet adaptor.  This is a common low-cost OEM pocket ethernet
-       adaptor, sold under many names.
+       ethernet adapter.  This is a common low-cost OEM pocket ethernet
+       adapter, sold under many names.
 
   Sources:
        This driver was written from the packet driver assembly code provided by
@@ -28,7 +35,7 @@ static char *version =
 
                                        Theory of Operation
        
-       The RTL8002 adaptor seems to be built around a custom spin of the SEEQ
+       The RTL8002 adapter seems to be built around a custom spin of the SEEQ
        controller core.  It probably has a 16K or 64K internal packet buffer, of
        which the first 4K is devoted to transmit and the rest to receive.
        The controller maintains the queue of received packet and the packet buffer
@@ -40,7 +47,7 @@ static char *version =
        The station address is stored in a standard bit-serial EEPROM which must be
        read (ughh) by the device driver.  (Provisions have been made for
        substituting a 74S288 PROM, but I haven't gotten reports of any models
-       using it.)  Unlike built-in devices, a pocket adaptor can temporarily lose
+       using it.)  Unlike built-in devices, a pocket adapter can temporarily lose
        power without indication to the device driver.  The major effect is that
        the station address, receive filter (promiscuous, etc.) and transceiver
        must be reset.
@@ -53,7 +60,7 @@ static char *version =
 
        Since the bulk data transfer of the actual packets through the slow
        parallel port dominates the driver's running time, four distinct data
-       (non-register) transfer modes are provided by the adaptor, two in each
+       (non-register) transfer modes are provided by the adapter, two in each
        direction.  In the first mode timing for the nibble transfers is
        provided through the data port.  In the second mode the same timing is
        provided through the control port.  In either case the data is read from
@@ -96,35 +103,26 @@ static char *version =
 
 #include "atp.h"
 
-/* Compatibility definitions for earlier kernel versions. */
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c, in ioport.h for later versions. */
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-/* The map from IRQ number (as passed to the interrupt handler) to
-   'struct device'. */
-extern struct device *irq2dev_map[16];
-#endif
-
-#ifndef HAVE_ALLOC_SKB
-#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
-#define kfree_skbmem(addr, size) kfree_s(addr,size);
-#endif
-
-#ifndef HAVE_PORTRESERVE
-#define check_region(ioaddr, size)             0
-#define request_region(ioaddr, size,name)      do ; while (0)
-#endif
-
 /* use 0 for production, 1 for verification, >2 for debug */
 #ifndef NET_DEBUG
-#define NET_DEBUG 4
+#define NET_DEBUG 1
 #endif
 static unsigned int net_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
 #define ETHERCARD_TOTAL_SIZE   3
 
+/* This code, written by wwc@super.org, resets the adapter every
+   TIMED_CHECKER ticks.  This recovers from an unknown error which
+   hangs the device. */
+#define TIMED_CHECKER (HZ/4)
+#ifdef TIMED_CHECKER
+#include <linux/timer.h>
+static void atp_timed_checker(unsigned long ignored);
+static struct device *atp_timed_dev;
+static struct timer_list atp_timer = {NULL, NULL, 0, 0, atp_timed_checker};
+#endif
+
 /* Index to functions, as function prototypes. */
 
 extern int atp_probe(struct device *dev);
@@ -145,7 +143,7 @@ static struct enet_statistics *net_get_stats(struct device *dev);
 static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
 
 \f
-/* Check for a network adaptor of this type, and return '0' iff one exists.
+/* Check for a network adapter of this type, and return '0' iff one exists.
    If dev->base_addr == 0, probe all likely locations.
    If dev->base_addr == 1, always return failure.
    If dev->base_addr == 2, allocate space for the device and return success
@@ -189,7 +187,7 @@ static int atp_probe1(struct device *dev, short ioaddr)
        status = read_nibble(ioaddr, CMR1);
 
        if ((status & 0x78) != 0x08) {
-               /* The pocket adaptor probe failed, restore the control register. */
+               /* The pocket adapter probe failed, restore the control register. */
                outb(saved_ctrl_reg, ioaddr + PAR_CONTROL);
                return 1;
        }
@@ -215,7 +213,7 @@ static int atp_probe1(struct device *dev, short ioaddr)
        /* Read the station address PROM.  */
        get_node_ID(dev);
 
-       printk("%s: Pocket adaptor found at %#3x, IRQ %d, SAPROM "
+       printk("%s: Pocket adapter found at %#3x, IRQ %d, SAPROM "
                   "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
                   dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
                   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
@@ -237,7 +235,7 @@ static int atp_probe1(struct device *dev, short ioaddr)
                lp->addr_mode = CMR2h_Normal;
        }
 
-       /* For the ATP adaptor the "if_port" is really the data transfer mode. */
+       /* For the ATP adapter the "if_port" is really the data transfer mode. */
        dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4;
        if (dev->mem_end & 0xf)
                net_debug = dev->mem_end & 7;
@@ -248,6 +246,12 @@ static int atp_probe1(struct device *dev, short ioaddr)
        dev->get_stats  = net_get_stats;
        dev->set_multicast_list = &set_multicast_list;
 
+#ifdef TIMED_CHECKER
+       del_timer(&atp_timer);
+       atp_timer.expires = TIMED_CHECKER;
+       atp_timed_dev = dev;
+       add_timer(&atp_timer);
+#endif
        return 0;
 }
 
@@ -260,7 +264,7 @@ static void get_node_ID(struct device *dev)
        
        write_reg(ioaddr, CMR2, CMR2_EEPROM);     /* Point to the EEPROM control registers. */
        
-       /* Some adaptors have the station address at offset 15 instead of offset
+       /* Some adapters have the station address at offset 15 instead of offset
           zero.  Check for it, and fix it if needed. */
        if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff)
                sa_offset = 15;
@@ -322,7 +326,7 @@ static int net_open(struct device *dev)
           port or interrupt may be shared. */
        if (irq2dev_map[dev->irq] != 0
                || (irq2dev_map[dev->irq] = dev) == 0
-               || request_irq(dev->irq, &net_interrupt, 0, "atp")) {
+               || request_irq(dev->irq, &net_interrupt, 0, "ATP")) {
                return -EAGAIN;
        }
 
@@ -422,7 +426,7 @@ net_send_packet(struct sk_buff *skb, struct device *dev)
                           inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
                           :  "IRQ conflict");
                lp->stats.tx_errors++;
-               /* Try to restart the adaptor. */
+               /* Try to restart the adapter. */
                hardware_init(dev);
                dev->tbusy=0;
                dev->trans_start = jiffies;
@@ -497,7 +501,7 @@ net_interrupt(int irq, struct pt_regs * regs)
        /* Disable additional spurious interrupts. */
        outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
 
-       /* The adaptor's output is currently the IRQ line, switch it to data. */
+       /* The adapter's output is currently the IRQ line, switch it to data. */
        write_reg(ioaddr, CMR2, CMR2_NULL);
        write_reg(ioaddr, IMR, 0);
 
@@ -532,7 +536,7 @@ net_interrupt(int irq, struct pt_regs * regs)
                } else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) {
                        if (net_debug > 6)  printk("handling Tx done..");
                        /* Clear the Tx interrupt.  We should check for too many failures
-                          and reinitialize the adaptor. */
+                          and reinitialize the adapter. */
                        write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);
                        if (status & (ISR_TxErr<<3)) {
                                lp->stats.collisions++;
@@ -574,14 +578,19 @@ net_interrupt(int irq, struct pt_regs * regs)
     }
 
        /* This following code fixes a rare (and very difficult to track down)
-          problem where the adaptor forgets its ethernet address. */
+          problem where the adapter forgets its ethernet address. */
        {
                int i;
                for (i = 0; i < 6; i++)
                        write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
+#ifdef TIMED_CHECKER
+               del_timer(&atp_timer);
+               atp_timer.expires = TIMED_CHECKER;
+               add_timer(&atp_timer);
+#endif
        }
 
-       /* Tell the adaptor that it can go back to using the output line as IRQ. */
+       /* Tell the adapter that it can go back to using the output line as IRQ. */
     write_reg(ioaddr, CMR2, CMR2_IRQOUT);
        /* Enable the physical interrupt line, which is sure to be low until.. */
        outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
@@ -596,6 +605,41 @@ net_interrupt(int irq, struct pt_regs * regs)
        return;
 }
 
+#ifdef TIMED_CHECKER
+/* This following code fixes a rare (and very difficult to track down)
+   problem where the adapter forgets its ethernet address. */
+static void atp_timed_checker(unsigned long ignored)
+{
+  int i;
+  int ioaddr = atp_timed_dev->base_addr;
+
+  if (!atp_timed_dev->interrupt)
+       {
+         for (i = 0; i < 6; i++)
+#if 0
+               if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])
+                 {
+                       struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
+                       write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
+                       if (i == 2)
+                         lp->stats.tx_errors++;
+                       else if (i == 3)
+                         lp->stats.tx_dropped++;
+                       else if (i == 4)
+                         lp->stats.collisions++;
+                       else
+                         lp->stats.rx_errors++;
+                 }
+#else
+         write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
+#endif
+       }
+  del_timer(&atp_timer);
+  atp_timer.expires = TIMED_CHECKER;
+  add_timer(&atp_timer);
+}
+#endif
+
 /* We have a good packet(s), get it/them out of the buffers. */
 static void net_rx(struct device *dev)
 {
@@ -708,7 +752,7 @@ net_get_stats(struct device *dev)
        return &lp->stats;
 }
 
-/* Set or clear the multicast filter for this adaptor.
+/* Set or clear the multicast filter for this adapter.
    num_addrs == -1     Promiscuous mode, receive all packets
    num_addrs == 0      Normal mode, clear multicast list
    num_addrs > 0       Multicast mode, receive normal and MC packets, and do
index 64fa762be4f1de2fb3a23cf80f4261c7e40b7ff9..d6cbb85a70ef8b8c7424b0b0fc672a398b898173 100644 (file)
@@ -68,7 +68,7 @@
     0) have a copy of the loadable modules code installed on your system.
     1) copy ewrk3.c from the  /linux/drivers/net directory to your favourite
     temporary directory.
-    2) edit the  source code near  line 1340 to reflect  the I/O address and
+    2) edit the  source code near  line 1830 to reflect  the I/O address and
     IRQ you're using.
     3) compile  ewrk3.c, but include -DMODULE in  the command line to ensure
     that the correct bits are compiled (see end of source code).
@@ -78,7 +78,7 @@
     6) run the net startup bits for your new eth?? interface manually 
     (usually /etc/rc.inet[12] at boot time). 
     7) enjoy!
-    
+
     [Alan Cox: Changed this so you can insmod ewrk3.o irq=x io=y]
 
     Note that autoprobing is not allowed in loadable modules - the system is
       0.24    31-oct-94   Added uid checks in some ioctls
       0.30     1-nov-94   BETA code release
       0.31     5-dec-94   Added check/snarf_region code.
+      0.32    16-jan-95   Broadcast packet fix
 
     =========================================================================
 */
 
-static char *version = "ewrk3.c:v0.31 12/5/94 davies@wanton.lkg.dec.com\n";
+static char *version = "ewrk3.c:v0.32 1/16/95 davies@wanton.lkg.dec.com\n";
 
 #include <stdarg.h>
 #include <linux/kernel.h>
@@ -195,6 +196,7 @@ static int ewrk3_debug = 1;
 
 #define EWRK3_IO_BASE 0x100             /* Start address for probe search */
 #define EWRK3_IOP_INC 0x20              /* I/O address increment */
+#define EWRK3_TOTAL_SIZE 0x20           /* required I/O address space */
 #define EWRK3_IO_SEARCH 0x007dff7f      /* probe search mask */
 static long mem_chkd = EWRK3_IO_SEARCH; /* holds which I/O addrs should be */
                                        /* checked, for multi-EWRK3 case */
@@ -212,9 +214,8 @@ static long mem_chkd = EWRK3_IO_SEARCH; /* holds which I/O addrs should be */
 #define EISA_SLOT_INC 0x1000
 #endif
 
-#ifndef CRC_POLYNOMIAL
-#define CRC_POLYNOMIAL 0x04c11db7       /* Ethernet CRC polynomial */
-#endif /* CRC_POLYNOMIAL */
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL   /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL   /* Ethernet CRC, little endian */
 
 /*
 ** EtherWORKS 3 shared memory window sizes
@@ -349,10 +350,11 @@ int ewrk3_probe(struct device *dev)
 
   if (base_addr > 0x0ff) {           /* Check a single specified location. */
     if (!autoprobed) {                /* Module or fixed location */
-      if (!check_region(base_addr, EWRK3_IOP_INC)) {
+      if (!check_region(base_addr, EWRK3_TOTAL_SIZE)) {
        if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==1) {
          if (DevicePresent(base_addr) == 0) {      /* Is EWRK3 really here? */
-           request_region(base_addr, EWRK3_IOP_INC,"ewrk3"); /* Register I/O region */
+                                                   /* Register I/O Region */
+           request_region(base_addr, EWRK3_IOP_INC, "ewrk3");
            status = ewrk3_hw_init(dev, base_addr);
          } else {
            printk("ewrk3_probe(): No device found\n");
@@ -1239,20 +1241,19 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
 /*
 ** Calculate the hash code and update the logical address filter
 ** from a list of ethernet multicast addresses.
-** Derived from a 'C' program in the AMD data book:
-** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)", 
-** Pub #17781, Rev. A, May 1993
+** Little endian crc one liner from Matt Thomas, DEC.
 **
+** Note that when clearing the table, the broadcast bit must remain asserted
+** to receive broadcast messages.
 */
 static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
 {
   struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
-  int iobase = dev->base_addr;
-  char j, ctrl, bit, octet;
+  int i, iobase = dev->base_addr;
+  char j, bit, byte;
   short *p = (short *) multicast_table;
-  unsigned short hashcode;
-  int i;
-  long int crc, poly = (long int) CRC_POLYNOMIAL;
+  u_short hashcode;
+  u_long crc, poly = CRC_POLYNOMIAL_LE;
 
   while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
 
@@ -1272,48 +1273,49 @@ static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, c
        i++;
       }
     }
-  } else if (num_addrs == 0) {
+  } else {
+    /* Clear table except for broadcast bit */
     if (lp->shmem_length == IO_ONLY) {
-      for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
+      for (i=0; i<(HASH_TABLE_LEN >> 4) - 1; i++) {
+       outb(0x00, EWRK3_DATA);
+      } 
+      outb(0x80, EWRK3_DATA); i++;           /* insert the broadcast bit */
+      for (; i<(HASH_TABLE_LEN >> 3); i++) {
        outb(0x00, EWRK3_DATA);
       } 
     } else {
       memset(multicast_table, 0, (HASH_TABLE_LEN >> 3));
+      *(multicast_table + (HASH_TABLE_LEN >> 4) - 1) = 0x80;
     }
-  } else {
+
+    /* Update table */
     for (i=0;i<num_addrs;i++) {              /* for each address in the list */
-      if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* multicast address? */ 
-       crc = (long int) 0xffffffff;         /* init CRC for each address */
-       for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
-         for(j=0;j<8;j++) {                 /* process each address bit */
-           bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
-           ctrl = ((crc < 0) ? 1 : 0);      /* shift the control bit */
-           crc <<= 1;                       /* shift the CRC */
-           if (bit ^ ctrl) {                /* (bit) XOR (control bit) */
-             crc ^= poly;                   /* (CRC) XOR (polynomial) */
-           }
+      if ((*addrs & 0x01) == 1) {            /* multicast address? */ 
+       crc = 0xffffffff;                    /* init CRC for each address */
+       for (byte=0;byte<ETH_ALEN;byte++) {  /* for each address byte */
+                                            /* process each address bit */ 
+         for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+           crc = (crc >> 1) ^ (((crc ^ bit) & 0x01) ? poly : 0);
          }
        }
-       hashcode = ((crc >>= 23) & 0x01);    /* hashcode is 9 MSb of CRC ... */
-       for (j=0;j<8;j++) {                  /* ... in reverse order. */
-         hashcode <<= 1;
-         crc >>= 1;
-         hashcode |= (crc & 0x01);
-       }                                      
-                                      
-       octet = hashcode >> 3;               /* bit[3-8] -> octet in filter */
-                                            /* bit[0-2] -> bit in octet */
+       hashcode = crc & ((1 << 9) - 1);     /* hashcode is 9 LSb of CRC */
+
+       byte = hashcode >> 3;                /* bit[3-8] -> byte in filter */
+       bit = 1 << (hashcode & 0x07);        /* bit[0-2] -> bit in byte */
+
        if (lp->shmem_length == IO_ONLY) {
          unsigned char tmp;
 
-         outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+         outw((short)((long)multicast_table) + byte, EWRK3_PIR1);
          tmp = inb(EWRK3_DATA);
-         tmp |= (1 << (hashcode & 0x07));
-         outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
+         tmp |= bit;
+         outw((short)((long)multicast_table) + byte, EWRK3_PIR1);
          outb(tmp, EWRK3_DATA); 
        } else {
-         multicast_table[octet] |= (1 << (hashcode & 0x07));
+         multicast_table[byte] |= bit;
        }
+      } else {                               /* skip this address */
+       addrs += ETH_ALEN;
       }
     }
   }
@@ -1337,13 +1339,13 @@ static struct device *isa_probe(struct device *dev)
        iobase += EWRK3_IOP_INC, i++) {
     if (tmp & 0x01) {
       /* Anything else registered here? */
-      if (!check_region(iobase, EWRK3_IOP_INC)) {    
+      if (!check_region(iobase, EWRK3_TOTAL_SIZE)) {    
        if (DevicePresent(iobase) == 0) {
 /*
 ** Device found. Mark its (I/O) location for future reference. Only 24
 ** EtherWORKS devices can exist between 0x100 and 0x3e0.
 */
-         request_region(iobase, EWRK3_IOP_INC,"ewrk3");
+         request_region(iobase, EWRK3_IOP_INC, "ewrk3");
          if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
            dev = alloc_device(dev, iobase);
          } else {
@@ -1379,14 +1381,14 @@ static struct device *eisa_probe(struct device *dev)
   for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
 
     /* Anything else registered here? */
-    if (!check_region(iobase, EWRK3_IOP_INC)) {
+    if (!check_region(iobase, EWRK3_TOTAL_SIZE)) {
       if (DevicePresent(iobase) == 0) {
 /*
 ** Device found. Mark its slot location for future reference. Only 7
 ** EtherWORKS devices can exist in EISA space....
 */
        mem_chkd |= (0x01 << (i + 24));
-       request_region(iobase, EWRK3_IOP_INC,"ewrk3");
+       request_region(iobase, EWRK3_IOP_INC, "ewrk3");
        if (num_ewrk3s > 0) {        /* only gets here in autoprobe */
          dev = alloc_device(dev, iobase);
        } else {
@@ -1827,7 +1829,6 @@ static struct device thisEthwrk = {
   0x300, 5,  /* I/O address, IRQ */
   0, 0, 0, NULL, ewrk3_probe };
        
-       
 int io=0x300;  /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
 int irq=5;     /* or use the insmod io= irq= options           */
 
index d1ef4100259a90fe697cbcb6e3cfa65119adbaf9..c8252503eaad5e7e942a1ab19223384ca0e953e5 100644 (file)
@@ -1,6 +1,6 @@
 /* lance.c: An AMD LANCE ethernet driver for linux. */
 /*
-       Written 1993-94 by Donald Becker.
+       Written 1993,1994,1995 by Donald Becker.
 
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.
@@ -15,7 +15,7 @@
           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 */
 
-static char *version = "lance.c:v1.06 11/29/94 becker@cesdis.gsfc.nasa.gov\n";
+static char *version = "lance.c:v1.07 1/18/95 becker@cesdis.gsfc.nasa.gov\n";
 
 #include <linux/config.h>
 #include <linux/kernel.h>
@@ -188,7 +188,8 @@ struct lance_init_block {
 };
 
 struct lance_private {
-       char devname[8];
+       char *name;
+       void *pad;
        /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
        struct lance_rx_head rx_ring[RX_RING_SIZE];
        struct lance_tx_head tx_ring[TX_RING_SIZE];
@@ -263,7 +264,8 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
                for (pci_index = 0; pci_index < 8; pci_index++) {
                        unsigned char pci_bus, pci_device_fn;
                        unsigned long pci_ioaddr;
-               
+                       unsigned short pci_command;
+
                        if (pcibios_find_device (AMD_VENDOR_ID, AMD_DEVICE_ID, pci_index,
                                                                         &pci_bus, &pci_device_fn) != 0)
                                break;
@@ -273,6 +275,18 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
                                                                          PCI_BASE_ADDRESS_0, &pci_ioaddr);
                        /* Remove I/O space marker in bit 0. */
                        pci_ioaddr &= ~3;
+                       /* PCI Spec 2.1 states that it is either the driver or PCI card's
+                        * responsibility to set the PCI Master Enable Bit if needed.
+                        *      (From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
+                        */
+                       pcibios_read_config_word(pci_bus, pci_device_fn,
+                                                                        PCI_COMMAND, &pci_command);
+                       if ( ! (pci_command & PCI_COMMAND_MASTER)) {
+                               printk("PCI Master Bit has not been set. Setting...\n");
+                               pci_command |= PCI_COMMAND_MASTER;
+                               pcibios_write_config_word(pci_bus, pci_device_fn,
+                                                                                 PCI_COMMAND, pci_command);
+                       }
                        printk("Found PCnet/PCI at %#lx, irq %d (mem_start is %#lx).\n",
                                   pci_ioaddr, pci_irq_line, mem_start);
                        mem_start = lance_probe1(pci_ioaddr, mem_start);
@@ -300,6 +314,7 @@ unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
        struct lance_private *lp;
        short dma_channels;                                     /* Mark spuriously-busy DMA channels */
        int i, reset_val, lance_version;
+       char *chipname;
        /* Flags for specific chips or boards. */
        unsigned char hpJ2405A = 0;                                             /* HP ISA adaptor */
        int hp_builtin = 0;                                     /* HP on-board ethernet. */
@@ -357,7 +372,8 @@ unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
                                                + PKT_BUF_SZ*(RX_RING_SIZE + TX_RING_SIZE),
                                                &mem_start);
 
-       printk("%s: %s at %#3x,", dev->name, chip_table[lance_version].name, ioaddr);
+       chipname = chip_table[lance_version].name;
+       printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
 
        /* There is a 16 byte station address PROM at the base address.
           The first six bytes are the station address. */
@@ -365,11 +381,12 @@ unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
                printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
 
        dev->base_addr = ioaddr;
-       request_region(ioaddr, LANCE_TOTAL_SIZE,"lance");
+       request_region(ioaddr, LANCE_TOTAL_SIZE, chip_table[lance_version].name);
 
        /* Make certain the data structures used by the LANCE are aligned. */
        dev->priv = (void *)(((int)dev->priv + 7) & ~7);
        lp = (struct lance_private *)dev->priv;
+       lp->name = chipname;
        lp->rx_buffs = (long)dev->priv + sizeof(struct lance_private);
        lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ])
                                                   (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE);
@@ -464,7 +481,7 @@ unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
        if (dev->dma == 4) {
                printk(", no DMA needed.\n");
        } else if (dev->dma) {
-               if (request_dma(dev->dma, "lance")) {
+               if (request_dma(dev->dma, chipname)) {
                        printk("DMA %d allocation failed.\n", dev->dma);
                        return mem_start;
                } else
@@ -480,7 +497,7 @@ unsigned long lance_probe1(int ioaddr, unsigned long mem_start)
                        if (test_bit(dma, &dma_channels))
                                continue;
                        outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
-                       if (request_dma(dma, "lance"))
+                       if (request_dma(dma, chipname))
                                continue;
                        set_dma_mode(dma, DMA_MODE_CASCADE);
                        enable_dma(dma);
@@ -534,7 +551,7 @@ lance_open(struct device *dev)
        int i;
 
        if (dev->irq == 0 ||
-               request_irq(dev->irq, &lance_interrupt, 0, "lance")) {
+               request_irq(dev->irq, &lance_interrupt, 0, lp->name)) {
                return -EAGAIN;
        }
 
@@ -587,7 +604,11 @@ lance_open(struct device *dev)
        while (i++ < 100)
                if (inw(ioaddr+LANCE_DATA) & 0x0100)
                        break;
-       outw(0x0142, ioaddr+LANCE_DATA);
+       /* 
+        * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+        * reports that doing so triggers a bug in the '974.
+        */
+       outw(0x0042, ioaddr+LANCE_DATA);
 
        if (lance_debug > 2)
                printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",
index 123f893240a4b1e866a234dd381920aa19128e43..af7f70e82a44512ea3b7ad812e58b02a3be38943 100644 (file)
@@ -40,8 +40,9 @@
    Given that almost all of these functions are handled in the current
    socket-based scheme, putting ethercard devices in /dev/ seems pointless.
    
-   [Removed all support for /dev network devices. When someone adds streams then
-    by magic we get them, but otherwise they are un-needed and a space waste]
+   [Removed all support for /dev network devices. When someone adds
+    streams then by magic we get them, but otherwise they are un-needed
+       and a space waste]
 */
 
 /* The list of used and available "eth" slots (for "eth0", "eth1", etc.) */
@@ -51,7 +52,7 @@ static struct device *ethdev_index[MAX_ETH_CARDS];
 unsigned long lance_init(unsigned long mem_start, unsigned long mem_end);
 unsigned long pi_init(unsigned long mem_start, unsigned long mem_end);
 unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end);
-
+unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end);
 
 /*
   net_dev_init() is our network device initialization routine.
@@ -62,11 +63,17 @@ unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end);
 unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
 {
 
-#if defined(CONFIG_LANCE)                      /* Note this is _not_ CONFIG_AT1500. */
+       /* Network device initialization for devices that must allocate
+          low-memory or contiguous DMA buffers.
+          */
+#if defined(CONFIG_LANCE)
        mem_start = lance_init(mem_start, mem_end);
 #endif
 #if defined(CONFIG_PI)
        mem_start = pi_init(mem_start, mem_end);
+#endif 
+#if defined(CONFIG_DEC_ELCP)
+       mem_start = dec21040_init(mem_start, mem_end);
 #endif 
        return mem_start;
 }
@@ -82,14 +89,33 @@ unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end)
  */
 
 struct device *
-init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
+init_etherdev(struct device *dev, int sizeof_priv, unsigned long *mem_startp)
 {
        int new_device = 0;
        int i;
 
+       /* Use an existing correctly named device in Space.c:dev_base. */
        if (dev == NULL) {
                int alloc_size = sizeof(struct device) + sizeof("eth%d  ")
-                       + sizeof_private + 3;
+                       + sizeof_priv + 3;
+               struct device *cur_dev;
+               char pname[8];          /* Putative name for the device.  */
+
+               for (i = 0; i < MAX_ETH_CARDS; ++i)
+                       if (ethdev_index[i] == NULL) {
+                               sprintf(pname, "eth%d", i);
+                               for (cur_dev = dev_base; cur_dev; cur_dev = cur_dev->next)
+                                       if (strcmp(pname, cur_dev->name) == 0) {
+                                               dev = cur_dev;
+                                               dev->init = NULL;
+                                               if (mem_startp && *mem_startp ) {
+                                                       dev->priv = (void*) *mem_startp;
+                                                       *mem_startp += sizeof_priv + 3;
+                                               } else
+                                                       dev->priv = kmalloc(sizeof_priv + 3, GFP_KERNEL);
+                                               goto found;
+                                       }
+                       }
 
                alloc_size &= ~3;               /* Round to dword boundary. */
 
@@ -99,12 +125,14 @@ init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
                } else
                        dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
                memset(dev, 0, alloc_size);
-               if (sizeof_private)
+               if (sizeof_priv)
                        dev->priv = (void *) (dev + 1);
-               dev->name = sizeof_private + (char *)(dev + 1);
+               dev->name = sizeof_priv + (char *)(dev + 1);
                new_device = 1;
        }
 
+       found:                                          /* From the double loop above. */
+
        if (dev->name &&
                ((dev->name[0] == '\0') || (dev->name[0] == ' '))) {
                for (i = 0; i < MAX_ETH_CARDS; ++i)
@@ -115,7 +143,7 @@ init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
                        }
        }
 
-       ether_setup(dev); /* should this be called here? */
+       ether_setup(dev);       /* Hmmm, should this be called here? */
        
        if (new_device) {
                /* Append the device to the device queue. */
index 8988e2d2494927576c62c85e51e28a3619754898..6f015688753fec93609b2298c63988fd2ccc4f3f 100644 (file)
@@ -1,6 +1,6 @@
 /* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
 /*
-       Written 1993-94 by Donald Becker.
+       Written 1993,1994,1995 by Donald Becker.
 
        Copyright 1993 United States Government as represented by the
        Director, National Security Agency.
        Center of Excellence in Space Data and Information Sciences
                Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
 
-       This is a driver for the SMC Ultra ethercard.
+       This is a driver for the SMC Ultra and SMC EtherEZ ethercards.
 
+       This driver uses the cards in the 8390-compatible, shared memory mode.
+       Most of the run-time complexity is handled by the generic code in
+       8390.c.  The code in this file is responsible for
+
+               ultra_probe()           Detecting and initializing the card.
+               ultra_probe1()  
+
+               ultra_open()            The card-specific details of starting, stopping
+               ultra_reset_8390()      and resetting the 8390 NIC core.
+               ultra_close()
+
+               ultra_block_input()             Routines for reading and writing blocks of
+               ultra_block_output()    packet buffer memory.
+
+       This driver enables the shared memory only when doing the actual data
+       transfers to avoid a bug in early version of the card that corrupted
+       data transferred by a AHA1542.
+
+       This driver does not support the programmed-I/O data transfer mode of
+       the EtherEZ.  That support (if available) is smc-ez.c.  Nor does it
+       use the non-8390-compatible "Altego" mode. (No support currently planned.)
 */
 
 static char *version =
-       "smc-ultra.c:v1.11 11/21/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+       "smc-ultra.c:v1.12 1/18/95 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -93,10 +114,13 @@ int ultra_probe1(struct device *dev, int ioaddr)
        char *model_name;
        unsigned char eeprom_irq = 0;
        /* Values from various config regs. */
-       unsigned char num_pages, irqreg, addr, reg4 = inb(ioaddr + 4) & 0x7f;
+       unsigned char num_pages, irqreg, addr;
+       unsigned char idreg = inb(ioaddr + 7);
+       unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
 
        /* Check the ID nibble. */
-       if ((inb(ioaddr + 7) & 0xF0) != 0x20)
+       if ((idreg & 0xF0) != 0x20                      /* SMC Ultra */
+               && (idreg & 0xF0) != 0x40)              /* SMC EtherEZ */
                return ENODEV;
 
        /* Select the station address register set. */
@@ -110,7 +134,9 @@ int ultra_probe1(struct device *dev, int ioaddr)
        if (dev == NULL)
                dev = init_etherdev(0, sizeof(struct ei_device), 0);
 
-       printk("%s: SMC Ultra at %#3x,", dev->name, ioaddr);
+       model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
+
+       printk("%s: %s at %#3x,", dev->name, model_name, ioaddr);
 
        for (i = 0; i < 6; i++)
                printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
@@ -128,8 +154,6 @@ int ultra_probe1(struct device *dev, int ioaddr)
           can find the card after a warm boot. */
        outb(reg4, ioaddr + 4);
 
-       model_name = "SMC Ultra";
-
        if (dev->irq < 2) {
                unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15};
                int irq;
@@ -146,8 +170,8 @@ int ultra_probe1(struct device *dev, int ioaddr)
        }
 
 
-       /* OK, were are certain this is going to work.  Setup the device. */
-       request_region(ioaddr, 32,"smc-ultra");
+       /* OK, we are certain this is going to work.  Setup the device. */
+       request_region(ioaddr, 32, model_name);
 
        /* The 8390 isn't at the base address, so fake the offset */
        dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
@@ -192,7 +216,7 @@ ultra_open(struct device *dev)
 {
        int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
 
-       if (request_irq(dev->irq, ei_interrupt, 0, "SMC Ultra"))
+       if (request_irq(dev->irq, ei_interrupt, 0, ei_status.name))
                return -EAGAIN;
 
        outb(ULTRA_MEMENB, ioaddr);     /* Enable memory, 16 bit mode. */
diff --git a/drivers/net/tulip.c b/drivers/net/tulip.c
new file mode 100644 (file)
index 0000000..add32d6
--- /dev/null
@@ -0,0 +1,733 @@
+/* tulip.c: A DEC 21040 ethernet driver for linux. */
+/*
+   NOTICE: this version works with kernels 1.1.82 and later only!
+       Written 1994,1995 by Donald Becker.
+
+       This software may be used and distributed according to the terms
+       of the GNU Public License, incorporated herein by reference.
+
+       This driver is for the SMC EtherPower PCI ethernet adapter.
+       It should work with most other DEC 21*40-based ethercards.
+
+       The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+       Center of Excellence in Space Data and Information Sciences
+          Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+*/
+
+static char *version = "tulip.c:v0.03 1/18/95 becker@cesdis.gsfc.nasa.gov\n";
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+/* This will be in linux/etherdevice.h someday. */
+struct device *init_etherdev(struct device *dev, int sizeof_private,
+                                                        unsigned long *mem_startp);
+
+/* The total size is unusually large: The 21040 aligns each of its 16
+   longword-wide registers on a quadword boundary. */
+#define TULIP_TOTAL_SIZE 0x80
+
+#ifdef HAVE_DEVLIST
+struct netdev_entry tulip_drv =
+{"Tulip", tulip_pci_probe, TULIP_TOTAL_SIZE, NULL};
+#endif
+
+#define TULIP_DEBUG 3
+#ifdef TULIP_DEBUG
+int tulip_debug = TULIP_DEBUG;
+#else
+int tulip_debug = 1;
+#endif
+
+/*
+                               Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the DECchip 21040 "Tulip", Digital's
+single-chip ethernet controller for PCI, as used on the SMC EtherPower
+ethernet adapter.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS should be set to assign the
+PCI INTA signal to an otherwise unused system IRQ line.  While it's
+physically possible to shared PCI interrupt lines, the kernel doesn't
+support it. 
+
+III. Driver operation
+
+IIIa. Ring buffers
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+The current driver uses a statically allocated Rx ring of descriptors and
+buffers, and a list of the Tx buffers.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)         After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.     Iff the 'tp->tx_full' flag is set, it clears both the
+tx_full and tbusy flags.
+
+IV. Notes
+
+Thanks to Duke Kamstra of SMC for providing an EtherPower board.
+
+The DEC databook doesn't document which Rx filter settings accept broadcast
+packets.  Nor does it document how to configure the part to configure the
+serial subsystem for normal (vs. loopback) operation or how to have it
+autoswitch between internal 10baseT, SIA and AUI transceivers.
+
+The databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written.   Hmmm, now how is that possible?
+*/
+
+#define DEC_VENDOR_ID  0x1011          /* Hex 'D' :-> */
+#define DEC_21040_ID   0x0002          /* Change for 21140. */
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE   4
+#define RX_RING_SIZE   4
+#define PKT_BUF_SZ             1536                    /* Size of each temporary Rx buffer.*/
+
+/* Offsets to the Command and Status Registers, "CSRs".  All accesses
+   must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+       CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+       CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+       CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+       int status;
+       int length;
+       char *buffer1, *buffer2;                        /* We use only buffer 1.  */
+};
+
+struct tulip_tx_desc {
+       int status;
+       int length;
+       char *buffer1, *buffer2;                        /* We use only buffer 1.  */
+};
+
+struct tulip_private {
+       char devname[8];                        /* Used only for kernel debugging. */
+       struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+       struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+       struct sk_buff* tx_skbuff[TX_RING_SIZE];
+       long rx_buffs;                          /* Address of temporary Rx buffers. */
+       struct enet_statistics stats;
+       int setup_frame[48];            /* Pseudo-Tx frame to init address table. */
+       unsigned int cur_rx, cur_tx;            /* The next free ring entry */
+       unsigned int dirty_rx, dirty_tx;        /* The ring entries to be free()ed. */
+       unsigned int tx_full:1;
+       int pad0, pad1;                                         /* Used for 8-byte alignment */
+};
+
+static unsigned long tulip_probe1(unsigned long mem_start, int ioaddr,
+                                                                 int irq);
+static int tulip_open(struct device *dev);
+static void tulip_init_ring(struct device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct device *dev);
+static int tulip_rx(struct device *dev);
+static void tulip_interrupt(int irq, struct pt_regs *regs);
+static int tulip_close(struct device *dev);
+static struct enet_statistics *tulip_get_stats(struct device *dev);
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+static int set_mac_address(struct device *dev, void *addr);
+
+\f
+
+/* This 21040 probe is unlike most other board probes.  We can use memory
+   efficiently by allocating a large contiguous region and dividing it
+   ourselves.  This is done by having the initialization occur before
+   the 'kmalloc()' memory management system is started. */
+
+unsigned long dec21040_init(unsigned long mem_start, unsigned long mem_end)
+{
+
+    if (pcibios_present()) {
+           int pci_index;
+               printk("tulip.c: PCI bios is present, checking for devices...\n");
+               for (pci_index = 0; pci_index < 8; pci_index++) {
+                       unsigned char pci_bus, pci_device_fn, pci_irq_line;
+                       unsigned long pci_ioaddr;
+               
+                       if (pcibios_find_device (DEC_VENDOR_ID, DEC_21040_ID, pci_index,
+                                                                        &pci_bus, &pci_device_fn) != 0)
+                               break;
+                       pcibios_read_config_byte(pci_bus, pci_device_fn,
+                                                                        PCI_INTERRUPT_LINE, &pci_irq_line);
+                       pcibios_read_config_dword(pci_bus, pci_device_fn,
+                                                                         PCI_BASE_ADDRESS_0, &pci_ioaddr);
+                       /* Remove I/O space marker in bit 0. */
+                       pci_ioaddr &= ~3;
+                       if (tulip_debug > 2)
+                               printk("Found DEC PCI Tulip at I/O %#lx, IRQ %d.\n",
+                                          pci_ioaddr, pci_irq_line);
+                       mem_start = tulip_probe1(mem_start, pci_ioaddr, pci_irq_line);
+               }
+       }
+
+       return mem_start;
+}
+
+unsigned long tulip_probe1(unsigned long mem_start, int ioaddr, int irq)
+{
+       static int did_version = 0;                     /* Already printed version info. */
+       struct device *dev;
+       struct tulip_private *tp;
+       int i;
+
+       if (tulip_debug > 0  &&  did_version++ == 0)
+               printk(version);
+
+       dev = init_etherdev(0, sizeof(struct tulip_private)
+                                               + PKT_BUF_SZ*RX_RING_SIZE,
+                                               &mem_start);
+
+       printk("%s: DEC 21040 Tulip at %#3x,", dev->name, ioaddr);
+
+       /* The station address ROM is read byte serially.  The register must
+          be polled, waiting for the value to be read bit serially from the
+          EEPROM.
+          */
+       outl(0, ioaddr + CSR9);         /* Reset the pointer with a dummy write. */
+       for (i = 0; i < 6; i++) {
+               int value, boguscnt = 100000;
+               do
+                       value = inl(ioaddr + CSR9);
+               while (value < 0  && --boguscnt > 0);
+               printk(" %2.2x", dev->dev_addr[i] = value);
+       }
+
+       /* We do a request_region() only to register /proc/ioports info. */
+       request_region(ioaddr, TULIP_TOTAL_SIZE, "DEC Tulip Ethernet");
+
+       dev->base_addr = ioaddr;
+       dev->irq = irq;
+
+       /* Make certain the data structures are quadword aligned. */
+       dev->priv = (void *)(((int)dev->priv + 7) & ~7);
+       tp = (struct tulip_private *)dev->priv;
+       tp->rx_buffs = (long)dev->priv + sizeof(struct tulip_private);
+
+       printk(", Rx buffers at %#x, IRQ %d\n", tp->rx_buffs, dev->irq);
+
+       /* The Tulip-specific entries in the device structure. */
+       dev->open = &tulip_open;
+       dev->hard_start_xmit = &tulip_start_xmit;
+       dev->stop = &tulip_close;
+       dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_MULTICAST
+       dev->set_multicast_list = &set_multicast_list;
+#endif
+#ifdef HAVE_SET_MAC_ADDR
+       dev->set_mac_address = &set_mac_address;
+#endif
+
+       return mem_start;
+}
+
+\f
+static int
+tulip_open(struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+
+       /* Reset the chip, holding bit 0 set at least 10 PCI cycles. */
+       outl(0xfff80001, ioaddr + CSR0);
+       SLOW_DOWN_IO;
+       /* Deassert reset.  Wait the specified 50 PCI cycles by initializing
+          Tx and Rx queues and the address filter list. */
+       outl(0xfff80000, ioaddr + CSR0);
+
+       if (irq2dev_map[dev->irq] != NULL
+               || (irq2dev_map[dev->irq] = dev) == NULL
+               || dev->irq == 0
+               || request_irq(dev->irq, &tulip_interrupt, 0, "DEC 21040 Tulip")) {
+               return -EAGAIN;
+       }
+
+       if (tulip_debug > 1)
+               printk("%s: tulip_open() irq %d.\n",
+                          dev->name, dev->irq);
+
+       tulip_init_ring(dev);
+
+       /* Fill the whole address filter table with our physical address. */
+       { 
+               unsigned short *eaddrs = (unsigned short *)dev->dev_addr;
+               int *setup_frm = tp->setup_frame, i;
+
+               /* You must add the broadcast address when doing perfect filtering! */
+               *setup_frm++ = 0xffff;
+               *setup_frm++ = 0xffff;
+               *setup_frm++ = 0xffff;
+               /* Fill the rest of the accept table with our physical address. */
+               for (i = 1; i < 16; i++) {
+                       *setup_frm++ = eaddrs[0];
+                       *setup_frm++ = eaddrs[1];
+                       *setup_frm++ = eaddrs[2];
+               }
+               /* Put the setup frame on the Tx list. */
+               tp->tx_ring[0].length = 0x08000000 | 192;
+               tp->tx_ring[0].buffer1 = (char *)tp->setup_frame;
+               tp->tx_ring[0].buffer2 = 0;
+               tp->tx_ring[0].status = 0x80000000;
+
+               tp->cur_tx++, tp->dirty_tx++;
+       }
+
+       outl((int)tp->rx_ring, ioaddr + CSR3);
+       outl((int)tp->tx_ring, ioaddr + CSR4);
+
+       /* Turn on the xcvr interface. */
+       outl(0x00000000, ioaddr + CSR13);
+       outl(0x00000004, ioaddr + CSR13);
+
+       /* Start the chip's Tx and Rx processes. */
+       outl(0xfffe2002, ioaddr + CSR6);
+
+       /* Trigger an immediate transmit demand to process the setup frame. */
+       outl(0, ioaddr + CSR1);
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       /* Enable interrupts by setting the interrupt mask. */
+       outl(0xFFFFFFFF, ioaddr + CSR7);
+
+       if (tulip_debug > 2) {
+               printk("%s: Done tulip_open(), CSR0 %8.8x, CSR13 %8.8x.\n",
+                          dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR13));
+       }
+       return 0;
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void
+tulip_init_ring(struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int i;
+
+       tp->tx_full = 0;
+       tp->cur_rx = tp->cur_tx = 0;
+       tp->dirty_rx = tp->dirty_tx = 0;
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               tp->rx_ring[i].status = 0x80000000;     /* Owned by Tulip chip */
+               tp->rx_ring[i].length = PKT_BUF_SZ;
+               tp->rx_ring[i].buffer1 = (char *)(tp->rx_buffs + i*PKT_BUF_SZ);
+               tp->rx_ring[i].buffer2 = (char *)&tp->rx_ring[i+1];
+       }
+       /* Mark the last entry as wrapping the ring. */ 
+       tp->rx_ring[i-1].length = PKT_BUF_SZ | 0x02000000;
+       tp->rx_ring[i-1].buffer2 = (char *)&tp->rx_ring[0];
+
+       /* The Tx buffer descriptor is filled in as needed, but we
+          do need to clear the ownership bit. */
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               tp->tx_ring[i].status = 0x00000000;
+       }
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       int ioaddr = dev->base_addr;
+       int entry;
+
+       /* Transmitter timeout, serious problems. */
+       if (dev->tbusy) {
+               int tickssofar = jiffies - dev->trans_start;
+               int i;
+               if (tickssofar < 20)
+                       return 1;
+               printk("%s: transmit timed out, status %8.8x, SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+                          dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+                          inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+               printk("  Rx ring %8.8x: ", (int)tp->rx_ring);
+               for (i = 0; i < RX_RING_SIZE; i++)
+                       printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+               printk("\n  Tx ring %8.8x: ", (int)tp->tx_ring);
+               for (i = 0; i < TX_RING_SIZE; i++)
+                       printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+               printk("\n");
+
+               tp->stats.tx_errors++;
+               /* We should reinitialize the hardware here. */
+               dev->tbusy=0;
+               dev->trans_start = jiffies;
+               return 0;
+       }
+
+       if (skb == NULL || skb->len <= 0) {
+               printk("%s: Obsolete driver layer request made: skbuff==NULL.\n",
+                          dev->name);
+               dev_tint(dev);
+               return 0;
+       }
+
+       /* Block a timer-based transmit from overlapping.  This could better be
+          done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+          If this ever occurs the queue layer is doing something evil! */
+       if (set_bit(0, (void*)&dev->tbusy) != 0) {
+               printk("%s: Transmitter access conflict.\n", dev->name);
+               return 1;
+       }
+
+       /* Caution: the write order is important here, set the base address
+          with the "ownership" bits last. */
+
+       /* Calculate the next Tx descriptor entry. */
+       entry = tp->cur_tx % TX_RING_SIZE;
+
+       tp->tx_full = 1;
+       tp->tx_skbuff[entry] = skb;
+       tp->tx_ring[entry].length = skb->len |
+               (entry == TX_RING_SIZE-1 ? 0xe2000000 : 0xe0000000);
+       tp->tx_ring[entry].buffer1 = skb->data;
+       tp->tx_ring[entry].buffer2 = 0;
+       tp->tx_ring[entry].status = 0x80000000; /* Pass ownership to the chip. */
+
+       tp->cur_tx++;
+
+       /* Trigger an immediate transmit demand. */
+       outl(0, ioaddr + CSR1);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void tulip_interrupt(int irq, struct pt_regs *regs)
+{
+       struct device *dev = (struct device *)(irq2dev_map[irq]);
+       struct tulip_private *lp;
+       int csr5, ioaddr, boguscnt=10;
+
+       if (dev == NULL) {
+               printk ("tulip_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+
+       ioaddr = dev->base_addr;
+       lp = (struct tulip_private *)dev->priv;
+       if (dev->interrupt)
+               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+
+       dev->interrupt = 1;
+
+       do {
+               csr5 = inl(ioaddr + CSR5);
+               /* Acknowledge all of the current interrupt sources ASAP. */
+               outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+               if (tulip_debug > 4)
+                       printk("%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+                                  dev->name, csr5, inl(dev->base_addr + CSR5));
+
+               if ((csr5 & 0x00018000) == 0)
+                       break;
+
+               if (csr5 & 0x0040)                      /* Rx interrupt */
+                       tulip_rx(dev);
+
+               if (csr5 & 0x0001) {            /* Tx-done interrupt */
+                       int dirty_tx = lp->dirty_tx;
+
+                       while (dirty_tx < lp->cur_tx) {
+                               int entry = dirty_tx % TX_RING_SIZE;
+                               int status = lp->tx_ring[entry].status;
+
+                               if (status < 0)
+                                       break;                  /* It still hasn't been Txed */
+
+                               if (status & 0x8000) {
+                                       /* There was an major error, log it. */
+                                       lp->stats.tx_errors++;
+                                       if (status & 0x4104) lp->stats.tx_aborted_errors++;
+                                       if (status & 0x0C00) lp->stats.tx_carrier_errors++;
+                                       if (status & 0x0200) lp->stats.tx_window_errors++;
+                                       if (status & 0x0002) lp->stats.tx_fifo_errors++;
+                                       if (status & 0x0080) lp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+                                       if (status & 0x0100) lp->stats.collisions16++;
+#endif
+                               } else {
+#ifdef ETHER_STATS
+                                       if (status & 0x0001) lp->stats.tx_deferred++;
+#endif
+                                       lp->stats.collisions += (status >> 3) & 15;
+                                       lp->stats.tx_packets++;
+                               }
+
+                               /* Free the original skb. */
+                               dev_kfree_skb(lp->tx_skbuff[entry], FREE_WRITE);
+                               dirty_tx++;
+                       }
+
+#ifndef final_version
+                       if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+                               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+                                          dirty_tx, lp->cur_tx, lp->tx_full);
+                               dirty_tx += TX_RING_SIZE;
+                       }
+#endif
+
+                       if (lp->tx_full && dev->tbusy
+                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+                               /* The ring is no longer full, clear tbusy. */
+                               lp->tx_full = 0;
+                               dev->tbusy = 0;
+                               mark_bh(NET_BH);
+                       }
+
+                       lp->dirty_tx = dirty_tx;
+               }
+
+               /* Log errors. */
+               if (csr5 & 0x8000) {    /* Abnormal error summary bit. */
+                       if (csr5 & 0x0008) lp->stats.tx_errors++; /* Tx babble. */
+                       if (csr5 & 0x0100) {            /* Missed a Rx frame. */
+                               lp->stats.rx_errors++;
+                               lp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+                       }
+                       if (csr5 & 0x0800) {
+                               printk("%s: Something Wicked happened! %8.8x.\n",
+                                          dev->name, csr5);
+                               /* Hmmmmm, it's not clear what to do here. */
+                       }
+               }
+               if (--boguscnt < 0) {
+                       printk("%s: Too much work at interrupt, csr5=0x%8.8x.\n",
+                                  dev->name, csr5);
+                       /* Clear all interrupt sources. */
+                       outl(0x0001ffff, ioaddr + CSR5);
+                       break;
+               }
+       } while (1);
+
+       if (tulip_debug > 3)
+               printk("%s: exiting interrupt, csr5=%#4.4x.\n",
+                          dev->name, inl(ioaddr + CSR5));
+
+       /* Special code for testing *only*. */
+       {
+               static int stopit = 10;
+               if (dev->start == 0  &&  --stopit < 0) {
+                       printk("%s: Emergency stop, looping startup interrupt.\n",
+                                  dev->name);
+                       free_irq(irq);
+               }
+       }
+
+       dev->interrupt = 0;
+       return;
+}
+
+static int
+tulip_rx(struct device *dev)
+{
+       struct tulip_private *lp = (struct tulip_private *)dev->priv;
+       int entry = lp->cur_rx % RX_RING_SIZE;
+       int i;
+               
+       if (tulip_debug > 4)
+               printk(" In tulip_rx().\n");
+       /* If we own the next entry, it's a new packet. Send it up. */
+       while (lp->rx_ring[entry].status >= 0) {
+               int status = lp->rx_ring[entry].status;
+
+               if (tulip_debug > 4)
+                       printk("  tulip_rx() status was %8.8x.\n", status);
+               if ((status & 0x0300) != 0x0300) {
+                       printk("%s: Ethernet frame spanned multiple buffers, status %8.8x!\n",
+                                  dev->name, status);
+               } else if (status & 0x8000) {
+                       /* There was a fatal error. */
+                       lp->stats.rx_errors++; /* end of a packet.*/
+                       if (status & 0x0890) lp->stats.rx_length_errors++;
+                       if (status & 0x0004) lp->stats.rx_frame_errors++;
+                       if (status & 0x0002) lp->stats.rx_crc_errors++;
+                       if (status & 0x0001) lp->stats.rx_fifo_errors++;
+               } else {
+                       /* Malloc up new buffer, compatible with net-2e. */
+                       short pkt_len = lp->rx_ring[entry].status >> 16;
+                       struct sk_buff *skb;
+
+                       skb = alloc_skb(pkt_len, GFP_ATOMIC);
+                       if (skb == NULL) {
+                               printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+                               /* Check that at least two ring entries are free.
+                                  If not, free one and mark stats->rx_dropped++. */
+                               for (i=0; i < RX_RING_SIZE; i++)
+                                       if (lp->rx_ring[(entry+i) % RX_RING_SIZE].status < 0)
+                                               break;
+
+                               if (i > RX_RING_SIZE -2) {
+                                       lp->stats.rx_dropped++;
+                                       lp->rx_ring[entry].status = 0x80000000;
+                                       lp->cur_rx++;
+                               }
+                               break;
+                       }
+                       skb->len = pkt_len;
+                       skb->dev = dev;
+                       memcpy(skb->data, lp->rx_ring[entry].buffer1, pkt_len);
+                       printk("%s: New packet length %d status %#x %#x %#x %#x to %#x.\n",
+                                  dev->name, pkt_len, lp->rx_ring[entry].status,
+                                  lp->rx_ring[entry].length, lp->rx_ring[entry].buffer1,
+                                  lp->rx_ring[entry].buffer2,
+                                  lp->rx_ring[entry].buffer1);
+                       netif_rx(skb);
+                       lp->stats.rx_packets++;
+               }
+
+               lp->rx_ring[entry].status = 0x80000000;
+               entry = (++lp->cur_rx) % RX_RING_SIZE;
+       }
+
+       return 0;
+}
+
+static int
+tulip_close(struct device *dev)
+{
+       int ioaddr = dev->base_addr;
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+       dev->start = 0;
+       dev->tbusy = 1;
+
+       if (tulip_debug > 1)
+               printk("%s: Shutting down ethercard, status was %2.2x.\n",
+                          dev->name, inl(ioaddr + CSR5));
+
+       /* Disable interrupts by clearing the interrupt mask. */
+       outl(0x00000000, ioaddr + CSR7);
+       /* Stop the chip's Tx and Rx processes. */
+       outl(inl(ioaddr + CSR6) & ~0x2002, ioaddr + CSR6);
+
+       tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+       free_irq(dev->irq);
+       irq2dev_map[dev->irq] = 0;
+
+       return 0;
+}
+
+static struct enet_statistics *
+tulip_get_stats(struct device *dev)
+{
+       struct tulip_private *tp = (struct tulip_private *)dev->priv;
+       short ioaddr = dev->base_addr;
+
+       tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+       return &tp->stats;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+   num_addrs == -1             Promiscuous mode, receive all packets
+   num_addrs == 0              Normal mode, clear multicast list
+   num_addrs > 0               Multicast mode, receive normal and MC packets, and do
+                                               best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+       short ioaddr = dev->base_addr;
+       int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+
+       if (num_addrs > 15) {
+               /* Too many to filter perfectly -- accept all multicasts. */
+               outl(csr6 | 0x0080, ioaddr + CSR6);
+       } else if (num_addrs < 0) {                     /* Set promiscuous. */
+               outl(csr6 | 0x00C0, ioaddr + CSR6);
+               /* Log any net taps. */
+               printk("%s: Promiscuous mode enabled.\n", dev->name);
+       } else {
+               struct tulip_private *tp = (struct tulip_private *)dev->priv;
+               int *setup_frm = tp->setup_frame;
+               unsigned short *eaddrs = addrs;
+               int i;
+
+               /* We have <= 15 addresses that we can use the wonderful
+                  16 address perfect filtering of the Tulip.  Note that only
+                  the low shortword of setup_frame[] is valid. */
+               outl(csr6 | 0x0000, ioaddr + CSR6);
+               for(i = 0; i < num_addrs; i++) {
+                       *setup_frm++ = *eaddrs++;
+                       *setup_frm++ = *eaddrs++;
+                       *setup_frm++ = *eaddrs++;
+               }
+               /* Fill the rest of the table with our physical address. */
+               eaddrs = (unsigned short *)dev->dev_addr;
+               do {
+                       *setup_frm++ = eaddrs[0];
+                       *setup_frm++ = eaddrs[1];
+                       *setup_frm++ = eaddrs[2];
+               } while (++i < 16);
+
+               /* Now add this frame to the Tx list. */
+       }
+}
+
+static int
+set_mac_address(struct device *dev, void *addr)
+{
+       int i;
+       if (dev->start)
+               return -EBUSY;
+       printk("%s: Setting MAC address to ", dev->name);
+       for (i = 0; i < 6; i++)
+               printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+       printk(".\n");
+       return 0;
+}
+
+\f
+/*
+ * Local variables:
+ *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c tulip.c"
+ *  c-indent-level: 4
+ *  tab-width: 4
+ * End:
+ */
index 1aa26b84e481fc1479277ce7b0122ffd24257252..bd306a14ceccfb17088d404ff024fcfaae12cbaa 100644 (file)
@@ -52,9 +52,11 @@ SCSI_OBJS := $(SCSI_OBJS) sg.o
 SCSI_SRCS := $(SCSI_SRCS) sg.c
 endif
 
+SCSI_SRCS := $(SCSI_SRCS) qlogic.c
 ifdef CONFIG_SCSI_QLOGIC
 SCSI_OBJS := $(SCSI_OBJS) qlogic.o
-SCSI_SRCS := $(SCSI_SRCS) qlogic.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) qlogic.o
 endif
 
 ifdef CONFIG_SCSI_AHA152X
index 787019c9576e80c2f8db819c405a444c7491c021..4977fe258dbc0bcf3d26662f40b9033e5c460bef 100644 (file)
  * General Public License for more details.
  
  *
- * $Id: aha152x.c,v 1.6 1994/11/24 20:35:27 root Exp $
+ * $Id: aha152x.c,v 1.8 1995/01/21 22:07:19 root Exp root $
  *
 
  * $Log: aha152x.c,v $
+ * Revision 1.8  1995/01/21  22:07:19  root
+ * - snarf_region => request_region
+ * - aha152x_intr interface change
+ *
+ * Revision 1.7  1995/01/02  23:19:36  root
+ * - updated COMMAND_SIZE to cmd_len
+ * - changed sti() to restore_flags()
+ * - fixed some #ifdef which generated warnings
+ *
  * Revision 1.6  1994/11/24  20:35:27  root
  * - problem with odd number of bytes in fifo fixed
  *
 #if 0
 #endif
 
-#define DEBUG_QUEUE
 #define DEBUG_PHASES
-
-#endif
-
-#define DEBUG_RESET             /* resets should be rare */
-#define DEBUG_ABORT             /* aborts too */
+#define DEBUG_RESET
+#define DEBUG_ABORT
 
 #define DEBUG_DEFAULT (debug_reset|debug_abort)
 
+#endif
+
 /* END OF DEFINES */
 
 /* some additional "phases" for getphase() */
@@ -330,6 +337,18 @@ static void enter_driver(const char *);
 static void leave_driver(const char *);
 #endif
 
+/* possible i/o addresses for the AIC-6260 */
+static unsigned short ports[] =
+{
+  0x340,      /* default first */
+  0x140
+};
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+/* possible interrupt channels */
+static unsigned short irqs[] = { 9, 10, 11, 12, 0 };
+
+#if !defined(SKIP_BIOSTEST)
 /* possible locations for the Adaptec BIOS */
 static void *addresses[] =
 {
@@ -345,17 +364,6 @@ static void *addresses[] =
 };
 #define ADDRESS_COUNT (sizeof( addresses ) / sizeof( void * ))
 
-/* possible i/o addresses for the AIC-6260 */
-static unsigned short ports[] =
-{
-  0x340,      /* default first */
-  0x140
-};
-#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
-
-/* possible interrupt channels */
-static unsigned short ints[] = { 9, 10, 11, 12 };
-
 /* signatures for various AIC-6[23]60 based controllers.
    The point in detecting signatures is to avoid useless
    and maybe harmful probes on ports. I'm not sure that
@@ -378,6 +386,7 @@ static struct signature {
   { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },  /* Gigabyte Local-Bus-SCSI */
 };
 #define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+#endif
 
 
 static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
@@ -537,8 +546,10 @@ static int aha152x_porttest(int port_base)
 
 int aha152x_detect(Scsi_Host_Template * tpnt)
 {
-  int                 i, j,  ok;
+  int                 i, ok;
+#if defined(AUTOCONF)
   aha152x_config      conf;
+#endif
   int                 interrupt_level;
   
   if(setup_called)
@@ -585,9 +596,9 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
         }
 
       i=0;
-      while(ints[i] && (interrupt_level!=ints[i]))
+      while(irqs[i] && (interrupt_level!=irqs[i]))
         i++;
-      if(!ints[i])
+      if(!irqs[i])
         {
           printk("illegal IRQ %d\n", interrupt_level);
           panic("aha152x panics in line %d", __LINE__);
@@ -615,6 +626,8 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
   else
     {
 #if !defined(SKIP_BIOSTEST)
+      int j;
+
       ok=0;
       for( i=0; i < ADDRESS_COUNT && !ok; i++)
         for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
@@ -651,7 +664,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
 
       conf.cf_port = (GETPORT(PORTA)<<8) + GETPORT(PORTB);
 
-      interrupt_level = ints[conf.cf_irq];
+      interrupt_level = irqs[conf.cf_irq];
       this_host       = conf.cf_id;
       can_disconnect  = conf.cf_tardisc;
       can_doparity    = !conf.cf_parity;
@@ -722,7 +735,7 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
          can_disconnect ? "enabled" : "disabled",
          can_doparity ? "enabled" : "disabled");
 
-  request_region(port_base, TEST-SCSISEQ,"aha152x");        /* Register */
+  request_region(port_base, TEST-SCSISEQ, "aha152x");        /* Register */
   
   /* not expecting any interrupts */
   SETPORT(SIMODE0, 0);
@@ -737,6 +750,8 @@ int aha152x_detect(Scsi_Host_Template * tpnt)
  */
 int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
+  unsigned long flags;
+
 #if defined(DEBUG_RACE)
   enter_driver("queue");
 #else
@@ -749,13 +764,10 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 #if defined(DEBUG_QUEUE)
   if(aha152x_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( ", pieces = %d size = %u), ",
-            SCpnt->use_sg,
-            SCpnt->request_bufflen );
+    printk( ", cmd_len=%d, pieces = %d size = %u), ",
+            SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
     disp_ports();
   }
 #endif
@@ -790,6 +802,7 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
   SCpnt->SCp.sent_command        = 0;
 
   /* Turn led on, when this is the first command. */
+  save_flags(flags);
   cli();
   commands++;
   if(commands==1)
@@ -807,7 +820,7 @@ int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
       SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
       SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
     }
-  sti();
+  restore_flags(flags);
 
 #if defined(DEBUG_RACE)
   leave_driver("queue");
@@ -831,8 +844,10 @@ int aha152x_command( Scsi_Cmnd *SCpnt )
  */
 int aha152x_abort( Scsi_Cmnd *SCpnt)
 {
+  unsigned long flags;
   Scsi_Cmnd *ptr, *prev;
 
+  save_flags(flags);
   cli();
 
 #if defined(DEBUG_ABORT)
@@ -857,7 +872,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
         prev->host_scribble = ptr->host_scribble;
       else
         issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
-      sti();
+      restore_flags(flags);
 
       ptr->host_scribble = NULL;
       ptr->result = DID_ABORT << 16;
@@ -874,7 +889,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
       if(!current_SC)
         printk("bus busy w/o current command, ");
  
-      sti();
+      restore_flags(flags);
       return SCSI_ABORT_BUSY;
     }
 
@@ -883,7 +898,7 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
   if(current_SC)
   { 
     /* target entered bus free before COMMAND COMPLETE, nothing to abort */
-    sti();
+    restore_flags(flags);
     current_SC->result = DID_ERROR << 16;
     current_SC->done(current_SC);
     current_SC = (Scsi_Cmnd *) NULL;
@@ -922,7 +937,8 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
         abort_result=SCSI_ABORT_SUCCESS;
         aborting++;
         abortion_complete=0;
-        sti();
+
+        sti();  /* Hi Eric, guess what ;-) */
   
         /* sleep until the abortion is complete */
         while(!abortion_complete)
@@ -933,13 +949,13 @@ int aha152x_abort( Scsi_Cmnd *SCpnt)
     else
       {
         /* we're already aborting a command */
-        sti();
-        return( SCSI_ABORT_BUSY );
+        restore_flags(flags);
+        return SCSI_ABORT_BUSY;
       }
 
   /* command wasn't found */
   printk("command not found\n");
-  sti();
+  restore_flags(flags);
   return SCSI_ABORT_NOT_RUNNING;
 }
 
@@ -983,6 +999,7 @@ static void aha152x_reset_ports(void)
  */
 int aha152x_reset(Scsi_Cmnd * __unused)
 {
+  unsigned long flags;
   Scsi_Cmnd *ptr, *prev, *next;
 
   aha152x_reset_ports();
@@ -1008,6 +1025,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
            current_SC=NULL;
          }
 
+       save_flags(flags);
        cli();
        prev=NULL; ptr=disconnected_SC;
        while(ptr)
@@ -1033,7 +1051,7 @@ int aha152x_reset(Scsi_Cmnd * __unused)
               ptr = (Scsi_Cmnd *) ptr->host_scribble;
             }
         }
-       sti();
+       restore_flags(flags);
 
 #if defined( DEBUG_RESET )
        if(aha152x_debug & debug_reset)
@@ -1093,6 +1111,7 @@ int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array )
  */
 void aha152x_done( int error )
 {
+  unsigned long flags;
   Scsi_Cmnd *done_SC;
 
 #if defined(DEBUG_DONE)
@@ -1110,6 +1129,7 @@ void aha152x_done( int error )
         printk("done(%x), ", error);
 #endif
 
+      save_flags(flags);
       cli();
 
       done_SC = current_SC;
@@ -1124,7 +1144,7 @@ void aha152x_done( int error )
       if(aha152x_debug & debug_queues) 
         printk("ok (%d), ", commands);
 #endif
-      sti();
+      restore_flags(flags);
 
       SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
       SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
@@ -1165,6 +1185,7 @@ void aha152x_done( int error )
  */
 void aha152x_intr( int irqno, struct pt_regs * regs )
 {
+  unsigned int flags;
   int done=0, phase;
 
 #if defined(DEBUG_RACE)
@@ -1181,7 +1202,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
      intr(). To avoid race conditions we have to return
      immediately afterwards. */
   CLRBITS( DMACNTRL0, INTEN);
-  sti();
+  sti();  /* Yes, sti() really needs to be here */
 
   /* disconnected target is trying to reconnect.
      Only possible, if we have disconnected nexuses and
@@ -1202,10 +1223,11 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
          if(aha152x_debug & debug_queues)
           printk("i+, ");
 #endif
+         save_flags(flags);
           cli();
           append_SC( &issue_SC, current_SC);
           current_SC=NULL;
-          sti();
+          restore_flags(flags);
         }
 
       /* disable sequences */
@@ -1265,7 +1287,9 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
         printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
 #endif
 
+      save_flags(flags);
       cli();
+
 #if defined(DEBUG_QUEUES)
       if(aha152x_debug & debug_queues)
         printk("d-, ");
@@ -1281,7 +1305,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
         }
 
       current_SC->SCp.phase &= ~disconnected;
-      sti();
+      restore_flags(flags);
 
       SETPORT( SIMODE0, 0 );
       SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
@@ -1298,13 +1322,14 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
       /* bus is free to issue a queued command */
       if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
         {
+          save_flags(flags);
           cli();
 #if defined(DEBUG_QUEUES)
           if(aha152x_debug & debug_queues)
             printk("i-, ");
 #endif
           current_SC = remove_first_SC( &issue_SC );
-          sti();
+          restore_flags(flags);
 
 #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
          if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
@@ -1579,15 +1604,13 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 #if defined(DEBUG_CMD)
           if(aha152x_debug & debug_cmd)
           {
-            printk("DFIFOEMP, outsw (%d words), ",
-                   current_SC->cmd_len >>1 );
+            printk("DFIFOEMP, outsw (%d bytes, %d words), ",
+                  current_SC->cmd_len, current_SC->cmd_len >> 1 );
             disp_ports();
           }
 #endif
   
-          outsw( DATAPORT,
-                 &current_SC->cmnd,
-               current_SC->cmd_len >>1 );
+          outsw( DATAPORT, &current_SC->cmnd, current_SC->cmd_len >> 1 );
 
 #if defined(DEBUG_CMD)
          if(aha152x_debug & debug_cmd)
@@ -1597,16 +1620,31 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
           }
 #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)
@@ -1774,6 +1812,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 
       if(current_SC->SCp.phase & disconnected)
         {
+          save_flags(flags);
           cli();
 #if defined(DEBUG_QUEUES)
          if(aha152x_debug & debug_queues)
@@ -1781,7 +1820,7 @@ void aha152x_intr( int irqno, struct pt_regs * regs )
 #endif
           append_SC( &disconnected_SC, current_SC);
           current_SC = NULL;
-          sti();
+          restore_flags(flags);
 
           SETBITS( SCSISEQ, ENRESELI );
 
@@ -2223,8 +2262,10 @@ static void disp_ports(void)
 #ifdef DEBUG_AHA152X
   int s;
 
+#ifdef SKIP_PORTS
   if(aha152x_debug & debug_skipports)
        return;
+#endif
 
   printk("\n%s: ", current_SC ? "on bus" : "waiting");
 
@@ -2436,6 +2477,9 @@ static int in_driver=0;
  */
 static void enter_driver(const char *func)
 {
+  unsigned long flags;
+
+  save_flags(flags);
   cli();
   printk("aha152x: entering %s() (%x)\n", func, jiffies);
   if(in_driver)
@@ -2446,11 +2490,14 @@ static void enter_driver(const char *func)
 
   in_driver++;
   should_leave=func;
-  sti();
+  restore_flags(flags);
 }
 
 static void leave_driver(const char *func)
 {
+  unsigned long flags;
+
+  save_flags(flags);
   cli();
   printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
   if(!in_driver)
@@ -2461,7 +2508,7 @@ static void leave_driver(const char *func)
 
   in_driver--;
   should_leave=func;
-  sti();
+  restore_flags(flags);
 }
 #endif
 
@@ -2522,8 +2569,10 @@ static void show_command(Scsi_Cmnd *ptr)
  */
 static void show_queues(void)
 {
+  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 )
@@ -2541,5 +2590,5 @@ static void show_queues(void)
 
   disp_ports();
   disp_enintr();
-  sti();
+  restore_flags(flags);
 }
index b8c9ae9bd1b5906e8fb2a93eff8a9d7d2931192d..b43129ff86aa11d030993254fc68497ced728805 100644 (file)
@@ -2,7 +2,7 @@
 #define _AHA152X_H
 
 /*
- * $Id: aha152x.h,v 1.6 1994/11/24 21:35:38 root Exp root $
+ * $Id: aha152x.h,v 1.8 1995/01/21 22:11:07 root Exp root $
  */
 
 #if defined(__KERNEL__)
@@ -22,7 +22,7 @@ int        aha152x_biosparam(Disk *, int, int*);
    (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.6 $"
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.8 $"
 
 /* Initial value of Scsi_Host entry */
 #define AHA152X       { /* next */             NULL,                       \
index 3ecd317246f9c2b93faa6dc02a83936b4edd4fdf..a06fb947a6246ccc557254ab722943f00c4e8564 100644 (file)
@@ -40,9 +40,9 @@
  * support I need.                                          *
  *                                                          *
  *  Thanks also to Greg Hosler who did a lot of testing and *
- *  found quite a number of bugs during the development.   *
+ *  found quite a number of bugs during the development.    *
  ************************************************************
- *  last change: 95/01/15                                   *
+ *  last change: 95/01/20                                   *
  ************************************************************/
 
 /* Look in eata_dma.h for configuration information */
@@ -76,14 +76,14 @@ static struct eata_sp status[MAXIRQ];       /* Statuspacket array   */
 
 static struct geom_emul geometry;      /* Drive 1 & 2 geometry */
 
-#if DEBUG
+#if DEBUG_EATA
 static ulong int_counter = 0;
 static ulong queue_counter = 0;
 #endif
 
 const char *eata_info(struct Scsi_Host *host)
 {
-    static char *information = "EATA SCSI HBA Driver\n";
+    static char *information = "EATA SCSI HBA Driver";
     return information;
 }
 
@@ -108,7 +108,7 @@ void eata_int_handler(int irq, struct pt_regs * regs)
         if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
            continue;
 
-       DBG(DEBUG, int_counter++);
+       DBG(DEBUG_EATA, int_counter++);
 
        sp=&SD(sh)->sp;
 
@@ -141,24 +141,27 @@ void eata_int_handler(int irq, struct pt_regs * regs)
        }
 
        eata_stat = inb(base + HA_RSTATUS);     
-       DBG(DBG_INTR, printk("IRQ %d received, base 0x%04x, pid %lx, target: %x, "
-                            "lun: %x, ea_s: 0x%02x, hba_s: 0x%02x \n", 
+       DBG(DBG_INTR, printk("IRQ %d received, base 0x%04x, pid %lx, target: "
+                            "%x, lun: %x, ea_s: 0x%02x, hba_s: 0x%02x \n", 
                             irq, base, cmd->pid, cmd->target, cmd->lun, 
                             eata_stat, hba_stat));
 
        switch (hba_stat) {
-       case 0x00:              /* status OK */
+       case 0x00:              /* NO Error */
+#if 0
            if (scsi_stat == INTERMEDIATE_GOOD && cmd->device->type != TYPE_TAPE)
                result = DID_ERROR << 16;
 
            /* If there was a bus reset, redo operation on each target */
-           else if (scsi_stat == CONDITION_GOOD
-                    && cmd->device->type == TYPE_DISK
-                    && (HD(cmd)->t_state[cmd->target] == RESET))
+           else 
+#endif
+           if (scsi_stat == CONDITION_GOOD
+               && cmd->device->type == TYPE_DISK
+               && (HD(cmd)->t_state[cmd->target] == RESET))
                result = DID_BUS_BUSY << 16;        
            else
-               result = DID_OK << 16;
-           if (scsi_stat == 0)
+               result = DID_OK << 16;
+           if (scsi_stat == GOOD)
                HD(cmd)->t_state[cmd->target] = FALSE;
            HD(cmd)->t_timeout[cmd->target] = 0;
            break;
@@ -181,7 +184,6 @@ void eata_int_handler(int irq, struct pt_regs * regs)
 
            for (i = 0; i < MAXTARGET; i++)
                HD(cmd)->t_state[i] = RESET;
-
            break;
        case 0x07:              /* Bus Parity Error */
        case 0x0c:              /* Controller Ram Parity */
@@ -196,23 +198,42 @@ void eata_int_handler(int irq, struct pt_regs * regs)
            result = DID_ERROR << 16;
            break;
        }
-       cmd->result = result | scsi_stat;
+       cmd->result = result
 
+#if DGB_INTR2
+       if (scsi_stat || result || hba_stat) 
+         printk("hba_stat: 0x%02x,scsi_stat: 0x%02x, sense_key: 0x%x, "
+                "result: 0x%08x\n", hba_stat, 
+                scsi_stat,cmd->sense_buffer[2] & 0xf, result); 
+       DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+#endif
        if (scsi_stat == CHECK_CONDITION) { 
-           cmd->result |= (DRIVER_SENSE << 24);
+           switch (cmd->sense_buffer[2] & 0xf) {
+               case NO_SENSE:
+               case RECOVERED_ERROR:
+                   break;
+               case ILLEGAL_REQUEST:
+                   cmd->result |= (DID_BAD_TARGET << 16);
+                   break;
+               case NOT_READY:
+               case MEDIUM_ERROR:
+               case HARDWARE_ERROR:
+               case UNIT_ATTENTION:
+               case DATA_PROTECT:
+               case BLANK_CHECK:
+               case COPY_ABORTED:
+               case ABORTED_COMMAND:
+               case VOLUME_OVERFLOW:
+               case MISCOMPARE:
+               default:
+                   cmd->result |= (DRIVER_SENSE << 24);
+           }
        }
-
-       DBG(DBG_INTR,printk("scsi_stat: 0x%02x, result: 0x%08x\n",  
-                           scsi_stat, result)); 
-       DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
-
        cp->status = FREE;   /* now we can release the slot  */
  
        restore_flags(flags);
    
-       DBG(DBG_INTR,printk("Calling scsi_done(%lx)\n",(long)cmd));
        cmd->scsi_done(cmd);
-       DBG(DBG_INTR,printk("returned from scsi_done(%lx)\n",(long)cmd));
  
        save_flags(flags);
        cli();
@@ -251,7 +272,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
     save_flags(flags);
     cli();
 
-    DBG(DEBUG,queue_counter++);
+    DBG(DEBUG_EATA, queue_counter++);
 
     hd = HD(cmd);
     sh = cmd->host;
@@ -269,7 +290,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
     if (x == sh->can_queue) { 
 
         DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
-#if DEBUG
+#if DEBUG_EATA
         panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n", 
              queue_counter, int_counter);
 #else
@@ -335,7 +356,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
       return (0);
     }
     DBG(DBG_QUEUE,printk("Queued base 0x%04lx pid: %lx target: %x lun: %x slot %d irq %d\n",
-                         (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
+          (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
     DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
     restore_flags(flags);
     return (0);
@@ -546,9 +567,10 @@ char * get_board_data(ulong base, uint irq, uint id)
 
     eata_send_command((ulong) &cp, (uint) base, EATA_CMD_DMA_SEND_CP);
     while (!(inb(base + HA_RAUXSTAT) & HA_AIRQ));
-    inb((uint) base + HA_RSTATUS);
-
-    return (buff);
+    if(inb((uint) base + HA_RSTATUS) & 1)
+        return (NULL);
+    else
+        return (buff);
 }
     
 int check_blink_state(long base)
@@ -670,35 +692,40 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
            free_irq(gc->IRQ);  
        } else {
            printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
-           return (0);
+           return (FALSE);
        }
     } else {                   /* More than one HBA on this IRQ */
        if (reg_IRQL[gc->IRQ]) {
            printk("Can't support more than one HBA on this IRQ,\n"
                   "  if the IRQ is edge triggered. Sorry.\n");
-           return (0);
+           return (FALSE);
        } else
            reg_IRQ[gc->IRQ]++;
     }
 
     request_region(base, 9, "eata_dma");
 
-    if(gc->HAA_valid == FALSE) gc->MAX_CHAN = 0;
+    if ((buff = get_board_data((uint)base, gc->IRQ, gc->scsi_id[3])) == NULL){
+        printk("HBA at %#x didn't react on INQUIRY. Sorry.\n", (ulong) base);
+       return (FALSE);
+    }
 
-    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
-                              (gc->MAX_CHAN + 1));
     if(ntohs(gc->queuesiz) == 0) {
         gc->queuesiz = ntohs(64);
            printk("Warning: Queue size had to be corrected.\n"
                   "This might be a PM2012 with a defective Firmware\n");
     }
 
-    buff = get_board_data((uint)base, gc->IRQ, gc->scsi_id[3]);
+    if(gc->HAA_valid == FALSE || ntohl(gc->len) == 0x1c || ntohl(gc->len) == 0x1e) 
+        gc->MAX_CHAN = 0;
 
     if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6)
-       && strncmp("PM3222", &buff[16], 6) && strncmp("PM3224", &buff[16], 6))
-      gc->MAX_CHAN = 0;
+         && strncmp("PM3222", &buff[16], 6) && strncmp("PM3224", &buff[16], 6))
+        gc->MAX_CHAN = 0;
     
+    size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
+                              (gc->MAX_CHAN + 1));
+
     if (gc->MAX_CHAN) {
        printk("This is a multichannel HBA. Linux doesn't support them,\n");
        printk("so we'll try to register every channel as a virtual HBA.\n");
@@ -722,7 +749,19 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
        SD(sh)->revision[3] = '.';
        SD(sh)->revision[4] = buff[35];
        SD(sh)->revision[5] = 0;
-
+       switch (ntohl(gc->len)) {
+       case 0x1c:
+           SD(sh)->EATA_revision = 'a';
+           break;
+       case 0x1e:
+           SD(sh)->EATA_revision = 'b';
+           break;
+       case 0x22:
+           SD(sh)->EATA_revision = 'c';
+           break;
+       default:
+           SD(sh)->EATA_revision = '?';
+       }
        sh->base = (char *) base;
        sh->irq = gc->IRQ;
        sh->dma_channel = dma_channel;
@@ -732,9 +771,9 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
        sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
 
        if (gc->OCS_enabled == TRUE) {
-           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV;
-            if (sh->cmd_per_lun < 2)
-                sh->cmd_per_lun = 2;
+           sh->cmd_per_lun = sh->can_queue/C_P_L_DIV; 
+           if (sh->cmd_per_lun > C_P_L_CURRENT_MAX)
+               sh->cmd_per_lun = C_P_L_CURRENT_MAX;
        } else {
            sh->cmd_per_lun = 1;
        }
@@ -784,7 +823,8 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
 
        hd->next = NULL;        /* build a linked list of all HBAs */
        hd->prev = last_HBA;
-       hd->prev->next = sh;
+       if(hd->prev != NULL)
+           hd->prev->next = sh;
        last_HBA = sh;
 
        registered_HBAs++;
@@ -792,10 +832,6 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
     return (1);
 }
 
-/* flag: -1 scan for primary   HBA
- *        0 scan for secondary HBA
- * buf :  pointer to data structure for read config command
- */
 
 long find_EISA(struct get_conf *buf)
 {
@@ -822,48 +858,35 @@ long find_EISA(struct get_conf *buf)
                DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
                        (int)pal1, (int)pal2, (int)pal3));
 #endif
-               if (get_conf_PIO(base, buf)) {
+               if (get_conf_PIO(base, buf) == TRUE) {
                    DBG(DBG_PROBE&&DBG_EISA,print_config(buf));
-                   if ((buf->SECOND == FALSE) && (buf->IRQ)) {
-                       /* We just found a primary EISA, so there is no primary
-                        * ISA HBA and we can take it from the EISA list. 
-                        */
-                       ISAbases[0] = 0;
+                   if (buf->IRQ) {          /* We'll check the 
+                                             * primary/secondary stuff
+                                             * later
+                                             */
                        EISAbases[i] = 0;
-                       return ((long)base);
-                   } else if ((buf->SECOND == TRUE) && (buf->IRQ)) {
-                       /* We've found a secondary EISA, so there is no 
-                        * secondary ISA HBA  */
-                       ISAbases[1] = 0;
-                       /* and we can take it from the list and return it */
-                       EISAbases[i] = 0;
-                       return ((long)base);
-                   } else {
-                       EISAbases[i] = 0;
-                       printk("No valid IRQ. HBA removed from list\n");
-                   }
-                } else
-                   /* Nothing found here so we take it from the list */
-                   EISAbases[i] = 0;  
+                       return ((ulong)base);
+                   } 
+                   printk("No valid IRQ. HBA removed from list\n");
+               } 
+               /* Nothing found here so we take it from the list */
+               EISAbases[i] = 0;  
 #if CHECKPAL
-           }
+           } 
 #endif
-        }
+       }
     }
     return (0l);               /* Nothing found  :-(             */
 }
 
 long find_ISA(struct get_conf *buf)
 {
-    int i, l;
+    int l;
     long ret;
 
-    ret = (long)NULL;
-
     for (l = 0; l < MAXISA; l++) {     
         if (ISAbases[l]) {     
-           i = get_conf_PIO((struct eata_register *)ISAbases[l], buf);
-           if (i == TRUE) {
+           if (get_conf_PIO((struct eata_register *)ISAbases[l], buf) == TRUE){
                ret = ISAbases[l];
                ISAbases[l] = 0;
                return (ret);
@@ -987,20 +1010,14 @@ int eata_detect(Scsi_Host_Template * tpnt)
     DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG,
        printk("Using lots of delays to let you read the debugging output\n"));
 
-    printk("Now scanning for PCI HBAs\n");
-
     find_PCI(&gc, tpnt);
 
-    printk("Now scanning for EISA HBAs\n");
-
-    for (i = 0; i <= MAXEISA; i++) {
+    for (i = 0; i < MAXEISA; i++) {
        base = find_EISA(&gc);
        if (base)
            register_HBA(base, &gc, tpnt);
     }
 
-    printk("Now scanning for ISA HBAs\n");
-
     for (i = 0; i <= MAXISA; i++) {
        base = find_ISA(&gc);
        if (base)
@@ -1016,14 +1033,15 @@ int eata_detect(Scsi_Host_Template * tpnt)
         HBA_ptr = SD(HBA_ptr)->prev;
 
     printk("Registered HBAs:\n");
-    printk("HBA no. VID: Boardtype:  Revis: Bus: BaseIO: IRQ: Chan: ID: Prim: QS: SG: CPL:\n");
+    printk("HBA no. VID: Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr: QS: SG: CPL:\n");
     for (i = 1; i <= registered_HBAs; i++) {
-        printk("scsi%-2d: %.4s %.11s v%s ", HBA_ptr->host_no, 
-              SD(HBA_ptr)->vendor, SD(HBA_ptr)->name, SD(HBA_ptr)->revision);
+        printk("scsi%-2d: %.4s %.10s v%s 2.0%c  ", HBA_ptr->host_no, 
+              SD(HBA_ptr)->vendor, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+              SD(HBA_ptr)->EATA_revision);
        if(SD(HBA_ptr)->bustype == 'P') printk("PCI "); 
        else if(SD(HBA_ptr)->bustype == 'E') printk("EISA"); 
-       else printk(" ISA");
-       printk(" 0x%04x   %2d     %d   %d     %d  %2d  %2d   %2d\n", 
+       else printk("ISA ");
+       printk(" %#.4x   %2d   %d   %d   %d  %2d  %2d   %2d\n", 
               (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, 
               HBA_ptr->this_id, SD(HBA_ptr)->primary, HBA_ptr->can_queue, 
               HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
index ebb7f704f23d372185fea95caf6f55a3de31a828..9f9aad65cef0fd1dba0055564229489744d3e798 100644 (file)
@@ -2,7 +2,7 @@
 * Header file for eata_dma.c Linux EATA-DMA SCSI driver *
 * (c) 1993,94,95 Michael Neuffer                        *
 *********************************************************
-* last change: 95/01/15                                 *
+* last change: 95/01/16                                 *
 ********************************************************/
 
 
@@ -16,7 +16,7 @@
 
 #define VER_MAJOR 2
 #define VER_MINOR 1
-#define VER_SUB   "0g"
+#define VER_SUB   "0h"
 
 /************************************************************************
  * Here you can configure your drives that are using a non-standard     *
@@ -49,7 +49,7 @@
  * Debug options.                                                       * 
  * Enable DEBUG and whichever options you require.                      *
  ************************************************************************/
-#define DEBUG          1       /* Enable debug code.                   */
+#define DEBUG_EATA     1       /* Enable debug code.                   */
 #define DPT_DEBUG       0       /* Bobs special                         */
 #define DBG_DELAY       0      /* Build in delays so debug messages can be
                                 * be read before they vanish of the top of
 #define DBG_COM        0       /* Trace command call                   */
 #define DBG_QUEUE      0       /* Trace command queueing.              */
 #define DBG_INTR       0       /* Trace interrupt service routine.     */
+#define DBG_INTR2      0       /* Trace interrupt service routine.     */
 #define DBG_REGISTER    0       /* */
 #define DBG_ABNORM     1       /* Debug abnormal actions (reset, abort)*/
 
-#if DEBUG 
+#if DEBUG_EATA 
 #define DBG(x, y)      if ((x)) {y;} 
 #else
 #define DBG(x, y)
@@ -91,7 +92,7 @@
         0,      /* sg_tablesize */   \
         0,      /* cmd_per_lun  */   \
         0,      /* present      */   \
-        0,      /* True if ISA  */   \
+        1,      /* True if ISA  */   \
        ENABLE_CLUSTERING }
 
 int eata_detect(Scsi_Host_Template *);
@@ -121,21 +122,19 @@ int eata_reset(Scsi_Cmnd *);
 #define MAXIRQ    16 
 #define MAXTARGET  8
 
-/* PCI Bus And Device Limitations */
+#define MAX_PCI_DEVICES   32             /* Maximum # Of Devices Per Bus   */
+#define MAX_METHOD_2      16             /* Max Devices For Method 2       */
+#define MAX_PCI_BUS       16             /* Maximum # Of Busses Allowed    */
 
-#define MAX_PCI_DEVICES          32       /* Maximum # Of Devices Per Bus   */
-#define MAX_METHOD_2             16       /* Max Devices For Method 2       */
-#define MAX_PCI_BUS              16       /* Maximum # Of Busses Allowed    */
+#define SG_SIZE           64 
+#define C_P_L_DIV          8             /* 1 <= C_P_L_DIV <= 8            */
+#define C_P_L_CURRENT_MAX  2             /* Until this limit is removed    */
 
-
-#define SG_SIZE   64
-#define C_P_L_DIV 32     
-
-#define FREE      0
-#define USED      1
-#define TIMEOUT   2
-#define RESET     4
-#define LOCKED    8
+#define FREE       0
+#define USED       1
+#define TIMEOUT    2
+#define RESET      4
+#define LOCKED     8
 
 #define HD(cmd)  ((hostdata *)&(cmd->host->hostdata))
 #define CD(cmd)  ((struct eata_ccb *)(cmd->host_scribble))
@@ -335,6 +334,7 @@ typedef struct hstd{
   char   vendor[9];
   char   name[18];
   char   revision[6];
+  char   EATA_revision;
   unchar bustype;              /* bustype of HBA             */
   unchar channel;              /* no. of scsi channel        */
   unchar state;                /* state of HBA               */
@@ -388,4 +388,6 @@ typedef struct emul_pp {
   struct lun_map lunmap[4];
 }emulpp;
 
+
+
 #endif /* _EATA_H */
index 940326eceb753a35cd9a964f7ffabf111c8115d9..14aa8f9e41a87063463d72b678eb6848615a7487 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  This file is in2000.c, written and
  *  Copyright (C) 1993  Brad McLean
- *     Last edit 08/25/94 WDE
+ *     Last edit 1/19/95 TZ
  * Disclaimer:
  * Note:  This is ugly.  I know it, I wrote it, but my whole
  * focus was on getting the damn thing up and out quickly.
@@ -49,6 +49,9 @@
  *
  * 1/7/95 Fix from Peter Lu (swift@world.std.com) for datalen vs. dataptr
  * logic, much more stable under load.
+ *
+ * 1/19/95 (zerucha@shell.portal.com) Added module and biosparam support for
+ * larger SCSI hard drives (untested).
  */
 
 #include <linux/kernel.h>
@@ -684,5 +687,33 @@ int in2000_biosparam(Disk * disk, int dev, int* iinfo)
     iinfo[0] = 64;
     iinfo[1] = 32;
     iinfo[2] = size >> 11;
+/* This should approximate the large drive handling that the DOS ASPI manager
+   uses.  Drives very near the boundaries may not be handled correctly (i.e.
+   near 2.0 Gb and 4.0 Gb) */
+    if (iinfo[2] > 1024) {
+       iinfo[0] = 64;
+       iinfo[1] = 63;
+       iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+       }
+    if (iinfo[2] > 1024) {
+       iinfo[0] = 128;
+       iinfo[1] = 63;
+       iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+       }
+    if (iinfo[2] > 1024) {
+       iinfo[0] = 255;
+       iinfo[1] = 63;
+       iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]);
+       if (iinfo[2] > 1023)
+           iinfo[2] = 1023;
+       }
     return 0;
     }
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = IN2000;
+
+#include "scsi_module.c"
+#endif
+
index 7bd9b94f26d2d13d573845ddb8c5946dc4f536c6..5fc57ba5483d84b3282aa8461dadb1a048e2dc16 100644 (file)
@@ -14,7 +14,7 @@
    Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
    (you can reference it, but it is incomplete and inaccurate in places)
 
-   Version 0.38a
+   Version 0.38b
 
    This also works with loadable SCSI as a module.  Check configuration
    options QL_INT_ACTIVE_HIGH and QL_TURBO_PDMA for PCMCIA usage (which
@@ -25,6 +25,9 @@
 */
 /*----------------------------------------------------------------*/
 /* Configuration */
+/* Set this if you are using the PCMCIA adapter - it will automatically
+   take care of several settings */
+#define QL_PCMCIA 0
 
 /* Set the following to 2 to use normal interrupt (active high/totempole-
    tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
        cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
        the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
 
+/* Option Synchronization */
+       
+#if QL_PCMCIA
+#undef QL_INT_ACTIVE_HIGH
+#undef QL_TURBO_PDMA
+#define QL_INT_ACTIVE_HIGH 0
+#define QL_TURBO_PDMA 0
+#endif
+
 /*----------------------------------------------------------------*/
 
 #include "../block/blk.h"      /* to get disk capacity */
@@ -118,6 +130,8 @@ static void ql_zap(void);
 void   ql_zap()
 {
 int    x;
+unsigned long  flags;
+       save_flags( flags );
        cli();
        x = inb(qbase + 0xd);
        REG0;
@@ -125,7 +139,7 @@ int x;
        outb(2, qbase + 3);                             /* reset chip */
        if (x & 0x80)
                REG1;
-       sti();
+       restore_flags( flags );
 }
 
 /*----------------------------------------------------------------*/
@@ -228,8 +242,11 @@ int        i,k;
 static void    ql_icmd(Scsi_Cmnd * cmd)
 {
 unsigned int       i;
+unsigned long  flags;
+
        qabort = 0;
 
+       save_flags( flags );
        cli();
        REG0;
 /* clearing of interrupts and the fifo is needed */
@@ -274,7 +291,7 @@ unsigned int            i;
                outb(cmd->cmnd[i], qbase + 2);
        qlcmd = cmd;
        outb(0x41, qbase + 3);  /* select and send command */
-       sti();
+       restore_flags( flags );
 }
 /*----------------------------------------------------------------*/
 /* process scsi command - usually after interrupt */
@@ -464,6 +481,7 @@ int qlogic_detect(Scsi_Host_Template * host)
 int    i, j;                   /* these are only used by IRQ detect */
 int    qltyp;                  /* type of chip */
 struct Scsi_Host       *hreg;  /* registered host structure */
+unsigned long  flags;
 
 /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself decodes the
    address - I check 230 first since MIDI cards are typically at 330
@@ -479,8 +497,10 @@ struct     Scsi_Host       *hreg;  /* registered host structure */
 */
 
        for (qbase = 0x230; qbase < 0x430; qbase += 0x100) {
+#ifndef PCMCIA
                if( check_region( qbase , 0x10 ) )
                        continue;
+#endif                 
                REG1;
                if ( ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 )
                  && ( (inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7 ) )
@@ -506,6 +526,7 @@ struct      Scsi_Host       *hreg;  /* registered host structure */
 #endif
 #if QL_USE_IRQ
 /* IRQ probe - toggle pin and check request pending */
+       save_flags( flags );
        cli();
        i = 0xffff;
        j = 3;
@@ -525,17 +546,19 @@ struct    Scsi_Host       *hreg;  /* registered host structure */
                i >>= 1, qlirq++;       /* should check for exactly 1 on */
        if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, SA_INTERRUPT, "qlogic"))
                host->can_queue = 1;
-       sti();
+       restore_flags( flags );
 #endif
+#ifndef PCMCIA
        request_region( qbase , 0x10 ,"qlogic");
-
+#endif
        hreg = scsi_register( host , 0 );       /* no host data */
        hreg->io_port = qbase;
        hreg->n_io_port = 16;
        if( qlirq != -1 )
                hreg->irq = qlirq;
 
-       sprintf(qinfo, "Qlogic Driver version 0.38a, chip %02X at %03X, IRQ %d", qltyp, qbase, qlirq);
+       sprintf(qinfo, "Qlogic Driver version 0.38b, chip %02X at %03X, IRQ %d, Opts:%d%d",
+           qltyp, qbase, qlirq, QL_INT_ACTIVE_HIGH, QL_TURBO_PDMA );
        host->name = qinfo;
 
        return 1;
index c5e4a1180dcf1e908e1d2b7258efc794fa72b4d1..bf8bbe30954bcca07696af47a19dbf43b947656b 100644 (file)
@@ -93,7 +93,6 @@ static void     ad1848_start_input (int dev, unsigned long buf, int count, int i
 static int      ad1848_prepare_for_IO (int dev, int bsize, int bcount);
 static void     ad1848_reset (int dev);
 static void     ad1848_halt (int dev);
-void            ad1848_interrupt (int dev, struct pt_regs * regs);
 
 static int
 ad_read (ad1848_info * devc, int reg)
index b1a627b7cf0786e58782d37655ca6ece1ca5467b..9560babb758b151816a91f63653e4014a120211b 100644 (file)
@@ -128,7 +128,7 @@ gusintr (int irq, struct pt_regs * regs)
 
 #ifndef EXCLUDE_GUSMAX
   if (have_gus_max)
-    ad1848_interrupt (irq);
+    ad1848_interrupt (irq, regs);
 #endif
 
   while (1)
index c52b30c113010ca3030d86e8e7d00e73eff62e40..4d8fdf76fed4c0810dbd8069833d11ec488654e9 100644 (file)
@@ -225,7 +225,7 @@ void sound_timer_interrupt(void);
 /*     From ad1848.c */
 void ad1848_init (char *name, int io_base, int irq, int dma_playback, int dma_capture);
 int ad1848_detect (int io_base);
-void     ad1848_interrupt (int dev);
+void     ad1848_interrupt (int dev, struct pt_regs *regs);
 long attach_ms_sound(long mem_start, struct address_info * hw_config);
 int probe_ms_sound(struct address_info *hw_config);
 
index b485d9b8eebd0a59e5dea4cb4902d051840f40e4..51fbebb0370af052ad0ac0f8a8f6e8ec1c16c0b4 100644 (file)
@@ -84,7 +84,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
                mpnt->vm_task = current;
                mpnt->vm_start = PAGE_MASK & (unsigned long) p;
                mpnt->vm_end = TASK_SIZE;
-               mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+               mpnt->vm_page_prot = PAGE_COPY;
 #ifdef VM_STACK_FLAGS
                mpnt->vm_flags = VM_STACK_FLAGS;
                mpnt->vm_pte = 0;
index b5d51fb998f6bdfb012971b98df3b7611d16bf37..0c0ef125b8bc72eea369d4655a201fde0ac988e1 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -305,7 +305,7 @@ unsigned long * create_tables(char * p,int argc,int envc,int ibcs)
                mpnt->vm_task = current;
                mpnt->vm_start = PAGE_MASK & (unsigned long) p;
                mpnt->vm_end = TASK_SIZE;
-               mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+               mpnt->vm_page_prot = PAGE_COPY;
                mpnt->vm_flags = VM_STACK_FLAGS;
                mpnt->vm_ops = NULL;
                mpnt->vm_offset = 0;
index da188a39cfc2fc90f6825a484d986a6430f433cb..b22d58265c36dd8f6ba0bcaa5395da7441e5eb05 100644 (file)
@@ -88,7 +88,7 @@ struct vm_operations_struct msdos_file_mmap = {
  */
 int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
-       if (vma->vm_page_prot & PAGE_RW)        /* only PAGE_COW or read-only supported now */
+       if (vma->vm_flags & VM_SHARED)  /* only PAGE_COW or read-only supported now */
                return -EINVAL;
        if (vma->vm_offset & (inode->i_sb->s_blocksize - 1))
                return -EINVAL;
@@ -105,3 +105,4 @@ int msdos_mmap(struct inode * inode, struct file * file, struct vm_area_struct *
        return 0;
 }
 
+
index 66a3cfe4fce2a9c81b7b54727d034edb4ab49534..11753b8b25062cea3171d6eea1fb89b4f2a2ce7a 100644 (file)
@@ -33,13 +33,13 @@ static inline int get_max_filename(unsigned long address)
        if (get_fs() == KERNEL_DS)
                return 0;
        vma = find_vma(current, address);
-       if (!vma || vma->vm_start > address || !(vma->vm_page_prot & PAGE_USER))
+       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_page_prot & PAGE_USER))
+          (vma->vm_next->vm_flags & VM_READ))
                return 0;
        return address;
 }
index fad26fd1cc24b10d76b30cae94cb048cc56e453d..3e1380741b52a944f7ad6dff404b4c42b30d7077 100644 (file)
@@ -92,7 +92,7 @@ struct vm_operations_struct nfs_file_mmap = {
 /* This is used for a general mmap of a nfs file */
 int nfs_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
-       if (vma->vm_page_prot & PAGE_RW)        /* only PAGE_COW or read-only supported now */
+       if (vma->vm_flags & VM_SHARED)  /* only PAGE_COW or read-only supported now */
                return -EINVAL;
        if (!inode->i_sb || !S_ISREG(inode->i_mode))
                return -EACCES;
index 02f35038c8b3b736a49c35e528d0301a1c288cac..f2516ce2c00c1a5abbce6e60d1d1a50a0c4dbacf 100644 (file)
@@ -334,21 +334,23 @@ static struct task_struct ** get_task(pid_t pid)
 
 static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr)
 {
-       unsigned long page;
+       pgd_t *dir;
+       pte_t *table, pte;
 
        if (!p || !*p || ptr >= TASK_SIZE)
                return 0;
-       page = *PAGE_DIR_OFFSET(*p,ptr);
-       if (!(page & PAGE_PRESENT))
+       dir = PAGE_DIR_OFFSET(*p,ptr);
+       if (pgd_none(*dir))
+               return 0;
+       if (pgd_bad(*dir)) {
+               printk("bad page directory entry %08lx\n", pgd_val(*dir));
                return 0;
-       page &= PAGE_MASK;
-       page += PAGE_PTR(ptr);
-       page = *(unsigned long *) page;
-       if (!(page & PAGE_PRESENT))
+       }
+       table = (pte_t *) (pgd_page(*dir) + PAGE_PTR(ptr));
+       pte = *table;
+       if (!pte_present(pte))
                return 0;
-       page &= PAGE_MASK;
-       page += ptr & ~PAGE_MASK;
-       return page;
+       return pte_page(pte) + (ptr & ~PAGE_MASK);
 }
 
 static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer)
@@ -511,9 +513,10 @@ static int get_stat(int pid, char * buffer)
 static int get_statm(int pid, char * buffer)
 {
        struct task_struct ** p = get_task(pid);
-       int i, tpag;
+       pgd_t *pagedir;
+       pte_t *pte;
+       int i, j, tpag;
        int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
-       unsigned long ptbl, *buf, *pte, *pagedir, map_nr;
 
        if (!p || !*p)
                return 0;
@@ -521,15 +524,21 @@ static int get_statm(int pid, char * buffer)
        if ((*p)->state != TASK_ZOMBIE) {
          pagedir = PAGE_DIR_OFFSET(*p, 0);
          for (i = 0; i < 0x300; ++i) {
-           if ((ptbl = pagedir[i]) == 0) {
+           if (pgd_none(pagedir[i])) {
              tpag -= PTRS_PER_PAGE;
              continue;
            }
-           buf = (unsigned long *)(ptbl & PAGE_MASK);
-           for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) {
-             if (*pte != 0) {
+           if (pgd_bad(pagedir[i])) {
+               printk("bad page table dir %08lx\n", pgd_val(pagedir[i]));
+               pgd_clear(pagedir+i);
+               tpag -= PTRS_PER_PAGE;
+               continue;
+           }
+           pte = (pte_t *) pgd_page(pagedir[i]);
+           for (j = 0; j < PTRS_PER_PAGE; j++, pte++) {
+             if (!pte_none(*pte)) {
                ++size;
-               if (*pte & 1) {
+               if (pte_present(*pte)) {
                  ++resident;
                  if (tpag > 0)
                    ++trs;
@@ -537,13 +546,12 @@ static int get_statm(int pid, char * buffer)
                    ++drs;
                  if (i >= 15 && i < 0x2f0) {
                    ++lrs;
-                   if (*pte & 0x40)
+                   if (pte_dirty(*pte))
                      ++dt;
                    else
                      --drs;
                  }
-                 map_nr = MAP_NR(*pte);
-                 if (map_nr < (high_memory / PAGE_SIZE) && mem_map[map_nr] > 1)
+                 if (pte_page(*pte) < high_memory && mem_map[MAP_NR(pte_page(*pte))] > 1)
                    ++share;
                }
              }
index 9569e1cdb5c1eef0ae8b770b6619cb353c6d3e8e..c50170ef638c1d4cf3c33e370491ad34a1fdc175 100644 (file)
 
 static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
 {
+       pgd_t *pgdir;
+       pte_t pte;
+       char * page;
        struct task_struct * tsk;
        unsigned long addr, pid;
        char *tmp;
-       unsigned long pte, page;
        int i;
 
        if (count < 0)
@@ -47,20 +49,22 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
        while (count > 0) {
                if (current->signal & ~current->blocked)
                        break;
-               pte = *PAGE_DIR_OFFSET(tsk,addr);
-               if (!(pte & PAGE_PRESENT))
+               pgdir = PAGE_DIR_OFFSET(tsk,addr);
+               if (pgd_none(*pgdir))
                        break;
-               pte &= PAGE_MASK;
-               pte += PAGE_PTR(addr);
-               page = *(unsigned long *) pte;
-               if (!(page & 1))
+               if (pgd_bad(*pgdir)) {
+                       printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
+                       pgd_clear(pgdir);
                        break;
-               page &= PAGE_MASK;
-               page += addr & ~PAGE_MASK;
+               }
+               pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+               if (!pte_present(pte))
+                       break;
+               page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
                i = PAGE_SIZE-(addr & ~PAGE_MASK);
                if (i > count)
                        i = count;
-               memcpy_tofs(tmp,(void *) page,i);
+               memcpy_tofs(tmp, page, i);
                addr += i;
                tmp += i;
                count -= i;
@@ -73,10 +77,12 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
 
 static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
 {
+       pgd_t * pgdir;
+       pte_t * pte;
+       char * page;
        struct task_struct * tsk;
        unsigned long addr, pid;
        char *tmp;
-       unsigned long pte, page;
        int i;
 
        if (count < 0)
@@ -96,24 +102,24 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
        while (count > 0) {
                if (current->signal & ~current->blocked)
                        break;
-               pte = *PAGE_DIR_OFFSET(tsk,addr);
-               if (!(pte & PAGE_PRESENT))
+               pgdir = PAGE_DIR_OFFSET(tsk,addr);
+               if (pgd_none(*pgdir))
                        break;
-               pte &= PAGE_MASK;
-               pte += PAGE_PTR(addr);
-               page = *(unsigned long *) pte;
-               if (!(page & PAGE_PRESENT))
+               if (pgd_bad(*pgdir)) {
+                       printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
+                       pgd_clear(pgdir);
                        break;
-               if (!(page & 2)) {
-                       do_wp_page(0,addr,current,0);
-                       continue;
                }
-               page &= PAGE_MASK;
-               page += addr & ~PAGE_MASK;
+               pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
+               if (!pte_present(pte))
+                       break;
+               if (!pte_write(pte))
+                       break;
+               page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
                i = PAGE_SIZE-(addr & ~PAGE_MASK);
                if (i > count)
                        i = count;
-               memcpy_fromfs((void *) page,tmp,i);
+               memcpy_fromfs(page, tmp, i);
                addr += i;
                tmp += i;
                count -= i;
@@ -142,93 +148,112 @@ static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int
        }
 }
 
-int
-mem_mmap(struct inode * inode, struct file * file,
+/*
+ * This isn't really reliable by any means..
+ */
+int mem_mmap(struct inode * inode, struct file * file,
             struct vm_area_struct * vma)
 {
-  struct task_struct *tsk;
-  unsigned long *src_table, *dest_table, stmp, dtmp;
-  struct vm_area_struct *src_vma = 0;
-  int i;
-
-  /* Get the source's task information */
-
-  tsk = NULL;
-  for (i = 1 ; i < NR_TASKS ; i++)
-    if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
-      tsk     = task[i];
-      src_vma = task[i]->mm->mmap;
-      break;
-    }
-
-  if (!tsk)
-    return -EACCES;
-
-/* Ensure that we have a valid source area.  (Has to be mmap'ed and
-   have valid page information.)  We can't map shared memory at the
-   moment because working out the vm_area_struct & nattach stuff isn't
-   worth it. */
-
-  stmp = vma->vm_offset;
-  while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
-    while (src_vma && stmp > src_vma->vm_end)
-      src_vma = src_vma->vm_next;
-    if (!src_vma || (src_vma->vm_flags & VM_SHM))
-      return -EINVAL;
-
-    src_table = PAGE_DIR_OFFSET(tsk, stmp);
-    if (!*src_table)
-      return -EINVAL;
-    src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
-    if (!*src_table)
-      return -EINVAL;
-
-    if (stmp < src_vma->vm_start) {
-      if (!(src_vma->vm_flags & VM_GROWSDOWN))
-       return -EINVAL;
-      if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
-       return -EINVAL;
-    }
-    stmp += PAGE_SIZE;
-  }
-
-  src_vma = task[i]->mm->mmap;
-  stmp    = vma->vm_offset;
-  dtmp    = vma->vm_start;
-
-  while (dtmp < vma->vm_end) {
-    while (src_vma && stmp > src_vma->vm_end)
-      src_vma = src_vma->vm_next;
-
-    src_table = PAGE_DIR_OFFSET(tsk, stmp);
-    src_table = (unsigned long *)((*src_table & PAGE_MASK) + PAGE_PTR(stmp));
-
-    dest_table = PAGE_DIR_OFFSET(current, dtmp);
-
-    if (!*dest_table) {
-      *dest_table = get_free_page(GFP_KERNEL);
-      if (!*dest_table) { oom(current); *dest_table=BAD_PAGE; }
-      else *dest_table |= PAGE_TABLE;
-    }
-    
-    dest_table = (unsigned long *)((*dest_table & PAGE_MASK) + PAGE_PTR(dtmp));
-
-    if (!(*src_table & PAGE_PRESENT)) 
-      do_no_page(src_vma, stmp, PAGE_PRESENT);
-
-    if ((vma->vm_flags & VM_WRITE) && !(*src_table & PAGE_RW))
-      do_wp_page(src_vma, stmp, PAGE_RW | PAGE_PRESENT);
-
-    *src_table |= PAGE_DIRTY;
-    *dest_table = *src_table;
-    mem_map[MAP_NR(*src_table)]++;
-
-    stmp += PAGE_SIZE;
-    dtmp += PAGE_SIZE;
-  }
-
-  invalidate();
-  return 0;
+       struct task_struct *tsk;
+       pgd_t *src_dir, *dest_dir;
+       pte_t *src_table, *dest_table;
+       unsigned long stmp, dtmp;
+       struct vm_area_struct *src_vma = NULL;
+       int i;
+
+       /* Get the source's task information */
+
+       tsk = NULL;
+       for (i = 1 ; i < NR_TASKS ; i++)
+               if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
+                       tsk = task[i];
+                       src_vma = task[i]->mm->mmap;
+                       break;
+               }
+
+       if (!tsk)
+               return -EACCES;
+
+       /* Ensure that we have a valid source area.  (Has to be mmap'ed and
+        have valid page information.)  We can't map shared memory at the
+        moment because working out the vm_area_struct & nattach stuff isn't
+        worth it. */
+
+       stmp = vma->vm_offset;
+       while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
+               while (src_vma && stmp > src_vma->vm_end)
+                       src_vma = src_vma->vm_next;
+               if (!src_vma || (src_vma->vm_flags & VM_SHM))
+                       return -EINVAL;
+
+               src_dir = PAGE_DIR_OFFSET(tsk, stmp);
+               if (pgd_none(*src_dir))
+                       return -EINVAL;
+               if (pgd_bad(*src_dir)) {
+                       printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
+                       return -EINVAL;
+               }
+
+               src_table = (pte_t *)(pgd_page(*src_dir) + PAGE_PTR(stmp));
+               if (pte_none(*src_table))
+                       return -EINVAL;
+
+               if (stmp < src_vma->vm_start) {
+                       if (!(src_vma->vm_flags & VM_GROWSDOWN))
+                               return -EINVAL;
+                       if (src_vma->vm_end - stmp > current->rlim[RLIMIT_STACK].rlim_cur)
+                               return -EINVAL;
+               }
+               stmp += PAGE_SIZE;
+       }
+
+       src_vma = task[i]->mm->mmap;
+       stmp    = vma->vm_offset;
+       dtmp    = vma->vm_start;
+
+       while (dtmp < vma->vm_end) {
+               while (src_vma && stmp > src_vma->vm_end)
+                       src_vma = src_vma->vm_next;
+
+               src_dir = PAGE_DIR_OFFSET(tsk, stmp);
+               src_table = (pte_t *) (pgd_page(*src_dir) + PAGE_PTR(stmp));
+
+               dest_dir = PAGE_DIR_OFFSET(current, dtmp);
+
+               if (pgd_none(*dest_dir)) {
+                       unsigned long page = get_free_page(GFP_KERNEL);
+                       if (!page)
+                               return -ENOMEM;
+                       if (pgd_none(*dest_dir)) {
+                               pgd_set(dest_dir, (pte_t *) page);
+                       } else {
+                               free_page(page);
+                       }
+               }
+
+               if (pgd_bad(*dest_dir)) {
+                       printk("Bad dest directory entry %08lx\n", pgd_val(*dest_dir));
+                       return -EINVAL;
+               }
+
+               dest_table = (pte_t *) (pgd_page(*dest_dir) + PAGE_PTR(dtmp));
+
+               if (!pte_present(*src_table))
+                       do_no_page(src_vma, stmp, 1);
+
+               if ((vma->vm_flags & VM_WRITE) && !pte_write(*src_table))
+                       do_wp_page(src_vma, stmp, 1);
+
+               *src_table = pte_mkdirty(*src_table);
+               *dest_table = *src_table;
+               mem_map[MAP_NR(pte_page(*src_table))]++;
+
+               stmp += PAGE_SIZE;
+               dtmp += PAGE_SIZE;
+       }
+
+       invalidate();
+       return 0;
 }
 
 static struct file_operations proc_mem_operations = {
index d1102b4ce391a994e420c270afd5849efd21bf88..115634b9da8abdf666877275a86475f6e80e0b65 100644 (file)
 
 extern unsigned long high_memory;
 
-static int check_one_table(unsigned long * page_dir)
+static int check_one_table(struct pde * page_dir)
 {
-       unsigned long pg_table = *page_dir;
-
-       if (!pg_table)
+       if (pgd_none(*page_dir))
                return 0;
-       if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
+       if (pgd_bad(*page_dir))
                return 1;
-       }
        return 0;
 }
 
 /*
- * This function frees up all page tables of a process when it exits.
+ * This function checks all page tables of "current"
  */
 void check_page_tables(void)
 {
-       unsigned long pg_dir;
+       struct pgd * pg_dir;
        static int err = 0;
 
        int stack_level = (long)(&pg_dir)-current->kernel_stack_page;
        if (stack_level < 1500) printk ("** %d ** ",stack_level);
-       pg_dir = current->tss.cr3;
-       if (mem_map[MAP_NR(pg_dir)] > 1) {
-               return;
-       }
-       if (err == 0){
-               unsigned long *page_dir = (unsigned long *) pg_dir;
-               unsigned long *base = page_dir;
+       pg_dir = PAGE_DIR_OFFSET(current, 0);
+       if (err == 0) {
                int i;
                for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++){
                        int notok = check_one_table(page_dir);
                        if (notok){
                                err++;
-                               printk ("|%d| ",page_dir-base);
+                               printk ("|%d:%08lx| ",i, page_dir->pgd);
                        }
                }
-               if (err) printk ("Erreur MM %d\n",err);
+               if (err) printk ("\nErreur MM %d\n",err);
        }
 }
-
index ecf9dfa54ee9e6c7cbb09ee6e2956fa7dc8883af..5d305670d4d836f749862d5af3177d21de381329 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ALPHA_PAGE_H
 #define _ALPHA_PAGE_H
 
+#define CONFIG_STRICT_MM_TYPECHECKS
+
 #define invalidate_all() \
 __asm__ __volatile__( \
        "lda $16,-2($31)\n\t" \
@@ -19,29 +21,114 @@ __asm__ __volatile__( \
 #define PAGE_SIZE                      (1UL << PAGE_SHIFT)
 #define PGDIR_SIZE                     (1UL << PGDIR_SHIFT)
 
+#ifdef __KERNEL__
+
 #define PAGE_OFFSET 0xFFFFFC0000000000
 #define MAP_NR(addr) (((addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED (1<<31)
 
 typedef unsigned int mem_map_t;
 
-#define PAGE_PRESENT   0x001
-#define PAGE_RW                0x002
-#define PAGE_USER      0x004
-#define PAGE_ACCESSED  0x020
-#define PAGE_DIRTY     0x040
-#define PAGE_COW       0x200   /* implemented in software (one of the AVL bits) */
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x)     ((x).pte)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
 
-#define PAGE_PRIVATE   (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_SHARED    (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_COPY      (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_READONLY  (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_EXECONLY  (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_TABLE     (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
 
-#define PAGE_CHG_MASK (PAGE_MASK | PAGE_ACCESSED | PAGE_DIRTY)
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
 
-#ifdef __KERNEL__
+#define pte_val(x)     (x)
+#define pgd_val(x)     (x)
+#define pgprot_val(x)  (x)
+
+#define __pte(x)       (x)
+#define __pgd(x)       (x)
+#define __pgprot(x)    (x)
+
+#endif
+
+/*
+ * OSF/1 PAL-code-imposed page table bits
+ */
+#define _PAGE_VALID    0x0001
+#define _PAGE_FOR      0x0002  /* used for page protection (fault on read) */
+#define _PAGE_FOW      0x0004  /* used for page protection (fault on write) */
+#define _PAGE_FOE      0x0008  /* used for page protection (fault on exec) */
+#define _PAGE_ASM      0x0010
+#define _PAGE_KRE      0x0100  /* xxx - see below on the "accessed" bit */
+#define _PAGE_URE      0x0200  /* xxx */
+#define _PAGE_KWE      0x1000  /* used to do the dirty bit in software */
+#define _PAGE_UWE      0x2000  /* used to do the dirty bit in software */
+
+/* .. and these are ours ... */
+#define _PAGE_COW      0x10000
+#define _PAGE_DIRTY    0x20000
+#define _PAGE_ACCESSED 0x40000
+
+/*
+ * NOTE! The "accessed" bit isn't necessarily exact: it can be kept exactly
+ * by software (use the KRE/URE/KWE/UWE bits appropritely), but I'll fake it.
+ * Under Linux/AXP, the "accessed" bit just means "read", and I'll just use
+ * the KRE/URE bits to watch for it. That way we don't need to overload the
+ * KWE/UWE bits with both handling dirty and accessed.
+ *
+ * Note that the kernel uses the accessed bit just to check whether to page
+ * out a page or not, so it doesn't have to be exact anyway.
+ */
+
+#define __DIRTY_BITS   (_PAGE_DIRTY | _PAGE_KWE | _PAGE_UWE)
+#define __ACCESS_BITS  (_PAGE_ACCESSED | _PAGE_KRE | _PAGE_URE)
+
+#define _PFN_MASK      0xFFFFFFFF00000000
+
+#define _PAGE_TABLE    (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS)
+#define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS)
+
+/*
+ * All the normal masks have the "page accessed" bits on, as any time they are used,
+ * the page is accessed. They are cleared only by the page-out routines
+ */
+#define PAGE_NONE      __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define PAGE_SHARED    __pgprot(_PAGE_VALID | __ACCESS_BITS)
+#define PAGE_COPY      __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_COW)
+#define PAGE_READONLY  __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW)
+#define PAGE_KERNEL    __pgprot(_PAGE_VALID | _PAGE_ASM | __ACCESS_BITS | __DIRTY_BITS)
+
+#define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x))
+
+#define __P000 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define __P001 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOW | _PAGE_FOE)
+#define __P010 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOE)
+#define __P011 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOE)
+#define __P100 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOR | _PAGE_FOW)
+#define __P101 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOW)
+#define __P110 _PAGE_NORMAL(_PAGE_COW | _PAGE_FOR)
+#define __P111 _PAGE_NORMAL(_PAGE_COW)
+
+#define __S000 _PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW | _PAGE_FOE)
+#define __S001 _PAGE_NORMAL(_PAGE_FOW | _PAGE_FOE)
+#define __S010 _PAGE_NORMAL(_PAGE_FOR | _PAGE_FOE)
+#define __S011 _PAGE_NORMAL(_PAGE_FOE)
+#define __S100 _PAGE_NORMAL(_PAGE_FOR | _PAGE_FOW)
+#define __S101 _PAGE_NORMAL(_PAGE_FOW)
+#define __S110 _PAGE_NORMAL(_PAGE_FOR)
+#define __S111 _PAGE_NORMAL(0)
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -50,8 +137,9 @@ typedef unsigned int mem_map_t;
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern unsigned long __bad_page(void);
-extern unsigned long __bad_pagetable(void);
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
 extern unsigned long __zero_page(void);
 
 #define BAD_PAGETABLE __bad_pagetable()
@@ -74,7 +162,6 @@ extern unsigned long __zero_page(void);
 #define PTR_MASK                       (~(sizeof(void*)-1))
 
 /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-/* 64-bit machines, beware!  SRB. */
 #define SIZEOF_PTR_LOG2                        3
 
 /* to find an entry in a page-table-directory */
@@ -83,7 +170,7 @@ extern unsigned long __zero_page(void);
  * This is just for getting it through the compiler right now
  */
 #define PAGE_DIR_OFFSET(tsk,address) \
-((unsigned long *) ((tsk)->tss.ptbr + ((((unsigned long)(address)) >> 21) & PTR_MASK & ~PAGE_MASK)))
+((pgd_t *) ((tsk)->tss.ptbr + ((((unsigned long)(address)) >> 21) & PTR_MASK & ~PAGE_MASK)))
 
 /* to find an entry in a page-table */
 #define PAGE_PTR(address)              \
@@ -104,6 +191,57 @@ do { \
                invalidate(); \
 } while (0)
 
+extern unsigned long high_memory;
+
+/*
+ * 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 << (32-PAGE_SHIFT)) | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
+{ pgd_val(*pgdp) = _PAGE_TABLE | (((unsigned long) ptep) << (32-PAGE_SHIFT)); }
+
+extern inline unsigned long pte_page(pte_t pte)        { return (pte_val(pte) & _PFN_MASK) >> (32-PAGE_SHIFT); }
+extern inline unsigned long pgd_page(pgd_t pgd)        { return (pgd_val(pgd) & _PFN_MASK) >> (32-PAGE_SHIFT); }
+
+extern inline int pte_none(pte_t pte)          { return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_VALID; }
+extern inline 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) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
+extern inline int pgd_present(pgd_t pgd)       { return pgd_val(pgd) & _PAGE_VALID; }
+extern inline void pgd_clear(pgd_t * pgdp)     { pgd_val(*pgdp) = 0; }
+
+/*
+ * 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_FOR); }
+extern inline int pte_write(pte_t pte)         { return !(pte_val(pte) & _PAGE_FOW); }
+extern inline int pte_exec(pte_t pte)          { return !(pte_val(pte) & _PAGE_FOE); }
+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_FOW; return pte; }
+extern inline pte_t pte_rdprotect(pte_t pte)   { pte_val(pte) |= _PAGE_FOR; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte)   { pte_val(pte) |= _PAGE_FOE; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)     { pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
+extern inline pte_t pte_mkold(pte_t pte)       { pte_val(pte) &= ~(__ACCESS_BITS); 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_FOW; return pte; }
+extern inline pte_t pte_mkread(pte_t pte)      { pte_val(pte) &= _PAGE_FOR; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte)      { pte_val(pte) &= _PAGE_FOE; return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)     { pte_val(pte) |= __DIRTY_BITS; return pte; }
+extern inline pte_t pte_mkyoung(pte_t pte)     { pte_val(pte) |= __ACCESS_BITS; return pte; }
+extern inline pte_t pte_mkcow(pte_t pte)       { pte_val(pte) |= _PAGE_COW; return pte; }
+
 #endif /* __KERNEL__ */
 
 #endif /* _ALPHA_PAGE_H */
index d412af19d3e6dd21fffb4e748a8f81550cd17a23..e6ec3a81bd759007c758834ef9e675601175c32f 100644 (file)
@@ -1,40 +1,96 @@
 #ifndef _I386_PAGE_H
 #define _I386_PAGE_H
 
+#define CONFIG_STRICT_MM_TYPECHECKS
+
 #define invalidate() \
 __asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax")
 
-                       /* PAGE_SHIFT determines the page size */
+/* 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__
+
 #define PAGE_OFFSET    0
 #define MAP_NR(addr) ((addr) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED (1<<15)
 
 typedef unsigned short mem_map_t;
 
-#define PAGE_PRESENT   0x001
-#define PAGE_RW                0x002
-#define PAGE_USER      0x004
-#define PAGE_PWT       0x008   /* 486 only - not used currently */
-#define PAGE_PCD       0x010   /* 486 only - not used currently */
-#define PAGE_ACCESSED  0x020
-#define PAGE_DIRTY     0x040
-#define PAGE_COW       0x200   /* implemented in software (one of the AVL bits) */
+#ifdef CONFIG_STRICT_MM_TYPECHECKS
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
 
-#define PAGE_PRIVATE   (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_SHARED    (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_COPY      (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED | PAGE_COW)
-#define PAGE_READONLY  (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_EXECONLY  (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED)
-#define PAGE_TABLE     (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED)
+#define pte_val(x)     ((x).pte)
+#define pgd_val(x)     ((x).pgd)
+#define pgprot_val(x)  ((x).pgprot)
 
-#define PAGE_CHG_MASK (PAGE_MASK | PAGE_ACCESSED | PAGE_DIRTY | PAGE_PWT | PAGE_PCD)
+#define __pte(x)       ((pte_t) { (x) } )
+#define __pgd(x)       ((pgd_t) { (x) } )
+#define __pgprot(x)    ((pgprot_t) { (x) } )
 
-#ifdef __KERNEL__
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+typedef unsigned long pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x)     (x)
+#define pgd_val(x)     (x)
+#define pgprot_val(x)  (x)
+
+#define __pte(x)       (x)
+#define __pgd(x)       (x)
+#define __pgprot(x)    (x)
+
+#endif
+
+#define _PAGE_PRESENT  0x001
+#define _PAGE_RW       0x002
+#define _PAGE_USER     0x004
+#define _PAGE_ACCESSED 0x020
+#define _PAGE_DIRTY    0x040
+#define _PAGE_COW      0x200   /* implemented in software (one of the AVL bits) */
+
+#define _PAGE_TABLE    (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+#define PAGE_NONE      __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY      __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_READONLY  __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_KERNEL    __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+
+/*
+ * The i386 can't do page protection for execute, and considers that the same are read.
+ * Also, write permissions imply read permissions. This is the closest we can get..
+ */
+#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
 
 /*
  * Define this if things work differently on a i386 and a i486:
@@ -53,8 +109,9 @@ extern unsigned long pg0[1024];
  * ZERO_PAGE is a global shared page that is always zero: used
  * for zero-mapped memory areas etc..
  */
-extern unsigned long __bad_page(void);
-extern unsigned long __bad_pagetable(void);
+extern pte_t __bad_page(void);
+extern pte_t * __bad_pagetable(void);
+
 extern unsigned long __zero_page(void);
 
 #define BAD_PAGETABLE __bad_pagetable()
@@ -82,10 +139,10 @@ extern unsigned long __zero_page(void);
 
 /* to find an entry in a page-table-directory */
 #define PAGE_DIR_OFFSET(tsk,address) \
-((((unsigned long)(address)) >> 22) + (unsigned long *) (tsk)->tss.cr3)
+((((unsigned long)(address)) >> 22) + (pgd_t *) (tsk)->tss.cr3)
 
 /* to find an entry in a page-table */
-#define PAGE_PTR(address)              \
+#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 */
@@ -99,6 +156,57 @@ do { \
                __asm__ __volatile__("movl %0,%%cr3": :"a" ((tsk)->tss.cr3)); \
 } 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; }
+
+/*
+ * 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_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; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline unsigned long pte_page(pte_t pte)        { return pte_val(pte) & PAGE_MASK; }
+extern inline unsigned long pgd_page(pgd_t pgd)        { return pgd_val(pgd) & PAGE_MASK; }
+
+extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
+{ pgd_val(*pgdp) = _PAGE_TABLE | (unsigned long) ptep; }
+
 #endif /* __KERNEL__ */
 
 #endif /* _I386_PAGE_H */
index 2024c3e72d583c9e857b38dc2a46593a33a1ef67..27b56611bde2e8b597627ba9026bff66210a6b06 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id$
+/* $Id: aztcd.h,v 0.80 1995/01/21 19:55:04 root Exp $
  * Definitions for a AztechCD268 CD-ROM interface
  *     Copyright (C) 1994, 1995  Werner Zimmermann
  *
  *
  *  History:   W.Zimmermann adaption to Aztech CD268-01A Version 1.3
  *             Oktober 1994 Email: zimmerma@rz.fht-esslingen.de
- *  Note:      Points marked with ??? are questionable !
  */
 
 /* *** change this to set the I/O port address */
 #define AZT_BASE_ADDR          0x320
 
+/* use incompatible ioctls for reading in raw and cooked mode */
+#define AZT_PRIVATE_IOCTLS
+
 /* Increase this if you get lots of timeouts; if you get kernel panic, replace
    STEN_LOW_WAIT by STEN_LOW in the source code */
 #define AZT_STATUS_DELAY       400       /*for timer wait, STEN_LOW_WAIT*/
 /* number of times to retry a command before giving up */
 #define AZT_RETRY_ATTEMPTS     3
 
-/*defines for compatibility with mcd.c/mcd.h for Mitsumi drive, will probably
-  go away, when the AZTECH driver is integrated in the standard Linux kernel*/
-#ifdef CONFIG_AZTCD
-#else
-#define AZTCD_TIMER                MCD_TIMER
-#define aztcd_init                 mcd_init
-#define do_aztcd_request           do_mcd_request
-#define aztcd_setup                mcd_setup
-#define check_aztcd_media_change    check_mcd_media_change
-#endif
-
 /* port access macros */
 #define CMD_PORT               azt_port
 #define DATA_PORT              azt_port
 #define ACMD_SET_MODE          0xA1            /* set drive mode */
 #define ACMD_SET_VOLUME                0xAE            /* set audio level */
 
-/* borrowed from hd.c */
 #define SET_TIMER(func, jifs) \
-       ((timer_table[AZTCD_TIMER].expires = jiffies + jifs), \
-       (timer_table[AZTCD_TIMER].fn = func), \
-       (timer_active |= 1<<AZTCD_TIMER))
+        delay_timer.expires = jifs; \
+        delay_timer.function = (void *) func; \
+        add_timer(&delay_timer);
 
-#define CLEAR_TIMER            timer_active &= ~(1<<AZTCD_TIMER)
+#define CLEAR_TIMER             del_timer(&delay_timer)
 
 #define MAX_TRACKS             104
 
index 8911a68198debe13dbf036ba9a30e13844a0691f..3829b1c36ec475fd0519f5c0340e5b352d6a8184 100644 (file)
@@ -5,7 +5,6 @@ typedef struct desc_struct {
        unsigned long a,b;
 } desc_table[256];
 
-extern unsigned long swapper_pg_dir[1024];
 extern desc_table idt,gdt;
 
 #define GDT_NUL 0
index 35347bd7c4ca4b60aef8cc154eda920e8d8e6aa6..8249c8e594b58f46f44ef974c2dcbc7cb7034747 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _LINUX_MM_H
 #define _LINUX_MM_H
 
+extern unsigned long high_memory;
+
 #include <asm/page.h>
 
 #include <linux/sched.h>
@@ -11,6 +13,8 @@
 #define VERIFY_READ 0
 #define VERIFY_WRITE 1
 
+extern pgd_t swapper_pg_dir[1024];
+
 extern int verify_area(int, const void *, unsigned long);
 
 /*
@@ -32,14 +36,14 @@ struct vm_area_struct {
        struct task_struct * vm_task;           /* VM area parameters */
        unsigned long vm_start;
        unsigned long vm_end;
-       unsigned short vm_page_prot;
+       pgprot_t vm_page_prot;
        unsigned short vm_flags;
-/* linked list of VM areas per task, sorted by address */
-       struct vm_area_struct * vm_next;
 /* AVL tree of VM areas per task, sorted by address */
+       short vm_avl_height;
        struct vm_area_struct * vm_avl_left;
        struct vm_area_struct * vm_avl_right;
-       short vm_avl_height;
+/* linked list of VM areas per task, sorted by address */
+       struct vm_area_struct * vm_next;
 /* for areas with inode, the circular list inode->i_mmap */
 /* for shm areas, the circular list of attaches */
 /* otherwise unused */
@@ -74,6 +78,13 @@ struct vm_area_struct {
 
 #define VM_STACK_FLAGS 0x0177
 
+/*
+ * mapping from the currently active vm_flags protection bits (the
+ * low four bits) to a page protection mask..
+ */
+extern pgprot_t protection_map[16];
+
+
 /*
  * These are the virtual MM functions - opening of an area, closing and
  * unmapping it (needed to keep files on disk up-to-date etc), pointer
@@ -90,8 +101,8 @@ struct vm_operations_struct {
                unsigned long page, int write_access);
        unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
                unsigned long page);
-       void (*swapout)(struct vm_area_struct *,  unsigned long, unsigned long *);
-       unsigned long (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
+       void (*swapout)(struct vm_area_struct *,  unsigned long, pte_t *);
+       pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
 extern mem_map_t * mem_map;
@@ -167,8 +178,8 @@ extern void clear_page_tables(struct task_struct * tsk);
 extern int copy_page_tables(struct task_struct * to);
 extern int clone_page_tables(struct task_struct * to);
 extern int unmap_page_range(unsigned long from, unsigned long size);
-extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask);
-extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
+extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
+extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
 extern void do_wp_page(struct vm_area_struct * vma, unsigned long address, int write_access);
 extern void do_no_page(struct vm_area_struct * vma, unsigned long address, int write_access);
@@ -187,9 +198,10 @@ extern int vread(char *buf, char *addr, int count);
 
 /* swap.c */
 
-extern void swap_free(unsigned long page_nr);
-extern unsigned long swap_duplicate(unsigned long page_nr);
-extern unsigned long swap_in(unsigned long entry);
+extern void swap_free(unsigned long);
+extern void swap_duplicate(unsigned long);
+extern void swap_in(struct vm_area_struct *, pte_t *, unsigned long id, int write_access);
+
 extern void si_swapinfo(struct sysinfo * val);
 extern void rw_swap_page(int rw, unsigned long nr, char * buf);
 
@@ -211,8 +223,6 @@ extern unsigned long get_unmapped_area(unsigned long);
 #define write_swap_page(nr,buf) \
        rw_swap_page(WRITE,(nr),(buf))
 
-extern unsigned long high_memory;
-
 #define GFP_BUFFER     0x00
 #define GFP_ATOMIC     0x01
 #define GFP_USER       0x02
@@ -276,7 +286,7 @@ extern inline int delete_from_swap_cache(unsigned long addr)
 #ifdef SWAP_CACHE_INFO
        swap_cache_del_total++;
 #endif 
-       entry = (unsigned long) xchg_ptr(swap_cache + MAP_NR(addr), NULL);
+       entry= (unsigned long) xchg_ptr(swap_cache + MAP_NR(addr), NULL);
        if (entry)  {
 #ifdef SWAP_CACHE_INFO
                swap_cache_del_success++;
index ff4190a17562ab07d91883d74feaee0a5a3b1d1a..8bdf6edd0c0781d3256548afcd67bfba578e8f68 100644 (file)
@@ -25,7 +25,7 @@
 /* Configuration method #1 */
 #define PCI_CONFIG1_ADDRESS_REG  0xcf8
 #define PCI_CONFIG1_ENABLE 0x80000000
-#define PCI_CONFIG1_TUPPLE (bus, device, function, register)   \
+#define PCI_CONFIG1_TUPPLE(bus, device, function, register)    \
         (PCI_CONFIG1_ENABLE | ((bus) << 16) & 0xff0000 |       \
         ((device) << 11) & 0xf800 | ((function) << 8) & 0x700 | \
         ((register) << 2) & 0xfc)
@@ -34,7 +34,7 @@
 /* Configuration method #2, deprecated */
 #define PCI_CONFIG2_ENABLE_REG 0xcf8
 #define PCI_CONFIG2_ENABLE     0xf0
-#define PCI_CONFIG2_TUPPLE (function)                          \
+#define PCI_CONFIG2_TUPPLE(function)                           \
        (PCI_CONFIG2_ENABLE | ((function) << 1) & 0xe)
 #define PCI_CONFIG2_FORWARD_REG        0xcfa
 
@@ -208,7 +208,8 @@ struct pci_class_type {
 #define PCI_DEVICE_ID_S3_864_1         0x88c0
 #define PCI_DEVICE_ID_S3_864_2         0x88c1
 #define PCI_DEVICE_ID_S3_928           0x88b0
-#define PCI_DEVICE_ID_S3_964           0x88d0
+#define PCI_DEVICE_ID_S3_964_1         0x88d0
+#define PCI_DEVICE_ID_S3_964_2         0x88d1
 #define PCI_DEVICE_ID_S3_811           0x8811
 
 #define PCI_VENDOR_ID_OPTI             0x1045
@@ -257,12 +258,17 @@ struct pci_class_type {
 #define PCI_VENDOR_ID_N9               0x105D
 #define PCI_DEVICE_ID_N9_I128          0x2309
 
-#define PCI_VENDOR_ID_ALI              0x1025
-#define PCI_DEVICE_ID_ALI_M1435                0x1435
+#define PCI_VENDOR_ID_AI               0x1025
+#define PCI_DEVICE_ID_AI_M1435         0x1435
+
+#define PCI_VENDOR_ID_AL               0x10b9
+#define PCI_DEVICE_ID_AL_M1449         0x4449
+#define PCI_DEVICE_ID_AL_M1451         0x1451
 
 #define PCI_VENDOR_ID_TSENG            0x100c
 #define PCI_DEVICE_ID_TSENG_W32P_2     0x3202
-#define PCI_DEVICE_ID_TSENG_W32P_5     0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_b     0x3205
+#define PCI_DEVICE_ID_TSENG_W32P_a     0x3207
 
 #define PCI_VENDOR_ID_CMD              0x1095
 #define PCI_DEVICE_ID_CMD_640          0x0640
@@ -276,8 +282,8 @@ struct pci_class_type {
 #define PCI_VENDOR_ID_VLSI             0x1004
 #define PCI_DEVICE_ID_VLSI_82C593      0x0006
 
-#define PCI_VENDOR_ID_A              0x1005
-#define PCI_DEVICE_ID_AL_2301          0x2301
+#define PCI_VENDOR_ID_ADL              0x1005
+#define PCI_DEVICE_ID_ADL_2301         0x2301
 
 #define PCI_VENDOR_ID_SYMPHONY         0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101     0x0001
@@ -285,13 +291,18 @@ struct pci_class_type {
 #define PCI_VENDOR_ID_TRIDENT          0x1023
 #define PCI_DEVICE_ID_TRIDENT_9420     0x9420
 
+#define PCI_VENDOR_ID_CONTAQ           0x1023
+#define PCI_DEVICE_ID_CONTAQ_82C599    0x0600
+
+#define PCI_VENDOR_ID_NS               0x100b
+
 struct pci_vendor_type {
        unsigned short vendor_id;
        char *vendor_name;
 };
 
 
-#define PCI_VENDOR_NUM 24
+#define PCI_VENDOR_NUM 27
 #define PCI_VENDOR_TYPE { \
        {PCI_VENDOR_ID_NCR,             "NCR"}, \
        {PCI_VENDOR_ID_ADAPTEC,         "Adaptec"}, \
@@ -307,16 +318,19 @@ struct pci_vendor_type {
        {PCI_VENDOR_ID_WEITEK,          "Weitek"}, \
        {PCI_VENDOR_ID_CIRRUS,          "Cirrus Logic"}, \
        {PCI_VENDOR_ID_BUSLOGIC,        "Bus Logic"}, \
-       {PCI_VENDOR_ID_N9,              "Number #9"}, \
-       {PCI_VENDOR_ID_ALI,             "ALI"}, \
+       {PCI_VENDOR_ID_N9,              "Number Nine"}, \
+       {PCI_VENDOR_ID_AI,              "Acer Incorporated"}, \
+       {PCI_VENDOR_ID_AL,              "Acer Labs"}, \
        {PCI_VENDOR_ID_TSENG,           "Tseng'Lab"}, \
        {PCI_VENDOR_ID_CMD,             "CMD"}, \
        {PCI_VENDOR_ID_VISION,          "Vision"}, \
        {PCI_VENDOR_ID_AMD,             "AMD"}, \
        {PCI_VENDOR_ID_VLSI,            "VLSI"}, \
-       {PCI_VENDOR_ID_AL,              "Advance Logic"}, \
+       {PCI_VENDOR_ID_ADL,             "Advance Logic"}, \
        {PCI_VENDOR_ID_SYMPHONY,        "Symphony"}, \
-       {PCI_VENDOR_ID_TRIDENT,         "Trident"} \
+       {PCI_VENDOR_ID_TRIDENT,         "Trident"}, \
+       {PCI_VENDOR_ID_CONTAQ,          "Contaq"}, \
+       {PCI_VENDOR_ID_NS,              "NS"} \
 }
 
 
@@ -335,7 +349,7 @@ struct pci_device_type {
        char *device_name;
 };
 
-#define PCI_DEVICE_NUM 45
+#define PCI_DEVICE_NUM 50
 #define PCI_DEVICE_TYPE { \
        {0xff,  PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C810,       "53c810"}, \
        {0xff,  PCI_VENDOR_ID_NCR,      PCI_DEVICE_ID_NCR_53C815,       "53c815"}, \
@@ -346,8 +360,9 @@ struct pci_device_type {
        {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_864_1,         "Vision 864-P"}, \
        {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_864_2,         "Vision 864-P"}, \
        {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_928,           "Vision 928-P"}, \
-       {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_964,           "Vision 964-P"}, \
-       {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_811,           "Trio64"}, \
+       {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_964_1,         "Vision 964-P"}, \
+       {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_964_2,         "Vision 964-P"}, \
+       {0xff,  PCI_VENDOR_ID_S3,       PCI_DEVICE_ID_S3_811,           "Trio32/Trio64"}, \
        {0x02,  PCI_VENDOR_ID_OPTI,     PCI_DEVICE_ID_OPTI_82C822,      "82C822"}, \
        {0xff,  PCI_VENDOR_ID_OPTI,     PCI_DEVICE_ID_OPTI_82C621,      "82C621"}, \
        {0xff,  PCI_VENDOR_ID_UMC,      PCI_DEVICE_ID_UMC_UM8881F,      "UM8881F"}, \
@@ -372,16 +387,20 @@ struct pci_device_type {
        {0xff,  PCI_VENDOR_ID_CIRRUS,   PCI_DEVICE_ID_CIRRUS_6729,      "CL 6729"}, \
        {0xff,  PCI_VENDOR_ID_BUSLOGIC,PCI_DEVICE_ID_BUSLOGIC_946C,     "946C"}, \
        {0xff,  PCI_VENDOR_ID_N9,       PCI_DEVICE_ID_N9_I128,          "Imagine 128"}, \
-       {0xff,  PCI_VENDOR_ID_ALI,      PCI_DEVICE_ID_ALI_M1435,        "M1435"}, \
+       {0xff,  PCI_VENDOR_ID_AI,       PCI_DEVICE_ID_AI_M1435,         "M1435"}, \
+       {0xff,  PCI_VENDOR_ID_AL,       PCI_DEVICE_ID_AL_M1449,         "M1449"}, \
+       {0xff,  PCI_VENDOR_ID_AL,       PCI_DEVICE_ID_AL_M1451,         "M1451"}, \
        {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_2,     "ET4000W32P"}, \
-       {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_5,     "ET4000W32P"}, \
+       {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_b,     "ET4000W32P rev B"}, \
+       {0xff,  PCI_VENDOR_ID_TSENG,    PCI_DEVICE_ID_TSENG_W32P_a,     "ET4000W32P rev A"}, \
        {0xff,  PCI_VENDOR_ID_CMD,      PCI_DEVICE_ID_CMD_640,          "640A"}, \
        {0xff,  PCI_VENDOR_ID_VISION,   PCI_DEVICE_ID_VISION_QD8500,    "QD-8500PCI"}, \
        {0xff,  PCI_VENDOR_ID_AMD,      PCI_DEVICE_ID_AMD_LANCE,        "79C970"}, \
        {0xff,  PCI_VENDOR_ID_VLSI,     PCI_DEVICE_ID_VLSI_82C593,      "82C593-FC1"}, \
-       {0xff,  PCI_VENDOR_ID_AL,       PCI_DEVICE_ID_AL_2301,          "2301"}, \
+       {0xff,  PCI_VENDOR_ID_ADL,      PCI_DEVICE_ID_ADL_2301,         "2301"}, \
        {0xff,  PCI_VENDOR_ID_SYMPHONY, PCI_DEVICE_ID_SYMPHONY_101,     "82C101"}, \
-       {0xff,  PCI_VENDOR_ID_TRIDENT,  PCI_DEVICE_ID_TRIDENT_9420,     "TG 9420"} \
+       {0xff,  PCI_VENDOR_ID_TRIDENT,  PCI_DEVICE_ID_TRIDENT_9420,     "TG 9420"}, \
+       {0xff,  PCI_VENDOR_ID_CONTAQ,   PCI_DEVICE_ID_CONTAQ_82C599,    "82C599"} \
 }
 
 /* An item of this structure has the following meaning */
index 2d71ee47eefe3257de0b500dc92e3be9df8fe4bb..6210530c15d94d3a652f1d54cd5a9c2920f06ef4 100644 (file)
@@ -123,7 +123,7 @@ struct mm_struct {
        struct vm_area_struct * mmap_avl;
 };
 
-#define INIT_MMAP { &init_task, 0, 0x40000000, PAGE_SHARED, }
+#define INIT_MMAP { &init_task, 0, 0x40000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
 #define INIT_MM { \
                0, \
index e28dc6c1ac65c7e6079f6ce58ffeb1517bacbd5a..acb9ca26e885d7c842f9449745929448c9a366e7 100644 (file)
@@ -31,7 +31,6 @@
  *
  * MCD_TIMER           Mitsumi CD-ROM Timer
  *
- * AZTCD_TIMER         Aztech CD-ROM Timer
  */
 
 #define BLANK_TIMER    0
@@ -49,7 +48,6 @@
 #define MCD_TIMER      23
 
 #define HD_TIMER2      24
-#define AZTCD_TIMER     25
 
 struct timer_struct {
        unsigned long expires;
index 64ae79953ce9fcfcd6e920008607e510552165be..6daf3e9517bf9cd4ab6140cbd7c10d507d19bd75 100644 (file)
@@ -118,7 +118,7 @@ static int xd_reread_partitions (int dev);
 static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count);
 static void xd_recalibrate (u_char drive);
 
-static void xd_interrupt_handler (int unused);
+static void xd_interrupt_handler (int irq, struct pt_regs * regs);
 static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
index c152b2c52f53788910ed72bbb1ca24de7f347243..6337cbff06a8f64e3718e566d3cbc32d6884978c 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -22,7 +22,7 @@ static int shm_map (struct vm_area_struct *shmd, int remap);
 static void killseg (int id);
 static void shm_open (struct vm_area_struct *shmd);
 static void shm_close (struct vm_area_struct *shmd);
-static unsigned long shm_swap_in (struct vm_area_struct *, unsigned long, unsigned long);
+static pte_t shm_swap_in(struct vm_area_struct *, unsigned long, unsigned long);
 
 static int shm_tot = 0; /* total number of shared memory pages */
 static int shm_rss = 0; /* number of shared memory pages that are in memory */
@@ -161,7 +161,6 @@ static void killseg (int id)
 {
        struct shmid_ds *shp;
        int i, numpages;
-       ulong page;
 
        shp = shm_segs[id];
        if (shp == IPC_NOID || shp == IPC_UNUSED) {
@@ -180,13 +179,15 @@ static void killseg (int id)
        }
        numpages = shp->shm_npages;
        for (i = 0; i < numpages ; i++) {
-               if (!(page = shp->shm_pages[i]))
+               pte_t pte;
+               pte_val(pte) = shp->shm_pages[i];
+               if (pte_none(pte))
                        continue;
-               if (page & PAGE_PRESENT) {
-                       free_page (page & PAGE_MASK);
+               if (pte_present(pte)) {
+                       free_page (pte_page(pte));
                        shm_rss--;
                } else {
-                       swap_free (page);
+                       swap_free(pte_val(pte));
                        shm_swp--;
                }
        }
@@ -414,20 +415,26 @@ static inline void remove_attach (struct shmid_ds * shp, struct vm_area_struct *
  */
 static int shm_map (struct vm_area_struct *shmd, int remap)
 {
-       unsigned long *page_table;
+       pgd_t *page_dir;
+       pte_t *page_table;
        unsigned long tmp, shm_sgn;
 
        /* check that the range is unmapped */
        if (!remap)
                for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
-                       page_table = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-                       if (*page_table & PAGE_PRESENT) {
-                               page_table = (ulong *) (PAGE_MASK & *page_table);
-                               page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
-                               if (*page_table) {
-                                       /* printk("shmat() -> EINVAL because address 0x%lx is already mapped.\n",tmp); */
-                                       return -EINVAL;
-                               }
+                       page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
+                       if (pgd_none(*page_dir))
+                               continue;
+                       if (pgd_bad(*page_dir)) {
+                               printk("bad ipc page directory entry %08lx\n", pgd_val(*page_dir));
+                               pgd_clear(page_dir);
+                               continue;
+                       }
+                       page_table = (pte_t *) pgd_page(*page_dir);     
+                       page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
+                       if (!pte_none(*page_table)) {
+                               /* printk("shmat() -> EINVAL because address 0x%lx is already mapped.\n",tmp); */
+                               return -EINVAL;
                        }
                }
 
@@ -440,24 +447,22 @@ static int shm_map (struct vm_area_struct *shmd, int remap)
 
        /* check that the range has page_tables */
        for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
-               page_table = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-               if (*page_table & PAGE_PRESENT) {
-                       page_table = (ulong *) (PAGE_MASK & *page_table);
+               page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
+               if (!pgd_none(*page_dir)) {
+                       page_table = (pte_t *) pgd_page(*page_dir);
                        page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
-                       if (*page_table) {
-                               if (*page_table & PAGE_PRESENT) {
+                       if (!pte_none(*page_table)) {
+                               if (pte_present(*page_table)) {
                                        --current->mm->rss;
-                                       free_page (*page_table & PAGE_MASK);
-                               }
-                               else
-                                       swap_free (*page_table);
-                               *page_table = 0;
+                                       free_page (pte_page(*page_table));
+                               } else
+                                       swap_free(pte_val(*page_table));
+                               pte_clear(page_table);
                        }
                } else {
-                       unsigned long new_pt;
-                       if (!(new_pt = get_free_page(GFP_KERNEL)))
+                       if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL)))
                                return -ENOMEM;
-                       *page_table = new_pt | PAGE_TABLE;
+                       pgd_set(page_dir, page_table);
                        tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
                }
        }
@@ -466,10 +471,10 @@ static int shm_map (struct vm_area_struct *shmd, int remap)
        shm_sgn = shmd->vm_pte + ((shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT);
        for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE,
             shm_sgn += (1 << SHM_IDX_SHIFT)) {
-               page_table = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-               page_table = (ulong *) (PAGE_MASK & *page_table);
+               page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
+               page_table = (pte_t *) pgd_page(*page_dir);
                page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-               *page_table = shm_sgn;
+               pte_val(*page_table) = shm_sgn;
        }
        invalidate();
        return 0;
@@ -623,9 +628,9 @@ int sys_shmdt (char *shmaddr)
 /*
  * page not present ... go through shm_pages
  */
-static unsigned long shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, unsigned long code)
+static pte_t shm_swap_in(struct vm_area_struct * shmd, unsigned long offset, unsigned long code)
 {
-       unsigned long page;
+       pte_t pte;
        struct shmid_ds *shp;
        unsigned int id, idx;
 
@@ -633,57 +638,60 @@ static unsigned long shm_swap_in(struct vm_area_struct * shmd, unsigned long off
        if (id != ((shmd->vm_pte >> SHM_ID_SHIFT) & SHM_ID_MASK)) {
                printk ("shm_swap_in: code id = %d and shmd id = %ld differ\n",
                        id, (shmd->vm_pte >> SHM_ID_SHIFT) & SHM_ID_MASK);
-               return BAD_PAGE | PAGE_SHARED;
+               return BAD_PAGE;
        }
        if (id > max_shmid) {
                printk ("shm_swap_in: id=%d too big. proc mem corrupted\n", id);
-               return BAD_PAGE | PAGE_SHARED;
+               return BAD_PAGE;
        }
        shp = shm_segs[id];
        if (shp == IPC_UNUSED || shp == IPC_NOID) {
                printk ("shm_swap_in: id=%d invalid. Race.\n", id);
-               return BAD_PAGE | PAGE_SHARED;
+               return BAD_PAGE;
        }
        idx = (code >> SHM_IDX_SHIFT) & SHM_IDX_MASK;
        if (idx != (offset >> PAGE_SHIFT)) {
                printk ("shm_swap_in: code idx = %u and shmd idx = %lu differ\n",
                        idx, offset >> PAGE_SHIFT);
-               return BAD_PAGE | PAGE_SHARED;
+               return BAD_PAGE;
        }
        if (idx >= shp->shm_npages) {
                printk ("shm_swap_in : too large page index. id=%d\n", id);
-               return BAD_PAGE | PAGE_SHARED;
+               return BAD_PAGE;
        }
 
-       if (!(shp->shm_pages[idx] & PAGE_PRESENT)) {
-               if (!(page = get_free_page(GFP_KERNEL))) {
+       pte_val(pte) = shp->shm_pages[idx];
+       if (!pte_present(pte)) {
+               unsigned long page = get_free_page(GFP_KERNEL);
+               if (!page) {
                        oom(current);
-                       return BAD_PAGE | PAGE_SHARED;
+                       return BAD_PAGE;
                }
-               if (shp->shm_pages[idx] & PAGE_PRESENT) {
+               pte_val(pte) = shp->shm_pages[idx];
+               if (pte_present(pte)) {
                        free_page (page);
                        goto done;
                }
-               if (shp->shm_pages[idx]) {
-                       read_swap_page (shp->shm_pages[idx], (char *) page);
-                       if (shp->shm_pages[idx] & PAGE_PRESENT)  {
+               if (!pte_none(pte)) {
+                       read_swap_page(pte_val(pte), (char *) page);
+                       pte_val(pte) = shp->shm_pages[idx];
+                       if (pte_present(pte))  {
                                free_page (page);
                                goto done;
                        }
-                       swap_free (shp->shm_pages[idx]);
+                       swap_free(pte_val(pte));
                        shm_swp--;
                }
                shm_rss++;
-               shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY);
+               pte = pte_mkdirty(mk_pte(page, PAGE_SHARED));
+               shp->shm_pages[idx] = pte_val(pte);
        } else
                --current->mm->maj_flt;  /* was incremented in do_no_page */
 
 done:
        current->mm->min_flt++;
-       page = shp->shm_pages[idx];
-       page &= ~(PAGE_RW & ~shmd->vm_page_prot);  /* write-protect */
-       mem_map[MAP_NR(page)]++;
-       return page;
+       mem_map[MAP_NR(pte_page(pte))]++;
+       return pte_modify(pte, shmd->vm_page_prot);
 }
 
 /*
@@ -694,7 +702,7 @@ static unsigned long swap_idx = 0; /* next to swap */
 
 int shm_swap (int prio)
 {
-       unsigned long page;
+       pte_t page;
        struct shmid_ds *shp;
        struct vm_area_struct *shmd;
        unsigned int swap_nr;
@@ -724,8 +732,8 @@ int shm_swap (int prio)
                goto check_id;
        }
 
-       page = shp->shm_pages[idx];
-       if (!(page & PAGE_PRESENT))
+       pte_val(page) = shp->shm_pages[idx];
+       if (!pte_present(page))
                goto check_table;
        swap_attempts++;
 
@@ -737,7 +745,10 @@ int shm_swap (int prio)
        }
        for (shmd = shp->attaches; ; ) {
            do {
-               unsigned long tmp, *pte;
+               pgd_t *page_dir;
+               pte_t *page_table, pte;
+               unsigned long tmp;
+
                if ((shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK) != id) {
                        printk ("shm_swap: id=%ld does not match shmd->vm_pte.id=%ld\n", id, shmd->vm_pte >> SHM_ID_SHIFT & SHM_ID_MASK);
                        continue;
@@ -745,24 +756,26 @@ int shm_swap (int prio)
                tmp = shmd->vm_start + (idx << PAGE_SHIFT) - shmd->vm_offset;
                if (!(tmp >= shmd->vm_start && tmp < shmd->vm_end))
                        continue;
-               pte = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
-               if (!(*pte & PAGE_PRESENT)) {
+               page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
+               if (pgd_none(*page_dir) || pgd_bad(*page_dir)) {
                        printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
                                        id, shmd->vm_start, idx);
-                       *pte = 0;
+                       pgd_clear(page_dir);
                        continue;
                }
-               pte = (ulong *) (PAGE_MASK & *pte);
-               pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
-               tmp = *pte;
-               if (!(tmp & PAGE_PRESENT))
+               page_table = (pte_t *) pgd_page(*page_dir);
+               page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
+               pte = *page_table;
+               if (!pte_present(pte))
                        continue;
-               if (tmp & PAGE_ACCESSED) {
-                       *pte &= ~PAGE_ACCESSED;
+               if (pte_young(pte)) {
+                       *page_table = pte_mkold(pte);
                        continue;
                }
-               *pte = shmd->vm_pte | idx << SHM_IDX_SHIFT;
-               mem_map[MAP_NR(page)]--;
+               if (pte_page(pte) != pte_page(page))
+                       printk("shm_swap_out: page and pte mismatch\n");
+               pte_val(*page_table) = shmd->vm_pte | idx << SHM_IDX_SHIFT;
+               mem_map[MAP_NR(pte_page(pte))]--;
                shmd->vm_task->mm->rss--;
                invalid++;
            /* continue looping through circular list */
@@ -771,14 +784,13 @@ int shm_swap (int prio)
                break;
        }
 
-       if (mem_map[MAP_NR(page)] != 1)
+       if (mem_map[MAP_NR(pte_page(page))] != 1)
                goto check_table;
-       page &= PAGE_MASK;
        shp->shm_pages[idx] = swap_nr;
        if (invalid)
                invalidate();
-       write_swap_page (swap_nr, (char *) page);
-       free_page (page);
+       write_swap_page (swap_nr, (char *) pte_page(page));
+       free_page(pte_page(page));
        swap_successes++;
        shm_swp++;
        shm_rss--;
index b0d0a77788e13e67a04c8e0eca1e1ad6df2c58dd..604913176121ce025363d4b818c690113d8627ca 100644 (file)
@@ -28,7 +28,7 @@ char * strncpy(char * dest,const char *src,size_t count)
 {
        char *tmp = dest;
 
-       while ((*dest++ = *src++) != '\0' && --count)
+       while (count-- && (*dest++ = *src++) != '\0')
                /* nothing */;
 
        return tmp;
@@ -64,7 +64,7 @@ char * strncat(char *dest, const char *src, size_t count)
 
 int strcmp(const char * cs,const char * ct)
 {
-       register char __res;
+       register signed char __res;
 
        while (1) {
                if ((__res = *cs - *ct++) != 0 || !*cs++)
@@ -76,7 +76,7 @@ int strcmp(const char * cs,const char * ct)
 
 int strncmp(const char * cs,const char * ct,size_t count)
 {
-       register char __res = 0;
+       register signed char __res = 0;
 
        while (count) {
                if ((__res = *cs - *ct++) != 0 || !*cs++)
@@ -89,9 +89,7 @@ int strncmp(const char * cs,const char * ct,size_t count)
 
 char * strchr(const char * s,char c)
 {
-       const char ch = c;
-
-       for(; *s != ch; ++s)
+       for(; *s != c; ++s)
                if (*s == '\0')
                        return NULL;
        return (char *) s;
@@ -211,11 +209,12 @@ void * memmove(void * dest,const void *src,size_t count)
 int memcmp(const void * cs,const void * ct,size_t count)
 {
        const unsigned char *su1, *su2;
+       signed char res = 0;
 
        for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
-               if (*su1 != *su2)
-                       return((*su1 < *su2) ? -1 : +1);
-       return(0);
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
 }
 
 /*
index eac1bc77a592d046a200f8ec0c5e3335afee0199..05bd2748bc19ffad1fd2d76c1065f6d760e1b6d8 100644 (file)
@@ -85,45 +85,51 @@ static inline void file_mmap_sync_page(struct vm_area_struct * vma,
 static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start,
        size_t size, unsigned int flags)
 {
-       unsigned long page_dir;
-       unsigned long *page_table, *dir;
-       unsigned long poff, pcnt, pc;
+       pgd_t * dir;
+       unsigned long poff, pcnt;
 
        size = size >> PAGE_SHIFT;
        dir = PAGE_DIR_OFFSET(current,start);
        poff = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
        start -= vma->vm_start;
-       if ((pcnt = PTRS_PER_PAGE - poff) > size)
+       pcnt = PTRS_PER_PAGE - poff;
+       if (pcnt > size)
                pcnt = size;
 
-       for ( ; size > 0; ++dir, size -= pcnt,
-            pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
-               if (!(PAGE_PRESENT & (page_dir = *dir))) {
-                       if (page_dir)
-                               printk("file_mmap_sync: bad page directory.\n");
+       for ( ; size > 0; ++dir, size -= pcnt, pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
+               pte_t *page_table;
+               unsigned long pc;
+
+               if (pgd_none(*dir)) {
                        poff = 0;
                        start += pcnt*PAGE_SIZE;
                        continue;
                }
-               page_table = (unsigned long *)(PAGE_MASK & page_dir);
-               if (poff) {
-                       page_table += poff;
+               if (pgd_bad(*dir)) {
+                       printk("file_mmap_sync: bad page directory entry %08lx.\n", pgd_val(*dir));
+                       pgd_clear(dir);
                        poff = 0;
+                       start += pcnt*PAGE_SIZE;
+                       continue;
                }
+               page_table = poff + (pte_t *) pgd_page(*dir);
+               poff = 0;
                for (pc = pcnt; pc--; page_table++, start += PAGE_SIZE) {
-                       unsigned long page = *page_table;
-                       if (!(page & PAGE_PRESENT))
+                       pte_t pte;
+
+                       pte = *page_table;
+                       if (!pte_present(pte))
                                continue;
-                       if (!(page & PAGE_DIRTY))
+                       if (!pte_dirty(pte))
                                continue;
-                       mem_map[MAP_NR(page)]++;
                        if (flags & MS_INVALIDATE) {
-                               *page_table = 0;
-                               free_page(page);
-                       } else
-                               *page_table = page & ~PAGE_DIRTY;
-                       file_mmap_sync_page(vma, start, page);
-                       free_page(page);
+                               pte_clear(page_table);
+                       } else {
+                               mem_map[MAP_NR(pte_page(pte))]++;
+                               *page_table = pte_mkclean(pte);
+                       }
+                       file_mmap_sync_page(vma, start, pte_page(pte));
+                       free_page(pte_page(pte));
                }
        }
        invalidate();
@@ -135,8 +141,7 @@ static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start,
  */
 static void file_mmap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len)
 {
-       if (vma->vm_page_prot & PAGE_RW)
-               file_mmap_sync(vma, start, len, MS_ASYNC);
+       file_mmap_sync(vma, start, len, MS_ASYNC);
 }
 
 /*
@@ -144,8 +149,7 @@ static void file_mmap_unmap(struct vm_area_struct *vma, unsigned long start, siz
  */
 static void file_mmap_close(struct vm_area_struct * vma)
 {
-       if (vma->vm_page_prot & PAGE_RW)
-               file_mmap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC);
+       file_mmap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC);
 }
 
 /*
@@ -157,10 +161,10 @@ static void file_mmap_close(struct vm_area_struct * vma)
  */
 void file_mmap_swapout(struct vm_area_struct * vma,
        unsigned long offset,
-       unsigned long *pte)
+       pte_t *page_table)
 {
        printk("swapout not implemented on shared files..\n");
-       *pte = 0;
+       pte_clear(page_table);
 }
 
 /*
index 57fa9a7a4adb68196423c7dfb29dee24c29cc3e3..deb3f33c7501fc4ff803c3dee8b6b75a239d4658 100644 (file)
@@ -76,34 +76,42 @@ void oom(struct task_struct * task)
        send_sig(SIGKILL,task,1);
 }
 
-static void free_one_table(unsigned long * page_dir)
+static inline void free_one_pte(pte_t * page_table)
 {
-       int j;
-       unsigned long pg_table = *page_dir;
-       unsigned long * page_table;
+       pte_t page = *page_table;
 
-       if (!pg_table)
+       if (pte_none(page))
                return;
-       *page_dir = 0;
-       if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) {
-               printk("Bad page table: [%p]=%08lx\n",page_dir,pg_table);
+       pte_clear(page_table);
+       if (!pte_present(page)) {
+               swap_free(pte_val(page));
                return;
        }
-       if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
+       free_page(pte_page(page));
+       return;
+}
+
+static void free_one_table(pgd_t * page_dir)
+{
+       int j;
+       pgd_t pg_table = *page_dir;
+       pte_t * page_table;
+       unsigned long page;
+
+       if (pgd_none(pg_table))
+               return;
+       pgd_clear(page_dir);
+       if (pgd_bad(pg_table)) {
+               printk("Bad page table: [%p]=%08lx\n",page_dir,pgd_val(pg_table));
                return;
-       page_table = (unsigned long *) (pg_table & PAGE_MASK);
-       for (j = 0 ; j < PTRS_PER_PAGE ; j++,page_table++) {
-               unsigned long pg = *page_table;
-               
-               if (!pg)
-                       continue;
-               *page_table = 0;
-               if (pg & PAGE_PRESENT)
-                       free_page(PAGE_MASK & pg);
-               else
-                       swap_free(pg);
        }
-       free_page(PAGE_MASK & pg_table);
+       page = pgd_page(pg_table);
+       if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
+               return;
+       page_table = (pte_t *) page;
+       for (j = 0 ; j < PTRS_PER_PAGE ; j++,page_table++)
+               free_one_pte(page_table);
+       free_page(page);
 }
 
 /*
@@ -116,7 +124,7 @@ static void free_one_table(unsigned long * page_dir)
 void clear_page_tables(struct task_struct * tsk)
 {
        int i;
-       unsigned long * page_dir;
+       pgd_t * page_dir;
 
        if (!tsk)
                return;
@@ -128,9 +136,9 @@ void clear_page_tables(struct task_struct * tsk)
                return;
        }
        if (mem_map[MAP_NR((unsigned long) page_dir)] > 1) {
-               unsigned long * new_pg;
+               pgd_t * new_pg;
 
-               if (!(new_pg = (unsigned long*) get_free_page(GFP_KERNEL))) {
+               if (!(new_pg = (pgd_t *) get_free_page(GFP_KERNEL))) {
                        oom(tsk);
                        return;
                }
@@ -152,7 +160,7 @@ void clear_page_tables(struct task_struct * tsk)
 void free_page_tables(struct task_struct * tsk)
 {
        int i;
-       unsigned long * page_dir;
+       pgd_t * page_dir;
 
        if (!tsk)
                return;
@@ -200,60 +208,59 @@ int clone_page_tables(struct task_struct * tsk)
 int copy_page_tables(struct task_struct * tsk)
 {
        int i;
-       unsigned long *old_page_dir;
-       unsigned long *new_page_dir;
+       pgd_t *old_page_dir;
+       pgd_t *new_page_dir;
 
-       new_page_dir = (unsigned long *) get_free_page(GFP_KERNEL);
+       new_page_dir = (pgd_t *) get_free_page(GFP_KERNEL);
        if (!new_page_dir)
                return -ENOMEM;
        old_page_dir = PAGE_DIR_OFFSET(current, 0);
        SET_PAGE_DIR(tsk, new_page_dir);
        for (i = 0 ; i < PTRS_PER_PAGE ; i++,old_page_dir++,new_page_dir++) {
                int j;
-               unsigned long old_pg_table, *old_page_table;
-               unsigned long new_pg_table, *new_page_table;
+               pgd_t old_pg_table;
+               pte_t *old_page_table, *new_page_table;
 
                old_pg_table = *old_page_dir;
-               if (!old_pg_table)
+               if (pgd_none(old_pg_table))
                        continue;
-               if (old_pg_table >= high_memory || !(old_pg_table & PAGE_PRESENT)) {
+               if (pgd_bad(old_pg_table)) {
                        printk("copy_page_tables: bad page table: "
                                "probable memory corruption\n");
-                       *old_page_dir = 0;
+                       pgd_clear(old_page_dir);
                        continue;
                }
-               if (mem_map[MAP_NR(old_pg_table)] & MAP_PAGE_RESERVED) {
+               if (mem_map[MAP_NR(pgd_page(old_pg_table))] & MAP_PAGE_RESERVED) {
                        *new_page_dir = old_pg_table;
                        continue;
                }
-               if (!(new_pg_table = get_free_page(GFP_KERNEL))) {
+               if (!(new_page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
                        free_page_tables(tsk);
                        return -ENOMEM;
                }
-               old_page_table = (unsigned long *) (PAGE_MASK & old_pg_table);
-               new_page_table = (unsigned long *) (PAGE_MASK & new_pg_table);
+               old_page_table = (pte_t *) pgd_page(old_pg_table);
+               pgd_set(new_page_dir, new_page_table);
                for (j = 0 ; j < PTRS_PER_PAGE ; j++,old_page_table++,new_page_table++) {
-                       unsigned long pg;
-                       pg = *old_page_table;
-                       if (!pg)
+                       pte_t pte = *old_page_table;
+                       if (pte_none(pte))
                                continue;
-                       if (!(pg & PAGE_PRESENT)) {
-                               *new_page_table = swap_duplicate(pg);
+                       if (!pte_present(pte)) {
+                               swap_duplicate(pte_val(pte));
+                               *new_page_table = pte;
                                continue;
                        }
-                       if (pg > high_memory || (mem_map[MAP_NR(pg)] & MAP_PAGE_RESERVED)) {
-                               *new_page_table = pg;
+                       if (pte_page(pte) > high_memory || (mem_map[MAP_NR(pte_page(pte))] & MAP_PAGE_RESERVED)) {
+                               *new_page_table = pte;
                                continue;
                        }
-                       if (pg & PAGE_COW)
-                               pg &= ~PAGE_RW;
-                       if (delete_from_swap_cache(pg))
-                               pg |= PAGE_DIRTY;
-                       *new_page_table = pg;
-                       *old_page_table = pg;
-                       mem_map[MAP_NR(pg)]++;
+                       if (pte_cow(pte))
+                               pte = pte_wrprotect(pte);
+                       if (delete_from_swap_cache(pte_page(pte)))
+                               pte = pte_mkdirty(pte);
+                       *new_page_table = pte;
+                       *old_page_table = pte;
+                       mem_map[MAP_NR(pte_page(pte))]++;
                }
-               *new_page_dir = new_pg_table | PAGE_TABLE;
        }
        invalidate();
        return 0;
@@ -265,8 +272,8 @@ int copy_page_tables(struct task_struct * tsk)
  */
 int unmap_page_range(unsigned long from, unsigned long size)
 {
-       unsigned long page, page_dir;
-       unsigned long *page_table, *dir;
+       pgd_t page_dir, * dir;
+       pte_t page, * page_table;
        unsigned long poff, pcnt, pc;
 
        if (from & ~PAGE_MASK) {
@@ -281,57 +288,54 @@ int unmap_page_range(unsigned long from, unsigned long size)
 
        for ( ; size > 0; ++dir, size -= pcnt,
             pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
-               if (!(page_dir = *dir)) {
+               page_dir = *dir;
+               if (pgd_none(page_dir)) {
                        poff = 0;
                        continue;
                }
-               if (!(page_dir & PAGE_PRESENT)) {
+               if (pgd_bad(page_dir)) {
                        printk("unmap_page_range: bad page directory.");
                        continue;
                }
-               page_table = (unsigned long *)(PAGE_MASK & page_dir);
+               page_table = (pte_t *) pgd_page(page_dir);
                if (poff) {
                        page_table += poff;
                        poff = 0;
                }
                for (pc = pcnt; pc--; page_table++) {
-                       if ((page = *page_table) != 0) {
-                               *page_table = 0;
-                               if (PAGE_PRESENT & page) {
-                                       if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+                       page = *page_table;
+                       if (!pte_none(page)) {
+                               pte_clear(page_table);
+                               if (pte_present(page)) {
+                                       if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
                                                if (current->mm->rss > 0)
                                                        --current->mm->rss;
-                                       free_page(PAGE_MASK & page);
+                                       free_page(pte_page(page));
                                } else
-                                       swap_free(page);
+                                       swap_free(pte_val(page));
                        }
                }
                if (pcnt == PTRS_PER_PAGE) {
-                       *dir = 0;
-                       free_page(PAGE_MASK & page_dir);
+                       pgd_clear(dir);
+                       free_page(pgd_page(page_dir));
                }
        }
        invalidate();
        return 0;
 }
 
-int zeromap_page_range(unsigned long from, unsigned long size, int mask)
+int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot)
 {
-       unsigned long *page_table, *dir;
+       pgd_t * dir;
+       pte_t * page_table;
        unsigned long poff, pcnt;
-       unsigned long page;
+       pte_t zero_pte;
 
-       if (mask) {
-               if ((mask & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT) {
-                       printk("zeromap_page_range: mask = %08x\n",mask);
-                       return -EINVAL;
-               }
-               mask |= ZERO_PAGE;
-       }
        if (from & ~PAGE_MASK) {
                printk("zeromap_page_range: from = %08lx\n",from);
                return -EINVAL;
        }
+       zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
        dir = PAGE_DIR_OFFSET(current,from);
        size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
        poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
@@ -339,33 +343,34 @@ int zeromap_page_range(unsigned long from, unsigned long size, int mask)
                pcnt = size;
 
        while (size > 0) {
-               if (!(PAGE_PRESENT & *dir)) {
-                               /* clear page needed here?  SRB. */
-                       if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) {
+               if (!pgd_present(*dir)) {
+                       if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
                                invalidate();
                                return -ENOMEM;
                        }
-                       if (PAGE_PRESENT & *dir) {
+                       if (pgd_present(*dir)) {
                                free_page((unsigned long) page_table);
-                               page_table = (unsigned long *)(PAGE_MASK & *dir++);
+                               page_table = (pte_t *) pgd_page(*dir);
                        } else
-                               *dir++ = ((unsigned long) page_table) | PAGE_TABLE;
+                               pgd_set(dir, page_table);
                } else
-                       page_table = (unsigned long *)(PAGE_MASK & *dir++);
+                       page_table = (pte_t *) pgd_page(*dir);
+               dir++;
                page_table += poff;
                poff = 0;
                for (size -= pcnt; pcnt-- ;) {
-                       if ((page = *page_table) != 0) {
-                               *page_table = 0;
-                               if (page & PAGE_PRESENT) {
-                                       if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+                       pte_t page = *page_table;
+                       if (!pte_none(page)) {
+                               pte_clear(page_table);
+                               if (pte_present(page)) {
+                                       if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
                                                if (current->mm->rss > 0)
                                                        --current->mm->rss;
-                                       free_page(PAGE_MASK & page);
+                                       free_page(pte_page(page));
                                } else
-                                       swap_free(page);
+                                       swap_free(pte_val(page));
                        }
-                       *page_table++ = mask;
+                       *page_table++ = zero_pte;
                }
                pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
        }
@@ -378,18 +383,12 @@ int zeromap_page_range(unsigned long from, unsigned long size, int mask)
  * mappings are removed. any references to nonexistent pages results
  * in null mappings (currently treated as "copy-on-access")
  */
-int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask)
+int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot)
 {
-       unsigned long *page_table, *dir;
+       pgd_t * dir;
+       pte_t * page_table;
        unsigned long poff, pcnt;
-       unsigned long page;
 
-       if (mask) {
-               if ((mask & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT) {
-                       printk("remap_page_range: mask = %08x\n",mask);
-                       return -EINVAL;
-               }
-       }
        if ((from & ~PAGE_MASK) || (to & ~PAGE_MASK)) {
                printk("remap_page_range: from = %08lx, to=%08lx\n",from,to);
                return -EINVAL;
@@ -401,52 +400,44 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size, i
                pcnt = size;
 
        while (size > 0) {
-               if (!(PAGE_PRESENT & *dir)) {
-                       /* clearing page here, needed?  SRB. */
-                       if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) {
+               if (!pgd_present(*dir)) {
+                       if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
                                invalidate();
                                return -1;
                        }
-                       *dir++ = ((unsigned long) page_table) | PAGE_TABLE;
-               }
-               else
-                       page_table = (unsigned long *)(PAGE_MASK & *dir++);
-               if (poff) {
-                       page_table += poff;
-                       poff = 0;
-               }
+                       if (pgd_present(*dir)) {
+                               free_page((unsigned long) page_table);
+                               page_table = (pte_t *) pgd_page(*dir);
+                       } else
+                               pgd_set(dir, page_table);
+               } else
+                       page_table = (pte_t *) pgd_page(*dir);
+               dir++;
+               page_table += poff;
+               poff = 0;
 
                for (size -= pcnt; pcnt-- ;) {
-                       if ((page = *page_table) != 0) {
-                               *page_table = 0;
-                               if (PAGE_PRESENT & page) {
-                                       if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
+                       pte_t page = *page_table;
+                       if (!pte_none(page)) {
+                               pte_clear(page_table);
+                               if (pte_present(page)) {
+                                       if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
                                                if (current->mm->rss > 0)
                                                        --current->mm->rss;
-                                       free_page(PAGE_MASK & page);
+                                       free_page(pte_page(page));
                                } else
-                                       swap_free(page);
+                                       swap_free(pte_val(page));
                        }
-
-                       /*
-                        * the first condition should return an invalid access
-                        * when the page is referenced. current assumptions
-                        * cause it to be treated as demand allocation in some
-                        * cases.
-                        */
-                       if (!mask)
-                               *page_table++ = 0;      /* not present */
-                       else if (to >= high_memory)
-                               *page_table++ = (to | mask);
-                       else if (!mem_map[MAP_NR(to)])
-                               *page_table++ = 0;      /* not present */
-                       else {
-                               *page_table++ = (to | mask);
+                       if (to >= high_memory)
+                               *page_table = mk_pte(to, prot);
+                       else if (mem_map[MAP_NR(to)]) {
+                               *page_table = mk_pte(to, prot);
                                if (!(mem_map[MAP_NR(to)] & MAP_PAGE_RESERVED)) {
                                        ++current->mm->rss;
                                        mem_map[MAP_NR(to)]++;
                                }
                        }
+                       page_table++;
                        to += PAGE_SIZE;
                }
                pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
@@ -456,77 +447,52 @@ int remap_page_range(unsigned long from, unsigned long to, unsigned long size, i
 }
 
 /*
- * This function puts a page in memory at the wanted address.
- * It returns the physical address of the page gotten, 0 if
- * out of memory (either when trying to access page-table or
- * page.)
+ * sanity-check function..
  */
-unsigned long put_page(struct task_struct * tsk,unsigned long page,
-       unsigned long address,int prot)
+static void put_page(pte_t * page_table, pte_t pte)
 {
-       unsigned long *page_table;
-
-       if ((prot & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT)
-               printk("put_page: prot = %08x\n",prot);
-       if (page >= high_memory) {
-               printk("put_page: trying to put page %08lx at %08lx\n",page,address);
-               return 0;
-       }
-       page_table = PAGE_DIR_OFFSET(tsk,address);
-       if ((*page_table) & PAGE_PRESENT)
-               page_table = (unsigned long *) (PAGE_MASK & *page_table);
-       else {
-               printk("put_page: bad page directory entry\n");
-               oom(tsk);
-               *page_table = BAD_PAGETABLE | PAGE_TABLE;
-               return 0;
-       }
-       page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-       if (*page_table) {
+       if (!pte_none(*page_table)) {
                printk("put_page: page already exists\n");
-               *page_table = 0;
-               invalidate();
+               free_page(pte_page(pte));
+               return;
        }
-       *page_table = page | prot;
 /* no need for invalidate */
-       return page;
+       *page_table = pte;
 }
 
 /*
- * The previous function doesn't work very well if you also want to mark
- * the page dirty: exec.c wants this, as it has earlier changed the page,
- * and we want the dirty-status to be correct (for VM). Thus the same
- * routine, but this time we mark it dirty too.
+ * This routine is used to map in a page into an address space: needed by
+ * execve() for the initial stack and environment pages.
  */
 unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsigned long address)
 {
-       unsigned long tmp, *page_table;
+       pgd_t * page_dir;
+       pte_t * page_table;
 
        if (page >= high_memory)
                printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address);
        if (mem_map[MAP_NR(page)] != 1)
                printk("mem_map disagrees with %08lx at %08lx\n",page,address);
-       page_table = PAGE_DIR_OFFSET(tsk,address);
-       if (PAGE_PRESENT & *page_table)
-               page_table = (unsigned long *) (PAGE_MASK & *page_table);
-       else {
-               if (!(tmp = get_free_page(GFP_KERNEL)))
+       page_dir = PAGE_DIR_OFFSET(tsk,address);
+       if (pgd_present(*page_dir)) {
+               page_table = (pte_t *) pgd_page(*page_dir);
+       else {
+               if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL)))
                        return 0;
-               if (PAGE_PRESENT & *page_table) {
-                       free_page(tmp);
-                       page_table = (unsigned long *) (PAGE_MASK & *page_table);
+               if (pgd_present(*page_dir)) {
+                       free_page((unsigned long) page_table);
+                       page_table = (pte_t *) pgd_page(*page_dir);
                } else {
-                       *page_table = tmp | PAGE_TABLE;
-                       page_table = (unsigned long *) tmp;
+                       pgd_set(page_dir, page_table);
                }
        }
        page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
-       if (*page_table) {
+       if (!pte_none(*page_table)) {
                printk("put_dirty_page: page already exists\n");
-               *page_table = 0;
+               pte_clear(page_table);
                invalidate();
        }
-       *page_table = page | (PAGE_DIRTY | PAGE_PRIVATE);
+       *page_table = pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)));
 /* no need for invalidate */
        return page;
 }
@@ -538,61 +504,72 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  *
  * Goto-purists beware: the only reason for goto's here is that it results
  * in better assembly code.. The "default" path will see no jumps at all.
+ *
+ * Note that this routine assumes that the protection checks have been
+ * done by the caller (the low-level page fault routine in most cases).
+ * Thus we can safely just mark it writable once we've done any necessary
+ * COW.
+ *
+ * We also mark the page dirty at this point even though the page will
+ * change only once the write actually happens. This avoids a few races,
+ * and potentially makes it more efficient.
  */
 void do_wp_page(struct vm_area_struct * vma, unsigned long address,
        int write_access)
 {
-       unsigned long *pde, pte, old_page, prot;
-       unsigned long new_page;
+       pgd_t *page_dir;
+       pte_t *page_table, pte;
+       unsigned long old_page, new_page;
 
        new_page = __get_free_page(GFP_KERNEL);
-       pde = PAGE_DIR_OFFSET(vma->vm_task,address);
-       pte = *pde;
-       if (!(pte & PAGE_PRESENT))
+       page_dir = PAGE_DIR_OFFSET(vma->vm_task,address);
+       if (pgd_none(*page_dir))
                goto end_wp_page;
-       if ((pte & PAGE_TABLE) != PAGE_TABLE || pte >= high_memory)
+       if (pgd_bad(*page_dir))
                goto bad_wp_pagetable;
-       pte &= PAGE_MASK;
-       pte += PAGE_PTR(address);
-       old_page = *(unsigned long *) pte;
-       if (!(old_page & PAGE_PRESENT))
+       page_table = (pte_t *) pgd_page(*page_dir);
+       page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
+       pte = *page_table;
+       if (!pte_present(pte))
                goto end_wp_page;
+       if (pte_write(pte))
+               goto end_wp_page;
+       old_page = pte_page(pte);
        if (old_page >= high_memory)
                goto bad_wp_page;
-       if (old_page & PAGE_RW)
-               goto end_wp_page;
        vma->vm_task->mm->min_flt++;
-       prot = (old_page & ~PAGE_MASK) | PAGE_RW | PAGE_DIRTY;
-       old_page &= PAGE_MASK;
+       /*
+        * Do we need to copy?
+        */
        if (mem_map[MAP_NR(old_page)] != 1) {
                if (new_page) {
                        if (mem_map[MAP_NR(old_page)] & MAP_PAGE_RESERVED)
                                ++vma->vm_task->mm->rss;
                        copy_page(old_page,new_page);
-                       *(unsigned long *) pte = new_page | prot;
+                       *page_table = pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)));
                        free_page(old_page);
                        invalidate();
                        return;
                }
                free_page(old_page);
                oom(vma->vm_task);
-               *(unsigned long *) pte = BAD_PAGE | prot;
+               *page_table = BAD_PAGE;
                invalidate();
                return;
        }
-       *(unsigned long *) pte |= PAGE_RW | PAGE_DIRTY;
+       *page_table = pte_mkdirty(pte_mkwrite(pte));
        invalidate();
        if (new_page)
                free_page(new_page);
        return;
 bad_wp_page:
        printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
-       *(unsigned long *) pte = BAD_PAGE | PAGE_SHARED;
+       *page_table = BAD_PAGE;
        send_sig(SIGKILL, vma->vm_task, 1);
        goto end_wp_page;
 bad_wp_pagetable:
-       printk("do_wp_page: bogus page-table at address %08lx (%08lx)\n",address,pte);
-       *pde = BAD_PAGETABLE | PAGE_TABLE;
+       printk("do_wp_page: bogus page-table at address %08lx (%08lx)\n", address, pgd_val(*page_dir));
+       pgd_set(page_dir, BAD_PAGETABLE);
        send_sig(SIGKILL, vma->vm_task, 1);
 end_wp_page:
        if (new_page)
@@ -626,13 +603,11 @@ int verify_area(int type, const void * addr, unsigned long size)
                goto bad_area;
 
 good_area:
-       if (!wp_works_ok && type == VERIFY_WRITE)
-               goto check_wp_fault_by_hand;
+       if (type == VERIFY_WRITE)
+               goto check_write;
        for (;;) {
                struct vm_area_struct * next;
-               if (!(vma->vm_page_prot & PAGE_USER))
-                       goto bad_area;
-               if (type != VERIFY_READ && !(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
+               if (!(vma->vm_flags & VM_READ))
                        goto bad_area;
                if (vma->vm_end - start >= size)
                        return 0;
@@ -642,6 +617,22 @@ good_area:
                vma = next;
        }
 
+check_write:
+       if (!(vma->vm_flags & VM_WRITE))
+               goto bad_area;
+       if (!wp_works_ok)
+               goto check_wp_fault_by_hand;
+       for (;;) {
+               if (vma->vm_end - start >= size)
+                       break;
+               if (!vma->vm_next || vma->vm_end != vma->vm_next->vm_start)
+                       goto bad_area;
+               vma = vma->vm_next;
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       }
+       return 0;
+
 check_wp_fault_by_hand:
        size--;
        size += start & ~PAGE_MASK;
@@ -649,34 +640,35 @@ check_wp_fault_by_hand:
        start &= PAGE_MASK;
 
        for (;;) {
-               if (!(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
-                       goto bad_area;
-               do_wp_page(vma, start, PAGE_PRESENT);
+               do_wp_page(vma, start, 1);
                if (!size)
-                       return 0;
+                       break;
                size--;
                start += PAGE_SIZE;
                if (start < vma->vm_end)
                        continue;
                vma = vma->vm_next;
                if (!vma || vma->vm_start != start)
-                       break;
+                       goto bad_area;
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;;
        }
+       return 0;
 
 bad_area:
        return -EFAULT;
 }
 
-static inline void get_empty_page(struct task_struct * tsk, unsigned long address)
+static inline void get_empty_page(struct vm_area_struct * vma, pte_t * page_table)
 {
        unsigned long tmp;
 
        if (!(tmp = get_free_page(GFP_KERNEL))) {
-               oom(tsk);
-               tmp = BAD_PAGE;
+               oom(vma->vm_task);
+               put_page(page_table, BAD_PAGE);
+               return;
        }
-       if (!put_page(tsk,tmp,address,PAGE_PRIVATE))
-               free_page(tmp);
+       put_page(page_table, pte_mkwrite(mk_pte(tmp, vma->vm_page_prot)));
 }
 
 /*
@@ -691,80 +683,81 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
        unsigned long from_address, struct vm_area_struct * from_area,
        unsigned long newpage)
 {
-       unsigned long from;
-       unsigned long to;
-       unsigned long from_page;
-       unsigned long to_page;
+       pgd_t * from_dir, * to_dir;
+       pte_t * from_table, * to_table;
+       pte_t from, to;
 
-       from_page = (unsigned long)PAGE_DIR_OFFSET(from_area->vm_task,from_address);
-       to_page = (unsigned long)PAGE_DIR_OFFSET(to_area->vm_task,to_address);
+       from_dir = PAGE_DIR_OFFSET(from_area->vm_task,from_address);
 /* is there a page-directory at from? */
-       from = *(unsigned long *) from_page;
-       if (!(from & PAGE_PRESENT))
+       if (!pgd_present(*from_dir))
                return 0;
-       from &= PAGE_MASK;
-       from_page = from + PAGE_PTR(from_address);
-       from = *(unsigned long *) from_page;
+       from_table = (pte_t *) (pgd_page(*from_dir) + PAGE_PTR(from_address));
+       from = *from_table;
 /* is the page present? */
-       if (!(from & PAGE_PRESENT))
+       if (!pte_present(from))
                return 0;
-/* if it is private, it must be clean to be shared */
-       if (from & PAGE_DIRTY) {
-               if (from_area->vm_page_prot & PAGE_COW)
+/* if it is dirty it must be from a shared mapping to be shared */
+       if (pte_dirty(from)) {
+               if (!(from_area->vm_flags & VM_SHARED))
                        return 0;
-               if (!(from_area->vm_page_prot & PAGE_RW))
+               if (pte_write(from)) {
+                       printk("nonwritable, but dirty, shared page\n");
                        return 0;
-       }               
+               }
+       }
 /* is the page reasonable at all? */
-       if (from >= high_memory)
+       if (pte_page(from) >= high_memory)
                return 0;
-       if (mem_map[MAP_NR(from)] & MAP_PAGE_RESERVED)
+       if (mem_map[MAP_NR(pte_page(from))] & MAP_PAGE_RESERVED)
                return 0;
 /* is the destination ok? */
-       to = *(unsigned long *) to_page;
-       if (!(to & PAGE_PRESENT))
+       to_dir = PAGE_DIR_OFFSET(to_area->vm_task,to_address);
+       if (!pgd_present(*to_dir))
                return 0;
-       to &= PAGE_MASK;
-       to_page = to + PAGE_PTR(to_address);
-       if (*(unsigned long *) to_page)
+       to_table = (pte_t *) (pgd_page(*to_dir) + PAGE_PTR(to_address));
+       to = *to_table;
+       if (!pte_none(to))
                return 0;
 /* do we copy? */
        if (newpage) {
-               if (in_swap_cache(from)) { /* implies PAGE_DIRTY */
-                       if (from_area->vm_page_prot & PAGE_COW)
+               /* if it's in the swap cache, it's dirty by implication */
+               /* so we can't use it if it's not from a shared mapping */
+               if (in_swap_cache(pte_page(from))) {
+                       if (!(from_area->vm_flags & VM_SHARED))
                                return 0;
-                       if (!(from_area->vm_page_prot & PAGE_RW))
+                       if (!pte_write(from)) {
+                               printk("nonwritable, but dirty, shared page\n");
                                return 0;
+                       }
                }
-               copy_page((from & PAGE_MASK), newpage);
-               *(unsigned long *) to_page = newpage | to_area->vm_page_prot;
+               copy_page(pte_page(from), newpage);
+               *to_table = mk_pte(newpage, to_area->vm_page_prot);
                return 1;
        }
-/* do a final swap-cache test before sharing them.. */
-       if (in_swap_cache(from)) {
-               if (from_area->vm_page_prot & PAGE_COW)
-                       return 0;
-               if (!(from_area->vm_page_prot & PAGE_RW))
+/*
+ * do a final swap-cache test before sharing them: if it's in the swap
+ * cache, we have to remove it now, as we get two pointers to the same
+ * physical page and the cache can't handle it. Mark the original dirty.
+ *
+ * NOTE! Even if "from" is dirty, "to" will be clean: if we get here
+ * with a dirty "from", the from-mapping is a shared map, so we can trust
+ * the page contents to be up-to-date
+ */
+       if (in_swap_cache(pte_page(from))) {
+               if (!(from_area->vm_flags & VM_SHARED))
                        return 0;
-               from |= PAGE_DIRTY;
-               *(unsigned long *) from_page = from;
-               delete_from_swap_cache(from);
-               invalidate();
+               *from_table = pte_mkdirty(from);
+               delete_from_swap_cache(pte_page(from));
        }
-       mem_map[MAP_NR(from)]++;
-/* fill in the 'to' field, checking for COW-stuff */
-       to = (from & (PAGE_MASK | PAGE_DIRTY)) | to_area->vm_page_prot;
-       if (to & PAGE_COW)
-               to &= ~PAGE_RW;
-       *(unsigned long *) to_page = to;
+       mem_map[MAP_NR(pte_page(from))]++;
+       *to_table = mk_pte(pte_page(from), to_area->vm_page_prot);
 /* Check if we need to do anything at all to the 'from' field */
-       if (!(from & PAGE_RW))
+       if (!pte_write(from))
                return 1;
-       if (!(from_area->vm_page_prot & PAGE_COW))
+       if (from_area->vm_flags & VM_SHARED)
                return 1;
 /* ok, need to mark it read-only, so invalidate any possible old TB entry */
-       from &= ~PAGE_RW;
-       *(unsigned long *) from_page = from;
+       *from_table = pte_wrprotect(from);
        invalidate();
        return 1;
 }
@@ -789,7 +782,7 @@ static int share_page(struct vm_area_struct * area, unsigned long address,
                return 0;
        /* do we need to copy or can we just share? */
        give_page = 0;
-       if ((area->vm_page_prot & PAGE_COW) && write_access) {
+       if (write_access && !(area->vm_flags & VM_SHARED)) {
                if (!newpage)
                        return 0;
                give_page = newpage;
@@ -825,74 +818,79 @@ static int share_page(struct vm_area_struct * area, unsigned long address,
 /*
  * fill in an empty page-table if none exists.
  */
-static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned long address)
+static inline pte_t * get_empty_pgtable(struct task_struct * tsk,unsigned long address)
 {
+       pgd_t *p;
        unsigned long page;
-       unsigned long *p;
 
        p = PAGE_DIR_OFFSET(tsk,address);
-       if (PAGE_PRESENT & *p)
-               return *p;
-       if (*p) {
+       if (pgd_present(*p))
+               return (pte_t *) (PAGE_PTR(address) + pgd_page(*p));
+       if (!pgd_none(*p)) {
                printk("get_empty_pgtable: bad page-directory entry \n");
-               *p = 0;
+               pgd_clear(p);
        }
        page = get_free_page(GFP_KERNEL);
-       p = PAGE_DIR_OFFSET(tsk,address);
-       if (PAGE_PRESENT & *p) {
+       if (pgd_present(*p)) {
                free_page(page);
-               return *p;
+               return (pte_t *) (PAGE_PTR(address) + pgd_page(*p));
        }
-       if (*p) {
+       if (!pgd_none(*p)) {
                printk("get_empty_pgtable: bad page-directory entry \n");
-               *p = 0;
+               pgd_clear(p);
        }
        if (page) {
-               *p = page | PAGE_TABLE;
-               return *p;
+               pgd_set(p, (pte_t *) page);
+               return (pte_t *) (PAGE_PTR(address) + page);
        }
        oom(current);
-       *p = BAD_PAGETABLE | PAGE_TABLE;
-       return 0;
+       pgd_set(p, BAD_PAGETABLE);
+       return NULL;
 }
 
-static inline void do_swap_page(struct vm_area_struct * vma,
-       unsigned long address, unsigned long * pge, unsigned long entry)
+static inline void do_swap_page(struct vm_area_struct * vma, unsigned long address,
+       pte_t * page_table, pte_t entry, int write_access)
 {
-       unsigned long page;
+       pte_t page;
 
-       if (vma->vm_ops && vma->vm_ops->swapin)
-               page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, entry);
-       else
-               page = swap_in(entry);
-       if (*pge != entry) {
-               free_page(page);
+       if (!vma->vm_ops || !vma->vm_ops->swapin) {
+               swap_in(vma, page_table, pte_val(entry), write_access);
                return;
        }
-       page = page | vma->vm_page_prot;
-       if (mem_map[MAP_NR(page)] > 1 && (page & PAGE_COW))
-               page &= ~PAGE_RW;
+       page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry));
+       if (pte_val(*page_table) != pte_val(entry)) {
+               free_page(pte_page(page));
+               return;
+       }
+       if (mem_map[MAP_NR(pte_page(page))] > 1 && !(vma->vm_flags & VM_SHARED))
+               page = pte_wrprotect(page);
        ++vma->vm_task->mm->rss;
        ++vma->vm_task->mm->maj_flt;
-       *pge = page;
+       *page_table = page;
        return;
 }
 
+/*
+ * do_no_page() tries to create a new page mapping. It aggressively
+ * tries to share with existing pages, but makes a separate copy if
+ * the "write_access" parameter is true in order to avoid the next
+ * page fault.
+ */
 void do_no_page(struct vm_area_struct * vma, unsigned long address,
        int write_access)
 {
-       unsigned long page, entry, prot;
+       pte_t * page_table;
+       pte_t entry;
+       unsigned long page;
 
-       page = get_empty_pgtable(vma->vm_task,address);
-       if (!page)
+       page_table = get_empty_pgtable(vma->vm_task,address);
+       if (!page_table)
                return;
-       page &= PAGE_MASK;
-       page += PAGE_PTR(address);
-       entry = *(unsigned long *) page;
-       if (entry & PAGE_PRESENT)
+       entry = *page_table;
+       if (pte_present(entry))
                return;
-       if (entry) {
-               do_swap_page(vma, address, (unsigned long *) page, entry);
+       if (!pte_none(entry)) {
+               do_swap_page(vma, address, page_table, entry, write_access);
                return;
        }
        address &= PAGE_MASK;
@@ -900,7 +898,7 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
        if (!vma->vm_ops || !vma->vm_ops->nopage) {
                ++vma->vm_task->mm->rss;
                ++vma->vm_task->mm->min_flt;
-               get_empty_page(vma->vm_task,address);
+               get_empty_page(vma, page_table);
                return;
        }
        page = get_free_page(GFP_KERNEL);
@@ -911,18 +909,18 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
        }
        if (!page) {
                oom(current);
-               put_page(vma->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+               put_page(page_table, BAD_PAGE);
                return;
        }
        ++vma->vm_task->mm->maj_flt;
        ++vma->vm_task->mm->rss;
-       prot = vma->vm_page_prot;
        /*
         * The fourth argument is "no_share", which tells the low-level code
         * to copy, not share the page even if sharing is possible.  It's
-        * essentially an early COW detection ("moo at 5 AM").
+        * essentially an early COW detection 
         */
-       page = vma->vm_ops->nopage(vma, address, page, write_access && (prot & PAGE_COW));
+       page = vma->vm_ops->nopage(vma, address, page,
+               write_access && !(vma->vm_flags & VM_SHARED));
        if (share_page(vma, address, write_access, 0)) {
                free_page(page);
                return;
@@ -931,13 +929,16 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
         * This silly early PAGE_DIRTY setting removes a race
         * due to the bad i386 page protection. But it's valid
         * for other architectures too.
+        *
+        * Note that if write_access is true, we either now have
+        * a exclusive copy of the page, or this is a shared mapping,
+        * so we can make it writable and dirty to avoid having to
+        * handle that later.
         */
+       entry = mk_pte(page, vma->vm_page_prot);
        if (write_access) {
-               prot |= PAGE_DIRTY;     /* can't be COW-shared: see "no_share" above */
-       } else if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1)
-               prot &= ~PAGE_RW;
-       if (put_page(vma->vm_task, page, address, prot))
-               return;
-       free_page(page);
-       oom(current);
+               entry = pte_mkwrite(pte_mkdirty(entry));
+       } else if (mem_map[MAP_NR(page)] > 1 && !(vma->vm_flags & VM_SHARED))
+               entry = pte_wrprotect(entry);
+       put_page(page_table, entry);
 }
index 2af4d33e18a17449fac4e1246112ed3f68df3d04..16e9687475f1e980578d1baeb9b459f4232f58c1 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -35,10 +35,15 @@ static int anon_map(struct inode *, struct file *, struct vm_area_struct *);
  *
  */
 
+pgprot_t protection_map[16] = {
+       __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
+       __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
+};
+
 int do_mmap(struct file * file, unsigned long addr, unsigned long len,
        unsigned long prot, unsigned long flags, unsigned long off)
 {
-       int mask, error;
+       int error;
        struct vm_area_struct * vma;
 
        if ((len = PAGE_ALIGN(len)) == 0)
@@ -99,14 +104,6 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
         */
        if (file && (!file->f_op || !file->f_op->mmap))
                return -ENODEV;
-       mask = PAGE_PRESENT;
-       if (prot & (PROT_READ | PROT_EXEC))
-               mask |= PAGE_READONLY;
-       if (prot & PROT_WRITE)
-               if ((flags & MAP_TYPE) == MAP_PRIVATE)
-                       mask |= PAGE_COPY;
-               else
-                       mask |= PAGE_SHARED;
 
        vma = (struct vm_area_struct *)kmalloc(sizeof(struct vm_area_struct),
                GFP_KERNEL);
@@ -116,7 +113,6 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
        vma->vm_task = current;
        vma->vm_start = addr;
        vma->vm_end = addr + len;
-       vma->vm_page_prot = mask;
        vma->vm_flags = prot & (VM_READ | VM_WRITE | VM_EXEC);
        vma->vm_flags |= flags & (VM_GROWSDOWN | VM_DENYWRITE | VM_EXECUTABLE);
 
@@ -130,6 +126,7 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
                }
        } else
                vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
        vma->vm_ops = NULL;
        vma->vm_offset = off;
        vma->vm_inode = NULL;
@@ -658,7 +655,6 @@ void unmap_fixup(struct vm_area_struct *area,
        if (addr == area->vm_start && end == area->vm_end) {
                if (area->vm_ops && area->vm_ops->close)
                        area->vm_ops->close(area);
-               remove_shared_vm_struct(area);
                if (area->vm_inode)
                        iput(area->vm_inode);
                return;
@@ -700,7 +696,6 @@ void unmap_fixup(struct vm_area_struct *area,
        if (area->vm_ops && area->vm_ops->close) {
                area->vm_end = area->vm_start;
                area->vm_ops->close(area);
-               remove_shared_vm_struct(area);
        }
        insert_vm_struct(current, mpnt);
 }
@@ -763,6 +758,8 @@ int do_munmap(unsigned long addr, size_t len)
                mpnt = free;
                free = free->vm_next;
 
+               remove_shared_vm_struct(mpnt);
+
                st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
                end = addr+len;
                end = end > mpnt->vm_end ? mpnt->vm_end : end;
@@ -922,8 +919,7 @@ void merge_segments (struct task_struct * task, unsigned long start_addr, unsign
                        continue;
                if (mpnt->vm_ops != prev->vm_ops)
                        continue;
-               if (mpnt->vm_page_prot != prev->vm_page_prot ||
-                   mpnt->vm_flags != prev->vm_flags)
+               if (mpnt->vm_flags != prev->vm_flags)
                        continue;
                if (prev->vm_end != mpnt->vm_start)
                        continue;
index e8413d02808ef26d5ede1d32942f804548df83f4..f159c6e2fa606263fb1a6d6c3afabcd4d430d365 100644 (file)
 #include <asm/segment.h>
 #include <asm/system.h>
 
-static void change_protection(unsigned long start, unsigned long end, int prot)
+static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
 {
-       unsigned long *page_table, *dir;
-       unsigned long page, offset;
+       pgd_t *dir;
+       pte_t *page_table, entry;
+       unsigned long offset;
        int nr;
 
        dir = PAGE_DIR_OFFSET(current, start);
        offset = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
        nr = (end - start) >> PAGE_SHIFT;
        while (nr > 0) {
-               page = *dir;
-               dir++;
-               if (!(page & PAGE_PRESENT)) {
+               if (pgd_none(*dir)) {
+                       dir++;
                        nr = nr - PTRS_PER_PAGE + offset;
                        offset = 0;
                        continue;
                }
-               page_table = offset + (unsigned long *) (page & PAGE_MASK);
+               if (pgd_bad(*dir)) {
+                       printk("Bad page dir entry %08lx\n", pgd_val(*dir));
+                       pgd_clear(dir);
+                       dir++;
+                       nr = nr - PTRS_PER_PAGE + offset;
+                       offset = 0;
+                       continue;
+               }
+               page_table = offset + (pte_t *) pgd_page(*dir);
                offset = PTRS_PER_PAGE - offset;
                if (offset > nr)
                        offset = nr;
                nr = nr - offset;
                do {
-                       page = *page_table;
-                       if (page & PAGE_PRESENT)
-                               *page_table = (page & PAGE_CHG_MASK) | prot;
+                       entry = *page_table;
+                       if (pte_present(entry))
+                               *page_table = pte_modify(entry, newprot);
                        ++page_table;
                } while (--offset);
        }
@@ -49,7 +57,7 @@ static void change_protection(unsigned long start, unsigned long end, int prot)
 }
 
 static inline int mprotect_fixup_all(struct vm_area_struct * vma,
-       int newflags, int prot)
+       int newflags, pgprot_t prot)
 {
        vma->vm_flags = newflags;
        vma->vm_page_prot = prot;
@@ -58,7 +66,7 @@ static inline int mprotect_fixup_all(struct vm_area_struct * vma,
 
 static inline int mprotect_fixup_start(struct vm_area_struct * vma,
        unsigned long end,
-       int newflags, int prot)
+       int newflags, pgprot_t prot)
 {
        struct vm_area_struct * n;
 
@@ -81,7 +89,7 @@ static inline int mprotect_fixup_start(struct vm_area_struct * vma,
 
 static inline int mprotect_fixup_end(struct vm_area_struct * vma,
        unsigned long start,
-       int newflags, int prot)
+       int newflags, pgprot_t prot)
 {
        struct vm_area_struct * n;
 
@@ -104,7 +112,7 @@ static inline int mprotect_fixup_end(struct vm_area_struct * vma,
 
 static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
        unsigned long start, unsigned long end,
-       int newflags, int prot)
+       int newflags, pgprot_t prot)
 {
        struct vm_area_struct * left, * right;
 
@@ -140,33 +148,26 @@ static inline int mprotect_fixup_middle(struct vm_area_struct * vma,
 static int mprotect_fixup(struct vm_area_struct * vma, 
        unsigned long start, unsigned long end, unsigned int newflags)
 {
-       int prot, error;
+       pgprot_t newprot;
+       int error;
 
        if (newflags == vma->vm_flags)
                return 0;
-       prot = PAGE_PRESENT;
-       if (newflags & (VM_READ | VM_EXEC))
-               prot |= PAGE_READONLY;
-       if (newflags & VM_WRITE)
-               if (newflags & VM_SHARED)
-                       prot |= PAGE_SHARED;
-               else
-                       prot |= PAGE_COPY;
-
+       newprot = protection_map[vma->vm_flags & 0xf];
        if (start == vma->vm_start)
                if (end == vma->vm_end)
-                       error = mprotect_fixup_all(vma, newflags, prot);
+                       error = mprotect_fixup_all(vma, newflags, newprot);
                else
-                       error = mprotect_fixup_start(vma, end, newflags, prot);
+                       error = mprotect_fixup_start(vma, end, newflags, newprot);
        else if (end == vma->vm_end)
-               error = mprotect_fixup_end(vma, start, newflags, prot);
+               error = mprotect_fixup_end(vma, start, newflags, newprot);
        else
-               error = mprotect_fixup_middle(vma, start, end, newflags, prot);
+               error = mprotect_fixup_middle(vma, start, end, newflags, newprot);
 
        if (error)
                return error;
 
-       change_protection(start, end, prot);
+       change_protection(start, end, newprot);
        return 0;
 }
 
index c484254eae41f45768dfeeba233642517abba365..a746d23487913bad4b0982c5e608537e68c37b9b 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -28,9 +28,9 @@
 #define SWP_USED       1
 #define SWP_WRITEOK    3
 
-#define SWP_TYPE(entry) (((entry) & 0xfe) >> 1)
-#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << PAGE_SHIFT))
+#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
+#define SWP_OFFSET(entry) ((entry) >> 12)
+#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 12))
 
 int min_free_pages = 20;
 
@@ -70,10 +70,10 @@ extern inline void show_swap_cache_info(void)
 }
 #endif
 
-extern inline int add_to_swap_cache(unsigned long addr, unsigned long entry)
+static int add_to_swap_cache(unsigned long addr, unsigned long entry)
 {
        struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
-       
+
 #ifdef SWAP_CACHE_INFO
        swap_cache_add_total++;
 #endif
@@ -118,6 +118,10 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
                printk("rw_swap_page: weirdness\n");
                return;
        }
+       if (p->swap_map && !p->swap_map[offset]) {
+               printk("Hmm.. Trying to use unallocated swap (%08lx)\n", entry);
+               return;
+       }
        if (!(p->flags & SWP_USED)) {
                printk("Trying to swap to unused swap-device\n");
                return;
@@ -199,32 +203,32 @@ unsigned int get_swap_page(void)
        return 0;
 }
 
-unsigned long swap_duplicate(unsigned long entry)
+void swap_duplicate(unsigned long entry)
 {
        struct swap_info_struct * p;
        unsigned long offset, type;
 
        if (!entry)
-               return 0;
+               return;
        offset = SWP_OFFSET(entry);
        type = SWP_TYPE(entry);
        if (type == SHM_SWP_TYPE)
-               return entry;
+               return;
        if (type >= nr_swapfiles) {
                printk("Trying to duplicate nonexistent swap-page\n");
-               return 0;
+               return;
        }
        p = type + swap_info;
        if (offset >= p->max) {
                printk("swap_duplicate: weirdness\n");
-               return 0;
+               return;
        }
        if (!p->swap_map[offset]) {
                printk("swap_duplicate: trying to duplicate unused page\n");
-               return 0;
+               return;
        }
        p->swap_map[offset]++;
-       return entry;
+       return;
 }
 
 void swap_free(unsigned long entry)
@@ -267,52 +271,69 @@ void swap_free(unsigned long entry)
        wake_up(&lock_queue);
 }
 
-unsigned long swap_in(unsigned long entry)
+/*
+ * The tests may look silly, but it essentially makes sure that
+ * no other process did a swap-in on us just as we were waiting.
+ *
+ * Also, don't bother to add to the swap cache if this page-in
+ * was due to a write access.
+ */
+void swap_in(struct vm_area_struct * vma, pte_t * page_table,
+       unsigned long entry, int write_access)
 {
-       unsigned long page;
+       unsigned long page = get_free_page(GFP_KERNEL);
 
-       if (!(page = get_free_page(GFP_KERNEL))) {
+       if (pte_val(*page_table) != entry) {
+               free_page(page);
+               return;
+       }
+       if (!page) {
+               *page_table = BAD_PAGE;
+               swap_free(entry);
                oom(current);
-               return BAD_PAGE;
+               return;
        }
        read_swap_page(entry, (char *) page);
-       if (add_to_swap_cache(page, entry))
-               return page | PAGE_PRESENT;
+       if (pte_val(*page_table) != entry) {
+               free_page(page);
+               return;
+       }
+       if (!write_access && add_to_swap_cache(page, entry)) {
+               *page_table = mk_pte(page, vma->vm_page_prot);
+               return;
+       }
+       *page_table = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
        swap_free(entry);
-       return page | PAGE_DIRTY | PAGE_PRESENT;
+       return;
 }
 
-static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, unsigned long * table_ptr)
+static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, pte_t * page_table)
 {
-       unsigned long page, entry;
+       pte_t pte;
+       unsigned long entry;
+       unsigned long page;
 
-       page = *table_ptr;
-       if (!(PAGE_PRESENT & page))
+       pte = *page_table;
+       if (!pte_present(pte))
                return 0;
+       page = pte_page(pte);
        if (page >= high_memory)
                return 0;
        if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
                return 0;
-       
-       if ((PAGE_DIRTY & page) && delete_from_swap_cache(page))  {
-               *table_ptr &= ~PAGE_ACCESSED;
+       if ((pte_dirty(pte) && delete_from_swap_cache(page)) || pte_young(pte))  {
+               *page_table = pte_mkold(pte);
                return 0;
-       }
-       if (PAGE_ACCESSED & page) {
-               *table_ptr &= ~PAGE_ACCESSED;
-               return 0;
-       }
-       if (PAGE_DIRTY & page) {
-               page &= PAGE_MASK;
+       }       
+       if (pte_dirty(pte)) {
                if (mem_map[MAP_NR(page)] != 1)
                        return 0;
                if (vma->vm_ops && vma->vm_ops->swapout)
-                       vma->vm_ops->swapout(vma, offset, table_ptr);
-               else
-               {
+                       vma->vm_ops->swapout(vma, offset, page_table);
+               else {
                        if (!(entry = get_swap_page()))
                                return 0;
-                       *table_ptr = entry;
+                       pte_val(*page_table) = entry;
                        invalidate();
                        write_swap_page(entry, (char *) page);
                }
@@ -321,17 +342,16 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, u
        }
         if ((entry = find_in_swap_cache(page)))  {
                if (mem_map[MAP_NR(page)] != 1) {
-                       *table_ptr |= PAGE_DIRTY;
+                       *page_table = pte_mkdirty(pte);
                        printk("Aiee.. duplicated cached swap-cache entry\n");
                        return 0;
                }
-               *table_ptr = entry;
+               pte_val(*page_table) = entry;
                invalidate();
-               free_page(page & PAGE_MASK);
+               free_page(page);
                return 1;
        } 
-       page &= PAGE_MASK;
-       *table_ptr = 0;
+       pte_clear(page_table);
        invalidate();
        free_page(page);
        return 1 + mem_map[MAP_NR(page)];
@@ -366,10 +386,9 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, u
 
 static int swap_out_process(struct task_struct * p)
 {
+       pgd_t *pgdir;
        unsigned long address;
        unsigned long offset;
-       unsigned long *pgdir;
-       unsigned long pg_table;
        struct vm_area_struct* vma;
 
        /*
@@ -390,25 +409,25 @@ static int swap_out_process(struct task_struct * p)
        pgdir = PAGE_DIR_OFFSET(p, address);
        offset = address & ~PGDIR_MASK;
        address &= PGDIR_MASK;
-       for ( ; address < TASK_SIZE ;
-       pgdir++, address = address + PGDIR_SIZE, offset = 0) {
-               pg_table = *pgdir;
-               if (pg_table >= high_memory)
-                       continue;
-               if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
+       for ( ; address < TASK_SIZE ; pgdir++, address = address + PGDIR_SIZE, offset = 0) {
+               pte_t *pg_table;
+
+               if (pgd_none(*pgdir))
                        continue;
-               if (!(PAGE_PRESENT & pg_table)) {
-                       printk("swap_out_process (%s): bad page-table at vm %08lx: %08lx\n",
-                                       p->comm, address + offset, pg_table);
-                       *pgdir = 0;
+               if (pgd_bad(*pgdir)) {
+                       printk("Bad page directory at address %08lx: %08lx\n", address, pgd_val(*pgdir));
+                       pgd_clear(pgdir);
                        continue;
                }
-               pg_table &= 0xfffff000;
+               pg_table = (pte_t *) pgd_page(*pgdir);
+               if (mem_map[MAP_NR((unsigned long) pg_table)] & MAP_PAGE_RESERVED)
+                       continue;
+               pg_table += offset >> PAGE_SHIFT;
 
                /*
                 * Go through this page table.
                 */
-               for( ; offset < ~PGDIR_MASK ; offset += PAGE_SIZE) {
+               for( ; offset < ~PGDIR_MASK ; pg_table++, offset += PAGE_SIZE) {
                        /*
                         * Update vma again..
                         */
@@ -420,7 +439,7 @@ static int swap_out_process(struct task_struct * p)
                                        return 0;
                        }
 
-                       switch(try_to_swap_out(vma, offset+address-vma->vm_start, (unsigned long *) (pg_table + (offset >> 10)))) {
+                       switch(try_to_swap_out(vma, offset+address-vma->vm_start, pg_table)) {
                                case 0:
                                        break;
 
@@ -594,7 +613,7 @@ void free_pages(unsigned long addr, unsigned long order)
                        return;
                }
                printk("Trying to free free memory (%08lx): memory probably corrupted\n",addr);
-               printk("PC = %08lx\n",*(((unsigned long *)&addr)-1));
+               printk("PC = %p\n", __builtin_return_address(0));
                return;
        }
 }
@@ -726,62 +745,69 @@ void show_free_areas(void)
  */
 static int try_to_unuse(unsigned int type)
 {
-       int nr, pgt, pg;
-       unsigned long page, *ppage;
+       int nr;
        unsigned long tmp = 0;
        struct task_struct *p;
 
-       nr = 0;
-       
+       nr = 0; 
 /*
  * When we have to sleep, we restart the whole algorithm from the same
  * task we stopped in. That at least rids us of all races.
  */
 repeat:
        for (; nr < NR_TASKS ; nr++) {
+               pgd_t * page_dir;
+               int i;
+
                p = task[nr];
                if (!p)
                        continue;
-               for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) {
-                       ppage = pgt + PAGE_DIR_OFFSET(p, 0);
-                       page = *ppage;
-                       if (!page)
+               page_dir = PAGE_DIR_OFFSET(p, 0);
+               for (i = 0 ; i < PTRS_PER_PAGE ; page_dir++, i++) {
+                       int j;
+                       pte_t *page_table;
+
+                       if (pgd_none(*page_dir))
                                continue;
-                       if (!(page & PAGE_PRESENT) || (page >= high_memory))
+                       if (pgd_bad(*page_dir)) {
+                               printk("bad page directory entry [%d] %08lx\n", i, pgd_val(*page_dir));
+                               pgd_clear(page_dir);
                                continue;
-                       if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
+                       }
+                       page_table = (pte_t *) pgd_page(*page_dir);
+                       if (mem_map[MAP_NR((unsigned long) page_table)] & MAP_PAGE_RESERVED)
                                continue;
-                       ppage = (unsigned long *) (page & PAGE_MASK);   
-                       for (pg = 0 ; pg < PTRS_PER_PAGE ; pg++,ppage++) {
-                               page = *ppage;
-                               if (!page)
+                       for (j = 0 ; j < PTRS_PER_PAGE ; page_table++, j++) {
+                               pte_t pte;
+                               pte = *page_table;
+                               if (pte_none(pte))
                                        continue;
-                               if (page & PAGE_PRESENT) {
+                               if (pte_present(pte)) {
+                                       unsigned long page = pte_page(pte);
                                        if (page >= high_memory)
                                                continue;
-                                       if (!(page = in_swap_cache(page)))
+                                       if (!in_swap_cache(page))
                                                continue;
-                                       if (SWP_TYPE(page) != type)
+                                       if (SWP_TYPE(in_swap_cache(page)) != type)
                                                continue;
-                                       *ppage |= PAGE_DIRTY;
-                                       delete_from_swap_cache(*ppage);
+                                       delete_from_swap_cache(page);
+                                       *page_table = pte_mkdirty(pte);
                                        continue;
                                }
-                               if (SWP_TYPE(page) != type)
+                               if (SWP_TYPE(pte_val(pte)) != type)
                                        continue;
                                if (!tmp) {
                                        if (!(tmp = __get_free_page(GFP_KERNEL)))
                                                return -ENOMEM;
                                        goto repeat;
                                }
-                               read_swap_page(page, (char *) tmp);
-                               if (*ppage == page) {
-                                       *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE);
-                                       ++p->mm->rss;
-                                       swap_free(page);
-                                       tmp = 0;
-                               }
-                               goto repeat;
+                               read_swap_page(pte_val(pte), (char *) tmp);
+                               if (pte_val(*page_table) != pte_val(pte))
+                                       goto repeat;
+                               *page_table = pte_mkwrite(pte_mkdirty(mk_pte(tmp, PAGE_COPY)));
+                               ++p->mm->rss;
+                               swap_free(pte_val(pte));
+                               tmp = 0;
                        }
                }
        }
index 4da75f7cf65f9f5bf863732173e28da5cc3a69c9..a15ea3bcc4062852844ea46b3e99bb276a7736b2 100644 (file)
@@ -33,37 +33,56 @@ static struct vm_struct * vmlist = NULL;
  */
 #define VMALLOC_OFFSET (8*1024*1024)
 
-static inline void set_pgdir(unsigned long dindex, unsigned long value)
+static inline void set_pgdir(unsigned long dindex, pte_t * page_table)
 {
        struct task_struct * p;
 
        p = &init_task;
        do {
-               PAGE_DIR_OFFSET(p,0)[dindex] = value;
+               pgd_set(PAGE_DIR_OFFSET(p,0) + dindex, page_table);
+               p = p->next_task;
+       } while (p != &init_task);
+}
+
+static inline void clear_pgdir(unsigned long dindex)
+{
+       struct task_struct * p;
+
+       p = &init_task;
+       do {
+               pgd_clear(PAGE_DIR_OFFSET(p,0) + dindex);
                p = p->next_task;
        } while (p != &init_task);
 }
 
 static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
 {
-       unsigned long page, *pte;
+       pgd_t * dir;
+       pte_t * page_table;
+       unsigned long page;
 
-       if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
+       dir = swapper_pg_dir + dindex;
+       if (pgd_none(*dir))
                return 0;
-       page &= PAGE_MASK;
-       pte = index + (unsigned long *) page;
+       if (pgd_bad(*dir)) {
+               printk("bad page directory entry in free_area_pages: %08lx\n", pgd_val(*dir));
+               pgd_clear(dir);
+               return 0;
+       }
+       page = pgd_page(*dir);
+       page_table = index + (pte_t *) page;
        do {
-               unsigned long pg = *pte;
-               *pte = 0;
-               if (pg & PAGE_PRESENT)
-                       free_page(pg);
-               pte++;
+               pte_t pte = *page_table;
+               pte_clear(page_table);
+               if (pte_present(pte))
+                       free_page(pte_page(pte));
+               page_table++;
        } while (--nr);
-       pte = (unsigned long *) page;
-       for (nr = 0 ; nr < 1024 ; nr++, pte++)
-               if (*pte)
+       page_table = (pte_t *) page;
+       for (nr = 0 ; nr < PTRS_PER_PAGE ; nr++, page_table++)
+               if (!pte_none(*page_table))
                        return 0;
-       set_pgdir(dindex,0);
+       clear_pgdir(dindex);
        mem_map[MAP_NR(page)] = 1;
        free_page(page);
        invalidate();
@@ -72,31 +91,39 @@ static int free_area_pages(unsigned long dindex, unsigned long index, unsigned l
 
 static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
 {
-       unsigned long page, *pte;
+       pgd_t *dir;
+       pte_t *page_table;
 
-       page = swapper_pg_dir[dindex];
-       if (!page) {
-               page = get_free_page(GFP_KERNEL);
+       dir = swapper_pg_dir + dindex;
+       if (pgd_none(*dir)) {
+               unsigned long page = get_free_page(GFP_KERNEL);
                if (!page)
                        return -ENOMEM;
-               if (swapper_pg_dir[dindex]) {
+               if (!pgd_none(*dir)) {
                        free_page(page);
-                       page = swapper_pg_dir[dindex];
                } else {
                        mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
-                       set_pgdir(dindex, page | PAGE_SHARED);
+                       set_pgdir(dindex, (pte_t *) page);
                }
        }
-       page &= PAGE_MASK;
-       pte = index + (unsigned long *) page;
-       *pte = PAGE_SHARED;             /* remove a race with vfree() */
+       if (pgd_bad(*dir)) {
+               printk("Bad page dir entry in alloc_area_pages (%08lx)\n", pgd_val(*dir));
+               return -ENOMEM;
+       }
+       page_table = index + (pte_t *) pgd_page(*dir);
+       /*
+        * use a tempotary page-table entry to remove a race with
+        * vfree(): it mustn't free the page table from under us
+        * if we sleep in get_free_page()
+        */
+       *page_table = BAD_PAGE;
        do {
                unsigned long pg = get_free_page(GFP_KERNEL);
 
                if (!pg)
                        return -ENOMEM;
-               *pte = pg | PAGE_SHARED;
-               pte++;
+               *page_table = mk_pte(pg, PAGE_KERNEL);
+               page_table++;
        } while (--nr);
        invalidate();
        return 0;
index e82829e4a3ba48060f4ea29bd5b6e8745a6f9767..46990ae5a3eb05772c6889d0a9122efb43b35775 100644 (file)
@@ -335,10 +335,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
 #ifdef Not_Yet_Avail
        build_options(iph, opt);
 #endif
-#ifdef CONFIG_IP_FIREWALL
-       if(!ip_fw_chk(iph,ip_fw_blk_chain))
-               return -EPERM;
-#endif         
 
        return(20 + tmp);       /* IP header plus MAC header size */
 }