diff -u --recursive --new-file v1.1.83/linux/CREDITS linux/CREDITS --- v1.1.83/linux/CREDITS Sun Jan 22 21:39:37 1995 +++ linux/CREDITS Sun Jan 22 21:30:17 1995 @@ -953,6 +953,13 @@ 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 diff -u --recursive --new-file v1.1.83/linux/Makefile linux/Makefile --- v1.1.83/linux/Makefile Sun Jan 22 21:39:37 1995 +++ linux/Makefile Sun Jan 22 22:08:46 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 83 +SUBLEVEL = 84 ARCH = i386 diff -u --recursive --new-file v1.1.83/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c --- v1.1.83/linux/arch/alpha/boot/main.c Sun Jan 22 21:39:37 1995 +++ linux/arch/alpha/boot/main.c Sun Jan 22 14:37:57 1995 @@ -8,11 +8,11 @@ #include #include #include +#include #include #include #include -#include #include diff -u --recursive --new-file v1.1.83/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v1.1.83/linux/arch/alpha/mm/fault.c Sun Jan 22 21:39:37 1995 +++ linux/arch/alpha/mm/fault.c Sun Jan 22 14:38:19 1995 @@ -60,11 +60,18 @@ * 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; } diff -u --recursive --new-file v1.1.83/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v1.1.83/linux/arch/alpha/mm/init.c Sun Jan 22 21:39:37 1995 +++ linux/arch/alpha/mm/init.c Sun Jan 22 14:38:19 1995 @@ -38,10 +38,10 @@ * 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) diff -u --recursive --new-file v1.1.83/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.1.83/linux/arch/i386/config.in Sun Jan 22 21:39:37 1995 +++ linux/arch/i386/config.in Sun Jan 22 22:13:47 1995 @@ -9,6 +9,7 @@ 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 diff -u --recursive --new-file v1.1.83/linux/arch/i386/ibcs/binfmt_elf.c linux/arch/i386/ibcs/binfmt_elf.c --- v1.1.83/linux/arch/i386/ibcs/binfmt_elf.c Mon Jan 9 07:21:56 1995 +++ linux/arch/i386/ibcs/binfmt_elf.c Sun Jan 22 14:38:19 1995 @@ -65,7 +65,7 @@ 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; diff -u --recursive --new-file v1.1.83/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v1.1.83/linux/arch/i386/kernel/process.c Sun Jan 22 21:39:37 1995 +++ linux/arch/i386/kernel/process.c Sun Jan 22 14:38:19 1995 @@ -37,7 +37,7 @@ /* 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; diff -u --recursive --new-file v1.1.83/linux/arch/i386/kernel/ptrace.c linux/arch/i386/kernel/ptrace.c --- v1.1.83/linux/arch/i386/kernel/ptrace.c Sun Jan 22 21:39:37 1995 +++ linux/arch/i386/kernel/ptrace.c Sun Jan 22 14:38:19 1995 @@ -84,23 +84,30 @@ */ 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 @@ 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) diff -u --recursive --new-file v1.1.83/linux/arch/i386/kernel/vm86.c linux/arch/i386/kernel/vm86.c --- v1.1.83/linux/arch/i386/kernel/vm86.c Mon Jan 9 07:21:56 1995 +++ linux/arch/i386/kernel/vm86.c Sun Jan 22 14:38:19 1995 @@ -67,20 +67,24 @@ static void mark_screen_rdonly(struct task_struct * tsk) { - unsigned long tmp; - unsigned long *pg_table; + pgd_t *pg_dir; - 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++; - } + 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++; } } } diff -u --recursive --new-file v1.1.83/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v1.1.83/linux/arch/i386/mm/fault.c Sun Jan 22 21:39:38 1995 +++ linux/arch/i386/mm/fault.c Sun Jan 22 14:38:19 1995 @@ -25,6 +25,11 @@ * 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 @@ * 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 @@ * 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 @@ /* * 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 @@ 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]; diff -u --recursive --new-file v1.1.83/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c --- v1.1.83/linux/arch/i386/mm/init.c Mon Jan 16 14:18:13 1995 +++ linux/arch/i386/mm/init.c Sun Jan 22 14:38:19 1995 @@ -36,19 +36,19 @@ * 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 @@ "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 @@ */ 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 @@ 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 @@ 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; diff -u --recursive --new-file v1.1.83/linux/drivers/block/README.aztcd linux/drivers/block/README.aztcd --- v1.1.83/linux/drivers/block/README.aztcd Sun Jan 22 21:39:39 1995 +++ linux/drivers/block/README.aztcd Sun Jan 22 21:30:17 1995 @@ -45,7 +45,7 @@ 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 @@ Aztech CD-ROM Init: 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=, 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=, 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 -u --recursive --new-file v1.1.83/linux/drivers/block/README.fd linux/drivers/block/README.fd --- v1.1.83/linux/drivers/block/README.fd Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.fd Sun Jan 22 14:13:14 1995 @@ -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=,allowed_drive_mask + Sets the bitmask of allowed drives to . 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-.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-.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 diff -u --recursive --new-file v1.1.83/linux/drivers/block/README.ide linux/drivers/block/README.ide --- v1.1.83/linux/drivers/block/README.ide Fri Jan 13 16:57:03 1995 +++ linux/drivers/block/README.ide Sun Jan 22 22:13:47 1995 @@ -18,7 +18,7 @@ - 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 @@ 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. @@ -181,6 +225,11 @@ 4. Move /boot to /dos/boot with: cp -a /boot /dos ; rm -r /boot 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 diff -u --recursive --new-file v1.1.83/linux/drivers/block/aztcd.c linux/drivers/block/aztcd.c --- v1.1.83/linux/drivers/block/aztcd.c Sun Jan 22 21:39:39 1995 +++ linux/drivers/block/aztcd.c Sun Jan 22 21:30:17 1995 @@ -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) @@ -90,7 +90,10 @@ 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 ! */ @@ -110,11 +113,7 @@ #include #include -#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 @@ -128,7 +127,6 @@ #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 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 @@ azt_invalidate_buffers(); sync_dev(inode->i_rdev); /*??? isn't it a read only dev?*/ invalidate_buffers(inode -> i_rdev); + CLEAR_TIMER; } return; } diff -u --recursive --new-file v1.1.83/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.1.83/linux/drivers/block/floppy.c Mon Jan 16 14:18:15 1995 +++ linux/drivers/block/floppy.c Sun Jan 22 21:34:24 1995 @@ -92,6 +92,8 @@ #include +#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 @@ #define MODULE_AWARE_DRIVER -#ifdef CONFIG_BLK_DEV_FD #include #include #include @@ -989,7 +990,7 @@ /* 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 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; diff -u --recursive --new-file v1.1.83/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v1.1.83/linux/drivers/block/ide.c Sun Jan 22 21:39:39 1995 +++ linux/drivers/block/ide.c Sun Jan 22 22:13:47 1995 @@ -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) */ @@ -95,6 +95,11 @@ * 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 @@ -102,6 +107,7 @@ * - figure out how to support oddball "intelligent" caching cards */ +#include #include #include #include @@ -110,7 +116,6 @@ #include #include #include -#include #include #include #include @@ -130,8 +135,8 @@ #include #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 @@ *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 @@ /* 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 void do_identify (ide_dev_t *dev) { int bswap; + unsigned short model01; struct hd_driveid *id; unsigned long capacity, check; @@ -1601,16 +1611,23 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ * 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 @@ } #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 @@ 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 */ diff -u --recursive --new-file v1.1.83/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v1.1.83/linux/drivers/char/mem.c Wed Jan 11 21:14:27 1995 +++ linux/drivers/char/mem.c Sun Jan 22 14:38:19 1995 @@ -87,7 +87,13 @@ { 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 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; diff -u --recursive --new-file v1.1.83/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.1.83/linux/drivers/net/Makefile Fri Jan 13 10:12:22 1995 +++ linux/drivers/net/Makefile Fri Jan 20 11:34:39 1995 @@ -166,6 +166,9 @@ 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 diff -u --recursive --new-file v1.1.83/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v1.1.83/linux/drivers/net/at1700.c Mon Jan 16 14:18:19 1995 +++ linux/drivers/net/at1700.c Fri Jan 20 11:34:39 1995 @@ -16,20 +16,20 @@ 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 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 @@ -70,7 +70,6 @@ /* 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 @@ /* 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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++; } @@ -573,8 +572,6 @@ { struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; - - lp->open_time = 0; dev->tbusy = 1; dev->start = 0; diff -u --recursive --new-file v1.1.83/linux/drivers/net/atp.c linux/drivers/net/atp.c --- v1.1.83/linux/drivers/net/atp.c Mon Jan 16 14:18:20 1995 +++ linux/drivers/net/atp.c Fri Jan 20 11:34:39 1995 @@ -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 @@ 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 @@ 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 @@ 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 @@ #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 +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 void set_multicast_list(struct device *dev, int num_addrs, void *addrs); -/* 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ } 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 @@ } /* 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 @@ 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 @@ 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 diff -u --recursive --new-file v1.1.83/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v1.1.83/linux/drivers/net/ewrk3.c Mon Jan 16 14:18:20 1995 +++ linux/drivers/net/ewrk3.c Sun Jan 22 14:30:54 1995 @@ -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 @@ -121,11 +121,12 @@ 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 #include @@ -195,6 +196,7 @@ #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 @@ #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 @@ 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 @@ /* ** 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 @@ 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> 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>=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 @@ 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 @@ for (status = -ENODEV, i=1; i 0) { /* only gets here in autoprobe */ dev = alloc_device(dev, iobase); } else { @@ -1826,7 +1828,6 @@ 0, 0, 0, 0, 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 */ diff -u --recursive --new-file v1.1.83/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.1.83/linux/drivers/net/lance.c Mon Jan 16 14:18:20 1995 +++ linux/drivers/net/lance.c Fri Jan 20 11:34:39 1995 @@ -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 #include @@ -188,7 +188,8 @@ }; 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 @@ 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 @@ 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 ) + */ + 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 @@ 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 @@ + 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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", diff -u --recursive --new-file v1.1.83/linux/drivers/net/net_init.c linux/drivers/net/net_init.c --- v1.1.83/linux/drivers/net/net_init.c Tue Dec 6 11:41:30 1994 +++ linux/drivers/net/net_init.c Fri Jan 20 11:34:39 1995 @@ -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 @@ 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,12 +63,18 @@ 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 @@ */ 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 @@ } 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 @@ } } - 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. */ diff -u --recursive --new-file v1.1.83/linux/drivers/net/smc-ultra.c linux/drivers/net/smc-ultra.c --- v1.1.83/linux/drivers/net/smc-ultra.c Mon Jan 9 11:24:22 1995 +++ linux/drivers/net/smc-ultra.c Fri Jan 20 11:34:39 1995 @@ -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. @@ -12,12 +12,33 @@ 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 #include @@ -93,10 +114,13 @@ 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 @@ 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 @@ 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 @@ } - /* 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 @@ { 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 -u --recursive --new-file v1.1.83/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v1.1.83/linux/drivers/net/tulip.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/tulip.c Fri Jan 20 11:34:39 1995 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* 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); + + + +/* 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; +} + + +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; +} + + +/* + * 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: + */ diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v1.1.83/linux/drivers/scsi/Makefile Fri Jan 13 16:57:04 1995 +++ linux/drivers/scsi/Makefile Fri Jan 20 11:34:39 1995 @@ -52,9 +52,11 @@ 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 diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v1.1.83/linux/drivers/scsi/aha152x.c Mon Jan 16 14:18:21 1995 +++ linux/drivers/scsi/aha152x.c Sun Jan 22 22:13:38 1995 @@ -20,10 +20,19 @@ * 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 * @@ -252,16 +261,14 @@ #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 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 @@ }; #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 @@ { "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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) { + unsigned long flags; + #if defined(DEBUG_RACE) enter_driver("queue"); #else @@ -749,13 +764,10 @@ #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 @@ 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 @@ 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_abort( Scsi_Cmnd *SCpnt) { + unsigned long flags; Scsi_Cmnd *ptr, *prev; + save_flags(flags); cli(); #if defined(DEBUG_ABORT) @@ -857,7 +872,7 @@ 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 @@ if(!current_SC) printk("bus busy w/o current command, "); - sti(); + restore_flags(flags); return SCSI_ABORT_BUSY; } @@ -883,7 +898,7 @@ 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 @@ 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 @@ 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 @@ */ int aha152x_reset(Scsi_Cmnd * __unused) { + unsigned long flags; Scsi_Cmnd *ptr, *prev, *next; aha152x_reset_ports(); @@ -1008,6 +1025,7 @@ current_SC=NULL; } + save_flags(flags); cli(); prev=NULL; ptr=disconnected_SC; while(ptr) @@ -1033,7 +1051,7 @@ ptr = (Scsi_Cmnd *) ptr->host_scribble; } } - sti(); + restore_flags(flags); #if defined( DEBUG_RESET ) if(aha152x_debug & debug_reset) @@ -1093,6 +1111,7 @@ */ void aha152x_done( int error ) { + unsigned long flags; Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) @@ -1110,6 +1129,7 @@ printk("done(%x), ", error); #endif + save_flags(flags); cli(); done_SC = current_SC; @@ -1124,7 +1144,7 @@ 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_intr( int irqno, struct pt_regs * regs ) { + unsigned int flags; int done=0, phase; #if defined(DEBUG_RACE) @@ -1181,7 +1202,7 @@ 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 @@ 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 @@ 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 @@ } current_SC->SCp.phase &= ~disconnected; - sti(); + restore_flags(flags); SETPORT( SIMODE0, 0 ); SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); @@ -1298,13 +1322,14 @@ /* 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 @@ #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, - ¤t_SC->cmnd, - current_SC->cmd_len >>1 ); + outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 ); #if defined(DEBUG_CMD) if(aha152x_debug & debug_cmd) @@ -1597,16 +1620,31 @@ } #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 @@ if(current_SC->SCp.phase & disconnected) { + save_flags(flags); cli(); #if defined(DEBUG_QUEUES) if(aha152x_debug & debug_queues) @@ -1781,7 +1820,7 @@ #endif append_SC( &disconnected_SC, current_SC); current_SC = NULL; - sti(); + restore_flags(flags); SETBITS( SCSISEQ, ENRESELI ); @@ -2223,8 +2262,10 @@ #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 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 @@ 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 @@ in_driver--; should_leave=func; - sti(); + restore_flags(flags); } #endif @@ -2522,8 +2569,10 @@ */ 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 @@ disp_ports(); disp_enintr(); - sti(); + restore_flags(flags); } diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h --- v1.1.83/linux/drivers/scsi/aha152x.h Tue Nov 29 10:07:12 1994 +++ linux/drivers/scsi/aha152x.h Sun Jan 22 22:13:47 1995 @@ -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 @@ (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, \ diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/eata_dma.c linux/drivers/scsi/eata_dma.c --- v1.1.83/linux/drivers/scsi/eata_dma.c Sun Jan 22 21:39:41 1995 +++ linux/drivers/scsi/eata_dma.c Fri Jan 20 11:23:58 1995 @@ -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 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ save_flags(flags); cli(); - DBG(DEBUG,queue_counter++); + DBG(DEBUG_EATA, queue_counter++); hd = HD(cmd); sh = cmd->host; @@ -269,7 +290,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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); diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/eata_dma.h linux/drivers/scsi/eata_dma.h --- v1.1.83/linux/drivers/scsi/eata_dma.h Sun Jan 22 21:39:41 1995 +++ linux/drivers/scsi/eata_dma.h Fri Jan 20 11:23:58 1995 @@ -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 @@ -64,10 +64,11 @@ #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 @@ #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 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 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 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 @@ 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 */ @@ -387,5 +387,7 @@ ushort drive_type; /* In Little Endian ! */ struct lun_map lunmap[4]; }emulpp; + + #endif /* _EATA_H */ diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v1.1.83/linux/drivers/scsi/in2000.c Mon Jan 16 14:18:22 1995 +++ linux/drivers/scsi/in2000.c Fri Jan 20 11:34:39 1995 @@ -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 @@ -684,5 +687,33 @@ 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 + diff -u --recursive --new-file v1.1.83/linux/drivers/scsi/qlogic.c linux/drivers/scsi/qlogic.c --- v1.1.83/linux/drivers/scsi/qlogic.c Mon Jan 16 14:18:23 1995 +++ linux/drivers/scsi/qlogic.c Fri Jan 20 11:34:39 1995 @@ -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 @@ -69,6 +72,15 @@ 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 @@ void ql_zap() { int x; +unsigned long flags; + save_flags( flags ); cli(); x = inb(qbase + 0xd); REG0; @@ -125,7 +139,7 @@ outb(2, qbase + 3); /* reset chip */ if (x & 0x80) REG1; - sti(); + restore_flags( flags ); } /*----------------------------------------------------------------*/ @@ -228,8 +242,11 @@ 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 @@ 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 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 @@ */ 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 @@ #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 @@ 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; diff -u --recursive --new-file v1.1.83/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v1.1.83/linux/drivers/sound/ad1848.c Sun Jan 22 21:39:42 1995 +++ linux/drivers/sound/ad1848.c Fri Jan 20 10:23:18 1995 @@ -93,7 +93,6 @@ 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) diff -u --recursive --new-file v1.1.83/linux/drivers/sound/gus_card.c linux/drivers/sound/gus_card.c --- v1.1.83/linux/drivers/sound/gus_card.c Sun Jan 22 21:39:42 1995 +++ linux/drivers/sound/gus_card.c Fri Jan 20 10:23:41 1995 @@ -128,7 +128,7 @@ #ifndef EXCLUDE_GUSMAX if (have_gus_max) - ad1848_interrupt (irq); + ad1848_interrupt (irq, regs); #endif while (1) diff -u --recursive --new-file v1.1.83/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v1.1.83/linux/drivers/sound/sound_calls.h Sun Jan 22 21:39:42 1995 +++ linux/drivers/sound/sound_calls.h Fri Jan 20 10:24:13 1995 @@ -225,7 +225,7 @@ /* 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); diff -u --recursive --new-file v1.1.83/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v1.1.83/linux/fs/binfmt_elf.c Mon Jan 9 07:22:08 1995 +++ linux/fs/binfmt_elf.c Sun Jan 22 14:38:25 1995 @@ -84,7 +84,7 @@ 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; diff -u --recursive --new-file v1.1.83/linux/fs/exec.c linux/fs/exec.c --- v1.1.83/linux/fs/exec.c Sun Jan 22 21:39:42 1995 +++ linux/fs/exec.c Sun Jan 22 14:38:25 1995 @@ -305,7 +305,7 @@ 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; diff -u --recursive --new-file v1.1.83/linux/fs/msdos/mmap.c linux/fs/msdos/mmap.c --- v1.1.83/linux/fs/msdos/mmap.c Tue Dec 27 08:37:13 1994 +++ linux/fs/msdos/mmap.c Sun Jan 22 14:38:25 1995 @@ -88,7 +88,7 @@ */ 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; @@ -104,4 +104,5 @@ vma->vm_ops = &msdos_file_mmap; return 0; } + diff -u --recursive --new-file v1.1.83/linux/fs/namei.c linux/fs/namei.c --- v1.1.83/linux/fs/namei.c Sun Jan 22 21:39:42 1995 +++ linux/fs/namei.c Sun Jan 22 14:38:25 1995 @@ -33,13 +33,13 @@ 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; } diff -u --recursive --new-file v1.1.83/linux/fs/nfs/mmap.c linux/fs/nfs/mmap.c --- v1.1.83/linux/fs/nfs/mmap.c Wed Nov 30 21:47:39 1994 +++ linux/fs/nfs/mmap.c Sun Jan 22 14:38:25 1995 @@ -92,7 +92,7 @@ /* 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; diff -u --recursive --new-file v1.1.83/linux/fs/proc/array.c linux/fs/proc/array.c --- v1.1.83/linux/fs/proc/array.c Sun Jan 22 21:39:43 1995 +++ linux/fs/proc/array.c Sun Jan 22 14:38:25 1995 @@ -334,21 +334,23 @@ 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; - page &= PAGE_MASK; - page += PAGE_PTR(ptr); - page = *(unsigned long *) page; - if (!(page & PAGE_PRESENT)) - return 0; - page &= PAGE_MASK; - page += ptr & ~PAGE_MASK; - return page; + if (pgd_bad(*dir)) { + printk("bad page directory entry %08lx\n", pgd_val(*dir)); + return 0; + } + table = (pte_t *) (pgd_page(*dir) + PAGE_PTR(ptr)); + pte = *table; + if (!pte_present(pte)) + return 0; + 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_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 @@ 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 @@ ++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; } } diff -u --recursive --new-file v1.1.83/linux/fs/proc/mem.c linux/fs/proc/mem.c --- v1.1.83/linux/fs/proc/mem.c Fri Jan 13 10:12:23 1995 +++ linux/fs/proc/mem.c Sun Jan 22 14:38:25 1995 @@ -24,10 +24,12 @@ 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 @@ 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_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 @@ 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; + if (pgd_bad(*pgdir)) { + printk("Bad page dir entry %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); break; - pte &= PAGE_MASK; - pte += PAGE_PTR(addr); - page = *(unsigned long *) pte; - if (!(page & PAGE_PRESENT)) - 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 @@ } } -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; - } + 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; - invalidate(); - return 0; + 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 = { diff -u --recursive --new-file v1.1.83/linux/fs/umsdos/check.c linux/fs/umsdos/check.c --- v1.1.83/linux/fs/umsdos/check.c Sun Jul 24 17:39:44 1994 +++ linux/fs/umsdos/check.c Sun Jan 22 14:38:45 1995 @@ -12,44 +12,35 @@ 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); } } - diff -u --recursive --new-file v1.1.83/linux/include/asm-alpha/page.h linux/include/asm-alpha/page.h --- v1.1.83/linux/include/asm-alpha/page.h Mon Jan 16 14:18:24 1995 +++ linux/include/asm-alpha/page.h Sun Jan 22 22:11:05 1995 @@ -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 @@ #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) */ - -#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) +#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 __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; + +#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) -#ifdef __KERNEL__ +#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 @@ * 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 @@ #define PTR_MASK (~(sizeof(void*)-1)) /* sizeof(void*)==1<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) \ @@ -103,6 +190,57 @@ if ((tsk) == current) \ 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__ */ diff -u --recursive --new-file v1.1.83/linux/include/asm-i386/page.h linux/include/asm-i386/page.h --- v1.1.83/linux/include/asm-i386/page.h Mon Jan 16 14:18:24 1995 +++ linux/include/asm-i386/page.h Sun Jan 22 14:38:45 1995 @@ -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) */ - -#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) +#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 __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 | PAGE_PWT | PAGE_PCD) +#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) -#ifdef __KERNEL__ +/* + * 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 @@ * 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 @@ /* 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 */ @@ -98,6 +155,57 @@ if ((tsk) == current) \ __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__ */ diff -u --recursive --new-file v1.1.83/linux/include/linux/aztcd.h linux/include/linux/aztcd.h --- v1.1.83/linux/include/linux/aztcd.h Sun Jan 22 21:39:43 1995 +++ linux/include/linux/aztcd.h Sun Jan 22 21:30:17 1995 @@ -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 * @@ -20,12 +20,14 @@ * * 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*/ @@ -35,17 +37,6 @@ /* 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 @@ -87,13 +78,12 @@ #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< #include @@ -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 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 */ @@ -75,6 +79,13 @@ #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 * to the functions called when a no-page or a wp-page exception occurs. @@ -90,8 +101,8 @@ 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 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 @@ /* 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 @@ #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 @@ #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++; diff -u --recursive --new-file v1.1.83/linux/include/linux/pci.h linux/include/linux/pci.h --- v1.1.83/linux/include/linux/pci.h Sun Jan 22 21:39:44 1995 +++ linux/include/linux/pci.h Sun Jan 22 22:13:59 1995 @@ -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 @@ #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 @@ #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 @@ #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C593 0x0006 -#define PCI_VENDOR_ID_AL 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 @@ #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 @@ {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 @@ 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 @@ {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 @@ {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 */ diff -u --recursive --new-file v1.1.83/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.83/linux/include/linux/sched.h Sun Jan 22 21:39:44 1995 +++ linux/include/linux/sched.h Sun Jan 22 14:38:45 1995 @@ -123,7 +123,7 @@ 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, \ diff -u --recursive --new-file v1.1.83/linux/include/linux/timer.h linux/include/linux/timer.h --- v1.1.83/linux/include/linux/timer.h Sun Jan 22 21:39:44 1995 +++ linux/include/linux/timer.h Sun Jan 22 21:30:17 1995 @@ -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; diff -u --recursive --new-file v1.1.83/linux/include/linux/xd.h linux/include/linux/xd.h --- v1.1.83/linux/include/linux/xd.h Tue Apr 5 07:24:51 1994 +++ linux/include/linux/xd.h Sun Jan 22 00:02:55 1995 @@ -118,7 +118,7 @@ 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); diff -u --recursive --new-file v1.1.83/linux/ipc/shm.c linux/ipc/shm.c --- v1.1.83/linux/ipc/shm.c Sun Jan 22 21:39:44 1995 +++ linux/ipc/shm.c Sun Jan 22 14:38:51 1995 @@ -22,7 +22,7 @@ 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 @@ { struct shmid_ds *shp; int i, numpages; - ulong page; shp = shm_segs[id]; if (shp == IPC_NOID || shp == IPC_UNUSED) { @@ -180,13 +179,15 @@ } 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 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 @@ /* 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 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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--; diff -u --recursive --new-file v1.1.83/linux/lib/string.c linux/lib/string.c --- v1.1.83/linux/lib/string.c Sun Jan 22 21:39:45 1995 +++ linux/lib/string.c Fri Jan 20 11:34:39 1995 @@ -28,7 +28,7 @@ { char *tmp = dest; - while ((*dest++ = *src++) != '\0' && --count) + while (count-- && (*dest++ = *src++) != '\0') /* nothing */; return tmp; @@ -64,7 +64,7 @@ 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 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 @@ 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 @@ 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; } /* diff -u --recursive --new-file v1.1.83/linux/mm/filemap.c linux/mm/filemap.c --- v1.1.83/linux/mm/filemap.c Fri Jan 13 10:12:24 1995 +++ linux/mm/filemap.c Sun Jan 22 14:38:51 1995 @@ -85,45 +85,51 @@ 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_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_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 @@ */ 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); } /* diff -u --recursive --new-file v1.1.83/linux/mm/memory.c linux/mm/memory.c --- v1.1.83/linux/mm/memory.c Sun Jan 22 21:39:45 1995 +++ linux/mm/memory.c Sun Jan 22 14:38:51 1995 @@ -76,34 +76,42 @@ 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 @@ 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 @@ 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 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 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 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 @@ 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 @@ 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 @@ * 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 @@ 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 @@ } /* - * 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.) - */ -unsigned long put_page(struct task_struct * tsk,unsigned long page, - unsigned long address,int prot) -{ - 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) { + * sanity-check function.. + */ +static void put_page(pte_t * page_table, pte_t pte) +{ + 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 @@ * * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* * 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 @@ 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 @@ } 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 @@ * 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); } diff -u --recursive --new-file v1.1.83/linux/mm/mmap.c linux/mm/mmap.c --- v1.1.83/linux/mm/mmap.c Sun Jan 22 21:39:45 1995 +++ linux/mm/mmap.c Sun Jan 22 14:38:51 1995 @@ -35,10 +35,15 @@ * */ +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 @@ */ 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 @@ 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 @@ } } 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 @@ 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 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v1.1.83/linux/mm/mprotect.c linux/mm/mprotect.c --- v1.1.83/linux/mm/mprotect.c Sun Jan 22 21:39:45 1995 +++ linux/mm/mprotect.c Sun Jan 22 14:38:51 1995 @@ -16,32 +16,40 @@ #include #include -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 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_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_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_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 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; } diff -u --recursive --new-file v1.1.83/linux/mm/swap.c linux/mm/swap.c --- v1.1.83/linux/mm/swap.c Sun Jan 22 21:39:45 1995 +++ linux/mm/swap.c Sun Jan 22 14:38:51 1995 @@ -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 @@ } #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 @@ 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 @@ 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 @@ 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; - return 0; - } - if (PAGE_ACCESSED & 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_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 @@ } 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 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 @@ 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 @@ 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 @@ 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 @@ */ 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; } } } diff -u --recursive --new-file v1.1.83/linux/mm/vmalloc.c linux/mm/vmalloc.c --- v1.1.83/linux/mm/vmalloc.c Fri Jan 13 10:12:24 1995 +++ linux/mm/vmalloc.c Sun Jan 22 14:38:51 1995 @@ -33,37 +33,56 @@ */ #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 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; diff -u --recursive --new-file v1.1.83/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.83/linux/net/inet/ip.c Mon Jan 9 11:24:24 1995 +++ linux/net/inet/ip.c Sun Jan 22 21:23:16 1995 @@ -335,10 +335,6 @@ #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 */ }