diff -u --recursive --new-file v2.3.1/linux/CREDITS linux/CREDITS --- v2.3.1/linux/CREDITS Fri May 14 18:55:11 1999 +++ linux/CREDITS Fri May 14 08:59:54 1999 @@ -661,7 +661,7 @@ E: rgooch@atnf.csiro.au D: parent process death signal to children D: prctl() syscall -D: /proc/mtrr support to manipulate MTRRs on Pentium Pro's +D: /proc/mtrr support to manipulate MTRRs on Intel P6 family S: CSIRO Australia Telescope National Facility S: P.O. Box 76, Epping S: New South Wales, 2121 @@ -758,6 +758,13 @@ S: 77 Clarence Mews S: London SE16 1GD S: United Kingdom + +N: Bart Hartgers +E: bart@etpmod.phys.tue.nl +D: MTRR emulation with Centaur MCRs +S: Gen Stedmanstraat 212 +S: 5623 HZ Eindhoven +S: The Netherlands N: Kai Harrekilde-Petersen E: khp@dolphinics.no diff -u --recursive --new-file v2.3.1/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.3.1/linux/Documentation/Configure.help Fri May 14 18:55:11 1999 +++ linux/Documentation/Configure.help Fri May 14 08:59:54 1999 @@ -8855,6 +8855,9 @@ The AMD K6-2 (stepping 8 and above) and K6-3 processors have two MTRRs. These are supported. + + The Centaur C6 (WinChip) has 8 MCRs, allowing write-combining. These + are supported. Saying Y here also fixes a problem with buggy SMP BIOSes which only set the MTRRs for the boot CPU and not the secondary CPUs. This can diff -u --recursive --new-file v2.3.1/linux/Documentation/filesystems/hpfs.txt linux/Documentation/filesystems/hpfs.txt --- v2.3.1/linux/Documentation/filesystems/hpfs.txt Wed Jun 24 14:30:07 1998 +++ linux/Documentation/filesystems/hpfs.txt Thu May 13 23:48:20 1999 @@ -1,27 +1,271 @@ -Linux can read, but not write, OS/2 HPFS partitions. +Read/Write HPFS 1.98b +1998-1999, Mikulas Patocka -Mount options are the same as for msdos partitions. +email: mikulas@artax.karlin.mff.cuni.cz +homepage: http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi - uid=nnn All files in the partition will be owned by user id nnn. - gid=nnn All files in the partition will be in group nnn. - umask=nnn The permission mask (see umask(1)) for the partition. - conv=binary Data is returned exactly as is, with CRLFs. [default] - conv=text (Carriage return, line feed) is replaced with newline. - conv=auto Chooses, file by file, conv=binary or conv=text (by guessing) +CREDITS: +Chris Smith, 1993, original read-only HPFS, some code and hpfs structures file + is taken from it +Jacques Gelinas, MSDos mmap, Inspired by fs/nfs/mmap.c (Jon Tombs 15 Aug 1993) +Werner Almesberger, 1992, 1993, MSDos option parser & CR/LF conversion -There are mount options unique to HPFS. +Mount options - case=lower Convert file names to lower case. [default] - case=asis Return file names as is, in mixed case. +uid=xxx,gid=xxx,umask=xxx (default uid=gid=0 umask=default_system_umask) + Set owner/group/mode for files that do not have it specified in extended + attributes. Mode is inverted umask - for example umask 027 gives owner + all permission, group read permission and anybody else no access. Note + that for files mode is anded with 0666. If you want files to have 'x' + rights, you must use extended attributes. +case=lower,asis (default asis) + File name lowercasing in readdir. +conv=binary,text,auto (default binary) + CR/LF -> LF conversion, if auto, decision is made according to extension + - there is a list of text extensions (I thing it's better to not convert + text file than to damage binary file). If you want to change that list, + change it in the source. Original readonly HPFS contained some strange + heuristic alghoritm that I removed. I thing it's danger to let the + computer decide whether file is text or binary. For example, DJGPP + binaries contain small text message at the beginning and they could be + misidentified and damaged under some circumstances. +check=none,normal,strict (default normal) + Check level. Selecting none will cause only little speedup and big + danger. I tried to write it so that it won't crash if check=normal on + corrupted filesystems. check=strict means many superflous checks - + used for debugging (for example it checks if file is allocated in + bitmaps when accessing it). +errors=continue,remount-ro,panic (default remount-ro) + Behaviour when filesystem errors found. +chkdsk=no,errors,always (default errors) + When to mark filesystem dirty so that OS/2 checks it. +eas=no,ro,rw (default rw) + What to do with extended attributes. 'no' - ignore them and use always + values specified in uid/gid/mode options. 'ro' - read extended + attributes but do not create them. 'rw' - create extended attributes + when you use chmod/chown/chgrp/mknod/ln -s on the filesystem. +timeshift=(-)nnn (default 0) + Shifts the time by nnn seconds. For example, if you see under linux + one hour more, than under os/2, use timeshift=-3600. - nocheck Proceed even if "Improperly stopped flag is set" -Case is not significant in filename matching, like real HPFS. +File names +As in OS/2, filenames are case insensitive. However, shell thinks that names +are case sensitive, so for example when you create a file FOO, you can use +'cat FOO', 'cat Foo', 'cat foo' or 'cat F*' but not 'cat f*'. Note, that you +also won't be able to compile linux kernel (and maybe other things) on HPFS +because kernel creates different files with names like bootsect.S and +bootsect.s. When searching for file thats name has characters >= 128, codepages +are used - see below. +OS/2 ignores dots and spaces at the end of file name, so this driver does. If +you create 'a. ...', the file 'a' will be created, but you can still access it +under names 'a.', 'a..', 'a . . . ' etc. -Command line example - mkdir -p /os2/c - mount -t hpfs -o uid=100,gid=100 /dev/sda6 /os2/c -/etc/fstab example - /dev/sdb5 /d/f hpfs ro,uid=402,gid=402,umask=002 +Extended attributes + +On HPFS partion, OS/2 can associate to each file a special information called +extended attributes. Extended attributes are pairs of (key,value) where key is +an ascii string identifying that attribute and value is any string of bytes of +variable length. OS/2 stores window and icon positions and file types there. So +why not use it for unix-specific info like file owner or access rights? This +driver can do it. If you chown/chgrp/chmod on a hpfs partion, extended +attributes with keys "UID", "GID" or "MODE" and 2-byte values are created. Only +that extended attributes those value differs from defaults specified in mount +options are created. Once created, the extended attributes are never deleted, +they're just changed. It means that when your default uid=0 and you type +something like 'chown luser file; chown root file' the file will contain +extended attribute UID=0. And when you umount the fs and mount it again with +uid=luser_uid, the file will be still owned by root! If you chmod file to 444, +extended attribute "MODE" will not be set, this special case is done by setting +read-only flag. When you mknod a block or char device, besides "MODE", the +special 4-byte extended attribute "DEV" will be created containing the device +number. Currently this driver cannot resize extended attributes - it means +that if somebody (I don't know who?) has set "UID", "GID", "MODE" or "DEV" +attributes with different sizes, they won't be rewritten and changing these +values doesn't work. + + +Symlinks + +You can do symlinks on HPFS partion, symlinks are achieved by setting extended +attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and +chgrp symlinks but I don't know what is it good for. chmoding symlink results +in chmoding file where symlink points. These symlinks are just for Linux use and +incompatible with OS/2. OS/2 PmShell symlinks are not supported because they are +stored in very crazy way. They tried to do it so that link changes when file is +moved ... sometimes it works. But the link is partly stored in directory +extended attributes and partly in OS2SYS.INI. I don't want (and don't know how) +to analyze or change OS2SYS.INI. + + +Codepages + +HPFS can contain several uppercasing tables for several codepages and each +file has a pointer to codepage it's name is in. However OS/2 was created in +America where people don't care much about codepages and so multiple codepages +support is quite buggy. I have Czech OS/2 working in codepage 852 on my disk. +Once I booted English OS/2 working in cp 850 and I created a file on my 852 +partion. It marked file name codepage as 850 - good. But when I again booted +Czech OS/2, the file was completely inaccessible under any name. It seems that +OS/2 uppercases the search pattern with it's system code page (852) and file +name it's comparing to with its code page (850). These could never match. Is it +really what IBM developers wanted? But problems countinue. When I created in +Czech OS/2 another file in that direcotry, that file was inaccesible too. OS/2 +probably uses different uppercasing method when searching where to place a file +(note, that files in HPFS directory must be sorted) and when searching for +a file. Finally when I opened this directory in PmShell, PmShell crashed (the +funny thing was that, when rebooted, PmShell tried to reopen this directory +again :-). chkdsk happily ignores these errors and only low-level disk +modification saved me. Never mix different language versions of OS/2 on one +system although HPFS was designed to allow that. +OK, I could implement complex codepage support to this driver but I think it +would cause more problems than benefit with such buggy implementation in OS/2. +So this driver simply uses first codepage it finds for uppercasing and +lowercasing no matter what's file codepage index. Usually all file names are in +this codepage - if you don't try to do what I described above :-) + + +Known bugs + +HPFS386 on OS/2 server is not supported. HPFS386 installed on normal OS/2 client +should work. If you have OS/2 server, use only read-only mode. I don't know how +to handle some HPFS386 structures like access control list or extended perm +list, I don't know how to delete them when file is deleted and how to not +overwrite them with extended attributes. Send me some info on these structures +and I'll make it. However, this driver should detect presence of HPFS386 +structures, remount read-only and not destroy them (I hope). + +When there's not enough space for extended attributes, they will be truncated +and no error is returned. + +OS/2 can't access files if the path is longer than about 256 chars but this +driver allows you to do it. chkdsk ignores such errors. + +Sometimes you won't be able to delete some files on a very full filesystem +(returning error ENOSPC). That's because file in non-leaf node in directory tree +(one directory, if it's large, has dirents in tree on HPFS) must be replaced +with another node when deleted. And that new file might have larger name than +the old one so the new name doesn't fit in directory node (dnode). And that +would result in directory tree splitting, that takes disk space. Workaround is +to delete other files that are leaf (probability that the file is non-leaf is +about 1/50) or to truncate file first to make some space. +You encounter this problem only if you have many directories so that +preallocated directory band is full i.e. + number_of_directories / size_of_filesystem_in_mb > 4. + +You can't delete open directories. + +You can't rename over directories (what is it good for?). + +Renaming files so that only case changes doesn't work. This driver supports it +but vfs doesn't. Something like 'mv file FILE' won't work. + +When you try to create file with bad filename (too long or containing forbidden +characters), you get ENOENT error instead of EINVAL or ENAMETOOLONG. + +All atimes and directory mtimes are not updated. That's because of performance +reasons. If you extremely wish to update them, let me know, I'll write it (but +it will be slow). + +When the system is out of memory and swap, it may slightly corrupt filesystem +(lost files, unbalanced directories). (I guess all filesystem may do it). + +When compiled, you get warning: function declaration isn't a prototype. Does +anybody know what does it mean? + + +What does "unbalanced tree" message mean? + +Old versions of this driver created sometimes unbalanced dnode trees. OS/2 +chkdsk doesn't scream if the tree is unbalanced (and sometimes creates +unbalanced trees too :-) but both HPFS and HPFS386 contain bug that it rarely +crashes when the tree is not balanced. This driver handles unbalanced trees +correctly and writes warning if it finds them. If you see this message, this is +probably because of directories created with old version of this driver. +Workaround is to move all files from that directory to another and then back +again. Do it in Linux, not OS/2! If you see this message in directory that is +whole created by this driver, it is BUG - let me know about it. + + +Bugs in OS/2 + +When you have two (or more) lost directories pointing each to other, chkdsk +locks up when repairing filesystem. + +Sometimes (I think it's random) when you create a file with one-char name under +OS/2, OS/2 marks it as 'long'. chkdsk then removes this flag saying "Minor fs +error corrected". + +File names like "a .b" are marked as 'long' by OS/2 but chkdsk "corrects" it and +marks them as short (and writes "minor fs error corrected"). This bug is not in +HPFS386. + +Codepage bugs decsribed above. + +If you don't install fixpacks, there are many, many more... + + +History + +0.90 First public release +0.91 Fixed bug that caused shooting to memory when write_inode was called on + open inode (rarely happened) +0.92 Fixed a little memory leak in freeing directory inodes +0.93 Fixed bug that locked up the machine when there were too many filenames + with first 15 characters same + Fixed write_file to zero file when writing behind file end +0.94 Fixed a little memory leak when trying to delete busy file or directory +0.95 Fixed a bug that i_hpfs_parent_dir was not updated when moving files +1.90 First version for 2.1.1xx kernels +1.91 Fixed a bug that chk_sectors failed when sectors were at the end of disk + Fixed a race-condition when write_inode is called while deleting file + Fixed a bug that could possibly happen (with very low probability) when + using 0xff in filenames + Rewritten locking to avoid race-conditions + Mount option 'eas' now works + Fsync no longer returns error + Files beginning with '.' are marked hidden + Remount support added + Alloc is not so slow when filesystem becomes full + Atimes are no more updated because it slows down operation + Code cleanup (removed all commented debug prints) +1.92 Corrected a bug when sync was called just before closing file +1.93 Modified, so that it works with kernels >= 2.1.131, I don't know if it + works with previous versions + Fixed a possible problem with disks > 64G (but I don't have one, so I can't + test it) + Fixed a file overflow at 2G + Added new option 'timeshift' + Changed behaviour on HPFS386: It is now possible to operate on HPFS386 in + read-only mode + Fixed a bug that slowed down alloc and prevented allocating 100% space + (this bug was not destructive) +1.94 Added workaround for one bug in Linux + Fixed one buffer leak + Fixed some incompatibilities with large extended attributes (but it's still + not 100% ok, I have no info on it and OS/2 doesn't want to create them) + Rewritten allocation + Fixed a bug with i_blocks (du sometimes didn't display correct values) + Directories have no longer archive attribute set (some programs don't like + it) + Fixed a bug that it set badly one flag in large anode tree (it was not + destructive) +1.95 Fixed one buffer leak, that could happen on corrupted filesystem + Fixed one bug in allocation in 1.94 +1.96 Added workaround for one bug in OS/2 (HPFS locked up, HPFS386 reported + error sometimes when opening directories in PMSHELL) + Fixed a possible bitmap race + Fixed possible problem on large disks + You can now delete open files + Fixed a nondestructive race in rename +1.97 Support for HPFS v3 (on large partitions) + Fixed a bug that it didn't allow creation of files > 128M (it should be 2G) +1.97.1 Changed names of global symbols + Fixed a bug when chmoding or chowning root directory +1.98 Fixed a deadlock when using old_readdir + Better directory handling; workaround for "unbalanced tree" bug in OS/2 + + + vim: set textwidth=80: diff -u --recursive --new-file v2.3.1/linux/Documentation/svga.txt linux/Documentation/svga.txt --- v2.3.1/linux/Documentation/svga.txt Fri Jul 10 15:18:29 1998 +++ linux/Documentation/svga.txt Fri May 14 12:47:01 1999 @@ -1,5 +1,5 @@ - Video Mode Selection Support 2.11 - (c) 1995--1997 Martin Mares, + Video Mode Selection Support 2.13 + (c) 1995--1999 Martin Mares, -------------------------------------------------------------------------------- 1. Intro @@ -9,6 +9,11 @@ to usage of the BIOS, the selection is limited to boot time (before the kernel decompression starts) and works only on 80X86 machines. + ** Short intro for the impatient: Just use vga=ask for the first time, + ** enter `scan' on the video mode prompt, pick the mode you want to use, + ** remember its mode ID (the four-digit hexadecimal number) and then + ** set the vga parameter to this number (converted to decimal first). + The video mode to be used is selected by a kernel parameter which can be specified in the kernel Makefile (the SVGA_MODE=... line) or by the "vga=..." option of LILO (or some other boot loader you use) or by the "vidmode" utility @@ -268,3 +273,4 @@ - Removed the doc section describing adding of new probing functions as I try to get rid of _all_ hardware probing here. 2.12 (25-May-98)- Added support for VESA frame buffer graphics. +2.13 (14-May-99)- Minor documentation fixes. diff -u --recursive --new-file v2.3.1/linux/Makefile linux/Makefile --- v2.3.1/linux/Makefile Fri May 14 18:55:11 1999 +++ linux/Makefile Fri May 14 16:04:47 1999 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 3 -SUBLEVEL = 1 +SUBLEVEL = 2 EXTRAVERSION = ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c --- v2.3.1/linux/arch/alpha/kernel/alpha_ksyms.c Sat Jan 16 17:02:50 1999 +++ linux/arch/alpha/kernel/alpha_ksyms.c Fri May 14 12:41:22 1999 @@ -52,6 +52,7 @@ EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(perf_irq); diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/fpreg.c linux/arch/alpha/kernel/fpreg.c --- v2.3.1/linux/arch/alpha/kernel/fpreg.c Sun Aug 9 12:09:05 1998 +++ linux/arch/alpha/kernel/fpreg.c Fri May 14 12:41:22 1999 @@ -1,10 +1,10 @@ /* - * kernel/fpreg.c + * arch/alpha/kernel/fpreg.c * * (C) Copyright 1998 Linus Torvalds */ -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define STT(reg,val) asm volatile ("ftoit $f"#reg",%0" : "=r"(val)); #else #define STT(reg,val) asm volatile ("stt $f"#reg",%0" : "=m"(val)); @@ -52,7 +52,7 @@ return val; } -#ifdef __alpha_cix__ +#if defined(__alpha_cix__) || defined(__alpha_fix__) #define LDT(reg,val) asm volatile ("itoft %0,$f"#reg : : "r"(val)); #else #define LDT(reg,val) asm volatile ("ldt $f"#reg",%0" : : "m"(val)); diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/head.S linux/arch/alpha/kernel/head.S --- v2.3.1/linux/arch/alpha/kernel/head.S Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/kernel/head.S Fri May 14 12:41:22 1999 @@ -32,24 +32,26 @@ #ifdef __SMP__ .align 3 - .globl __start_cpu - .ent __start_cpu - /* On entry here from SRM console, the HWPCB of this processor - has been loaded, and $27 contains the task pointer */ -__start_cpu: - .prologue 0 - /* First order of business, load the GP */ - br $26,1f -1: ldgp $29,0($26) - /* We need to get current loaded up with our first task... */ - mov $27,$8 - /* Set FEN */ - lda $16,1($31) - call_pal PAL_wrfen - /* ... and then we can start the processor. */ - jsr $26,start_secondary + .globl __smp_callin + .ent __smp_callin + /* On entry here from SRM console, the HWPCB of the per-cpu + slot for this processor has been loaded. We've arranged + for the UNIQUE value for this process to contain the PCBB + of the target idle task. */ +__smp_callin: + .prologue 1 + ldgp $29,0($27) # First order of business, load the GP. + + call_pal PAL_rduniq # Grab the target PCBB. + mov $0,$16 # Install it. + call_pal PAL_swpctx + + lda $8,0x3fff # Find "current". + bic $30,$8,$8 + + jsr $26,smp_callin call_pal PAL_halt - .end __start_cpu + .end __smp_callin #endif /* __SMP__ */ .align 3 diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c --- v2.3.1/linux/arch/alpha/kernel/irq.c Sat Jan 16 17:02:50 1999 +++ linux/arch/alpha/kernel/irq.c Fri May 14 12:41:22 1999 @@ -192,13 +192,21 @@ } void -disable_irq(unsigned int irq_nr) +disable_irq_nosync(unsigned int irq_nr) { unsigned long flags; save_and_cli(flags); mask_irq(irq_nr); restore_flags(flags); +} + +void +disable_irq(unsigned int irq_nr) +{ + /* This works non-SMP, and SMP until we write code to distribute + interrupts to more that cpu 0. */ + disable_irq_nosync(irq_nr); } void diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.3.1/linux/arch/alpha/kernel/process.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/kernel/process.c Fri May 14 12:41:23 1999 @@ -75,33 +75,46 @@ return 0; } -static void __attribute__((noreturn)) -do_cpu_idle(void) +#ifdef __SMP__ +void +cpu_idle(void *unused) { /* An endless idle loop with no priority at all. */ current->priority = 0; + current->counter = -100; + while (1) { - check_pgt_cache(); - run_task_queue(&tq_scheduler); - current->counter = 0; - schedule(); - } -} + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ -#ifdef __SMP__ -void -cpu_idle(void *unused) -{ - do_cpu_idle(); + /* Although we are an idle CPU, we do not want to + get into the scheduler unnecessarily. */ + if (current->need_resched) { + schedule(); + check_pgt_cache(); + } + } } #endif asmlinkage int sys_idle(void) { - if (current->pid == 0) - do_cpu_idle(); - return -EPERM; + if (current->pid != 0) + return -EPERM; + + /* An endless idle loop with no priority at all. */ + current->priority = 0; + current->counter = -100; + init_idle(); + + while (1) { + /* FIXME -- EV6 and LCA45 know how to power down + the CPU. */ + + schedule(); + check_pgt_cache(); + } } void diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h --- v2.3.1/linux/arch/alpha/kernel/proto.h Sun Feb 21 19:06:36 1999 +++ linux/arch/alpha/kernel/proto.h Fri May 14 12:41:23 1999 @@ -151,6 +151,8 @@ extern void setup_smp(void); extern int smp_info(char *buffer); extern void handle_ipi(struct pt_regs *); +extern void smp_percpu_timer_interrupt(struct pt_regs *); +extern int smp_boot_cpuid; /* bios32.c */ extern void reset_for_srm(void); @@ -178,7 +180,7 @@ extern void wrmces(unsigned long mces); extern void cserve_ena(unsigned long); extern void cserve_dis(unsigned long); -extern void __start_cpu(unsigned long); +extern void __smp_callin(void); /* entry.S */ extern void entArith(void); diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/signal.c linux/arch/alpha/kernel/signal.c --- v2.3.1/linux/arch/alpha/kernel/signal.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/kernel/signal.c Fri May 14 12:41:23 1999 @@ -24,6 +24,9 @@ #include #include +#include "proto.h" + + #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c --- v2.3.1/linux/arch/alpha/kernel/smp.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/kernel/smp.c Fri May 14 12:41:23 1999 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -29,6 +30,8 @@ #include #include "proto.h" +#include "irq.h" + #define DEBUG_SMP 0 #if DEBUG_SMP @@ -37,62 +40,44 @@ #define DBGS(args) #endif -struct ipi_msg_flush_tb_struct { - volatile unsigned int flush_tb_mask; - union { - struct mm_struct * flush_mm; - struct vm_area_struct * flush_vma; - } p; - unsigned long flush_addr; - unsigned long flush_end; -}; - -static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned; -static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED; - +/* A collection of per-processor data. */ struct cpuinfo_alpha cpu_data[NR_CPUS]; -spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; -spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; - -unsigned int boot_cpu_id = 0; -static int smp_activated = 0; +/* A collection of single bit ipi messages. */ +static struct { + unsigned long bits __cacheline_aligned; +} ipi_data[NR_CPUS]; -int smp_found_config = 0; /* Have we found an SMP box */ -static int max_cpus = -1; +enum ipi_message_type { + IPI_RESCHEDULE, + IPI_CALL_FUNC, + IPI_CPU_STOP, +}; -unsigned int cpu_present_map = 0; +spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED; -int smp_num_cpus = 1; -int smp_num_probed = 0; /* Internal processor count */ +/* Set to a secondary's cpuid when it comes online. */ +static unsigned long smp_secondary_alive; -int smp_threads_ready = 0; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +unsigned long cpu_present_mask; /* Which cpus ids came online. */ +static int max_cpus = -1; /* Command-line limitation. */ +int smp_boot_cpuid; /* Which processor we booted from. */ +int smp_num_probed; /* Internal processor count */ +int smp_num_cpus = 1; /* Number that came online. */ +int smp_threads_ready; /* True once the per process idle is forked. */ cycles_t cacheflush_time; -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; - -volatile int ipi_bits[NR_CPUS] __cacheline_aligned; - -unsigned long boot_cpu_palrev; - -volatile int smp_commenced = 0; -volatile int smp_processors_ready = 0; - -volatile int cpu_number_map[NR_CPUS]; -volatile int cpu_logical_map[NR_CPUS]; +int cpu_number_map[NR_CPUS]; +int __cpu_logical_map[NR_CPUS]; extern void calibrate_delay(void); -extern struct thread_struct * original_pcb_ptr; - -static void smp_setup_percpu_timer(void); -static void secondary_cpu_start(int, struct task_struct *); -static void send_cpu_msg(char *, int); +extern asmlinkage void entInt(void); -/* Process bootcommand SMP options, like "nosmp" and "maxcpus=" */ + +/* + * Process bootcommand SMP options, like "nosmp" and "maxcpus=". + */ void __init smp_setup(char *str, int *ints) { @@ -102,100 +87,87 @@ max_cpus = 0; } -static void __init -smp_store_cpu_info(int id) +/* + * Called by both boot and secondaries to move global data into + * per-processor storage. + */ +static inline void __init +smp_store_cpu_info(int cpuid) { - /* This is it on Alpha, so far. */ - cpu_data[id].loops_per_sec = loops_per_sec; + cpu_data[cpuid].loops_per_sec = loops_per_sec; } -void __init -smp_commence(void) +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer(int cpuid) { - /* Lets the callin's below out of their loop. */ - mb(); - smp_commenced = 1; + cpu_data[cpuid].prof_counter = 1; + cpu_data[cpuid].prof_multiplier = 1; + +#ifdef NOT_YET_PROFILING + load_profile_irq(mid_xlate[cpu], lvl14_resolution); + if (cpu == smp_boot_cpuid) + enable_pil_irq(14); +#endif } +/* + * Where secondaries begin a life of C. + */ void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); DBGS(("CALLIN %d state 0x%lx\n", cpuid, current->state)); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif + + /* Turn on machine checks. */ + wrmces(7); + + /* Set trap vectors. */ + trap_init(); + + /* Set interrupt vector. */ + wrent(entInt, 0); + + /* Setup the scheduler for this processor. */ + init_idle(); /* Get our local ticker going. */ - smp_setup_percpu_timer(); + smp_setup_percpu_timer(cpuid); -#if 0 + /* Must have completely accurate bogos. */ + __sti(); calibrate_delay(); -#endif smp_store_cpu_info(cpuid); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif /* Allow master to continue. */ - set_bit(cpuid, (unsigned long *)&cpu_callin_map[cpuid]); -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif - -#ifdef NOT_YET - while(!task[cpuid] || current_set[cpuid] != task[cpuid]) - barrier(); -#endif + wmb(); + smp_secondary_alive = cpuid; -#ifdef HUH - local_flush_cache_all(); - local_flush_tlb_all(); -#endif -#if 0 - __sti(); -#endif -} - -asmlinkage int __init -start_secondary(void *unused) -{ - extern asmlinkage void entInt(void); - extern void paging_init_secondary(void); + /* Wait for the go code. */ + while (!smp_threads_ready) + barrier(); - wrmces(7); - paging_init_secondary(); - trap_init(); - wrent(entInt, 0); + printk(KERN_INFO "SMP: commencing CPU %d current %p\n", + cpuid, current); - smp_callin(); - while (!smp_commenced) - barrier(); -#if 1 - printk("start_secondary: commencing CPU %d current %p\n", - hard_smp_processor_id(), current); -#endif + /* Do nothing. */ cpu_idle(NULL); } + +/* + * Rough estimation for SMP scheduling, this is the number of cycles it + * takes for a fully memory-limited process to flush the SMP-local cache. + * + * We are not told how much cache there is, so we have to guess. + */ static void __init smp_tune_scheduling (void) { - /* - * Rough estimation for SMP scheduling, this is the number of - * cycles it takes for a fully memory-limited process to flush - * the SMP-local cache. - * - * We are not told how much cache there is, so we have to guess. - */ - struct percpu_struct *cpu; unsigned long on_chip_cache; unsigned long freq; @@ -231,259 +203,159 @@ cacheflush_time = freq / 1024 * on_chip_cache / 5000; } - /* - * Cycle through the processors sending START msgs to boot each. + * Send a message to a secondary's console. "START" is one such + * interesting message. ;-) */ -void __init -smp_boot_cpus(void) +static void +send_secondary_console_msg(char *str, int cpuid) { - int cpucount = 0; - int i, first, prev; - - printk("Entering SMP Mode.\n"); - -#if 0 - __sti(); -#endif - - for(i=0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - cpu_logical_map[i] = -1; - prof_counter[i] = 1; - prof_multiplier[i] = 1; - ipi_bits[i] = 0; - } - - cpu_number_map[boot_cpu_id] = 0; - cpu_logical_map[0] = boot_cpu_id; - current->processor = boot_cpu_id; /* ??? */ + struct percpu_struct *cpu; + register char *cp1, *cp2; + unsigned long cpumask; + size_t len; + long timeout; - smp_store_cpu_info(boot_cpu_id); - smp_tune_scheduling(); -#ifdef NOT_YET - printk("CPU%d: ", boot_cpu_id); - print_cpu_info(&cpu_data[boot_cpu_id]); - set_irq_udt(mid_xlate[boot_cpu_id]); -#endif - smp_setup_percpu_timer(); -#ifdef HUH - local_flush_cache_all(); -#endif - if (smp_num_probed == 1) - return; /* Not an MP box. */ + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + cpuid * hwrpb->processor_size); -#if NOT_YET - /* - * If SMP should be disabled, then really disable it! - */ - if (!max_cpus) - { - smp_found_config = 0; - printk(KERN_INFO "SMP mode deactivated.\n"); - } -#endif + cpumask = (1L << cpuid); + if (hwrpb->txrdy & cpumask) + goto delay1; + ready1: - for (i = 0; i < NR_CPUS; i++) { + cp2 = str; + len = strlen(cp2); + *(unsigned int *)&cpu->ipc_buffer[0] = len; + cp1 = (char *) &cpu->ipc_buffer[1]; + memcpy(cp1, cp2, len); - if (i == boot_cpu_id) - continue; + /* atomic test and set */ + wmb(); + set_bit(cpuid, &hwrpb->rxrdy); - if (cpu_present_map & (1 << i)) { - struct task_struct *idle; - int timeout; - - /* Cook up an idler for this guy. */ - kernel_thread(start_secondary, NULL, CLONE_PID); - idle = task[++cpucount]; - if (!idle) - panic("No idle process for CPU %d", i); - idle->processor = i; - - DBGS(("smp_boot_cpus: CPU %d state 0x%lx flags 0x%lx\n", - i, idle->state, idle->flags)); - - /* whirrr, whirrr, whirrrrrrrrr... */ -#ifdef HUH - local_flush_cache_all(); -#endif - secondary_cpu_start(i, idle); + if (hwrpb->txrdy & cpumask) + goto delay2; + ready2: + return; - /* wheee... it's going... wait for 5 secs...*/ - for (timeout = 0; timeout < 50000; timeout++) { - if (cpu_callin_map[i]) - break; - udelay(100); - } - if (cpu_callin_map[i]) { - /* Another "Red Snapper". */ - cpu_number_map[i] = cpucount; - cpu_logical_map[cpucount] = i; - } else { - cpucount--; - printk("smp_boot_cpus: Processor %d" - " is stuck 0x%lx.\n", i, idle->flags); - } - } - if (!(cpu_callin_map[i])) { - cpu_present_map &= ~(1 << i); - cpu_number_map[i] = -1; - } - } -#ifdef HUH - local_flush_cache_all(); -#endif - if (cpucount == 0) { - printk("smp_boot_cpus: ERROR - only one Processor found.\n"); - cpu_present_map = (1 << smp_processor_id()); - } else { - unsigned long bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) - bogosum += cpu_data[i].loops_per_sec; - } - printk("smp_boot_cpus: Total of %d Processors activated" - " (%lu.%02lu BogoMIPS).\n", - cpucount + 1, - (bogosum + 2500)/500000, - ((bogosum + 2500)/5000)%100); - smp_activated = 1; - smp_num_cpus = cpucount + 1; +delay1: + /* Wait one second. Note that jiffies aren't ticking yet. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready1; + udelay(10); + barrier(); } + goto timeout; - /* Setup CPU list for IRQ distribution scheme. */ - first = prev = -1; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_present_map & (1 << i)) { - if (first == -1) - first = i; - if (prev != -1) - cpu_data[i].next = i; - prev = i; - } +delay2: + /* Wait one second. */ + for (timeout = 100000; timeout > 0; --timeout) { + if (!(hwrpb->txrdy & cpumask)) + goto ready2; + udelay(10); + barrier(); } - cpu_data[prev].next = first; + goto timeout; - /* Ok, they are spinning and ready to go. */ - smp_processors_ready = 1; +timeout: + printk("Processor %x not ready\n", cpuid); + return; } -static void __init -smp_setup_percpu_timer(void) +/* + * A secondary console wants to send a message. Receive it. + */ +static void +recv_secondary_console_msg(void) { - int cpu = smp_processor_id(); - - prof_counter[cpu] = prof_multiplier[cpu] = 1; -#ifdef NOT_YET - load_profile_irq(mid_xlate[cpu], lvl14_resolution); - if (cpu == boot_cpu_id) - enable_pil_irq(14); -#endif -} - -extern void update_one_process(struct task_struct *p, unsigned long ticks, - unsigned long user, unsigned long system, - int cpu); + int mycpu, i, cnt; + unsigned long txrdy = hwrpb->txrdy; + char *cp1, *cp2, buf[80]; + struct percpu_struct *cpu; -void -smp_percpu_timer_interrupt(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); + DBGS(("recv_secondary_console_msg: TXRDY 0x%lx.\n", txrdy)); -#ifdef NOT_YET - clear_profile_irq(mid_xlate[cpu]); - if(!user_mode(regs)) - alpha_do_profile(regs->pc); -#endif + mycpu = hard_smp_processor_id(); - if (!--prof_counter[cpu]) { - int user = user_mode(regs); - if (current->pid) { - update_one_process(current, 1, user, !user, cpu); + for (i = 0; i < NR_CPUS; i++) { + if (!(txrdy & (1L << i))) + continue; - if (--current->counter < 0) { - current->counter = 0; - current->need_resched = 1; - } + DBGS(("recv_secondary_console_msg: " + "TXRDY contains CPU %d.\n", i)); - spin_lock(&ticker_lock); - if (user) { - if (current->priority < DEF_PRIORITY) { - kstat.cpu_nice++; - kstat.per_cpu_nice[cpu]++; - } else { - kstat.cpu_user++; - kstat.per_cpu_user[cpu]++; - } - } else { - kstat.cpu_system++; - kstat.per_cpu_system[cpu]++; - } - spin_unlock(&ticker_lock); - } - prof_counter[cpu] = prof_multiplier[cpu]; - } -} + cpu = (struct percpu_struct *) + ((char*)hwrpb + + hwrpb->processor_offset + + i * hwrpb->processor_size); -int __init -setup_profiling_timer(unsigned int multiplier) -{ -#ifdef NOT_YET - int i; - unsigned long flags; + printk(KERN_INFO "recv_secondary_console_msg: on %d from %d" + " HALT_REASON 0x%lx FLAGS 0x%lx\n", + mycpu, i, cpu->halt_reason, cpu->flags); - /* Prevent level14 ticker IRQ flooding. */ - if((!multiplier) || (lvl14_resolution / multiplier) < 500) - return -EINVAL; + cnt = cpu->ipc_buffer[0] >> 32; + if (cnt <= 0 || cnt >= 80) + strcpy(buf, "<<< BOGUS MSG >>>"); + else { + cp1 = (char *) &cpu->ipc_buffer[11]; + cp2 = buf; + strcpy(cp2, cp1); + + while ((cp2 = strchr(cp2, '\r')) != 0) { + *cp2 = ' '; + if (cp2[1] == '\n') + cp2[1] = ' '; + } + } - save_and_cli(flags); - for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1 << i)) { - load_profile_irq(mid_xlate[i], lvl14_resolution / multip -lier); - prof_multiplier[i] = multiplier; - } + printk(KERN_INFO "recv_secondary_console_msg: on %d " + "message is '%s'\n", mycpu, buf); } - restore_flags(flags); - return 0; - -#endif - return -EINVAL; -} - -/* Only broken Intel needs this, thus it should not even be - referenced globally. */ - -void __init -initialize_secondary(void) -{ + hwrpb->txrdy = 0; } -static void __init +/* + * Convince the console to have a secondary cpu begin execution. + */ +static int __init secondary_cpu_start(int cpuid, struct task_struct *idle) { struct percpu_struct *cpu; - int timeout; + struct pcb_struct *hwpcb; + long timeout; cpu = (struct percpu_struct *) ((char*)hwrpb + hwrpb->processor_offset + cpuid * hwrpb->processor_size); + hwpcb = (struct pcb_struct *) cpu->hwpcb; - /* Set context to idle thread this CPU will use when running - assumption is that the idle thread is all set to go... ??? */ - memcpy(&cpu->hwpcb[0], &idle->tss, sizeof(struct pcb_struct)); - cpu->hwpcb[4] = cpu->hwpcb[0]; /* UNIQUE set to KSP ??? */ + /* Initialize the CPU's HWPCB to something just good enough for + us to get started. Immediately after starting, we'll swpctx + to the target idle task's tss. Reuse the stack in the mean + time. Precalculate the target PCBB. */ + hwpcb->ksp = (unsigned long) idle + sizeof(union task_union) - 16; + hwpcb->usp = 0; + hwpcb->ptbr = idle->tss.ptbr; + hwpcb->pcc = 0; + hwpcb->asn = 0; + hwpcb->unique = virt_to_phys(&idle->tss); + hwpcb->flags = idle->tss.pal_flags; + hwpcb->res1 = hwpcb->res2 = 0; - DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx\n", - cpu->hwpcb[0], cpu->hwpcb[2], hwrpb->vptb)); + DBGS(("KSP 0x%lx PTBR 0x%lx VPTBR 0x%lx UNIQUE 0x%lx\n", + hwpcb->ksp, hwpcb->ptbr, hwrpb->vptb, hwcpb->unique)); DBGS(("Starting secondary cpu %d: state 0x%lx pal_flags 0x%lx\n", cpuid, idle->state, idle->tss.pal_flags)); /* Setup HWRPB fields that SRM uses to activate secondary CPU */ - hwrpb->CPU_restart = __start_cpu; - hwrpb->CPU_restart_data = (unsigned long) idle; + hwrpb->CPU_restart = __smp_callin; + hwrpb->CPU_restart_data = (unsigned long) __smp_callin; /* Recalculate and update the HWRPB checksum */ hwrpb_update_checksum(hwrpb); @@ -495,99 +367,97 @@ /* SRM III 3.4.1.3 */ cpu->flags |= 0x22; /* turn on Context Valid and Restart Capable */ cpu->flags &= ~1; /* turn off Bootstrap In Progress */ - mb(); + wmb(); - send_cpu_msg("START\r\n", cpuid); + send_secondary_console_msg("START\r\n", cpuid); - /* now, we wait... */ - for (timeout = 10000; !(cpu->flags & 1); timeout--) { - if (timeout <= 0) { - printk("Processor %d failed to start\n", cpuid); - /* needed for pset_info to work */ -#if 0 - ipc_processor_enable(cpu_to_processor(cpunum)); -#endif - return; - } - mdelay(1); + /* Wait 1 second for an ACK from the console. Note that jiffies + aren't ticking yet. */ + for (timeout = 100000; timeout > 0; timeout--) { + if (cpu->flags & 1) + goto started; + udelay(10); barrier(); } + printk(KERN_ERR "SMP: Processor %d failed to start.\n", cpuid); + return -1; + +started: DBGS(("secondary_cpu_start: SUCCESS for CPU %d!!!\n", cpuid)); + return 0; } -static void -send_cpu_msg(char *str, int cpuid) +/* + * Bring one cpu online. + */ +static int __init +smp_boot_one_cpu(int cpuid, int cpunum) { - struct percpu_struct *cpu; - register char *cp1, *cp2; - unsigned long cpumask; - size_t len; - int timeout; - - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + cpuid * hwrpb->processor_size); - - cpumask = (1L << cpuid); - if (hwrpb->txrdy & cpumask) - goto delay1; - ready1: - - cp2 = str; - len = strlen(cp2); - *(unsigned int *)&cpu->ipc_buffer[0] = len; - cp1 = (char *) &cpu->ipc_buffer[1]; - memcpy(cp1, cp2, len); - - /* atomic test and set */ - set_bit(cpuid, &hwrpb->rxrdy); + struct task_struct *idle; + long timeout; - if (hwrpb->txrdy & cpumask) - goto delay2; - ready2: - return; - -delay1: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready1; - udelay(100); + /* Cook up an idler for this guy. Note that the address we give + to kernel_thread is irrelevant -- it's going to start where + HWRPB.CPU_restart says to start. But this gets all the other + task-y sort of data structures set up like we wish. */ + kernel_thread((void *)__smp_callin, NULL, CLONE_PID|CLONE_VM); + idle = task[cpunum]; + if (!idle) + panic("No idle process for CPU %d", cpuid); + idle->processor = cpuid; + + /* Schedule the first task manually. */ + /* ??? Ingo, what is this? */ + idle->has_cpu = 1; + + DBGS(("smp_boot_one_cpu: CPU %d state 0x%lx flags 0x%lx\n", + cpuid, idle->state, idle->flags)); + + /* The secondary will change this once it is happy. Note that + secondary_cpu_start contains the necessary memory barrier. */ + smp_secondary_alive = -1; + + /* Whirrr, whirrr, whirrrrrrrrr... */ + if (secondary_cpu_start(cpuid, idle)) + return -1; + + /* We've been acked by the console; wait one second for the task + to start up for real. Note that jiffies aren't ticking yet. */ + for (timeout = 0; timeout < 100000; timeout++) { + if (smp_secondary_alive != -1) + goto alive; + udelay(10); barrier(); } - goto timeout; - -delay2: - for (timeout = 10000; timeout > 0; --timeout) { - if (!(hwrpb->txrdy & cpumask)) - goto ready2; - udelay(100); - barrier(); - } - goto timeout; -timeout: - printk("Processor %x not ready\n", cpuid); - return; + printk(KERN_ERR "SMP: Processor %d is stuck.\n", cpuid); + return -1; + +alive: + /* Another "Red Snapper". */ + cpu_number_map[cpuid] = cpunum; + __cpu_logical_map[cpunum] = cpuid; + return 0; } /* - * setup_smp() - * - * called from arch/alpha/kernel/setup.c:setup_arch() when __SMP__ defined + * Called from setup_arch. Detect an SMP system and which processors + * are present. */ void __init setup_smp(void) { struct percpu_struct *cpubase, *cpu; int i; - - boot_cpu_id = hard_smp_processor_id(); - if (boot_cpu_id != 0) { - printk("setup_smp: boot_cpu_id != 0 (%d).\n", boot_cpu_id); + + smp_boot_cpuid = hard_smp_processor_id(); + if (smp_boot_cpuid != 0) { + printk(KERN_WARNING "SMP: Booting off cpu %d instead of 0?\n", + smp_boot_cpuid); } if (hwrpb->nr_processors > 1) { + int boot_cpu_palrev; DBGS(("setup_smp: nr_processors %ld\n", hwrpb->nr_processors)); @@ -601,10 +471,9 @@ ((char *)cpubase + i*hwrpb->processor_size); if ((cpu->flags & 0x1cc) == 0x1cc) { smp_num_probed++; - /* assume here that "whami" == index */ - cpu_present_map |= (1 << i); - if (i != boot_cpu_id) - cpu->pal_revision = boot_cpu_palrev; + /* Assume here that "whami" == index */ + cpu_present_mask |= (1L << i); + cpu->pal_revision = boot_cpu_palrev; } DBGS(("setup_smp: CPU %d: flags 0x%lx type 0x%lx\n", @@ -614,76 +483,249 @@ } } else { smp_num_probed = 1; - cpu_present_map = (1 << boot_cpu_id); + cpu_present_mask = (1L << smp_boot_cpuid); } - printk("setup_smp: %d CPUs probed, cpu_present_map 0x%x," - " boot_cpu_id %d\n", - smp_num_probed, cpu_present_map, boot_cpu_id); + + printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_mask = %lx\n", + smp_num_probed, cpu_present_mask); } -static void -secondary_console_message(void) +/* + * Called by smp_init bring all the secondaries online and hold them. + */ +void __init +smp_boot_cpus(void) { - int mycpu, i, cnt; - unsigned long txrdy = hwrpb->txrdy; - char *cp1, *cp2, buf[80]; - struct percpu_struct *cpu; + int cpu_count, i; + unsigned long bogosum; - DBGS(("secondary_console_message: TXRDY 0x%lx.\n", txrdy)); + /* Take care of some initial bookkeeping. */ + memset(cpu_number_map, -1, sizeof(cpu_number_map)); + memset(__cpu_logical_map, -1, sizeof(__cpu_logical_map)); + memset(ipi_data, 0, sizeof(ipi_data)); + + cpu_number_map[smp_boot_cpuid] = 0; + __cpu_logical_map[0] = smp_boot_cpuid; + current->processor = smp_boot_cpuid; - mycpu = hard_smp_processor_id(); + smp_store_cpu_info(smp_boot_cpuid); + smp_tune_scheduling(); + smp_setup_percpu_timer(smp_boot_cpuid); + + init_idle(); + + /* Nothing to do on a UP box, or when told not to. */ + if (smp_num_probed == 1 || max_cpus == 0) { + printk(KERN_INFO "SMP mode deactivated.\n"); + return; + } + printk(KERN_INFO "SMP starting up secondaries.\n"); + + cpu_count = 1; for (i = 0; i < NR_CPUS; i++) { - if (!(txrdy & (1L << i))) + if (i == smp_boot_cpuid) continue; - DBGS(("secondary_console_message: " - "TXRDY contains CPU %d.\n", i)); + if (((cpu_present_mask >> i) & 1) == 0) + continue; - cpu = (struct percpu_struct *) - ((char*)hwrpb - + hwrpb->processor_offset - + i * hwrpb->processor_size); + if (smp_boot_one_cpu(i, cpu_count)) + continue; - printk("secondary_console_message: on %d from %d" - " HALT_REASON 0x%lx FLAGS 0x%lx\n", - mycpu, i, cpu->halt_reason, cpu->flags); + cpu_count++; + } - cnt = cpu->ipc_buffer[0] >> 32; - if (cnt <= 0 || cnt >= 80) - strcpy(buf, "<<< BOGUS MSG >>>"); - else { - cp1 = (char *) &cpu->ipc_buffer[11]; - cp2 = buf; - strcpy(cp2, cp1); - - while ((cp2 = strchr(cp2, '\r')) != 0) { - *cp2 = ' '; - if (cp2[1] == '\n') - cp2[1] = ' '; - } - } + if (cpu_count == 1) { + printk(KERN_ERR "SMP: Only one lonely processor alive.\n"); + return; + } + + bogosum = 0; + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) + bogosum += cpu_data[i].loops_per_sec; + } + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", + cpu_count, (bogosum + 2500) / 500000, + ((bogosum + 2500) / 5000) % 100); + + smp_num_cpus = cpu_count; +} + +/* + * Called by smp_init to release the blocking online cpus once they + * are all started. + */ +void __init +smp_commence(void) +{ + /* smp_init sets smp_threads_ready -- that's enough. */ + mb(); +} + +/* + * Only broken Intel needs this, thus it should not even be + * referenced globally. + */ + +void __init +initialize_secondary(void) +{ +} + + +extern void update_one_process(struct task_struct *p, unsigned long ticks, + unsigned long user, unsigned long system, + int cpu); + +void +smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + int user = user_mode(regs); + struct cpuinfo_alpha *data = &cpu_data[cpu]; + +#ifdef NOT_YET_PROFILING + clear_profile_irq(mid_xlate[cpu]); + if (!user) + alpha_do_profile(regs->pc); +#endif + + if (!--data->prof_counter) { + /* We need to make like a normal interrupt -- otherwise + timer interrupts ignore the global interrupt lock, + which would be a Bad Thing. */ + irq_enter(cpu, TIMER_IRQ); + + update_one_process(current, 1, user, !user, cpu); + if (current->pid) { + if (--current->counter < 0) { + current->counter = 0; + current->need_resched = 1; + } + + if (user) { + if (current->priority < DEF_PRIORITY) { + kstat.cpu_nice++; + kstat.per_cpu_nice[cpu]++; + } else { + kstat.cpu_user++; + kstat.per_cpu_user[cpu]++; + } + } else { + kstat.cpu_system++; + kstat.per_cpu_system[cpu]++; + } + } - printk("secondary_console_message: on %d message is '%s'\n", - mycpu, buf); + data->prof_counter = data->prof_multiplier; + irq_exit(cpu, TIMER_IRQ); } +} - hwrpb->txrdy = 0; +int __init +setup_profiling_timer(unsigned int multiplier) +{ +#ifdef NOT_YET_PROFILING + int i; + unsigned long flags; + + /* Prevent level14 ticker IRQ flooding. */ + if((!multiplier) || (lvl14_resolution / multiplier) < 500) + return -EINVAL; + + save_and_cli(flags); + for (i = 0; i < NR_CPUS; i++) { + if (cpu_present_mask & (1L << i)) { + load_profile_irq(mid_xlate[i], + lvl14_resolution / multiplier); + prof_multiplier[i] = multiplier; + } + } + restore_flags(flags); + + return 0; +#else + return -EINVAL; +#endif } -enum ipi_message_type { - IPI_TLB_ALL, - IPI_TLB_MM, - IPI_TLB_PAGE, - IPI_RESCHEDULE, - IPI_CPU_STOP + +static void +send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +{ + long i, j; + + /* Reduce the number of memory barriers by doing two loops, + one to set the bits, one to invoke the interrupts. */ + + mb(); /* Order out-of-band data and bit setting. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + set_bit(operation, &ipi_data[i].bits); + } + + mb(); /* Order bit setting and interrupt. */ + + for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { + if (to_whom & j) + wripir(i); + } +} + +/* Structure and data for smp_call_function. This is designed to + minimize static memory requirements. Plus it looks cleaner. */ + +struct smp_call_struct { + void (*func) (void *info); + void *info; + long wait; + atomic_t unstarted_count; + atomic_t unfinished_count; }; +static struct smp_call_struct *smp_call_function_data; + +/* Atomicly drop data into a shared pointer. The pointer is free if + it is initially locked. If retry, spin until free. */ + +static inline int +pointer_lock (void *lock, void *data, int retry) +{ + void *old, *tmp; + + mb(); +again: + /* Compare and swap with zero. */ + asm volatile ( + "1: ldq_l %0,%1\n" + " mov %3,%2\n" + " bne %0,2f\n" + " stq_c %2,%1\n" + " beq %2,1b\n" + "2:" + : "=&r"(old), "=m"(*(void **)lock), "=&r"(tmp) + : "r"(data) + : "memory"); + + if (old == 0) + return 0; + if (! retry) + return -EBUSY; + + while (*(void **)lock) + schedule(); + goto again; +} + void handle_ipi(struct pt_regs *regs) { int this_cpu = smp_processor_id(); - volatile int * pending_ipis = &ipi_bits[this_cpu]; + unsigned long *pending_ipis = &ipi_data[this_cpu].bits; unsigned long ops; DBGS(("handle_ipi: on CPU %d ops 0x%x PC 0x%lx\n", @@ -699,190 +741,189 @@ ops &= ~which; which = ffz(~which); - if (which < IPI_RESCHEDULE) { - if (which == IPI_TLB_ALL) - tbia(); - else if (which == IPI_TLB_MM) { - struct mm_struct * mm; - mm = ipi_msg_flush_tb.p.flush_mm; - if (mm == current->mm) - flush_tlb_current(mm); - } - else /* IPI_TLB_PAGE */ { - struct vm_area_struct * vma; - struct mm_struct * mm; - unsigned long addr; - - vma = ipi_msg_flush_tb.p.flush_vma; - mm = vma->vm_mm; - addr = ipi_msg_flush_tb.flush_addr; - - if (mm == current->mm) - flush_tlb_current_page(mm, vma, addr); - } - clear_bit(this_cpu, &ipi_msg_flush_tb.flush_tb_mask); - } - else if (which == IPI_RESCHEDULE) { + if (which == IPI_RESCHEDULE) { /* Reschedule callback. Everything to be done is done by the interrupt return path. */ } + else if (which == IPI_CALL_FUNC) { + struct smp_call_struct *data; + void (*func)(void *info); + void *info; + int wait; + + data = smp_call_function_data; + func = data->func; + info = data->info; + wait = data->wait; + + /* Notify the sending CPU that the data has been + received, and execution is about to begin. */ + mb(); + atomic_dec (&data->unstarted_count); + + /* At this point the structure may be gone unless + wait is true. */ + (*func)(info); + + /* Notify the sending CPU that the task is done. */ + mb(); + if (wait) atomic_dec (&data->unfinished_count); + } else if (which == IPI_CPU_STOP) { halt(); } else { - printk(KERN_CRIT "unknown_ipi() on CPU %d: %lu\n", + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); } } while (ops); + mb(); /* Order data access and bit testing. */ } cpu_data[this_cpu].ipi_count++; if (hwrpb->txrdy) - secondary_console_message(); + recv_secondary_console_msg(); } -static void -send_ipi_message(unsigned long to_whom, enum ipi_message_type operation) +void +smp_send_reschedule(int cpu) { - long i, j; - - /* Reduce the number of memory barriers by doing two loops, - one to set the bits, one to invoke the interrupts. */ - - mb(); /* Order out-of-band data and bit setting. */ - - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - set_bit(operation, &ipi_bits[i]); - } - - mb(); /* Order bit setting and interrupt. */ + send_ipi_message(1L << cpu, IPI_RESCHEDULE); +} - for (i = 0, j = 1; i < NR_CPUS; ++i, j <<= 1) { - if (to_whom & j) - wripir(i); - } +void +smp_send_stop(void) +{ + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + send_ipi_message(to_whom, IPI_CPU_STOP); } +/* + * Run a function on all other CPUs. + * The function to run. This must be fast and non-blocking. + * An arbitrary pointer to pass to the function. + * If true, keep retrying until ready. + * If true, wait until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. + * + * Does not return until remote CPUs are nearly ready to execute + * or are or have executed. + */ + int -smp_info(char *buffer) +smp_call_function (void (*func) (void *info), void *info, int retry, int wait) { - long i; - unsigned long sum = 0; - for (i = 0; i < NR_CPUS; i++) - sum += cpu_data[i].ipi_count; + unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id()); + struct smp_call_struct data; + long timeout; + + data.func = func; + data.info = info; + data.wait = wait; + atomic_set(&data.unstarted_count, smp_num_cpus - 1); + atomic_set(&data.unfinished_count, smp_num_cpus - 1); + + /* Aquire the smp_call_function_data mutex. */ + if (pointer_lock(&smp_call_function_data, &data, retry)) + return -EBUSY; + + /* Send a message to all other CPUs. */ + send_ipi_message(to_whom, IPI_CALL_FUNC); + + /* Wait for a minimal response. */ + timeout = jiffies + HZ; + while (atomic_read (&data.unstarted_count) > 0 + && time_before (jiffies, timeout)) + barrier(); - return sprintf(buffer, "CPUs probed %d active %d map 0x%x IPIs %ld\n", - smp_num_probed, smp_num_cpus, cpu_present_map, sum); -} + /* We either got one or timed out -- clear the lock. */ + mb(); + smp_call_function_data = 0; + if (atomic_read (&data.unstarted_count) > 0) + return -ETIMEDOUT; + + /* Wait for a complete response, if needed. */ + if (wait) { + while (atomic_read (&data.unfinished_count) > 0) + barrier(); + } -void -smp_send_reschedule(int cpu) -{ - send_ipi_message(1 << cpu, IPI_RESCHEDULE); + return 0; } -void -smp_send_stop(void) +static void +ipi_flush_tlb_all(void *ignored) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - send_ipi_message(to_whom, IPI_CPU_STOP); + tbia(); } void flush_tlb_all(void) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - send_ipi_message(to_whom, IPI_TLB_ALL); tbia(); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } - - if (timeout == 0) { - printk("flush_tlb_all: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + /* Although we don't have any data to pass, we do want to + synchronize with the other processors. */ + if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) { + printk(KERN_CRIT "flush_tlb_all: timed out\n"); } +} - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_mm(void *x) +{ + struct mm_struct *mm = (struct mm_struct *) x; + if (mm == current->mm) + flush_tlb_current(mm); } void flush_tlb_mm(struct mm_struct *mm) { - unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id()); - long timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_mm = mm; - send_ipi_message(to_whom, IPI_TLB_MM); - - if (mm != current->mm) - flush_tlb_other(mm); - else + if (mm == current->mm) flush_tlb_current(mm); + else + flush_tlb_other(mm); - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); + if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) { + printk(KERN_CRIT "flush_tlb_mm: timed out\n"); } +} - if (timeout == 0) { - printk("flush_tlb_mm: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; - } +struct flush_tlb_page_struct { + struct vm_area_struct *vma; + struct mm_struct *mm; + unsigned long addr; +}; - spin_unlock(&flush_tb_lock); +static void +ipi_flush_tlb_page(void *x) +{ + struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x; + if (data->mm == current->mm) + flush_tlb_current_page(data->mm, data->vma, data->addr); } void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) { - int cpu = smp_processor_id(); - unsigned long to_whom = cpu_present_map ^ (1 << cpu); - struct mm_struct * mm = vma->vm_mm; - int timeout = 1000000; - - spin_lock(&flush_tb_lock); - - ipi_msg_flush_tb.flush_tb_mask = to_whom; - ipi_msg_flush_tb.p.flush_vma = vma; - ipi_msg_flush_tb.flush_addr = addr; - send_ipi_message(to_whom, IPI_TLB_PAGE); - - if (mm != current->mm) - flush_tlb_other(mm); - else - flush_tlb_current_page(mm, vma, addr); + struct flush_tlb_page_struct data; + struct mm_struct *mm = vma->vm_mm; - while (ipi_msg_flush_tb.flush_tb_mask && --timeout) { - udelay(1); - barrier(); - } + data.vma = vma; + data.mm = mm; + data.addr = addr; - if (timeout == 0) { - printk("flush_tlb_page: STUCK on CPU %d mask 0x%x\n", - smp_processor_id(), - ipi_msg_flush_tb.flush_tb_mask); - ipi_msg_flush_tb.flush_tb_mask = 0; + if (mm == current->mm) + flush_tlb_current_page(mm, vma, addr); + else + flush_tlb_other(mm); + + if (smp_call_function(ipi_flush_tlb_page, &data, 1, 1)) { + printk(KERN_CRIT "flush_tlb_page: timed out\n"); } - - spin_unlock(&flush_tb_lock); } void @@ -892,6 +933,20 @@ flush_tlb_mm(mm); } + +int +smp_info(char *buffer) +{ + long i; + unsigned long sum = 0; + for (i = 0; i < NR_CPUS; i++) + sum += cpu_data[i].ipi_count; + + return sprintf(buffer, "CPUs probed %d active %d map 0x%lx IPIs %ld\n", + smp_num_probed, smp_num_cpus, cpu_present_mask, sum); +} + + #if DEBUG_SPINLOCK #ifdef MANAGE_SPINLOCK_IPL @@ -932,17 +987,16 @@ spin_lock(spinlock_t * lock) { long tmp; - long stuck = 1<<27; + long stuck; void *inline_pc = __builtin_return_address(0); unsigned long started = jiffies; int printed = 0; int cpu = smp_processor_id(); long old_ipl = spinlock_raise_ipl(lock); + stuck = 1L << 28; try_again: - stuck = 0x10000000; /* was 4G, now 256M */ - /* Use sub-sections to put the actual loop at the end of this object file's text section so as to perfect branch prediction. */ @@ -961,19 +1015,16 @@ " blbs %0,2b\n" " br 1b\n" ".previous" - : "=r" (tmp), - "=m" (__dummy_lock(lock)), - "=r" (stuck) - : "2" (stuck)); + : "=r" (tmp), "=m" (__dummy_lock(lock)), "=r" (stuck) + : "1" (__dummy_lock(lock)), "2" (stuck)); if (stuck < 0) { - if (!printed) { - printk("spinlock stuck at %p(%d) owner %s at %p\n", - inline_pc, cpu, lock->task->comm, - lock->previous); - printed = 1; - } - stuck = 1<<30; + printk(KERN_WARNING + "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n", + inline_pc, cpu, lock->task->comm, lock->previous, + lock->task->processor, lock->task->state); + stuck = 1L << 36; + printed = 1; goto try_again; } @@ -984,7 +1035,7 @@ lock->task = current; if (printed) { - printk("spinlock grabbed at %p(%d) %ld ticks\n", + printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n", inline_pc, cpu, jiffies - started); } } @@ -1006,7 +1057,7 @@ return ret; } #endif /* DEBUG_SPINLOCK */ - + #if DEBUG_RWLOCK void write_lock(rwlock_t * lock) { @@ -1038,18 +1089,17 @@ " blt %1,8b\n" " br 1b\n" ".previous" - : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy) - , "=&r" (stuck_lock), "=&r" (stuck_reader) - : "0" (__dummy_lock(lock)) - , "3" (stuck_lock), "4" (stuck_reader) - ); + : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (regy), + "=&r" (stuck_lock), "=&r" (stuck_reader) + : "0" (__dummy_lock(lock)), "3" (stuck_lock), "4" (stuck_reader)); if (stuck_lock < 0) { - printk("write_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck at %p\n", inline_pc); goto try_again; } if (stuck_reader < 0) { - printk("write_lock stuck on readers at %p\n", inline_pc); + printk(KERN_WARNING "write_lock stuck on readers at %p\n", + inline_pc); goto try_again; } } @@ -1079,11 +1129,10 @@ " br 1b\n" ".previous" : "=m" (__dummy_lock(lock)), "=&r" (regx), "=&r" (stuck_lock) - : "0" (__dummy_lock(lock)), "2" (stuck_lock) - ); + : "0" (__dummy_lock(lock)), "2" (stuck_lock)); if (stuck_lock < 0) { - printk("read_lock stuck at %p\n", inline_pc); + printk(KERN_WARNING "read_lock stuck at %p\n", inline_pc); goto try_again; } } diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c --- v2.3.1/linux/arch/alpha/kernel/time.c Sat Apr 24 17:54:08 1999 +++ linux/arch/alpha/kernel/time.c Fri May 14 12:41:23 1999 @@ -42,6 +42,9 @@ #include "proto.h" #include "irq.h" +extern rwlock_t xtime_lock; +extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + static int set_rtc_mmss(unsigned long); @@ -86,15 +89,15 @@ long nticks; #ifdef __SMP__ - extern void smp_percpu_timer_interrupt(struct pt_regs *); - extern unsigned int boot_cpu_id; - /* when SMP, do this for *all* CPUs, - but only do the rest for the boot CPU */ + /* When SMP, do this for *all* CPUs, but only do the rest for + the boot CPU. */ smp_percpu_timer_interrupt(regs); - if (smp_processor_id() != boot_cpu_id) - return; + if (smp_processor_id() != smp_boot_cpuid) + return; #endif + write_lock(&xtime_lock); + /* * Calculate how many ticks have passed since the last update, * including any previous partial leftover. Save any resulting @@ -124,6 +127,8 @@ int tmp = set_rtc_mmss(xtime.tv_sec); state.last_rtc_update = xtime.tv_sec - (tmp ? 600 : 0); } + + write_unlock(&xtime_lock); } /* @@ -226,7 +231,8 @@ { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq, diff, one_percent; + unsigned long cycle_freq, one_percent; + long diff; /* * The Linux interpretation of the CMOS clock register contents: @@ -242,7 +248,7 @@ if (!est_cycle_freq) { /* Sometimes the hwrpb->cycle_freq value is bogus. - Go another round to check up on it and see. */ + Go another round to check up on it and see. */ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); @@ -279,8 +285,7 @@ mon = CMOS_READ(RTC_MONTH); year = CMOS_READ(RTC_YEAR); - if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); @@ -328,18 +333,24 @@ void do_gettimeofday(struct timeval *tv) { - unsigned long flags, delta_cycles, delta_usec; - unsigned long sec, usec; - __u32 now; - extern volatile unsigned long lost_ticks; /*kernel/sched.c*/ + unsigned long sec, usec, lost, flags; + unsigned long delta_cycles, delta_usec, partial_tick; - now = rpcc(); - save_and_cli(flags); + read_lock_irqsave(&xtime_lock, flags); + + delta_cycles = rpcc() - state.last_time; sec = xtime.tv_sec; usec = xtime.tv_usec; - delta_cycles = now - state.last_time; - restore_flags(flags); + partial_tick = state.partial_tick; + lost = lost_ticks; + + read_unlock_irqrestore(&xtime_lock, flags); +#ifdef __SMP__ + /* Until and unless we figure out how to get cpu cycle counters + in sync and keep them there, we can't use the rpcc tricks. */ + delta_usec = lost * (1000000 / HZ); +#else /* * usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks) * = cycles * (s_t_p_c) * 1e6 / (2**48 * ticks) @@ -354,13 +365,10 @@ */ delta_usec = (delta_cycles * state.scaled_ticks_per_cycle - + state.partial_tick - + (lost_ticks << FIX_SHIFT) ) * 15625; + + partial_tick + + (lost << FIX_SHIFT)) * 15625; delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; - - /* the 'lost_tics' term above implements this: - * delta_usec += lost_ticks * (1000000 / HZ); - */ +#endif usec += delta_usec; if (usec >= 1000000) { @@ -375,13 +383,41 @@ void do_settimeofday(struct timeval *tv) { - cli(); - xtime = *tv; + unsigned long delta_usec; + long sec, usec; + + write_lock_irq(&xtime_lock); + + /* The offset that is added into time in do_gettimeofday above + must be subtracted out here to keep a coherent view of the + time. Without this, a full-tick error is possible. */ + +#ifdef __SMP__ + delta_usec = lost_ticks * (1000000 / HZ); +#else + delta_usec = rpcc() - state.last_time; + delta_usec = (delta_usec * state.scaled_ticks_per_cycle + + state.partial_tick + + (lost_ticks << FIX_SHIFT)) * 15625; + delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2; +#endif + + sec = tv->tv_sec; + usec = tv->tv_usec; + usec -= delta_usec; + if (usec < 0) { + usec += 1000000; + sec -= 1; + } + + xtime.tv_sec = sec; + xtime.tv_usec = usec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + + write_unlock_irq(&xtime_lock); } diff -u --recursive --new-file v2.3.1/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.3.1/linux/arch/alpha/kernel/traps.c Mon May 10 09:55:21 1999 +++ linux/arch/alpha/kernel/traps.c Fri May 14 12:41:23 1999 @@ -1,5 +1,5 @@ /* - * kernel/traps.c + * arch/alpha/kernel/traps.c * * (C) Copyright 1994 Linus Torvalds */ @@ -95,6 +95,9 @@ { if (regs->ps & 8) return; +#ifdef __SMP__ + printk("CPU %d ", hard_smp_processor_id()); +#endif printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); dik_show_regs(regs, r9_15); dik_show_code((unsigned int *)regs->pc); @@ -128,8 +131,8 @@ if (summary & 1) { /* Software-completion summary bit is set, so try to emulate the instruction. */ - if (implver() == IMPLVER_EV6) { - /* Whee! EV6 has precice exceptions. */ + if (!amask(AMASK_PRECISE_TRAP)) { + /* 21264 (except pass 1) has precise exceptions. */ if (alpha_fp_emul(regs.pc - 4)) return; } else { @@ -138,14 +141,12 @@ } } - lock_kernel(); #if 0 printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", current->comm, regs.pc, summary, write_mask); #endif die_if_kernel("Arithmetic fault", ®s, 0, 0); send_sig(SIGFPE, current, 1); - unlock_kernel(); } asmlinkage void @@ -235,10 +236,8 @@ unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs) { - lock_kernel(); die_if_kernel("Instruction fault", ®s, type, 0); force_sig(SIGILL, current); - unlock_kernel(); } @@ -453,10 +452,8 @@ unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); - lock_kernel(); printk("Forwarding unaligned exception at %lx (%lx)\n", pc, newpc); - unlock_kernel(); (®s)->pc = newpc; return; @@ -610,11 +607,9 @@ cnt = 0; } if (++cnt < 5) { - lock_kernel(); printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", current->comm, current->pid, regs->pc - 4, va, opcode, reg); - unlock_kernel(); } last_time = jiffies; } @@ -868,16 +863,12 @@ give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ - lock_kernel(); send_sig(SIGSEGV, current, 1); - unlock_kernel(); return; give_sigbus: regs->pc -= 4; - lock_kernel(); send_sig(SIGBUS, current, 1); - unlock_kernel(); return; } diff -u --recursive --new-file v2.3.1/linux/arch/alpha/mm/init.c linux/arch/alpha/mm/init.c --- v2.3.1/linux/arch/alpha/mm/init.c Mon Oct 12 11:40:12 1998 +++ linux/arch/alpha/mm/init.c Fri May 14 12:41:23 1999 @@ -256,26 +256,6 @@ return start_mem; } -#ifdef __SMP__ -/* - * paging_init_secondary(), called ONLY by secondary CPUs, - * sets up current->tss contents appropriately and does a load_PCB. - * note that current should be pointing at the idle thread task struct - * for this CPU. - */ -void -paging_init_secondary(void) -{ - current->tss.ptbr = init_task.tss.ptbr; - current->tss.pal_flags = 1; - current->tss.flags = 0; - load_PCB(¤t->tss); - tbia(); - - return; -} -#endif /* __SMP__ */ - #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_SRM) void srm_paging_stop (void) diff -u --recursive --new-file v2.3.1/linux/arch/i386/boot/video.S linux/arch/i386/boot/video.S --- v2.3.1/linux/arch/i386/boot/video.S Tue Sep 29 21:03:35 1998 +++ linux/arch/i386/boot/video.S Fri May 14 12:47:01 1999 @@ -1,14 +1,19 @@ ! -! Display adapter & video mode setup, version 2.12 (25-May-98) +! Display adapter & video mode setup, version 2.13 (14-May-99) ! -! Copyright (C) 1995 -- 1998 Martin Mares +! Copyright (C) 1995 -- 1999 Martin Mares ! Based on the original setup.S code (C) Linus Torvalds and Mats Anderson ! +! For further information, look at Documentation/svga.txt. +! #include /* for CONFIG_VIDEO_* */ ! Enable autodetection of SVGA adapters and modes. If you really need this -! feature, drop me a mail as I think of removing it some day... +! feature, drop me a mail as I think of removing it some day. You can +! always enter `scan' to get the video mode table and then use the real +! video mode numbers (those 4-digit hexadecimal numbers, NOT the menu +! item numbers) which don't rely on any autodetection. #undef CONFIG_VIDEO_SVGA ! Enable autodetection of VESA modes @@ -1939,7 +1944,7 @@ badmdt: .ascii "You passed an undefined mode number." db 0x0d, 0x0a, 0 vesaer: .ascii "Error: Scanning of VESA modes failed. Please " - .ascii "report to ." + .ascii "report to ." db 0x0d, 0x0a, 0 old_name: .ascii "CGA/MDA/HGA" db 0 diff -u --recursive --new-file v2.3.1/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.3.1/linux/arch/i386/defconfig Fri May 14 18:55:11 1999 +++ linux/arch/i386/defconfig Fri May 14 18:27:32 1999 @@ -305,6 +305,7 @@ CONFIG_USB_MOUSE=y CONFIG_USB_KBD=y # CONFIG_USB_AUDIO is not set +# CONFIG_USB_ACM is not set # # Filesystems diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/apm.c linux/arch/i386/kernel/apm.c --- v2.3.1/linux/arch/i386/kernel/apm.c Fri May 14 18:55:11 1999 +++ linux/arch/i386/kernel/apm.c Thu May 13 23:22:05 1999 @@ -314,7 +314,7 @@ static int debug = 0; static int apm_disabled = 0; -static struct wait_queue * process_list = NULL; +static DECLARE_WAIT_QUEUE_HEAD(process_list); static struct apm_bios_struct * user_list = NULL; static struct timer_list apm_timer; diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c --- v2.3.1/linux/arch/i386/kernel/mtrr.c Mon May 10 10:32:45 1999 +++ linux/arch/i386/kernel/mtrr.c Fri May 14 08:59:54 1999 @@ -1,6 +1,6 @@ /* Generic MTRR (Memory Type Range Register) driver. - Copyright (C) 1997-1998 Richard Gooch + Copyright (C) 1997-1999 Richard Gooch This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -196,6 +196,11 @@ 19990310 Richard Gooch Support K6-II/III based on Alan Cox's patches. v1.34 + 19990511 Bart Hartgers + Support Centaur C6 MCR's. + 19990512 Richard Gooch + Minor cleanups. + v1.35 */ #include #include @@ -232,7 +237,7 @@ #include #include "irq.h" -#define MTRR_VERSION "1.34 (19990310)" +#define MTRR_VERSION "1.35 (19990512)" #define TRUE 1 #define FALSE 0 @@ -313,8 +318,13 @@ /* Disable interrupts locally */ __save_flags (ctxt->flags); __cli (); - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return; - + switch (boot_cpu_data.x86_vendor) + { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: + return; + /*break;*/ + } /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) asm volatile ("movl %%cr4, %0\n\t" @@ -352,12 +362,14 @@ { unsigned long tmp; - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + switch (boot_cpu_data.x86_vendor) { + case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: __restore_flags (ctxt->flags); return; + /*break;*/ } - /* Flush caches and TLBs */ asm volatile ("wbinvd" : : : "memory" ); @@ -399,7 +411,9 @@ return (config & 0xff); /*break;*/ case X86_VENDOR_CYRIX: - /* Cyrix have 8 ARRs */ + /* Cyrix have 8 ARRs */ + case X86_VENDOR_CENTAUR: + /* and Centaur has 8 MCR's */ return 8; /*break;*/ case X86_VENDOR_AMD: @@ -422,6 +436,7 @@ /*break;*/ case X86_VENDOR_CYRIX: case X86_VENDOR_AMD: + case X86_VENDOR_CENTAUR: return 1; /*break;*/ } @@ -450,7 +465,6 @@ /* Clean up mask_lo so it gives the real address mask. */ mask_lo = (mask_lo & 0xfffff000UL); - /* This works correctly if size is a power of two, i.e. a contiguous range. */ *size = ~(mask_lo - 1); @@ -480,7 +494,6 @@ /* Enable interrupts if it was enabled previously */ __restore_flags (flags); - shift = ((unsigned char *) base)[1] & 0x0f; *base &= 0xfffff000UL; @@ -550,6 +563,20 @@ return; } /* End Function amd_get_mtrr */ +static struct +{ + unsigned long high; + unsigned long low; +} centaur_mcr[8]; + +static void centaur_get_mcr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + *base = centaur_mcr[reg].high & 0xfffff000; + *size = (~(centaur_mcr[reg].low & 0xfffff000))+1; + *type = MTRR_TYPE_WRCOMB; /* If it is there, it is write-combining */ +} /* End Function centaur_get_mcr */ + static void (*get_mtrr) (unsigned int reg, unsigned long *base, unsigned long *size, mtrr_type *type) = NULL; @@ -647,11 +674,10 @@ else /* Set the register to the base (already shifted for us), the type (off by one) and an inverted bitmask of the size - The size is the only odd bit. We are fed say 512K We invert this and we get 111 1111 1111 1011 but if you subtract one and invert you get the desired - 111 1111 1111 1100 mask + 111 1111 1111 1100 mask */ *(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1); /* @@ -663,10 +689,36 @@ if (do_safe) set_mtrr_done (&ctxt); } /* End Function amd_set_mtrr_up */ + +static void centaur_set_mcr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, + int do_safe) +{ + struct set_mtrr_context ctxt; + unsigned long low, high; + + if (do_safe) set_mtrr_prepare( &ctxt ); + if (size == 0) + { + /* Disable */ + high = low = 0; + } + else + { + high = base & 0xfffff000; /* base works on 4K pages... */ + low = ((~(size-1))&0xfffff000); + low |= 0x1f; /* only support write-combining... */ + } + centaur_mcr[reg].high = high; + centaur_mcr[reg].low = low; + wrmsr (0x110 + reg, low, high); + if (do_safe) set_mtrr_done( &ctxt ); +} /* End Function centaur_set_mtrr_up */ + static void (*set_mtrr_up) (unsigned int reg, unsigned long base, unsigned long size, mtrr_type type, int do_safe) = NULL; - + #ifdef __SMP__ struct mtrr_var_range @@ -694,23 +746,21 @@ { unsigned int lo, hi; int changed = FALSE; - - rdmsr(MTRRphysBase_MSR(index), lo, hi); + rdmsr(MTRRphysBase_MSR(index), lo, hi); if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); changed = TRUE; } - rdmsr(MTRRphysMask_MSR(index), lo, hi); + rdmsr(MTRRphysMask_MSR(index), lo, hi); if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { - wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); + wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); changed = TRUE; } - return changed; } /* End Function set_mtrr_var_range_testing */ @@ -723,7 +773,6 @@ for (i = 0; i < 2; i++) rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); - for (i = 0; i < 8; i++) rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); } /* End Function get_fixed_ranges */ @@ -777,14 +826,13 @@ unsigned long lo, dummy; nvrs = state->num_var_ranges = get_num_var_ranges(); - vrs = state->var_ranges + vrs = state->var_ranges = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL); if (vrs == NULL) nvrs = state->num_var_ranges = 0; for (i = 0; i < nvrs; i++) get_mtrr_var_range (i, &vrs[i]); - get_fixed_ranges (state->fixed_ranges); rdmsr (MTRRdefType_MSR, lo, dummy); @@ -818,7 +866,6 @@ if ( set_fixed_ranges_testing(state->fixed_ranges) ) change_mask |= MTRR_CHANGE_MASK_FIXED; - /* Set_mtrr_restore restores the old value of MTRRdefType, so to set it we fiddle with the saved value */ if ((ctxt->deftype_lo & 0xff) != state->def_type @@ -831,7 +878,7 @@ return change_mask; } /* End Function set_mtrr_state */ - + static atomic_t undone_count; static volatile int wait_barrier_execute = FALSE; static volatile int wait_barrier_cache_enable = FALSE; @@ -1025,13 +1072,22 @@ } /* Fall through */ case X86_VENDOR_CYRIX: + case X86_VENDOR_CENTAUR: if ( (base & 0xfff) || (size & 0xfff) ) { printk ("mtrr: size and base must be multiples of 4 kiB\n"); printk ("mtrr: size: %lx base: %lx\n", size, base); return -EINVAL; } - if (base + size < 0x100000) + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) + { + if (type != MTRR_TYPE_WRCOMB) + { + printk ("mtrr: only write-combining is supported\n"); + return -EINVAL; + } + } + else if (base + size < 0x100000) { printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n", base, size); @@ -1050,7 +1106,7 @@ } break; case X86_VENDOR_AMD: - /* Apply the K6 block alignment and size rules + /* Apply the K6 block alignment and size rules In order o Uncached or gathering only o 128K or bigger block @@ -1572,6 +1628,30 @@ if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n"); } /* End Function cyrix_arr_init */ +__initfunc(static void centaur_mcr_init (void)) +{ + unsigned i; + struct set_mtrr_context ctxt; + + set_mtrr_prepare (&ctxt); + /* Unfortunately, MCR's are read-only, so there is no way to + * find out what the bios might have done. + */ + /* Clear all MCR's. + * This way we are sure that the centaur_mcr array contains the actual + * values. The disadvantage is that any BIOS tweaks are thus undone. + */ + for (i = 0; i < 8; ++i) + { + centaur_mcr[i].high = 0; + centaur_mcr[i].low = 0; + wrmsr (0x110 + i , 0, 0); + } + /* Throw the main write-combining switch... */ + wrmsr (0x120, 0x01f0001f, 0); + set_mtrr_done (&ctxt); +} /* End Function centaur_mcr_init */ + __initfunc(static void mtrr_setup (void)) { printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION); @@ -1582,7 +1662,6 @@ set_mtrr_up = intel_set_mtrr_up; break; case X86_VENDOR_CYRIX: - printk ("mtrr: Using Cyrix style ARRs\n"); get_mtrr = cyrix_get_arr; set_mtrr_up = cyrix_set_arr_up; get_free_region = cyrix_get_free_region; @@ -1591,6 +1670,10 @@ get_mtrr = amd_get_mtrr; set_mtrr_up = amd_set_mtrr_up; break; + case X86_VENDOR_CENTAUR: + get_mtrr = centaur_get_mcr; + set_mtrr_up = centaur_set_mcr_up; + break; } } /* End Function mtrr_setup */ @@ -1611,6 +1694,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } } /* End Function mtrr_init_boot_cpu */ @@ -1675,6 +1761,9 @@ case X86_VENDOR_CYRIX: cyrix_arr_init (); break; + case X86_VENDOR_CENTAUR: + centaur_mcr_init (); + break; } # endif /* !__SMP__ */ diff -u --recursive --new-file v2.3.1/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.3.1/linux/arch/i386/kernel/setup.c Mon May 10 10:32:45 1999 +++ linux/arch/i386/kernel/setup.c Fri May 14 08:59:54 1999 @@ -9,6 +9,9 @@ * Force Cyrix 6x86(MX) and M II processors to report MTRR capability * and fix against Cyrix "coma bug" by * Zoltan Boszormenyi February 1999. + * + * Force Centaur C6 processors to report MTRR capability. + * Bart Hartgers , May 199. */ /* @@ -861,6 +864,8 @@ /* lv|=(1<<6); - may help too if the board can cope */ printk("now 0x%X", lv); wrmsr(0x107, lv, hv); + /* Emulate MTRRs using Centaur's MCR. */ + c->x86_capability |= X86_FEATURE_MTRR; } printk("\n"); } diff -u --recursive --new-file v2.3.1/linux/drivers/block/hpt343.c linux/drivers/block/hpt343.c --- v2.3.1/linux/drivers/block/hpt343.c Fri May 14 18:55:13 1999 +++ linux/drivers/block/hpt343.c Fri May 14 18:50:32 1999 @@ -370,7 +370,6 @@ inb(hpt343IoBase + 0x0011)); #endif - pci_write_config_byte(dev, HPT343_PCI_INIT_REG, 0x80); if (cmd & PCI_COMMAND_MEMORY) { if (dev->rom_address) { pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->rom_address | PCI_ROM_ADDRESS_ENABLE); diff -u --recursive --new-file v2.3.1/linux/drivers/block/ide-pci.c linux/drivers/block/ide-pci.c --- v2.3.1/linux/drivers/block/ide-pci.c Fri May 14 18:55:14 1999 +++ linux/drivers/block/ide-pci.c Fri May 14 18:50:32 1999 @@ -240,7 +240,6 @@ dev->base_address[i] |= PCI_BASE_ADDRESS_SPACE_IO; pci_read_config_word(dev, PCI_COMMAND, &pcicmd); - pci_write_config_byte(dev, 0x80, 0x80); if (!(pcicmd & PCI_COMMAND_MEMORY)) pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20); } diff -u --recursive --new-file v2.3.1/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.3.1/linux/drivers/char/mem.c Mon May 10 10:18:34 1999 +++ linux/drivers/char/mem.c Fri May 14 18:15:02 1999 @@ -51,14 +51,8 @@ #if defined(CONFIG_PPC) || defined(CONFIG_MAC) extern void adbdev_init(void); #endif -#ifdef CONFIG_USB_UHCI -int uhci_init(void); -#endif -#ifdef CONFIG_USB_OHCI -int ohci_init(void); -#endif -#ifdef CONFIG_USB_OHCI_HCD -int ohci_hcd_init(void); +#ifdef CONFIG_USB +extern void usb_init(void); #endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, @@ -609,15 +603,7 @@ printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); #ifdef CONFIG_USB -#ifdef CONFIG_USB_UHCI - uhci_init(); -#endif -#ifdef CONFIG_USB_OHCI - ohci_init(); -#endif -#ifdef CONFIG_USB_OHCI_HCD - ohci_hcd_init(); -#endif + usb_init(); #endif #if defined (CONFIG_FB) fbmem_init(); diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.3.1/linux/drivers/scsi/ide-scsi.c Thu Apr 22 19:24:50 1999 +++ linux/drivers/scsi/ide-scsi.c Thu May 13 23:23:27 1999 @@ -40,12 +40,11 @@ #include #include #include +#include #include #include #include - -#include "../block/ide.h" #include "scsi.h" #include "hosts.h" diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.3.1/linux/drivers/scsi/sg.c Fri May 14 18:55:22 1999 +++ linux/drivers/scsi/sg.c Fri May 14 17:56:58 1999 @@ -1334,13 +1334,13 @@ return sdp->headfp; } sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); - if (sfp) { - memset(sfp, 0, sizeof(Sg_fd)); - sfp->my_mem_src = SG_HEAP_KMAL; - } - else - return NULL; - + if (!sfp) + return NULL; + + memset(sfp, 0, sizeof(Sg_fd)); + sfp->my_mem_src = SG_HEAP_KMAL; + + init_waitqueue_head(&sfp->read_wait); sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? diff -u --recursive --new-file v2.3.1/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.3.1/linux/drivers/scsi/sr_ioctl.c Fri May 14 18:55:22 1999 +++ linux/drivers/scsi/sr_ioctl.c Fri May 14 16:04:36 1999 @@ -122,11 +122,9 @@ if (!quiet) printk(KERN_ERR "sr%d: CDROM (ioctl) reports ILLEGAL " "REQUEST.\n", target); - if ((SCpnt->sense_buffer[12] == 0x20 || - SCpnt->sense_buffer[12] == 0x24) && + if (SCpnt->sense_buffer[12] == 0x20 && SCpnt->sense_buffer[13] == 0x00) { /* sense: Invalid command operation code */ - /* or Invalid field in cdb */ err = -EDRIVE_CANT_DO_THIS; } else { err = -EINVAL; diff -u --recursive --new-file v2.3.1/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v2.3.1/linux/drivers/sound/dev_table.h Mon Apr 12 16:18:27 1999 +++ linux/drivers/sound/dev_table.h Thu May 13 23:22:48 1999 @@ -234,9 +234,9 @@ int parent_dev; /* 0 -> no parent, 1 to n -> parent=parent_dev+1 */ /* fields formerly in dmabuf.c */ - struct wait_queue *in_sleeper; - struct wait_queue *out_sleeper; - struct wait_queue *poll_sleeper; + wait_queue_head_t in_sleeper; + wait_queue_head_t out_sleeper; + wait_queue_head_t poll_sleeper; /* fields formerly in audio.c */ int audio_mode; diff -u --recursive --new-file v2.3.1/linux/drivers/usb/Config.in linux/drivers/usb/Config.in --- v2.3.1/linux/drivers/usb/Config.in Fri May 14 18:55:23 1999 +++ linux/drivers/usb/Config.in Fri May 14 18:09:57 1999 @@ -23,6 +23,7 @@ bool 'USB mouse support' CONFIG_USB_MOUSE bool 'USB keyboard support' CONFIG_USB_KBD bool 'USB audio parsing support' CONFIG_USB_AUDIO + bool 'USB Abstract Control Model support' CONFIG_USB_ACM fi endmenu diff -u --recursive --new-file v2.3.1/linux/drivers/usb/Makefile linux/drivers/usb/Makefile --- v2.3.1/linux/drivers/usb/Makefile Fri May 14 18:55:23 1999 +++ linux/drivers/usb/Makefile Fri May 14 18:09:57 1999 @@ -24,6 +24,10 @@ USBX_OBJS += mouse.o endif +ifeq ($(CONFIG_USB_ACM),y) + USBX_OBJS += acm.o +endif + ifeq ($(CONFIG_USB_KBD),y) USBX_OBJS += keyboard.o keymap.o endif diff -u --recursive --new-file v2.3.1/linux/drivers/usb/acm.c linux/drivers/usb/acm.c --- v2.3.1/linux/drivers/usb/acm.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/usb/acm.c Fri May 14 18:09:57 1999 @@ -0,0 +1,220 @@ +/* + * USB Abstract Control Model based on Brad Keryan's USB busmouse driver + * + * Armin Fuerst 5/8/1999 + * + * version 0.0: Driver sets up configuration, setus up data pipes, opens misc + * device. No actual data transfer is done, since we don't have bulk transfer, + * yet. Purely skeleton for now. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" + +#define USB_ACM_MINOR 32 + +struct acm_state { + int present; /* this acm is plugged in */ + int active; /* someone is has this acm's device open */ + struct usb_device *dev; + unsigned int readpipe,writepipe; +}; + +static struct acm_state static_acm_state; + +spinlock_t usb_acm_lock = SPIN_LOCK_UNLOCKED; + +static int acm_irq(int state, void *__buffer, void *dev_id) +{ +/* + signed char *data = __buffer; + struct acm_state *acm = &static_acm_state; + if(!acm->active) + return 1; +*/ + + /*We should so something useful here*/ + printk("ACM_USB_IRQ\n"); + + return 1; +} + +static int release_acm(struct inode * inode, struct file * file) +{ + struct acm_state *acm = &static_acm_state; + printk("ACM_FILE_RELEASE\n"); + +// fasync_acm(-1, file, 0); + if (--acm->active) + return 0; + return 0; +} + +static int open_acm(struct inode * inode, struct file * file) +{ + struct acm_state *acm = &static_acm_state; + printk("USB_FILE_OPEN\n"); + + if (!acm->present) + return -EINVAL; + if (acm->active++) + return 0; + return 0; +} + +static ssize_t write_acm(struct file * file, + const char * buffer, size_t count, loff_t *ppos) +{ + char * buffer="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + struct acm_state *acm = &static_acm_state; + printk("USB_FILE_WRITE\n"); + printk("writing:>%s<\n",buffer); + acm->dev->bus->op->bulk_msg(acm->dev,acm->writepipe,buffer, 26); + printk("done:>%s<\n",buffer); + printk("reading:>%s<\n",buffer); + acm->dev->bus->op->bulk_msg(acm->dev,acm->readpipe,buffer, 26); + printk("done:>%s<\n",buffer); + return -EINVAL; +} + +static ssize_t read_acm(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + printk("USB_FILE_READ\n"); + return -EINVAL; +} + +struct file_operations usb_acm_fops = { + NULL, /* acm_seek */ + read_acm, + write_acm, + NULL, /* acm_readdir */ + NULL, /* acm_poll */ + NULL, /* acm_ioctl */ + NULL, /* acm_mmap */ + open_acm, + NULL, /* flush */ + release_acm, + NULL, + NULL, /*fasync*/ +}; + +static struct miscdevice usb_acm = { + USB_ACM_MINOR, "USB ACM", &usb_acm_fops +}; + +static int acm_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct acm_state *acm = &static_acm_state; + int cfgnum; + + /* Only use CDC */ + if (dev->descriptor.bDeviceClass != 2 || + dev->descriptor.bDeviceSubClass != 0 || + dev->descriptor.bDeviceProtocol != 0) + return -1; + + /*Now scan all configs for a ACM configuration*/ + for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { + /* The first one should be Communications interface? */ + interface = &dev->config[cfgnum].interface[0]; + if (interface->bInterfaceClass != 2 || + interface->bInterfaceSubClass != 2 || + interface->bInterfaceProtocol != 1 || + interface->bNumEndpoints != 1) + continue; + + /*Which uses an interrupt input */ + endpoint = &interface->endpoint[0]; + if ((endpoint->bEndpointAddress & 0x80) != 0x80 || + (endpoint->bmAttributes & 3) != 3) + continue; + + /* The second one should be a Data interface? */ + interface = &dev->config[cfgnum].interface[1]; + if (interface->bInterfaceClass != 10 || + interface->bInterfaceSubClass != 0 || + interface->bInterfaceProtocol != 0 || + interface->bNumEndpoints != 2) + continue; + + /*With a bulk input */ + endpoint = &interface->endpoint[0]; + if ((endpoint->bEndpointAddress & 0x80) != 0x80 || + (endpoint->bmAttributes & 3) != 2) + continue; + + /*And a bulk output */ + endpoint = &interface->endpoint[1]; + if ((endpoint->bEndpointAddress & 0x80) == 0x80 || + (endpoint->bmAttributes & 3) != 2) + continue; + + printk("USB ACM found\n"); + usb_set_configuration(dev, dev->config[cfgnum].bConfigurationValue); + acm->dev=dev; + acm->readpipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[0]); + acm->writepipe=__create_pipe(dev,&dev->config[cfgnum].interface[1].endpoint[1]); + usb_request_irq(dev, usb_rcvctrlpipe(dev,&dev->config[cfgnum].interface[0].endpoint[0]), acm_irq, endpoint->bInterval, NULL); + acm->present = 1; + return 0; + } + + return -1; +} + +static void acm_disconnect(struct usb_device *dev) +{ + struct acm_state *acm = &static_acm_state; + + /* this might need work */ + acm->present = 0; +} + +static struct usb_driver acm_driver = { + "acm", + acm_probe, + acm_disconnect, + { NULL, NULL } +}; + +int usb_acm_init(void) +{ + struct acm_state *acm = &static_acm_state; + + misc_register(&usb_acm); + + acm->present = acm->active = 0; + + usb_register(&acm_driver); + printk(KERN_INFO "USB ACM registered.\n"); + return 0; +} + +#if 0 + +int init_module(void) +{ + return usb_acm_init(); +} + +void cleanup_module(void) +{ + /* this, too, probably needs work */ + usb_deregister(&acm_driver); + misc_deregister(&usb_acm); +} + +#endif diff -u --recursive --new-file v2.3.1/linux/drivers/usb/cpia.c linux/drivers/usb/cpia.c --- v2.3.1/linux/drivers/usb/cpia.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/cpia.c Fri May 14 18:33:12 1999 @@ -1246,7 +1246,7 @@ /* * This should be a separate module. */ -int cpia_init(void) +int usb_cpia_init(void) { usb_register(&cpia_driver); diff -u --recursive --new-file v2.3.1/linux/drivers/usb/hub.c linux/drivers/usb/hub.c --- v2.3.1/linux/drivers/usb/hub.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/hub.c Fri May 14 18:32:32 1999 @@ -394,7 +394,7 @@ /* * This should be a separate module. */ -int hub_init(void) +int usb_hub_init(void) { int pid; diff -u --recursive --new-file v2.3.1/linux/drivers/usb/inits.h linux/drivers/usb/inits.h --- v2.3.1/linux/drivers/usb/inits.h Fri Apr 30 08:20:30 1999 +++ linux/drivers/usb/inits.h Fri May 14 18:09:57 1999 @@ -2,5 +2,6 @@ int usb_kbd_init(void); int usb_audio_init(void); int hub_init(void); +int usb_acm_init(void); void hub_cleanup(void); void usb_mouse_cleanup(void); diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c --- v2.3.1/linux/drivers/usb/ohci-hcd.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/ohci-hcd.c Fri May 14 18:48:55 1999 @@ -234,10 +234,14 @@ return usb_dev; } +/* FIXME! */ +#define sohci_bulk_msg NULL + struct usb_operations sohci_device_operations = { sohci_usb_allocate, sohci_usb_deallocate, sohci_control_msg, + sohci_bulk_msg, sohci_request_irq, }; @@ -1429,7 +1433,6 @@ #endif - int usb_mouse_init(void); #ifdef MODULE void cleanup_module(void) @@ -1460,16 +1463,6 @@ if (retval < 0) break; -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif @@ -1478,12 +1471,3 @@ } return retval; } - -void cleanup_drivers(void) -{ - hub_cleanup(); -#ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -#endif -} - diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci.c linux/drivers/usb/ohci.c --- v2.3.1/linux/drivers/usb/ohci.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/ohci.c Fri May 14 18:48:55 1999 @@ -429,7 +429,7 @@ ohci_fill_new_td(td, td_set_dir_out(usb_pipeout(pipe)), TOGGLE_AUTO, OHCI_TD_ROUND, - dev->data, DATA_BUF_LEN, + &dev->data, DATA_BUF_LEN, dev_id, handler); /* * TODO: be aware that OHCI won't advance out of the 4kb @@ -728,6 +728,8 @@ return 0; } +/* FIXME! */ +#define ohci_bulk_msg NULL /* * functions for the generic USB driver @@ -736,6 +738,7 @@ ohci_usb_allocate, ohci_usb_deallocate, ohci_control_msg, + ohci_bulk_msg, ohci_request_irq, }; @@ -819,6 +822,18 @@ /* Enable control lists */ writel_set(OHCI_USB_IE | OHCI_USB_CLE | OHCI_USB_BLE, &ohci->regs->control); + /* Force global power enable -gal@cs.uni-magdeburg.de */ + /* + * This turns on global power switching for all the ports + * and tells the HC that all of the ports should be powered on + * all of the time. + * + * TODO: This could be battery draining for laptops.. We + * should implement power switching. + */ + writel_set( OHCI_ROOT_A_NPS, &ohci->regs->roothub.a ); + writel_mask( ~((__u32)OHCI_ROOT_A_PSM), &ohci->regs->roothub.a ); + /* Turn on power to the root hub ports (thanks Roman!) */ writel( OHCI_ROOT_LPSC, &ohci->regs->roothub.status ); @@ -1262,23 +1277,23 @@ * Initialize the polling table to call interrupts at the * intended intervals. */ - dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_32]); + dev->hcca->int_table[0] = virt_to_bus(&dev->ed[ED_INT_1]); for (i = 1; i < NUM_INTS; i++) { - if (i & 1) + if (i & 16) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_32]); + if (i & 8) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_16]); - else if (i & 2) + if (i & 4) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_8]); - else if (i & 4) + if (i & 2) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_4]); - else if (i & 8) + if (i & 1) dev->hcca->int_table[i] = virt_to_bus(&dev->ed[ED_INT_2]); - else if (i & 16) - dev->hcca->int_table[i] = - virt_to_bus(&dev->ed[ED_INT_1]); } /* @@ -1470,9 +1485,12 @@ #ifdef OHCI_TIMER /* * Inspired by Iñaky's driver. This function is a timer routine that - * is called OHCI_TIMER_FREQ times per second. It polls the root hub - * for status changes as on my system things are acting a bit odd at - * the moment.. + * is called every OHCI_TIMER_FREQ ms. It polls the root hub for + * status changes as on my system the RHSC interrupt just doesn't + * play well with others.. (so RHSC is turned off by default in this + * driver) + * [my controller is a "SiS 7001 USB (rev 16)"] + * -greg */ static void ohci_timer_func (unsigned long ohci_ptr) { @@ -1480,8 +1498,9 @@ ohci_root_hub_events(ohci); - /* press the snooze button... */ - mod_timer(&ohci_timer, jiffies + (OHCI_TIMER_FREQ*HZ)); + /* set the next timer */ + mod_timer(&ohci_timer, jiffies + ((OHCI_TIMER_FREQ*HZ)/1000)); + } /* ohci_timer_func() */ #endif @@ -1507,9 +1526,10 @@ #ifdef OHCI_TIMER init_timer(&ohci_timer); - ohci_timer.expires = jiffies + (OHCI_TIMER_FREQ*HZ); + ohci_timer.expires = jiffies + ((OHCI_TIMER_FREQ*HZ)/1000); ohci_timer.data = (unsigned long)ohci; ohci_timer.function = ohci_timer_func; + add_timer(&ohci_timer); #endif retval = -EBUSY; @@ -1644,18 +1664,6 @@ if (retval < 0) continue; - /* TODO check module params here to determine what to load */ - -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif diff -u --recursive --new-file v2.3.1/linux/drivers/usb/ohci.h linux/drivers/usb/ohci.h --- v2.3.1/linux/drivers/usb/ohci.h Tue May 11 10:04:03 1999 +++ linux/drivers/usb/ohci.h Fri May 14 18:45:47 1999 @@ -87,9 +87,14 @@ /* get the head_td */ #define ed_head_td(ed) ((ed)->_head_td & 0xfffffff0) -/* save the carry flag while setting the head_td */ +/* save the carry & halted flag while setting the head_td */ #define set_ed_head_td(ed, td) ((ed)->_head_td = (td) | ((ed)->_head_td & 3)) +/* Control the ED's halted flag */ +#define ohci_halt_ed(ed) ((ed)->_head_td |= 1) +#define ohci_unhalt_ed(ed) ((ed)->_head_td &= ~(__u32)1) +#define ohci_ed_halted(ed) ((ed)->_head_td & 1) + #define OHCI_ED_SKIP (1 << 14) #define OHCI_ED_MPS (0x7ff << 16) /* FIXME: should cap at the USB max packet size [0x4ff] */ @@ -257,12 +262,12 @@ /* * Read a MMIO register and re-write it after ANDing with (m) */ -#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) +#define writel_mask(m, a) writel( (readl((unsigned long)(a))) & (__u32)(m), (unsigned long)(a) ) /* * Read a MMIO register and re-write it after ORing with (b) */ -#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) +#define writel_set(b, a) writel( (readl((unsigned long)(a))) | (__u32)(b), (unsigned long)(a) ) #define PORT_CCS (1) /* port current connect status */ @@ -289,6 +294,16 @@ #define OHCI_ROOT_CRWE (1 << 31) /* Clear RemoteWakeupEnable */ /* + * Root hub A register masks + */ +#define OHCI_ROOT_A_NPS (1 << 9) +#define OHCI_ROOT_A_PSM (1 << 8) + +/* + * Root hub B register masks + */ + +/* * Interrupt register masks */ #define OHCI_INTR_SO (1) @@ -334,8 +349,10 @@ struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */ }; -#define OHCI_TIMER -#define OHCI_TIMER_FREQ (1) /* frequency of OHCI status checks */ +#define OHCI_TIMER /* enable the OHCI timer */ +#define OHCI_TIMER_FREQ (234) /* ms between each root hub status check */ + +#undef OHCI_RHSC_INT /* don't use root hub status interrupts */ /* Debugging code */ void show_ohci_ed(struct ohci_ed *ed); diff -u --recursive --new-file v2.3.1/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c --- v2.3.1/linux/drivers/usb/uhci.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/uhci.c Fri May 14 18:36:17 1999 @@ -418,8 +418,8 @@ struct uhci_device *dev = usb_to_uhci(usb_dev); unsigned long destination, status; struct uhci_td *td; - int ret, i; struct uhci_iso_td *isodesc; + int i; isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL); if (!isodesc) { @@ -700,6 +700,186 @@ return ret; } + +/* + * Bulk thread operations: we just mark the last TD + * in a bulk thread as an interrupt TD, and wake up + * the front-end on completion. + * + * We need to remove the TD from the lists (both interrupt + * list and TD lists) by hand if something bad happens! + */ +static DECLARE_WAIT_QUEUE_HEAD(bulk_wakeup); + +static int uhci_bulk_completed(int status, void *buffer, void *dev_id) +{ + wake_up(&bulk_wakeup); + return 0; /* Don't re-instate */ +} + +/* td points to the last td in the list, which interrupts on completion */ +static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) +{ + DECLARE_WAITQUEUE(wait, current); + struct uhci_qh *bulk_qh = uhci_qh_allocate(dev); + struct uhci_td *curtd; + + + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&bulk_wakeup, &wait); + + uhci_add_irq_list(dev->uhci, last, uhci_bulk_completed, NULL); + + /* FIXME: This is kinda kludged */ + /* Walk the TD list and update the QH pointer */ + { + int maxcount = 100; + + curtd = first; + do { + curtd->qh = bulk_qh; + if (curtd->link & 1) + break; + + curtd = bus_to_virt(curtd->link & ~0xF); + if (!--maxcount) { + printk("runaway tds!\n"); + break; + } + } while (1); + } + + uhci_insert_tds_in_qh(bulk_qh, first, last); + +// bulk0 is empty here... +// show_status(dev->uhci); +// show_queues(dev->uhci); + + /* Add it into the skeleton */ + /*WARNING! HUB HAS NO BULK QH TIL NOW!!!!!!!!!!!*/ + uhci_insert_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh); + +// now we're in the queue... but don't ask WHAT is in there ;-( +// show_status(dev->uhci); +// show_queues(dev->uhci); + + schedule_timeout(HZ/10); + + remove_wait_queue(&bulk_wakeup, &wait); + + /* Clean up in case it failed.. */ + uhci_remove_irq_list(last); + +#if 0 + printk("Looking for tds [%p, %p]\n", dev->control_td, td); +#endif + + /* Remove it from the skeleton */ + uhci_remove_qh(&dev->uhci->root_hub->skel_bulk0_qh, bulk_qh); + + uhci_qh_deallocate(bulk_qh); + + return uhci_td_result(dev, last); +} + +/* + * Send or receive a bulk message on a pipe. + * + * Note that the "pipe" structure is set up to map + * easily to the uhci destination fields. + * + * A bulk message is only built up from + * the data phase + * + * The data phase can be an arbitrary number of TD's + * although we currently had better not have more than + * 31 TD's here. + * + * 31 TD's is a minimum of 248 bytes worth of bulk + * information. + */ +static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *first, *td, *prevtd; + unsigned long destination, status; + int ret; + + if (len > usb_maxpacket(usb_dev->maxpacketsize) * 31) + printk("Warning, too much data for a bulk packet, crashing\n"); + + /* The "pipe" thing contains the destination in bits 8--18, 0x69 is IN */ + /* + IS THIS NECCESARY? PERHAPS WE CAN JUST USE THE PIPE + LOOK AT: usb_pipeout and the pipe bits + I FORGOT WHAT IT EXACTLY DOES + */ + if (usb_pipeout(pipe)) { + destination = (pipe & 0x0007ff00) | 0xE1; + } + else { + destination = (pipe & 0x0007ff00) | 0x69; + } + + /* Status: slow/fast, Active, Short Packet Detect Three Errors */ + status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); + + /* + * Build the TDs for the bulk request + */ + first = td = uhci_td_allocate(dev); + prevtd = first; //This is fake, but at least it's not NULL + while (len > 0) { + /* Build the TD for control status */ + int pktsze = len; + int maxsze = usb_maxpacket(pipe); + + if (pktsze > maxsze) + pktsze = maxsze; + + td->status = status; /* Status */ + td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ + td->buffer = virt_to_bus(data); + td->backptr = &prevtd->link; + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ + + data += maxsze; + len -= maxsze; + /* Alternate Data0/1 (start with Data0) */ + destination ^= 1 << 19; + } + td->link = 1; /* Terminate */ + + /* Start it up.. */ + ret = uhci_run_bulk(dev, first, td); + + { + int maxcount = 100; + struct uhci_td *curtd = first; + unsigned int nextlink; + + do { + nextlink = curtd->link; + uhci_remove_td(curtd); + uhci_td_deallocate(curtd); + if (nextlink & 1) /* Tail? */ + break; + + curtd = bus_to_virt(nextlink & ~0xF); + if (!--maxcount) { + printk("runaway td's!?\n"); + break; + } + } while (1); + } + + return ret; +} + static struct usb_device *uhci_usb_allocate(struct usb_device *parent) { struct usb_device *usb_dev; @@ -787,6 +967,7 @@ uhci_usb_allocate, uhci_usb_deallocate, uhci_control_msg, + uhci_bulk_msg, uhci_request_irq, }; @@ -1399,32 +1580,10 @@ if (retval < 0) continue; -#ifdef CONFIG_USB_MOUSE - usb_mouse_init(); -#endif -#ifdef CONFIG_USB_KBD - usb_kbd_init(); -#endif - hub_init(); -#ifdef CONFIG_USB_AUDIO - usb_audio_init(); -#endif -#ifdef CONFIG_USB_CPIA - cpia_init(); -#endif #ifdef CONFIG_APM apm_register_callback(&handle_apm_event); #endif - return 0; } return retval; -} - -void cleanup_drivers(void) -{ - hub_cleanup(); -#ifdef CONFIG_USB_MOUSE - usb_mouse_cleanup(); -#endif } diff -u --recursive --new-file v2.3.1/linux/drivers/usb/usb.c linux/drivers/usb/usb.c --- v2.3.1/linux/drivers/usb/usb.c Fri May 14 18:55:23 1999 +++ linux/drivers/usb/usb.c Fri May 14 18:43:45 1999 @@ -42,6 +42,55 @@ #include "usb.h" +#ifdef CONFIG_USB_UHCI +int uhci_init(void); +#endif +#ifdef CONFIG_USB_OHCI +int ohci_init(void); +#endif +#ifdef CONFIG_USB_OHCI_HCD +int ohci_hcd_init(void); +#endif + +int usb_init(void) +{ +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI + ohci_init(); +#endif +#ifdef CONFIG_USB_OHCI_HCD + ohci_hcd_init(); +#endif +#ifdef CONFIG_USB_MOUSE + usb_mouse_init(); +#endif +#ifdef CONFIG_USB_KBD + usb_kbd_init(); +#endif +#ifdef CONFIG_USB_AUDIO + usb_audio_init(); +#endif +#ifdef CONFIG_USB_ACM + usb_acm_init(); +#endif +#ifdef CONFIG_USB_CPIA + usb_cpia_init(); +#endif + + usb_hub_init(); + return 0; +} + +void cleanup_drivers(void) +{ + hub_cleanup(); +#ifdef CONFIG_USB_MOUSE + usb_mouse_cleanup(); +#endif +} + /* * We have a per-interface "registered driver" list. */ @@ -596,20 +645,20 @@ int usb_get_configuration(struct usb_device *dev) { - unsigned int cfgno,size; + unsigned int cfgno; unsigned char buffer[400]; unsigned char * bufptr; - bufptr=buffer; - for (cfgno=0;cfgnodescriptor.bNumConfigurations;cfgno++) { + bufptr = buffer; + for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { + unsigned int size; /* Get the first 8 bytes - guaranteed */ if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) return -1; /* Get the full buffer */ size = *(unsigned short *)(bufptr+2); - if (bufptr+size > buffer+sizeof(buffer)) - { + if (bufptr+size > buffer+sizeof(buffer)) { printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); size = buffer+sizeof(buffer)-bufptr; } @@ -617,9 +666,9 @@ return -1; /* Prepare for next configuration */ - bufptr+=size; + bufptr += size; } - return usb_parse_configuration(dev, buffer, size); + return usb_parse_configuration(dev, buffer, bufptr - buffer); } /* diff -u --recursive --new-file v2.3.1/linux/drivers/usb/usb.h linux/drivers/usb/usb.h --- v2.3.1/linux/drivers/usb/usb.h Fri May 14 18:55:23 1999 +++ linux/drivers/usb/usb.h Fri May 14 18:45:36 1999 @@ -6,6 +6,14 @@ #include #include +extern int usb_hub_init(void); +extern int usb_kbd_init(void); +extern int usb_cpia_init(void); +extern int usb_mouse_init(void); + +extern void hub_cleanup(void); +extern void usb_mouse_cleanup(void); + static __inline__ void wait_ms(unsigned int ms) { current->state = TASK_UNINTERRUPTIBLE; @@ -209,6 +217,7 @@ struct usb_device *(*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int); + int (*bulk_msg)(struct usb_device *, unsigned int, void *, int); int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); }; @@ -262,6 +271,7 @@ extern void usb_device_descriptor(struct usb_device *dev); extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); +extern void usb_destroy_configuration(struct usb_device *dev); /* * Calling this entity a "pipe" is glorifying it. A USB pipe diff -u --recursive --new-file v2.3.1/linux/drivers/video/Config.in linux/drivers/video/Config.in --- v2.3.1/linux/drivers/video/Config.in Fri May 14 18:55:23 1999 +++ linux/drivers/video/Config.in Thu May 13 23:48:20 1999 @@ -74,6 +74,7 @@ fi if [ "$ARCH" = "i386" ]; then bool 'VESA VGA graphics console' CONFIG_FB_VESA + bool 'VGA 16-color graphics console' CONFIG_FB_VGA16 define_bool CONFIG_VIDEO_SELECT y fi if [ "$CONFIG_VISWS" = "y" ]; then @@ -141,6 +142,7 @@ tristate 'Atari interleaved bitplanes (8 planes) support' CONFIG_FBCON_IPLAN2P8 # tristate 'Atari interleaved bitplanes (16 planes) support' CONFIG_FBCON_IPLAN2P16 tristate 'Mac variable bpp packed pixels support' CONFIG_FBCON_MAC + bool 'VGA 16-color planar support' CONFIG_FBCON_VGA_PLANES tristate 'VGA characters/attributes support' CONFIG_FBCON_VGA else # Guess what we need @@ -282,6 +284,9 @@ if [ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" ]; then define_bool CONFIG_FBCON_MAC m fi + fi + if [ "$CONFIG_FB_VGA16" = "y" ]; then + define_bool CONFIG_FBCON_VGA_PLANES y fi if [ "$CONFIG_FB_MDA" = "y" -o "$CONFIG_FB_VGA" = "y" ]; then define_bool CONFIG_FBCON_VGA y diff -u --recursive --new-file v2.3.1/linux/drivers/video/Makefile linux/drivers/video/Makefile --- v2.3.1/linux/drivers/video/Makefile Fri May 14 18:55:23 1999 +++ linux/drivers/video/Makefile Thu May 13 23:48:20 1999 @@ -202,6 +202,10 @@ L_OBJS += vesafb.o endif +ifeq ($(CONFIG_FB_VGA16),y) +L_OBJS += vga16fb.o +endif + ifeq ($(CONFIG_FB_VIRGE),y) L_OBJS += virgefb.o else @@ -459,6 +463,14 @@ else ifeq ($(CONFIG_FBCON_MFB),m) MX_OBJS += fbcon-mfb.o + endif +endif + +ifeq ($(CONFIG_FBCON_VGA_PLANES),y) +OX_OBJS += fbcon-vga-planes.o +else + ifeq ($(CONFIG_FBCON_VGA_PLANES),m) + MX_OBJS += fbcon-vga-planes.o endif endif diff -u --recursive --new-file v2.3.1/linux/drivers/video/fbcon-vga-planes.c linux/drivers/video/fbcon-vga-planes.c --- v2.3.1/linux/drivers/video/fbcon-vga-planes.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/video/fbcon-vga-planes.c Thu May 13 23:48:20 1999 @@ -0,0 +1,364 @@ +/* + * linux/drivers/video/fbcon-vga-planes.c -- Low level frame buffer operations + * for VGA 4-plane modes + * + * Copyright 1999 Ben Pfaff and Petr Vandrovec + * Based on code by Michael Schmitz + * Based on the old macfb.c 4bpp code by Alan Cox + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. */ + +#include +#include +#include +#include +#include +#include + +#include + +#include