diff -u --recursive --new-file v1.3.83/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt --- v1.3.83/linux/Documentation/digiboard.txt Thu Jan 1 02:00:00 1970 +++ linux/Documentation/digiboard.txt Thu Apr 4 15:57:41 1996 @@ -0,0 +1,72 @@ +The Linux Digiboard Driver +-------------------------- + +The Digiboard Driver for Linux supports the following boards: + + DigiBoard PC/Xe, PC/Xi, PC/Xeve + +Limitations: +------------ +Currently the Driver does not do autoprobing. You have to configure +the driver with the correct I/O address in drivers/char/pcxxconfig.h. + +The preconfigured I/O address is 0200h and the default memory address 0D0000h. +Use them and you will not have to worry about configuring anything. + +Supporting Tools: +----------------- +Some tools and more detailed up to date information can be found at +ftp://ftp.fuller.edu/Linux/digi + +The "ditty" tool described in the Digiboard Manuals for other Unixes +is also available. + +Currently the Linux MAKEDEV command does not support generating the Digiboard +Devices. Use the following script to generate the devices: + +------------------ mkdigidev begin +#!/bin/sh +# +# Script to create Digiboard Devices +# Christoph Lameter, April 4, 1996 +# +# Usage: +# mkdigidev [] +# + +DIGIMAJOR=30 +DIGICUMAJOR=31 + +BOARDS=$1 + +if [ "$BOARDS" = "" ]; then +BOARDS=1 +fi + +boardnum=0 +while [ $boardnum -lt $BOARDS ]; +do + for c in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; + do + name=`expr $boardnum \* 16 + $c` + mknod /dev/ttyd$name c $DIGIMAJOR $name + mknod /dev/ttyD$name c $DIGICUMAJOR $name + done + boardnum=`expr $boardnum + 1` +done +------------------ mkdigidev end + +The ttyd devices behave like the /dev/cua?? devices +and the ttyD devices are like the /dev/ttyS?? devices. + +Sources of Information +---------------------- + +Webpage: http://private.fuller.edu/clameter/digi.html + +Mailing List: digiboard@list.fuller.edu + +(Write e-mail to that address to subscribe. Common ListServ commands work. +Archive of messages available) + +Christoph Lameter (clameter@fuller.edu) 4. April 1996. diff -u --recursive --new-file v1.3.83/linux/Makefile linux/Makefile --- v1.3.83/linux/Makefile Wed Apr 3 16:06:54 1996 +++ linux/Makefile Thu Apr 4 09:20:50 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 83 +SUBLEVEL = 84 ARCH = i386 diff -u --recursive --new-file v1.3.83/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v1.3.83/linux/arch/alpha/defconfig Tue Apr 2 13:32:19 1996 +++ linux/arch/alpha/defconfig Thu Apr 4 14:48:02 1996 @@ -112,6 +112,8 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set CONFIG_SCSI_NCR53C7xx=y +CONFIG_SCSI_NCR53C7xx_sync=y +CONFIG_SCSI_NCR53C7xx_FAST=y # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC is not set @@ -178,6 +180,7 @@ # Character devices # CONFIG_SERIAL=y +# CONFIG_DIGI is not set # CONFIG_CYCLADES is not set # CONFIG_STALDRV is not set # CONFIG_PRINTER is not set diff -u --recursive --new-file v1.3.83/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c --- v1.3.83/linux/arch/alpha/kernel/bios32.c Sun Mar 31 00:13:16 1996 +++ linux/arch/alpha/kernel/bios32.c Thu Apr 4 09:17:19 1996 @@ -81,7 +81,11 @@ #if PCI_MODIFY +#if 0 static unsigned int io_base = 64*KB; /* <64KB are (E)ISA ports */ +#else +static unsigned int io_base = 0xb000; +#endif #if defined(CONFIG_ALPHA_XL) /* @@ -318,15 +322,18 @@ if (bus->self) { struct pci_dev *bridge = bus->self; /* - * Set up the top and bottom of the I/O memory segment + * Set up the top and bottom of the PCI I/O segment * for this bus. */ pcibios_read_config_dword(bridge->bus->number, bridge->devfn, 0x1c, &l); - l = l | (bio >> 8) | ((tio - 1) & 0xf000); + l = (l & 0xffff0000) | (bio >> 8) | ((tio - 1) & 0xf000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x1c, l); - + /* + * Set up the top and bottom of the PCI Memory segment + * for this bus. + */ l = ((bmem & 0xfff00000) >> 16) | ((tmem - 1) & 0xfff00000); pcibios_write_config_dword(bridge->bus->number, bridge->devfn, 0x20, l); @@ -445,6 +452,47 @@ outb(data | 0x40, ide_base+1); /* turn on IDE, really! */ } +/* + * A small note about bridges and interrupts. The DECchip 21050 (and later chips) + * adheres to the PCI-PCI bridge specification. This says that the interrupts on + * the other side of a bridge are swizzled in the following manner: + * + * Dev Interrupt Interupt + * Pin on Pin on + * Device Connector + * + * 4 A A + * B B + * C C + * D D + * + * 5 A B + * B C + * C D + * D A + * + * 6 A C + * B D + * C A + * D B + * + * 7 A D + * B A + * C B + * D C + * + * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. + * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 + * + * The following code is somewhat simplistic as it assumes only one bridge. + * I will fix it later (david.rusling@reo.mts.dec.com). + */ +static inline unsigned char bridge_swizzle(unsigned char pin, unsigned int slot) +{ + /* swizzle */ + return (((pin-1) + slot) % 4) + 1 ; +} + /* * Most evaluation boards share most of the fixup code, which is isolated here. * This function is declared "inline" as only one platform will ever be selected @@ -457,40 +505,64 @@ { struct pci_dev *dev; unsigned char pin; + unsigned char slot ; /* * Go through all devices, fixing up irqs as we see fit: */ for (dev = pci_devices; dev; dev = dev->next) { - dev->irq = 0; - /* - * Ignore things not on the primary bus - I'll figure - * this out one day - Dave Rusling - */ - if (dev->bus->number != 0) - continue; - - /* read the pin */ - pcibios_read_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_PIN, &pin); - if (irq_tab[PCI_SLOT(dev->devfn) - min_idsel][pin] != -1) - dev->irq = irq_tab[PCI_SLOT(dev->devfn) - min_idsel][pin]; + if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { + dev->irq = 0; + /* + * This device is not on the primary bus, we need to figure out which + * interrupt pin it will come in on. We know which slot it will come + * in on 'cos that slot is where the bridge is. Each time the interrupt + * line passes through a PCI-PCI bridge we must apply the swizzle function + * (see the inline static routine above). + */ + if (dev->bus->number != 0) { + struct pci_dev *curr = dev ; + /* read the pin and do the PCI-PCI bridge interrupt pin swizzle */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &pin); + /* cope with 0 */ + if (pin == 0) pin = 1 ; + /* follow the chain of bridges, swizzling as we go */ + do { + /* swizzle */ + pin = bridge_swizzle(pin, PCI_SLOT(curr->devfn)) ; + /* move up the chain of bridges */ + curr = curr->bus->self ; + } while (curr->bus->self) ; + /* The slot is the slot of the last bridge. */ + slot = PCI_SLOT(curr->devfn) ; + } else { + /* work out the slot */ + slot = PCI_SLOT(dev->devfn) ; + /* read the pin */ + pcibios_read_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_PIN, &pin); + } + if (irq_tab[slot - min_idsel][pin] != -1) + dev->irq = irq_tab[slot - min_idsel][pin]; #if PCI_MODIFY - /* tell the device: */ - pcibios_write_config_byte(dev->bus->number, dev->devfn, - PCI_INTERRUPT_LINE, dev->irq); + /* tell the device: */ + pcibios_write_config_byte(dev->bus->number, dev->devfn, + PCI_INTERRUPT_LINE, dev->irq); #endif - /* - * if its a VGA, enable its BIOS ROM at C0000 - */ - if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { - pcibios_write_config_dword(dev->bus->number, dev->devfn, - PCI_ROM_ADDRESS, - 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); + /* + * if its a VGA, enable its BIOS ROM at C0000 + */ + if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA) { + pcibios_write_config_dword(dev->bus->number, dev->devfn, + PCI_ROM_ADDRESS, + 0x000c0000 | PCI_ROM_ADDRESS_ENABLE); + } + } + + if (ide_base) { + enable_ide(ide_base); } - } - if (ide_base) { - enable_ide(ide_base); } } diff -u --recursive --new-file v1.3.83/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v1.3.83/linux/drivers/char/pcxx.c Wed Apr 3 16:06:55 1996 +++ linux/drivers/char/pcxx.c Thu Apr 4 15:57:41 1996 @@ -12,10 +12,15 @@ * This driver does NOT support DigiBoard's fastcook FEP option and * does not support the transparent print (i.e. digiprint) option. * - * Please email any suggestions or bug reports to troyd@skypoint.com + * This Driver is currently maintained by Christoph Lameter (clameter@fuller.edu) + * Please contact the mailing list for problems first. * + * Sources of Information: + * 1. The Linux Digiboard Page at http://private.fuller.edu/clameter/digi.html + * 2. The Linux Digiboard Mailing list at digiboard@list.fuller.edu + * (Simply write a message to introduce yourself to subscribe) * - * January 1996 Bug fixes by an unknown author and released as 1.5.2 + * 1.5.2 Fall 1995 Bug fixes by David Nugent * 1.5.3 March 9, 1996 Christoph Lameter: Fixed 115.2K Support. Memory * allocation harmonized with 1.3.X Series. * 1.5.4 March 30, 1996 Christoph Lameter: Fixup for 1.3.81. Use init_bh @@ -30,6 +35,7 @@ The driver supports the native 57.6K and 115K Baudrates under Linux, but some distributions like Slackware 3.0 dont like these high baudrates. */ + #include #include #include diff -u --recursive --new-file v1.3.83/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.83/linux/drivers/net/3c509.c Tue Apr 2 13:32:20 1996 +++ linux/drivers/net/3c509.c Thu Apr 4 09:17:19 1996 @@ -765,9 +765,17 @@ 0, 0, 0, 0, 0, NULL, el3_probe }; +static int io = 0; +static int irq = 0; + int init_module(void) { + dev_3c509.base_addr = io; + dev_3c509.irq = irq; + if (!EISA_bus && !io) { + printk("3c509: WARNING! Module load-time probing works reliably only for EISA bus!!\n"); + } if (register_netdev(&dev_3c509) != 0) return -EIO; return 0; diff -u --recursive --new-file v1.3.83/linux/fs/locks.c linux/fs/locks.c --- v1.3.83/linux/fs/locks.c Fri Feb 9 17:01:55 1996 +++ linux/fs/locks.c Thu Apr 4 09:17:19 1996 @@ -22,11 +22,11 @@ * process. Since locks still depend on the process id, locks are inherited * after an exec() but not after a fork(). This agrees with POSIX, and both * BSD and SVR4 practice. - * Andy Walker (andy@keo.kvaerner.no), February 14, 1995 + * Andy Walker (andy@lysaker.kvaerner.no), February 14, 1995 * * Scrapped free list which is redundant now that we allocate locks * dynamically with kmalloc()/kfree(). - * Andy Walker (andy@keo.kvaerner.no), February 21, 1995 + * Andy Walker (andy@lysaker.kvaerner.no), February 21, 1995 * * Implemented two lock personalities - F_FLOCK and F_POSIX. * @@ -47,18 +47,21 @@ * upgrading from shared to exclusive (or vice versa). When this happens * any processes blocked by the current lock are woken up and allowed to * run before the new lock is applied. + * Andy Walker (andy@lysaker.kvaerner.no), June 09, 1995 * - * NOTE: - * I do not intend to implement mandatory locks unless demand is *HUGE*. - * They are not in BSD, and POSIX.1 does not require them. I have never - * seen any public code that relied on them. As Kelly Carmichael suggests - * above, mandatory locks requires lots of changes elsewhere and I am - * reluctant to start something so drastic for so little gain. - * Andy Walker (andy@keo.kvaerner.no), June 09, 1995 - * * Removed some race conditions in flock_lock_file(), marked other possible * races. Just grep for FIXME to see them. * Dmitry Gorodchanin (begemot@bgm.rosprint.net), Feb 09, 1996. + * + * Addressed Dmitry's concerns. Deadlock checking no longer recursive. + * Lock allocation changed to GFP_ATOMIC as we can't afford to sleep + * once we've checked for blocking and deadlocking. + * Andy Walker (andy@lysaker.kvaerner.no), Apr 03, 1996. + * + * NOTE: + * Starting to look at mandatory locks - using SunOS as a model. + * Probably a configuration option because mandatory locking can cause + * all sorts of chaos with runaway processes. */ #include @@ -147,7 +150,7 @@ } } -/* flock() system call entry point. Apply a FLOCK style locks to +/* flock() system call entry point. Apply a FLOCK style lock to * an open file descriptor. */ asmlinkage int sys_flock(unsigned int fd, unsigned int cmd) @@ -167,8 +170,8 @@ return (flock_lock_file(filp, &file_lock, cmd & LOCK_UN ? 0 : cmd & LOCK_NB ? 0 : 1)); } -/* Report the first existing locks that would conflict with l. This implements - * the F_GETLK command of fcntl(). +/* Report the first existing lock that would conflict with l. + * This implements the F_GETLK command of fcntl(). */ int fcntl_getlk(unsigned int fd, struct flock *l) { @@ -209,9 +212,10 @@ return (0); } -/* Apply the lock described by l to an open file descriptor. This implements - * both the F_SETLK and F_SETLKW commands of fcntl(). It also emulates flock() - * in a pretty broken way for older C libraries. +/* Apply the lock described by l to an open file descriptor. + * This implements both the F_SETLK and F_SETLKW commands of fcntl(). + * It also emulates flock() in a pretty broken way for older C + * libraries. */ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) { @@ -335,8 +339,8 @@ return (1); } -/* Verify a call to flock() and fill in a file_lock structure with an appropriate - * FLOCK lock. +/* Verify a call to flock() and fill in a file_lock structure with + * an appropriate FLOCK lock. */ static int flock_make_lock(struct file *filp, struct file_lock *fl, unsigned int cmd) @@ -368,8 +372,8 @@ return (1); } -/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific checking - * before calling the locks_conflict(). +/* Determine if lock sys_fl blocks lock caller_fl. POSIX specific + * checking before calling the locks_conflict(). */ static int posix_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { @@ -383,8 +387,8 @@ return (locks_conflict(caller_fl, sys_fl)); } -/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific checking - * before calling the locks_conflict(). +/* Determine if lock sys_fl blocks lock caller_fl. FLOCK specific + * checking before calling the locks_conflict(). */ static int flock_locks_conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) { @@ -429,15 +433,15 @@ (fl2->fl_end >= fl1->fl_start)); } -/* This function tests for deadlock condition before putting a process to sleep. - * The detection scheme is recursive... we may need a test to make it exit if the - * function gets stuck due to bad lock data. 4.4 BSD uses a maximum depth of 50 - * for this. - * - * FIXME: - * IMHO this function is dangerous, deep recursion may result in kernel stack - * corruption. Perhaps we need to limit depth here. - * Dmitry Gorodchanin 09/02/96 +/* This function tests for deadlock condition before putting a process to + * sleep. The detection scheme is no longer recursive. Recursive was neat, + * but dangerous - we risked stack corruption if the lock data was bad, or + * if the recursion was too deep for any other reason. + * + * We rely on the fact that a task can only be on one lock's wait queue + * at a time. When we find blocked_task on a wait queue we can re-search + * with blocked_task equal to that queue's owner, until either blocked_task + * isn't found, or blocked_task is found on a queue owned by my_task. */ static int posix_locks_deadlock(struct task_struct *my_task, struct task_struct *blocked_task) @@ -445,20 +449,18 @@ struct wait_queue *dlock_wait; struct file_lock *fl; +next_task: for (fl = file_lock_table; fl != NULL; fl = fl->fl_nextlink) { - if (fl->fl_owner == NULL) - continue; /* Should never happen! */ - if (fl->fl_owner != my_task) + if (fl->fl_owner == NULL || fl->fl_wait == NULL) continue; - if (fl->fl_wait == NULL) - continue; /* no queues */ dlock_wait = fl->fl_wait; do { - if (dlock_wait->task != NULL) { - if (dlock_wait->task == blocked_task) - return (-EDEADLOCK); - if (posix_locks_deadlock(dlock_wait->task, blocked_task)) - return (-EDEADLOCK); + if (dlock_wait->task == blocked_task) { + if (fl->fl_owner == my_task) { + return(-EDEADLOCK); + } + blocked_task = fl->fl_owner; + goto next_task; } dlock_wait = dlock_wait->next; } while (dlock_wait != fl->fl_wait); @@ -466,7 +468,7 @@ return (0); } -/* Try to create a FLOCK lock on filp. We rely on FLOCK locks being sorting +/* Try to create a FLOCK lock on filp. We rely on FLOCK locks being sorted * first in an inode's lock list, and always insert new locks at the head * of the list. */ @@ -628,43 +630,46 @@ } caller = fl; added = 1; - goto next_lock; } - /* Processing for different lock types is a bit more complex. - */ - if (fl->fl_end < caller->fl_start) - goto next_lock; - if (fl->fl_start > caller->fl_end) - break; - if (caller->fl_type == F_UNLCK) - added = 1; - if (fl->fl_start < caller->fl_start) - left = fl; - /* If the next lock in the list has a higher end address than - * the new one, insert the new one here. - */ - if (fl->fl_end > caller->fl_end) { - right = fl; - break; - } - if (fl->fl_start >= caller->fl_start) { - /* The new lock completely replaces an old one (This may - * happen several times). + else { + /* Processing for different lock types is a bit + * more complex. */ - if (added) { - locks_delete_lock(before, 0); - continue; - } - /* Replace the old lock with the new one. Wake up - * anybody waiting for the old one, as the change in - * lock type might satisfy his needs. + if (fl->fl_end < caller->fl_start) + goto next_lock; + if (fl->fl_start > caller->fl_end) + break; + if (caller->fl_type == F_UNLCK) + added = 1; + if (fl->fl_start < caller->fl_start) + left = fl; + /* If the next lock in the list has a higher end + * address than the new one, insert the new one here. */ - wake_up(&fl->fl_wait); - fl->fl_start = caller->fl_start; - fl->fl_end = caller->fl_end; - fl->fl_type = caller->fl_type; - caller = fl; - added = 1; + if (fl->fl_end > caller->fl_end) { + right = fl; + break; + } + if (fl->fl_start >= caller->fl_start) { + /* The new lock completely replaces an old + * one (This may happen several times). + */ + if (added) { + locks_delete_lock(before, 0); + continue; + } + /* Replace the old lock with the new one. + * Wake up anybody waiting for the old one, + * as the change in lock type might satisfy + * their needs. + */ + wake_up(&fl->fl_wait); + fl->fl_start = caller->fl_start; + fl->fl_end = caller->fl_end; + fl->fl_type = caller->fl_type; + caller = fl; + added = 1; + } } /* Go on to next lock. */ @@ -672,18 +677,6 @@ before = &(*before)->fl_next; } - /* FIXME: - * Note: We may sleep in locks_alloc_lock(), so - * the 'before' pointer may be not valid any more. - * This can cause random kernel memory corruption. - * It seems the right way is to alloc two locks - * at the begining of this func, and then free them - * if they were not needed. - * Another way is to change GFP_KERNEL to GFP_ATOMIC - * in locks_alloc_lock() for this case. - * - * Dmitry Gorodchanin 09/02/96. - */ if (!added) { if (caller->fl_type == F_UNLCK) return (0); @@ -723,7 +716,7 @@ /* Okay, let's make a new file_lock structure... */ if ((tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), - GFP_KERNEL)) == NULL) + GFP_ATOMIC)) == NULL) return (tmp); tmp->fl_nextlink = NULL; @@ -759,11 +752,12 @@ } /* Delete a lock and free it. - * First remove our lock from the lock lists. Then remove all the blocked locks - * from our blocked list, waking up the processes that own them. If told to wait, - * then sleep on each of these lock's wait queues. Each blocked process will wake - * up and immediately wake up its own wait queue allowing us to be scheduled again. - * Lastly, wake up our own wait queue before freeing the file_lock structure. + * First remove our lock from the lock lists. Then remove all the blocked + * locks from our blocked list, waking up the processes that own them. If + * told to wait, then sleep on each of these lock's wait queues. Each + * blocked process will wake up and immediately wake up its own wait queue + * allowing us to be scheduled again. Lastly, wake up our own wait queue + * before freeing the file_lock structure. */ static void locks_delete_lock(struct file_lock **fl_p, unsigned int wait) diff -u --recursive --new-file v1.3.83/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h --- v1.3.83/linux/include/asm-alpha/atomic.h Sun Mar 24 12:09:36 1996 +++ linux/include/asm-alpha/atomic.h Thu Apr 4 14:48:02 1996 @@ -50,7 +50,30 @@ "m" (__atomic_fool_gcc(v))); } +/* + * Same as above, but return true if we counted down to zero + */ +extern __inline__ int atomic_sub_and_test(atomic_t i, atomic_t * v) +{ + unsigned long temp, result; + __asm__ __volatile__( + "\n1:\t" + "ldl_l %0,%1\n\t" + "subl %0,%3,%0\n\t" + "bis %0,%0,%2\n\t" + "stl_c %0,%1\n\t" + "beq %0,1b\n" + "2:" + :"=&r" (temp), + "=m" (__atomic_fool_gcc(v)), + "=&r" (result) + :"Ir" (i), + "m" (__atomic_fool_gcc(v))); + return result==0; +} + #define atomic_inc(v) atomic_add(1,(v)) #define atomic_dec(v) atomic_sub(1,(v)) +#define atomic_dec_and_test(v) atomic_sub_and_test(1,(v)) #endif diff -u --recursive --new-file v1.3.83/linux/include/asm-alpha/hwrpb.h linux/include/asm-alpha/hwrpb.h --- v1.3.83/linux/include/asm-alpha/hwrpb.h Wed Apr 3 16:06:56 1996 +++ linux/include/asm-alpha/hwrpb.h Thu Apr 4 15:56:47 1996 @@ -13,6 +13,8 @@ #define LCA4_CPU 4 /* LCA4 (21066/21068) */ #define EV5_CPU 5 /* EV5 (21164) */ #define EV45_CPU 6 /* EV4.5 (21064/xxx) */ +#define EV56_CPU 7 /* EV5.6 (21164) */ +#define EV6_CPU 8 /* EV6 (21164) */ /* * DEC system types for Alpha systems. Found in HWRPB. diff -u --recursive --new-file v1.3.83/linux/include/asm-alpha/posix_types.h linux/include/asm-alpha/posix_types.h --- v1.3.83/linux/include/asm-alpha/posix_types.h Wed Mar 27 08:19:29 1996 +++ linux/include/asm-alpha/posix_types.h Thu Apr 4 17:05:01 1996 @@ -10,7 +10,7 @@ typedef unsigned int __kernel_dev_t; typedef unsigned int __kernel_ino_t; typedef unsigned int __kernel_mode_t; -typedef unsigned short __kernel_nlink_t; +typedef unsigned int __kernel_nlink_t; typedef long __kernel_off_t; typedef int __kernel_pid_t; typedef unsigned int __kernel_uid_t; diff -u --recursive --new-file v1.3.83/linux/include/asm-i386/atomic.h linux/include/asm-i386/atomic.h --- v1.3.83/linux/include/asm-i386/atomic.h Wed Mar 20 14:38:42 1996 +++ linux/include/asm-i386/atomic.h Thu Apr 4 13:04:45 1996 @@ -53,4 +53,15 @@ :"m" (__atomic_fool_gcc(v))); } +static __inline__ int atomic_dec_and_test(atomic_t *v) +{ + unsigned char c; + + __asm__ __volatile__( + LOCK "decl %0; sete %1" + :"=m" (__atomic_fool_gcc(v)), "=qm" (c) + :"m" (__atomic_fool_gcc(v))); + return c != 0; +} + #endif diff -u --recursive --new-file v1.3.83/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v1.3.83/linux/include/asm-i386/system.h Wed Apr 3 16:06:57 1996 +++ linux/include/asm-i386/system.h Thu Apr 4 14:15:05 1996 @@ -221,10 +221,10 @@ #define cli() __asm__ __volatile__ ("cli": : :"memory") #define save_flags(x) \ -__asm__ __volatile__("pushfl ; popl %0":"=r" (x): /* no input */ :"memory") +__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory") #define restore_flags(x) \ -__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"r" (x):"memory") +__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define iret() __asm__ __volatile__ ("iret": : :"memory") diff -u --recursive --new-file v1.3.83/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.3.83/linux/include/linux/skbuff.h Mon Mar 25 10:22:51 1996 +++ linux/include/linux/skbuff.h Thu Apr 4 16:23:40 1996 @@ -18,6 +18,8 @@ #include #include +#include + #define CONFIG_SKB_CHECK 0 #define HAVE_ALLOC_SKB /* For the drivers to know */ @@ -101,7 +103,7 @@ unsigned short protocol; /* Packet protocol from driver. */ unsigned short truesize; /* Buffer size */ - int count; /* reference count */ + atomic_t count; /* reference count */ struct sk_buff *data_skb; /* Link to the actual data skb */ unsigned char *head; /* Head of buffer */ unsigned char *data; /* Data head pointer */ @@ -300,14 +302,13 @@ } /* - * Insert a packet before another one in a list. + * Insert a packet on a list. */ -extern __inline__ void __skb_insert(struct sk_buff *next, struct sk_buff *newsk, +extern __inline__ void __skb_insert(struct sk_buff *newsk, + struct sk_buff * prev, struct sk_buff *next, struct sk_buff_head * list) { - struct sk_buff * prev = next->prev; - newsk->next = next; newsk->prev = prev; next->prev = newsk; @@ -316,13 +317,16 @@ list->qlen++; } +/* + * Place a packet before a given packet in a list + */ extern __inline__ void skb_insert(struct sk_buff *old, struct sk_buff *newsk) { unsigned long flags; save_flags(flags); cli(); - __skb_insert(old, newsk, old->list); + __skb_insert(newsk, old->prev, old, old->list); restore_flags(flags); } @@ -330,26 +334,13 @@ * Place a packet after a given packet in a list. */ -extern __inline__ void __skb_append(struct sk_buff *prev, struct sk_buff *newsk, - struct sk_buff_head * list) -{ - struct sk_buff * next = prev->next; - - newsk->next = next; - newsk->prev = prev; - next->prev = newsk; - prev->next = newsk; - newsk->list = list; - list->qlen++; -} - extern __inline__ void skb_append(struct sk_buff *old, struct sk_buff *newsk) { unsigned long flags; save_flags(flags); cli(); - __skb_append(old, newsk, old->list); + __skb_insert(newsk, old, old->next, old->list); restore_flags(flags); } diff -u --recursive --new-file v1.3.83/linux/kernel/sched.c linux/kernel/sched.c --- v1.3.83/linux/kernel/sched.c Wed Apr 3 16:06:57 1996 +++ linux/kernel/sched.c Thu Apr 4 13:34:13 1996 @@ -179,11 +179,15 @@ struct task_struct *next = p->next_run; struct task_struct *prev = p->prev_run; + /* remove from list */ next->prev_run = prev; prev->next_run = next; - (p->prev_run = init_task.prev_run)->next_run = p; + /* add back to list */ p->next_run = &init_task; + prev = init_task.prev_run; init_task.prev_run = p; + p->prev_run = prev; + prev->next_run = p; } /* diff -u --recursive --new-file v1.3.83/linux/mm/kmalloc.c linux/mm/kmalloc.c --- v1.3.83/linux/mm/kmalloc.c Mon Mar 18 07:58:04 1996 +++ linux/mm/kmalloc.c Thu Apr 4 14:18:50 1996 @@ -78,7 +78,6 @@ struct size_descriptor { struct page_descriptor *firstfree; struct page_descriptor *dmafree; /* DMA-able memory */ - int size; int nblocks; int nmallocs; @@ -91,49 +90,85 @@ /* * For now it is unsafe to allocate bucket sizes between n and * n-sizeof(page_descriptor) where n is PAGE_SIZE * any power of two + * + * The blocksize and sizes arrays _must_ match! */ #if PAGE_SIZE == 4096 -struct size_descriptor sizes[] = +static const unsigned int blocksize[] = { + 32, + 64, + 128, + 252, + 508, + 1020, + 2040, + 4096 - 16, + 8192 - 16, + 16384 - 16, + 32768 - 16, + 65536 - 16, + 131072 - 16, + 0 +}; + +static struct size_descriptor sizes[] = { - {NULL, NULL, 32, 127, 0, 0, 0, 0, 0}, - {NULL, NULL, 64, 63, 0, 0, 0, 0, 0}, - {NULL, NULL, 128, 31, 0, 0, 0, 0, 0}, - {NULL, NULL, 252, 16, 0, 0, 0, 0, 0}, - {NULL, NULL, 508, 8, 0, 0, 0, 0, 0}, - {NULL, NULL, 1020, 4, 0, 0, 0, 0, 0}, - {NULL, NULL, 2040, 2, 0, 0, 0, 0, 0}, - {NULL, NULL, 4096 - 16, 1, 0, 0, 0, 0, 0}, - {NULL, NULL, 8192 - 16, 1, 0, 0, 0, 0, 1}, - {NULL, NULL, 16384 - 16, 1, 0, 0, 0, 0, 2}, - {NULL, NULL, 32768 - 16, 1, 0, 0, 0, 0, 3}, - {NULL, NULL, 65536 - 16, 1, 0, 0, 0, 0, 4}, - {NULL, NULL, 131072 - 16, 1, 0, 0, 0, 0, 5}, - {NULL, NULL, 0, 0, 0, 0, 0, 0, 0} + {NULL, NULL, 127, 0, 0, 0, 0, 0}, + {NULL, NULL, 63, 0, 0, 0, 0, 0}, + {NULL, NULL, 31, 0, 0, 0, 0, 0}, + {NULL, NULL, 16, 0, 0, 0, 0, 0}, + {NULL, NULL, 8, 0, 0, 0, 0, 0}, + {NULL, NULL, 4, 0, 0, 0, 0, 0}, + {NULL, NULL, 2, 0, 0, 0, 0, 0}, + {NULL, NULL, 1, 0, 0, 0, 0, 0}, + {NULL, NULL, 1, 0, 0, 0, 0, 1}, + {NULL, NULL, 1, 0, 0, 0, 0, 2}, + {NULL, NULL, 1, 0, 0, 0, 0, 3}, + {NULL, NULL, 1, 0, 0, 0, 0, 4}, + {NULL, NULL, 1, 0, 0, 0, 0, 5}, + {NULL, NULL, 0, 0, 0, 0, 0, 0} }; #elif PAGE_SIZE == 8192 +static const unsigned int blocksize[] = { + 64, + 128, + 248, + 504, + 1016, + 2040, + 4080, + 8192 - 32, + 16384 - 32, + 32768 - 32, + 65536 - 32, + 131072 - 32, + 262144 - 32, + 0 +}; + struct size_descriptor sizes[] = { - {NULL, NULL, 64, 127, 0, 0, 0, 0, 0}, - {NULL, NULL, 128, 63, 0, 0, 0, 0, 0}, - {NULL, NULL, 248, 31, 0, 0, 0, 0, 0}, - {NULL, NULL, 504, 16, 0, 0, 0, 0, 0}, - {NULL, NULL, 1016, 8, 0, 0, 0, 0, 0}, - {NULL, NULL, 2040, 4, 0, 0, 0, 0, 0}, - {NULL, NULL, 4080, 2, 0, 0, 0, 0, 0}, - {NULL, NULL, 8192 - 32, 1, 0, 0, 0, 0, 0}, - {NULL, NULL, 16384 - 32, 1, 0, 0, 0, 0, 1}, - {NULL, NULL, 32768 - 32, 1, 0, 0, 0, 0, 2}, - {NULL, NULL, 65536 - 32, 1, 0, 0, 0, 0, 3}, - {NULL, NULL, 131072 - 32, 1, 0, 0, 0, 0, 4}, - {NULL, NULL, 262144 - 32, 1, 0, 0, 0, 0, 5}, - {NULL, NULL, 0, 0, 0, 0, 0, 0, 0} + {NULL, NULL, 127, 0, 0, 0, 0, 0}, + {NULL, NULL, 63, 0, 0, 0, 0, 0}, + {NULL, NULL, 31, 0, 0, 0, 0, 0}, + {NULL, NULL, 16, 0, 0, 0, 0, 0}, + {NULL, NULL, 8, 0, 0, 0, 0, 0}, + {NULL, NULL, 4, 0, 0, 0, 0, 0}, + {NULL, NULL, 2, 0, 0, 0, 0, 0}, + {NULL, NULL, 1, 0, 0, 0, 0, 0}, + {NULL, NULL, 1, 0, 0, 0, 0, 1}, + {NULL, NULL, 1, 0, 0, 0, 0, 2}, + {NULL, NULL, 1, 0, 0, 0, 0, 3}, + {NULL, NULL, 1, 0, 0, 0, 0, 4}, + {NULL, NULL, 1, 0, 0, 0, 0, 5}, + {NULL, NULL, 0, 0, 0, 0, 0, 0} }; #else #error you need to make a version for your pagesize #endif #define NBLOCKS(order) (sizes[order].nblocks) -#define BLOCKSIZE(order) (sizes[order].size) +#define BLOCKSIZE(order) (blocksize[order]) #define AREASIZE(order) (PAGE_SIZE<<(sizes[order].gfporder)) @@ -160,31 +195,28 @@ } - -int get_order(int size) -{ - int order; - - /* Add the size of the header */ - size += sizeof(struct block_header); - for (order = 0; BLOCKSIZE(order); order++) - if (size <= BLOCKSIZE(order)) - return order; - return -1; -} - void *kmalloc(size_t size, int priority) { unsigned long flags; unsigned long type; - int order, i, sz, dma; + int order, dma; struct block_header *p; struct page_descriptor *page, **pg; - order = get_order(size); - if (order < 0) { - printk("kmalloc of too large a block (%d bytes).\n", (int) size); - return (NULL); + /* Get order */ + order = 0; + { + unsigned int realsize = size + sizeof(struct block_header); + for (;;) { + int ordersize = BLOCKSIZE(order); + if (realsize <= ordersize) + break; + order++; + if (ordersize) + continue; + printk("kmalloc of too large a block (%d bytes).\n", (int) size); + return NULL; + } } dma = 0; @@ -213,11 +245,8 @@ page = *pg; if (page) { p = page->firstfree; - if (p->bh_flags != MF_FREE) { - restore_flags(flags); - printk("Problem: block on freelist at %08lx isn't free.\n", (long) p); - return NULL; - } + if (p->bh_flags != MF_FREE) + goto not_free_on_freelist; goto found_it; } @@ -225,34 +254,32 @@ /* This can be done with ints on: This is private to this invocation */ restore_flags(flags); - /* sz is the size of the blocks we're dealing with */ - sz = BLOCKSIZE(order); - - page = (struct page_descriptor *) __get_free_pages(priority, - sizes[order].gfporder, dma); - - if (!page) { - static unsigned long last = 0; - if (priority != GFP_BUFFER && (last + 10 * HZ < jiffies)) { - last = jiffies; - printk("Couldn't get a free page.....\n"); + { + int i, sz; + + /* sz is the size of the blocks we're dealing with */ + sz = BLOCKSIZE(order); + + page = (struct page_descriptor *) __get_free_pages(priority, + sizes[order].gfporder, dma); + + if (!page) + goto no_free_page; + sizes[order].npages++; + + /* Loop for all but last block: */ + for (i = NBLOCKS(order), p = BH(page + 1); i > 1; i--, p = p->bh_next) { + p->bh_flags = MF_FREE; + p->bh_next = BH(((long) p) + sz); } - return NULL; - } - sizes[order].npages++; - - /* Loop for all but last block: */ - for (i = NBLOCKS(order), p = BH(page + 1); i > 1; i--, p = p->bh_next) { + /* Last block: */ p->bh_flags = MF_FREE; - p->bh_next = BH(((long) p) + sz); + p->bh_next = NULL; + + page->order = order; + page->nfree = NBLOCKS(order); + p = BH(page+1); } - /* Last block: */ - p->bh_flags = MF_FREE; - p->bh_next = NULL; - - page->order = order; - page->nfree = NBLOCKS(order); - p = BH(page+1); /* * Now we're going to muck with the "global" freelist @@ -276,6 +303,21 @@ memset(p+1, 0xf0, size); #endif return p + 1; /* Pointer arithmetic: increments past header */ + +no_free_page: + { + static unsigned long last = 0; + if (priority != GFP_BUFFER && (last + 10 * HZ < jiffies)) { + last = jiffies; + printk("Couldn't get a free page.....\n"); + } + return NULL; + } + +not_free_on_freelist: + restore_flags(flags); + printk("Problem: block on freelist at %08lx isn't free.\n", (long) p); + return NULL; } void kfree(void *ptr) diff -u --recursive --new-file v1.3.83/linux/mm/memory.c linux/mm/memory.c --- v1.3.83/linux/mm/memory.c Wed Apr 3 16:06:57 1996 +++ linux/mm/memory.c Thu Apr 4 16:07:12 1996 @@ -755,7 +755,7 @@ pte = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); if (write_access) { unsigned long page = get_free_page(GFP_KERNEL); - pte = pte_mkwrite(mk_pte(page, vma->vm_page_prot)); + pte = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); vma->vm_mm->rss++; tsk->min_flt++; if (!page) { diff -u --recursive --new-file v1.3.83/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v1.3.83/linux/net/core/skbuff.c Tue Apr 2 13:32:24 1996 +++ linux/net/core/skbuff.c Thu Apr 4 13:05:01 1996 @@ -390,22 +390,27 @@ * Insert a packet before another one in a list. */ -void __skb_insert(struct sk_buff *old, struct sk_buff *newsk) +void __skb_insert(struct sk_buff *newsk, + struct sk_buff * prev, struct sk_buff *next, + struct sk_buff_head * list) { - IS_SKB(old); + IS_SKB(prev); IS_SKB(newsk); + IS_SKB(next); - if(!old->next || !old->prev) + if(!prev->next || !prev->prev) + printk("insert after unlisted item!\n"); + if(!next->next || !next->prev) printk("insert before unlisted item!\n"); if(newsk->next || newsk->prev) printk("inserted item is already on a list.\n"); - newsk->next = old; - newsk->prev = old->prev; - old->prev = newsk; - newsk->prev->next = newsk; - newsk->list = old->list; - newsk->list->qlen++; + newsk->next = next; + newsk->prev = prev; + next->prev = newsk; + prev->next = newsk; + newsk->list = list; + list->qlen++; } @@ -437,25 +442,6 @@ restore_flags(flags); } -void __skb_append(struct sk_buff *old, struct sk_buff *newsk) -{ - IS_SKB(old); - IS_SKB(newsk); - - if(!old->next || !old->prev) - printk("append before unlisted item!\n"); - if(newsk->next || newsk->prev) - printk("append item is already on a list.\n"); - - newsk->prev = old; - newsk->next = old->next; - newsk->next->prev = newsk; - old->next = newsk; - newsk->list = old->list; - newsk->list->qlen++; - -} - /* * Remove an sk_buff from its list. Works even without knowing the list it * is sitting on, which can be handy at times. It also means that THE LIST @@ -724,30 +710,26 @@ static inline void __kfree_skbmem(struct sk_buff *skb) { /* don't do anything if somebody still uses us */ - if (--skb->count <= 0) { + if (atomic_dec_and_test(&skb->count)) { kfree(skb->head); - net_skbcount--; + atomic_dec(&net_skbcount); } } void kfree_skbmem(struct sk_buff *skb) { - unsigned long flags; void * addr = skb->head; - save_flags(flags); - cli(); /* don't do anything if somebody still uses us */ - if (--skb->count <= 0) { + if (atomic_dec_and_test(&skb->count)) { /* free the skb that contains the actual data if we've clone()'d */ if (skb->data_skb) { addr = skb; __kfree_skbmem(skb->data_skb); } kfree(addr); - net_skbcount--; + atomic_dec(&net_skbcount); } - restore_flags(flags); } /* diff -u --recursive --new-file v1.3.83/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v1.3.83/linux/net/ipv4/tcp_input.c Wed Apr 3 16:06:57 1996 +++ linux/net/ipv4/tcp_input.c Thu Apr 4 12:39:29 1996 @@ -1184,6 +1184,31 @@ } /* + * Add a sk_buff to the TCP receive queue, calculating + * the ACK sequence as we go.. + */ +static inline void tcp_insert_skb(struct sk_buff * skb, struct sk_buff_head * list) +{ + struct sk_buff * prev, * next; + u32 seq; + + /* + * Find where the new skb goes.. (This goes backwards, + * on the assumption that we get the packets in order) + */ + seq = skb->seq; + prev = list->prev; + next = (struct sk_buff *) list; + for (;;) { + if (prev == (struct sk_buff *) list || !after(prev->seq, seq)) + break; + next = prev; + prev = prev->prev; + } + __skb_insert(skb, prev, next, list); +} + +/* * Called for each packet when we find a new ACK endpoint sequence in it */ static inline u32 tcp_queue_ack(struct sk_buff * skb, struct sock * sk) @@ -1196,48 +1221,28 @@ if (skb->h.th->fin) tcp_fin(skb,sk,skb->h.th); return skb->end_seq; -} - +} -/* - * Add a sk_buff to the TCP receive queue, calculating - * the ACK sequence as we go.. - */ static void tcp_queue(struct sk_buff * skb, struct sock * sk, struct tcphdr *th, unsigned long saddr) { - struct sk_buff_head * list = &sk->receive_queue; - struct sk_buff * next; u32 ack_seq; - /* - * Find where the new skb goes.. (This goes backwards, - * on the assumption that we get the packets in order) - */ - next = list->prev; - while (next != (struct sk_buff *) list) { - if (!after(next->seq, skb->seq)) - break; - next = next->prev; - } - /* - * put it after the packet we found (which - * may be the list-head, but that's fine). - */ - __skb_append(next, skb, list); - next = skb->next; - + tcp_insert_skb(skb, &sk->receive_queue); /* * Did we get anything new to ack? */ ack_seq = sk->acked_seq; if (!after(skb->seq, ack_seq) && after(skb->end_seq, ack_seq)) { + struct sk_buff_head * list = &sk->receive_queue; + struct sk_buff * next; ack_seq = tcp_queue_ack(skb, sk); /* * Do we have any old packets to ack that the above * made visible? (Go forward from skb) */ + next = skb->next; while (next != (struct sk_buff *) list) { if (after(next->seq, ack_seq)) break; @@ -1472,65 +1477,58 @@ } /* - * Throw out all unnecessary packets: we've gone over the - * receive queue limit. This shouldn't happen in a normal - * TCP connection, but we might have gotten duplicates etc. - */ -static inline void tcp_forget_unacked(struct sk_buff_head * list) -{ - for (;;) { - struct sk_buff * skb = list->prev; - - /* gone through it all? */ - if (skb == (struct sk_buff *) list) - break; - if (skb->acked) - break; - __skb_unlink(skb, list); - } -} - -/* * This should be a bit smarter and remove partially * overlapping stuff too, but this should be good * enough for any even remotely normal case (and the * worst that can happen is that we have a few * unnecessary packets in the receive queue). + * + * This function is never called with an empty list.. */ static inline void tcp_remove_dups(struct sk_buff_head * list) { - struct sk_buff * skb = list->next; + struct sk_buff * next = list->next; for (;;) { - struct sk_buff * next; - - if (skb == (struct sk_buff *) list) + struct sk_buff * skb = next; + next = next->next; + if (next == (struct sk_buff *) list) break; - next = skb->next; - if (next->seq == skb->seq) { - if (before(next->end_seq, skb->end_seq)) { - __skb_unlink(next, list); - continue; - } - __skb_unlink(skb, list); + if (before(next->end_seq, skb->end_seq)) { + __skb_unlink(next, list); + kfree_skb(next, FREE_READ); + next = skb; + continue; } - skb = next; + if (next->seq != skb->seq) + continue; + __skb_unlink(skb, list); + kfree_skb(skb, FREE_READ); } } +/* + * Throw out all unnecessary packets: we've gone over the + * receive queue limit. This shouldn't happen in a normal + * TCP connection, but we might have gotten duplicates etc. + */ static void prune_queue(struct sk_buff_head * list) { - /* - * Throw out things we haven't acked. - */ - tcp_forget_unacked(list); + for (;;) { + struct sk_buff * skb = list->prev; - /* - * Throw out duplicates - */ - tcp_remove_dups(list); + /* gone through it all? */ + if (skb == (struct sk_buff *) list) + break; + if (!skb->acked) { + __skb_unlink(skb, list); + kfree_skb(skb, FREE_READ); + continue; + } + tcp_remove_dups(list); + break; + } } - /* * A TCP packet has arrived. diff -u --recursive --new-file v1.3.83/linux/net/netsyms.c linux/net/netsyms.c --- v1.3.83/linux/net/netsyms.c Sun Mar 31 00:13:19 1996 +++ linux/net/netsyms.c Thu Apr 4 15:57:41 1996 @@ -64,6 +64,8 @@ X(memcpy_fromiovec), X(sock_setsockopt), X(sock_getsockopt), + X(sk_alloc), + X(sk_free), X(sock_wake_async), X(sock_alloc_send_skb), X(skb_recv_datagram),