diff -u --recursive --new-file v2.1.126/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.126/linux/Documentation/Configure.help Fri Oct 23 22:01:18 1998 +++ linux/Documentation/Configure.help Thu Nov 5 09:56:15 1998 @@ -4058,24 +4058,46 @@ say M here and read Documentation/modules.txt. The module will be called NCR53c406.o. -Tekram DC390(T) (AMD PCscsi) SCSI support +Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support CONFIG_SCSI_DC390T - This driver supports the Tekram DC390(T) PCI SCSI host adapter with - the Am53C974A chip, and perhaps other cards using the same chip. - This driver does _not_ support the DC390W/U/F adaptor with the - NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one. + This driver supports PCI SCSI host adapters based on the Am53C974A + chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard + PCscsi/PCnet (Am53/79C974) solutions. + Documentation can be found in linux/drivers/scsi/README.tmscsim. + + Note that this driver does NOT support Tekram DC390W/U/F, which are + based on NCR/Symbios chips. Use the NCR53C8XX driver for those. + Also note, that there is another generic Am53C974 driver. If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be called tmscsim.o. +Skip support for other Am53/79C974 based SCSI adapters +CONFIG_SCSI_DC390T_NOGENSUPP + Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get + initial values for its settings, such as speed, termination, etc. + If it can't find this EEPROM, it will use defaults or the user + supplied boot/module parameters. For details on driver configuration + see linux/drivers/scsi/README.tmscsim. + + With this option set, if no EEPROM is found, the driver gives up and + thus only supports Tekram DC390(T) adapters. This can be useful if + you have a DC390(T) and another Am53C974 based adapter, which, for + some reason, you want to drive with the other AM53C974 driver. + + If unsure, say N. + AM53/79C974 PCI SCSI support CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. + + Note that there is another driver for AM53C974 based adapters: The + Tekram DC390(T) driver. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), @@ -7224,10 +7246,10 @@ Specialix IO8+ card support CONFIG_SPECIALIX - This is a driver for the Specialix IO8+ multiport card which gives - you many serial ports. You would need something like this to - connect more than two modems to your Linux box, for instance in - order to become a BBS. + This is a driver for the Specialix IO8+ multiport card (both the + ISA and the PCI version) which gives you many serial ports. You + would need something like this to connect more than two modems to + your Linux box, for instance in order to become a BBS. If you have a card like that, say Y here and read the file Documentation/specialix.txt. Also it's possible to say M here and diff -u --recursive --new-file v2.1.126/linux/Documentation/cdrom/ide-cd linux/Documentation/cdrom/ide-cd --- v2.1.126/linux/Documentation/cdrom/ide-cd Mon Aug 3 12:45:43 1998 +++ linux/Documentation/cdrom/ide-cd Sat Oct 24 10:43:47 1998 @@ -1,6 +1,8 @@ IDE-CD driver documentation Originally by scott snyder (19 May 1996) Carrying on the torch is: Erik Andersen +New maintainers (19 Oct 1998): Jens Axboe + Chris Zwilling 1. Introduction --------------- diff -u --recursive --new-file v2.1.126/linux/Documentation/specialix.txt linux/Documentation/specialix.txt --- v2.1.126/linux/Documentation/specialix.txt Sat May 2 14:19:52 1998 +++ linux/Documentation/specialix.txt Wed Oct 28 22:04:05 1998 @@ -17,7 +17,10 @@ written by Dmitry Gorodchanin. The specialix IO8+ card programming information was obtained from the CL-CD1865 Data Book, and Specialix document number 6200059: IO8+ Hardware - Functional Specification. + Functional Specification, augmented by document number 6200088: + Merak Hardware Functional Specification. (IO8+/PCI is also + called Merak) + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -67,6 +70,9 @@ other computer runs just fine with the Specialix card at 0x100.... The card occupies 4 addresses, but actually only two are really used. +The PCI version doesn't have any dip switches. The BIOS assigns +an IO address. + The driver now still autoprobes at 0x100, 0x180, 0x250 and 0x260. If that causes trouble for you, please report that. I'll remove autoprobing then. @@ -75,6 +81,9 @@ change any jumpers to change the IRQ. Just use a command line argument (irq=xx) to the insmod program to set the interrupt. +The BIOS assigns the IRQ on the PCI version. You have no say in what +IRQ to use in that case. + If your specialix cards are not at the default locations, you can use the kernel command line argument "specialix=io0,irq0,io1,irq1...". Here "io0" is the io address for the first card, and "irq0" is the @@ -99,6 +108,32 @@ in your /etc/lilo.conf file if you use lilo. +The Specialix driver is slightly odd: It allows you to have the second +or third card detected without having a first card. This has +advantages and disadvantages. A slot that isn't filled by an ISA card, +might be filled if a PCI card is detected. Thus if you have an ISA +card at 0x250 and a PCI card, you would get: + +sx0: specialix IO8+ Board at 0x100 not found. +sx1: specialix IO8+ Board at 0x180 not found. +sx2: specialix IO8+ board detected at 0x250, IRQ 12, CD1865 Rev. B. +sx3: specialix IO8+ Board at 0x260 not found. +sx0: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B. + +This would happen if you don't give any probe hints to the driver. +If you would specify: + + specialix=0x250,11 + +you'd get the following messages: + +sx0: specialix IO8+ board detected at 0x250, IRQ 11, CD1865 Rev. B. +sx1: specialix IO8+ board detected at 0xd800, IRQ 9, CD1865 Rev. B. + +ISA probing is aborted after the IO address you gave is exhausted, and +the PCI card is now detected as the second card. The ISA card is now +also forced to IRQ11.... + Baud rates ========== @@ -118,20 +153,26 @@ If you near the "limit" you will first start to see a graceful degradation in that the chip cannot keep the transmitter busy at all times. However with a central clock this slow, you can also get it to -miss incoming characters. +miss incoming characters. The driver will print a warning message when +you are outside the official specs. The messages usually show up in +the file /var/log/messages . The specialix card cannot reliably do 115k2. If you use it, you have to do "extensive testing" (*) to verify if it actually works. When "mgetty" communicates with my modem at 115k2 it reports: got: +++[0d]ATQ0V1H0[0d][0d][8a]O[cb][0d][8a] - ^^^^ ^^^^ ^^^^ + ^^^^ ^^^^ ^^^^ The three characters that have the "^^^" under them have suffered a bit error in the highest bit. In conclusion: I've tested it, and found that it simply DOESN'T work for me. I also suspect that this is also caused by the baud rate being just a little bit out of tune. +I upgraded the crystal to 66Mhz on one of my Specialix cards. Works +great! Contact me for details. (Voids warranty, requires a steady hand +and more such restrictions....) + (*) Cirrus logic CD1864 databook, page 40. @@ -248,7 +289,7 @@ Ports and devices ================= -Port 0 is the one furthest from the ISA connector. +Port 0 is the one furthest from the card-edge connector. Devices: @@ -265,10 +306,20 @@ done echo "" +If your system doesn't come with these devices preinstalled, bug your +linux-vendor about this. They have had ample time to get this +implemented by now. You cannot have more than 4 boards in one computer. The card only supports 4 different interrupts. If you really want this, contact me about this and I'll give you a few tips (requires soldering iron).... + +If you have enough PCI slots, you can probably use more than 4 PCI +versions of the card though.... + +The PCI version of the card cannot adhere to the mechanical part of +the PCI spec because the 8 serial connectors are simply too large. If +it doesn't fit in your computer, bring back the card. ------------------------------------------------------------------------ diff -u --recursive --new-file v2.1.126/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.126/linux/MAINTAINERS Fri Oct 23 22:01:19 1998 +++ linux/MAINTAINERS Tue Oct 27 10:10:08 1998 @@ -186,6 +186,12 @@ L: linux-hams@vger.rutgers.edu S: Maintained +DC390/AM53C974 SCSI driver +P: Kurt Garloff +M: K.Garloff@ping.de +W: ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ +S: Maintained + DECnet NETWORK LAYER P: Steven Whitehouse M: SteveW@ACM.org @@ -328,8 +334,10 @@ S: Odd Fixes IDE/ATAPI CDROM DRIVER -P: Erik Andersen -M: andersee@debian.org +P: Jens Axboe +M: axboe@image.dk +P: Chris Zwilling +M: chris@cloudnet.com L: linux-kernel@vger.rutgers.edu S: Maintained @@ -671,8 +679,10 @@ S: Maintained UNIFORM CDROM DRIVER -P: Erik Andersen -M: andersee@debian.org +P: Jens Axboe +M: axboe@image.dk +P: Chris Zwilling +M: chris@cloudnet.com L: linux-kernel@vger.rutgers.edu S: Maintained diff -u --recursive --new-file v2.1.126/linux/Makefile linux/Makefile --- v2.1.126/linux/Makefile Fri Oct 23 22:01:19 1998 +++ linux/Makefile Fri Oct 23 22:03:09 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 126 +SUBLEVEL = 127 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.1.126/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.1.126/linux/arch/alpha/defconfig Wed Sep 9 14:51:03 1998 +++ linux/arch/alpha/defconfig Wed Oct 28 22:10:04 1998 @@ -241,7 +241,6 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.126/linux/arch/alpha/kernel/osf_sys.c Thu Sep 17 17:53:34 1998 +++ linux/arch/alpha/kernel/osf_sys.c Thu Nov 5 09:58:29 1998 @@ -1306,6 +1306,7 @@ { struct timeval tmp; unsigned long ticks; + unsigned long tmp_timeout; if (get_tv32(&tmp, sleep)) goto fault; @@ -1313,18 +1314,11 @@ ticks = tmp.tv_usec; ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ); ticks += tmp.tv_sec * HZ; - current->timeout = ticks + jiffies; - current->state = TASK_INTERRUPTIBLE; - schedule(); + current->state = TASK_INTERRUPTIBLE; + ticks = schedule_timeout(ticks); if (remain) { - ticks = jiffies; - if (ticks < current->timeout) - ticks = current->timeout - ticks; - else - ticks = 0; - current->timeout = 0; tmp.tv_sec = ticks / HZ; tmp.tv_usec = ticks % HZ; if (put_tv32(remain, &tmp)) diff -u --recursive --new-file v2.1.126/linux/arch/alpha/kernel/sys_sio.c linux/arch/alpha/kernel/sys_sio.c --- v2.1.126/linux/arch/alpha/kernel/sys_sio.c Tue Aug 18 22:02:02 1998 +++ linux/arch/alpha/kernel/sys_sio.c Tue Oct 27 23:02:57 1998 @@ -110,6 +110,9 @@ * * This probably ought to be configurable via MILO. For * example, sound boards seem to like using IRQ 9. + * + * This is NOT how we should do it. PIRQ0-X should have + * their own IRQ's, the way intel uses the IO-APIC irq's. */ static unsigned long sio_route_tab __initdata = 0; @@ -238,7 +241,7 @@ avanti_pci_fixup(void) { layout_all_busses(DEFAULT_IO_BASE, APECS_AND_LCA_DEFAULT_MEM_BASE); - sio_pci_fixup(noname_map_irq, 0x0b0a090f); + sio_pci_fixup(noname_map_irq, 0x0b0a0e0f); sio_fixup_irq_levels(sio_collect_irq_levels()); enable_ide(0x26e); } diff -u --recursive --new-file v2.1.126/linux/arch/i386/boot/tools/build.c linux/arch/i386/boot/tools/build.c --- v2.1.126/linux/arch/i386/boot/tools/build.c Wed Jun 24 22:54:03 1998 +++ linux/arch/i386/boot/tools/build.c Sun Oct 25 14:16:21 1998 @@ -151,7 +151,7 @@ if (setup_sectors < SETUP_SECTS) setup_sectors = SETUP_SECTS; fprintf(stderr, "Setup is %d bytes.\n", i); - memset(buf, sizeof(buf), 0); + memset(buf, 0, sizeof(buf)); while (i < setup_sectors * 512) { c = setup_sectors * 512 - i; if (c > sizeof(buf)) diff -u --recursive --new-file v2.1.126/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.126/linux/arch/i386/defconfig Fri Oct 23 22:01:19 1998 +++ linux/arch/i386/defconfig Wed Nov 4 11:27:42 1998 @@ -146,8 +146,7 @@ # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_IN2000 is not set # CONFIG_SCSI_AM53C974 is not set -CONFIG_SCSI_BUSLOGIC=y -CONFIG_SCSI_OMIT_FLASHPOINT=y +# CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_DTC3280 is not set # CONFIG_SCSI_EATA_DMA is not set # CONFIG_SCSI_EATA_PIO is not set @@ -157,7 +156,12 @@ # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set # CONFIG_SCSI_NCR53C7xx is not set -# CONFIG_SCSI_NCR53C8XX is not set +CONFIG_SCSI_NCR53C8XX=y +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 +CONFIG_SCSI_NCR53C8XX_SYNC=20 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set +# CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set diff -u --recursive --new-file v2.1.126/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.126/linux/arch/i386/kernel/entry.S Thu Sep 17 17:53:34 1998 +++ linux/arch/i386/kernel/entry.S Tue Oct 27 10:20:47 1998 @@ -107,7 +107,7 @@ 2: popl %es; \ addl $4,%esp; \ 3: iret; \ -.section fixup,"ax"; \ +.section .fixup,"ax"; \ 4: movl $0,(%esp); \ jmp 1b; \ 5: movl $0,(%esp); \ diff -u --recursive --new-file v2.1.126/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.126/linux/arch/i386/kernel/setup.c Fri Oct 23 22:01:19 1998 +++ linux/arch/i386/kernel/setup.c Sat Oct 31 14:23:34 1998 @@ -81,6 +81,7 @@ extern int root_mountflags; extern int _etext, _edata, _end; +extern unsigned long cpu_hz; /* * This is set up by the setup-routine at boot-time @@ -617,6 +618,11 @@ p += sprintf(p, "stepping\t: %d\n", c->x86_mask); } else p += sprintf(p, "stepping\t: unknown\n"); + + if (c->x86_capability & X86_FEATURE_TSC) { + p += sprintf(p, "cpu MHz\t\t: %lu.%06lu\n", + cpu_hz / 1000000, (cpu_hz % 1000000)); + } /* Cache size */ if (c->x86_cache_size >= 0) diff -u --recursive --new-file v2.1.126/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.126/linux/arch/i386/mm/fault.c Fri Oct 9 13:27:05 1998 +++ linux/arch/i386/mm/fault.c Tue Oct 27 10:18:35 1998 @@ -156,7 +156,14 @@ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } - handle_mm_fault(tsk, vma, address, write); + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + if (!handle_mm_fault(tsk, vma, address, write)) + goto do_sigbus; /* * Did it hit the DOS screen memory VA from vm86 mode? @@ -243,4 +250,24 @@ } die("Oops", regs, error_code); do_exit(SIGKILL); + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +do_sigbus: + up(&mm->mmap_sem); + + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->tss.cr2 = address; + tsk->tss.error_code = error_code; + tsk->tss.trap_no = 14; + force_sig(SIGBUS, tsk); + + /* Kernel mode? Handle exceptions or die */ + if (!(error_code & 4)) + goto no_context; } diff -u --recursive --new-file v2.1.126/linux/arch/m68k/atari/time.c linux/arch/m68k/atari/time.c --- v2.1.126/linux/arch/m68k/atari/time.c Tue Jun 23 10:01:20 1998 +++ linux/arch/m68k/atari/time.c Thu Nov 5 09:58:29 1998 @@ -279,8 +279,7 @@ while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HWCLK_POLL_INTERVAL; - schedule(); + schedule_timeout(HWCLK_POLL_INTERVAL); } save_flags(flags); diff -u --recursive --new-file v2.1.126/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c --- v2.1.126/linux/arch/mips/kernel/irixsig.c Fri Oct 23 22:01:19 1998 +++ linux/arch/mips/kernel/irixsig.c Thu Nov 5 09:58:29 1998 @@ -568,7 +568,7 @@ asmlinkage int irix_sigpoll_sys(unsigned long *set, struct irix5_siginfo *info, struct timespec *tp) { - unsigned long expire = 0; + long expire = MAX_SCHEDULE_TIMEOUT; sigset_t kset; int i, sig, error, timeo = 0; @@ -603,21 +603,21 @@ error = -EINVAL; goto out; } - expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec)+jiffies; - current->timeout = expire; + expire = timespectojiffies(tp)+(tp->tv_sec||tp->tv_nsec); } while(1) { long tmp = 0; - current->state = TASK_INTERRUPTIBLE; schedule(); + current->state = TASK_INTERRUPTIBLE; + expire = schedule_timeout(expire); for (i=0; i<=4; i++) tmp |= (current->signal.sig[i] & kset.sig[i]); if (tmp) break; - if (tp && expire <= jiffies) { + if (!expire) { timeo = 1; break; } diff -u --recursive --new-file v2.1.126/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c --- v2.1.126/linux/arch/mips/kernel/sysirix.c Fri Oct 23 22:01:19 1998 +++ linux/arch/mips/kernel/sysirix.c Thu Nov 5 09:58:29 1998 @@ -1081,13 +1081,8 @@ asmlinkage int irix_sginap(int ticks) { - lock_kernel(); - if(ticks) { - current->timeout = ticks + jiffies; - current->state = TASK_INTERRUPTIBLE; - } - schedule(); - unlock_kernel(); + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(ticks); return 0; } diff -u --recursive --new-file v2.1.126/linux/arch/mips/sgi/kernel/indy_sc.c linux/arch/mips/sgi/kernel/indy_sc.c --- v2.1.126/linux/arch/mips/sgi/kernel/indy_sc.c Fri Oct 23 22:01:20 1998 +++ linux/arch/mips/sgi/kernel/indy_sc.c Mon Oct 26 09:57:55 1998 @@ -5,7 +5,6 @@ * Copyright (C) 1997 Ralf Baechle (ralf@gnu.org), * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com). */ -#include #include #include #include diff -u --recursive --new-file v2.1.126/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c --- v2.1.126/linux/arch/mips/sgi/kernel/setup.c Fri Oct 23 22:01:20 1998 +++ linux/arch/mips/sgi/kernel/setup.c Mon Oct 26 09:57:55 1998 @@ -5,6 +5,7 @@ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org) */ +#include #include #include #include diff -u --recursive --new-file v2.1.126/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c --- v2.1.126/linux/arch/ppc/8xx_io/uart.c Mon Oct 5 13:13:35 1998 +++ linux/arch/ppc/8xx_io/uart.c Thu Nov 5 09:58:29 1998 @@ -1314,12 +1314,11 @@ static void send_break(ser_info_t *info, int duration) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; #ifdef SERIAL_DEBUG_SEND_BREAK printk("rs_send_break(%d) jiff=%lu...", duration, jiffies); #endif begin_break(info); - schedule(); + schedule_timeout(duration); end_break(info); #ifdef SERIAL_DEBUG_SEND_BREAK printk("done jiffies=%lu\n", jiffies); @@ -1633,8 +1632,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -1691,8 +1689,7 @@ #endif current->state = TASK_INTERRUPTIBLE; /* current->counter = 0; make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) diff -u --recursive --new-file v2.1.126/linux/arch/ppc/apus_defconfig linux/arch/ppc/apus_defconfig --- v2.1.126/linux/arch/ppc/apus_defconfig Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/apus_defconfig Wed Oct 28 22:10:05 1998 @@ -297,7 +297,6 @@ # CONFIG_UNIX98_PTYS is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/chrp_defconfig linux/arch/ppc/chrp_defconfig --- v2.1.126/linux/arch/ppc/chrp_defconfig Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/chrp_defconfig Wed Oct 28 22:10:05 1998 @@ -265,7 +265,6 @@ # CONFIG_MOUSE is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig --- v2.1.126/linux/arch/ppc/common_defconfig Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/common_defconfig Wed Oct 28 22:10:05 1998 @@ -287,7 +287,6 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/defconfig linux/arch/ppc/defconfig --- v2.1.126/linux/arch/ppc/defconfig Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/defconfig Wed Oct 28 22:10:05 1998 @@ -296,7 +296,6 @@ # CONFIG_MOUSE is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig --- v2.1.126/linux/arch/ppc/mbx_defconfig Thu Aug 6 14:06:29 1998 +++ linux/arch/ppc/mbx_defconfig Wed Oct 28 22:10:05 1998 @@ -171,7 +171,6 @@ # CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_MOUSE is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig --- v2.1.126/linux/arch/ppc/pmac_defconfig Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/pmac_defconfig Wed Oct 28 22:10:05 1998 @@ -296,7 +296,6 @@ # CONFIG_MOUSE is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig --- v2.1.126/linux/arch/ppc/prep_defconfig Mon Oct 5 13:13:36 1998 +++ linux/arch/ppc/prep_defconfig Wed Oct 28 22:10:05 1998 @@ -246,7 +246,6 @@ # CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set -# CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set # CONFIG_VIDEO_DEV is not set diff -u --recursive --new-file v2.1.126/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile --- v2.1.126/linux/arch/sparc/boot/Makefile Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/boot/Makefile Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.8 1998/09/16 12:24:51 jj Exp $ +# $Id: Makefile,v 1.9 1998/10/26 20:01:03 davem Exp $ # Makefile for the Sparc boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -26,6 +26,10 @@ $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \ $(NETWORKS) $(DRIVERS) +# I wanted to make this depend upon BTOBJS so that a parallel +# build would work, but this fails because $(HEAD) cannot work +# properly as it will cause head.o to be built with the implicit +# rules not the ones in kernel/Makefile. Someone please fix. --DaveM vmlinux.o: dummy $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o diff -u --recursive --new-file v2.1.126/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.126/linux/arch/sparc/defconfig Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/defconfig Tue Oct 27 09:52:20 1998 @@ -21,6 +21,7 @@ CONFIG_VT_CONSOLE=y # CONFIG_AP1000 is not set # CONFIG_SUN4 is not set +# CONFIG_PCI is not set # # Console drivers @@ -67,6 +68,7 @@ # CONFIG_SPARCAUDIO is not set # CONFIG_SPARCAUDIO_AMD7930 is not set # CONFIG_SPARCAUDIO_CS4231 is not set +# CONFIG_SPARCAUDIO_DBRI is not set CONFIG_SUN_OPENPROMFS=m CONFIG_NET=y CONFIG_SYSVIPC=y @@ -74,7 +76,7 @@ CONFIG_SYSCTL=y CONFIG_BINFMT_AOUT=y CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y +CONFIG_BINFMT_MISC=m CONFIG_BINFMT_JAVA=m # @@ -82,51 +84,32 @@ # CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=y -CONFIG_MD_STRIPED=y +CONFIG_MD_LINEAR=m +CONFIG_MD_STRIPED=m CONFIG_MD_MIRRORING=m CONFIG_MD_RAID5=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m -# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_NBD=m # # Networking options # CONFIG_PACKET=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -# CONFIG_NETLINK_DEV is not set -CONFIG_FIREWALL=y -CONFIG_NET_ALIAS=y +# CONFIG_NETLINK is not set +# CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -CONFIG_IP_MULTICAST=y +# CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -CONFIG_IP_FIREWALL=y -# CONFIG_IP_FIREWALL_NETLINK is not set -# CONFIG_IP_TRANSPARENT_PROXY is not set -# CONFIG_IP_ALWAYS_DEFRAG is not set -CONFIG_IP_MASQUERADE=y - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_MASQUERADE_ICMP is not set - -# -# Protocol-specific masquerading support will be built as modules. -# -# CONFIG_IP_MASQUERADE_MOD is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set -CONFIG_IP_ALIAS=y -# CONFIG_ARPD is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # @@ -135,7 +118,7 @@ CONFIG_INET_RARP=m CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y -CONFIG_IPV6=y +CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set # @@ -145,7 +128,7 @@ # CONFIG_IPX_INTERN is not set # CONFIG_SPX is not set CONFIG_ATALK=m -CONFIG_X25=m +# CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set @@ -154,18 +137,7 @@ # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set -CONFIG_NET_SCHED=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_CSZ=m -CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -# CONFIG_NET_SCH_TEQL is not set -CONFIG_NET_SCH_TBF=y -# CONFIG_NET_QOS is not set -# CONFIG_NET_CLS is not set +# CONFIG_NET_SCHED is not set # # ISDN subsystem @@ -184,7 +156,7 @@ CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y -CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SG=m # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -235,21 +207,22 @@ # # Filesystems # -CONFIG_QUOTA=y +# CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y +CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set +CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -267,13 +240,12 @@ CONFIG_ROMFS_FS=m CONFIG_AUTOFS_FS=m CONFIG_AMIGA_PARTITION=y -CONFIG_UFS_FS=y +CONFIG_UFS_FS=m CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y -# CONFIG_SOLARIS_X86_PARTITION is not set +CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_ADFS_FS is not set -CONFIG_QNX4FS_FS=m -# CONFIG_QNX4FS_RW is not set +# CONFIG_QNX4FS_FS is not set # CONFIG_MAC_PARTITION is not set CONFIG_NLS=y diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c --- v2.1.126/linux/arch/sparc/kernel/devices.c Thu Apr 23 20:21:30 1998 +++ linux/arch/sparc/kernel/devices.c Tue Oct 27 09:52:20 1998 @@ -1,5 +1,5 @@ /* devices.c: Initial scan of the prom device tree for important - * Sparc device nodes which we need to find. + * Sparc device nodes which we need to find. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ @@ -14,8 +14,8 @@ #include #include -struct prom_cpuinfo linux_cpus[NR_CPUS]; -int linux_num_cpus; +struct prom_cpuinfo linux_cpus[32]; +int linux_num_cpus = 0; extern void cpu_probe(void); extern void clock_stop_probe(void); /* tadpole.c */ @@ -25,64 +25,55 @@ device_scan(unsigned long mem_start)) { char node_str[128]; - int nd, prom_node_cpu, thismid; - int cpu_nds[NR_CPUS]; /* One node for each cpu */ - int cpu_ctr = 0; + int thismid; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { - cpu_nds[0] = prom_root_node; - cpu_ctr++; + linux_num_cpus++; } else { int scan; scan = prom_getchild(prom_root_node); prom_printf("root child is %08lx\n", (unsigned long) scan); - nd = 0; while((scan = prom_getsibling(scan)) != 0) { prom_getstring(scan, "device_type", node_str, sizeof(node_str)); if(strcmp(node_str, "cpu") == 0) { - cpu_nds[cpu_ctr] = scan; - linux_cpus[cpu_ctr].prom_node = scan; + linux_cpus[linux_num_cpus].prom_node = scan; prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); - linux_cpus[cpu_ctr].mid = thismid; + linux_cpus[linux_num_cpus].mid = thismid; prom_printf("Found CPU %d \n", - cpu_ctr, (unsigned long) scan, + linux_num_cpus, (unsigned long) scan, thismid); - cpu_ctr++; + linux_num_cpus++; } }; - if(cpu_ctr == 0) { + if(linux_num_cpus == 0) { if (sparc_cpu_model == sun4d) { scan = prom_getchild(prom_root_node); for (scan = prom_searchsiblings(scan, "cpu-unit"); scan; scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) { int node = prom_getchild(scan); - + prom_getstring(node, "device_type", node_str, sizeof(node_str)); if (strcmp(node_str, "cpu") == 0) { prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid)); - cpu_nds[cpu_ctr] = node; - linux_cpus[cpu_ctr].prom_node = node; - linux_cpus[cpu_ctr].mid = thismid; + linux_cpus[linux_num_cpus].prom_node = node; + linux_cpus[linux_num_cpus].mid = thismid; prom_printf("Found CPU %d \n", - cpu_ctr, (unsigned long) node, + linux_num_cpus, (unsigned long) node, thismid); - cpu_ctr++; + linux_num_cpus++; } } } } - if(cpu_ctr == 0) { + if(linux_num_cpus == 0) { printk("No CPU nodes found, cannot continue.\n"); /* Probably a sun4e, Sun is trying to trick us ;-) */ halt(); } - printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); + printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus); }; - prom_node_cpu = cpu_nds[0]; - - linux_num_cpus = cpu_ctr; cpu_probe(); #ifdef CONFIG_SUN_AUXIO diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/ebus.c linux/arch/sparc/kernel/ebus.c --- v2.1.126/linux/arch/sparc/kernel/ebus.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/ebus.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.1 1998/09/18 10:43:43 jj Exp $ +/* $Id: ebus.c,v 1.2 1998/10/07 11:35:16 jj Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -141,6 +141,9 @@ (unsigned long)sparc_alloc_io (dev->base_address[i], 0, regs[i].reg_size, dev->prom_name, 0, 0); + /* Some drivers call 'check_region', so we release it */ + release_region(dev->base_address[i] & PAGE_MASK, PAGE_SIZE); + if (dev->base_address[i] == 0 ) { panic("ebus: unable sparc_alloc_io for dev %s", dev->prom_name); diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/init_task.c linux/arch/sparc/kernel/init_task.c --- v2.1.126/linux/arch/sparc/kernel/init_task.c Thu Apr 23 20:21:30 1998 +++ linux/arch/sparc/kernel/init_task.c Tue Oct 27 09:52:20 1998 @@ -6,7 +6,7 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct files * init_fd_array[NR_OPEN] = { NULL, }; +static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM; diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v2.1.126/linux/arch/sparc/kernel/irq.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/irq.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.89 1998/09/21 05:05:12 jj Exp $ +/* $Id: irq.c,v 1.91 1998/10/14 07:04:17 jj Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device @@ -8,6 +8,7 @@ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@metabyte.com) * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) */ #include @@ -191,13 +192,9 @@ restore_flags(flags); } -/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ +/* Per-processor IRQ and bh locking depth, both SMP and non-SMP code use this. */ +unsigned int local_bh_count[NR_CPUS]; unsigned int local_irq_count[NR_CPUS]; -#ifdef __SMP__ -atomic_t __sparc_bh_counter = ATOMIC_INIT(0); -#else -int __sparc_bh_counter = 0; -#endif #ifdef __SMP__ /* SMP interrupt locking on Sparc. */ @@ -208,14 +205,33 @@ /* This protects IRQ's. */ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; - /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); +atomic_t global_bh_count = ATOMIC_INIT(0); +atomic_t global_bh_lock = ATOMIC_INIT(0); + +/* This protects BH software state (masks, things like that). */ +spinlock_t sparc_bh_lock = SPIN_LOCK_UNLOCKED; + #ifdef DEBUG_IRQLOCK +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("wait_on_bh CPU#%d stuck at %08lx\n", cpu, where); stuck = INIT_STUCK; } + +static inline void wait_on_bh(int cpu, unsigned long where) +{ + int stuck = INIT_STUCK; + do { + STUCK; + /* nothing .. wait for the other bh's to go away */ + } while (atomic_read(&global_bh_count) != 0); +} + static unsigned long previous_irqholder; #undef INIT_STUCK @@ -225,36 +241,83 @@ #define STUCK \ if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } +/* + * We have to allow irqs to arrive between __sti and __cli + */ +#define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") + static inline void wait_on_irq(int cpu, unsigned long where) { int stuck = INIT_STUCK; int local_count = local_irq_count[cpu]; - /* Are we the only one in an interrupt context? */ - while (local_count != atomic_read(&global_irq_count)) { + for (;;) { + /* - * No such luck. Now we need to release the lock, - * _and_ release our interrupt context, because - * otherwise we'd have dead-locks and live-locks - * and other fun things. + * Wait until all interrupts are gone. Wait + * for bottom half handlers unless we're + * already executing in one.. */ - atomic_sub(local_count, &global_irq_count); + if (!atomic_read(&global_irq_count)) { + if (local_bh_count[cpu] || !atomic_read(&global_bh_count)) + break; + } + + /* Duh, we have to loop. Release the lock to avoid deadlocks */ spin_unlock(&global_irq_lock); - /* - * Wait for everybody else to go away and release - * their things before trying to get the lock again. - */ for (;;) { STUCK; + + __sti(); + SYNC_OTHER_CORES(cpu); + __cli(); + if (atomic_read(&global_irq_count)) continue; if (*((unsigned char *)&global_irq_lock)) continue; + if (!local_bh_count[cpu] && atomic_read(&global_bh_count)) + continue; if (spin_trylock(&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); + } +} + +/* + * This is called when we want to synchronize with + * bottom half handlers. We need to wait until + * no other CPU is executing any bottom half handler. + * + * Don't wait if we're already running in an interrupt + * context or are inside a bh handler. + */ +void synchronize_bh(void) +{ + unsigned long where; + + __asm__("mov %%i7, %0" : "=r" (where)); + + if (atomic_read(&global_bh_count) && !in_interrupt()) { + int cpu = smp_processor_id(); + wait_on_bh(cpu, where); + } +} + +/* + * This is called when we want to synchronize with + * interrupts. We may for example tell a device to + * stop sending interrupts: but to make sure there + * are no interrupts that are executing on another + * CPU we need to call this function. + */ +void synchronize_irq(void) +{ + if (atomic_read(&global_irq_count)) { + /* Stupid approach */ + cli(); + sti(); } } @@ -281,54 +344,106 @@ } while (*((volatile unsigned char *)&global_irq_lock)); } while (!spin_trylock(&global_irq_lock)); } - /* - * Ok, we got the lock bit. - * But that's actually just the easy part.. Now - * we need to make sure that nobody else is running + /* + * We also to make sure that nobody else is running * in an interrupt context. */ wait_on_irq(cpu, where); /* - * Finally. + * Ok, finally.. */ global_irq_holder = cpu; previous_irqholder = where; } +/* + * A global "cli()" while in an interrupt context + * turns into just a local cli(). Interrupts + * should use spinlocks for the (very unlikely) + * case that they ever want to protect against + * each other. + * + * If we already have local interrupts disabled, + * this will not turn a local disable into a + * global one (problems with spinlocks: this makes + * save_flags+cli+sti usable inside a spinlock). + */ void __global_cli(void) { - int cpu = smp_processor_id(); + unsigned int flags; unsigned long where; __asm__("mov %%i7, %0" : "=r" (where)); - __cli(); - get_irqlock(cpu, where); + + __save_flags(flags); + + if ((flags & PSR_PIL) != PSR_PIL) { + int cpu = smp_processor_id(); + __cli(); + if (!local_irq_count[cpu]) + get_irqlock(cpu, where); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); + int cpu = smp_processor_id(); + + if (!local_irq_count[cpu]) + release_irqlock(cpu); __sti(); } +/* + * SMP flags value to restore to: + * 0 - global cli + * 1 - global sti + * 2 - local cli + * 3 - local sti + */ unsigned long __global_save_flags(void) { - return global_irq_holder == (unsigned char) smp_processor_id(); + int retval; + int local_enabled = 0; + unsigned long flags; + + __save_flags(flags); + + if ((flags & PSR_PIL) != PSR_PIL) + local_enabled = 1; + + /* default to local */ + retval = 2 + local_enabled; + + /* check for global flags if we're not in an interrupt */ + if (!local_irq_count[smp_processor_id()]) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; + } + return retval; } void __global_restore_flags(unsigned long flags) { - if(flags & 1) { + switch (flags) { + case 0: __global_cli(); - } else { - /* release_irqlock() */ - if(global_irq_holder == smp_processor_id()) { - global_irq_holder = NO_PROC_ID; - spin_unlock(&global_irq_lock); - } - if(!(flags & 2)) - __sti(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + printk("global_restore_flags: %08lx (%08lx)\n", + flags, (&flags)[-1]); } } @@ -353,7 +468,7 @@ while (*((volatile unsigned char *)&global_irq_lock)) { if ((unsigned char) cpu == global_irq_holder) { struct pt_regs *regs = _opaque; - int sbh_cnt = atomic_read(&__sparc_bh_counter); + int sbh_cnt = atomic_read(&global_bh_count); int globl_locked = *((unsigned char *)&global_irq_lock); int globl_icount = atomic_read(&global_irq_count); int local_count = local_irq_count[cpu]; @@ -386,24 +501,6 @@ } #endif /* DEBUG_IRQLOCK */ - -/* There has to be a better way. */ -void synchronize_irq(void) -{ - int cpu = smp_processor_id(); - int local_count = local_irq_count[cpu]; - - if(local_count != atomic_read(&global_irq_count)) { - unsigned long flags; - - /* See comment below at __global_save_flags to understand - * why we must do it this way on Sparc. - */ - save_and_cli(flags); - restore_flags(flags); - } -} - #endif /* __SMP__ */ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) @@ -511,12 +608,13 @@ /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if (irqflags & SA_STATIC_ALLOC) + if (irqflags & SA_STATIC_ALLOC) { if (static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n", irq, devname); + } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), @@ -604,11 +702,12 @@ /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if (irqflags & SA_STATIC_ALLOC) + if (irqflags & SA_STATIC_ALLOC) { if (static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname); + } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/pcic.c linux/arch/sparc/kernel/pcic.c --- v2.1.126/linux/arch/sparc/kernel/pcic.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/pcic.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: pcic.c,v 1.2 1998/09/29 03:21:56 jj Exp $ +/* $Id: pcic.c,v 1.3 1998/10/07 11:34:56 jj Exp $ * pcic.c: Sparc/PCI controller support * * Copyright (C) 1998 V. Roganov and G. Raiko @@ -83,7 +83,7 @@ int node; int err; - if (pci_present()) { + if (pcibios_present()) { prom_printf("PCIC: called twice!\n"); prom_halt(); } @@ -426,7 +426,7 @@ /* A hack until do_gettimeofday prototype is moved to arch specific headers and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */ ((unsigned int *)do_gettimeofday)[0] = - 0x10800000 | (((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) & 0x003fffff); + 0x10800000 | ((((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) >> 2) & 0x003fffff); ((unsigned int *)do_gettimeofday)[1] = 0x01000000; BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM); diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v2.1.126/linux/arch/sparc/kernel/signal.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/signal.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.86 1998/09/29 09:46:04 davem Exp $ +/* $Id: signal.c,v 1.90 1998/10/18 03:31:05 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -75,6 +75,7 @@ __siginfo_fpu_t *fpu_save; unsigned long insns [2] __attribute__ ((aligned (8))); unsigned int extramask[_NSIG_WORDS - 1]; + unsigned int extra_size; /* Should be 0 */ __siginfo_fpu_t fpu_state; }; @@ -86,6 +87,7 @@ __siginfo_fpu_t *fpu_save; unsigned int insns [2]; stack_t stack; + unsigned int extra_size; /* Should be 0 */ __siginfo_fpu_t fpu_state; }; @@ -203,16 +205,19 @@ #endif current->used_math = 1; current->flags &= ~PF_USEDFPU; + + if (verify_area (VERIFY_READ, fpu, sizeof(*fpu))) + return -EFAULT; - err = copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], - (sizeof(unsigned long) * 32)); + err = __copy_from_user(¤t->tss.float_regs[0], &fpu->si_float_regs[0], + (sizeof(unsigned long) * 32)); err |= __get_user(current->tss.fsr, &fpu->si_fsr); err |= __get_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) - err |= copy_from_user(¤t->tss.fpqueue[0], - &fpu->si_fpqueue[0], - ((sizeof(unsigned long) + - (sizeof(unsigned long *)))*16)); + err |= __copy_from_user(¤t->tss.fpqueue[0], + &fpu->si_fpqueue[0], + ((sizeof(unsigned long) + + (sizeof(unsigned long *)))*16)); return err; } @@ -241,7 +246,7 @@ /* 2. Restore the state */ up_psr = regs->psr; - err |= copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); + err |= __copy_from_user(regs, &sf->info.si_regs, sizeof (struct pt_regs)); /* User can only change condition codes and FPU enabling in %psr. */ regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) @@ -250,14 +255,14 @@ err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - err |= restore_fpu_state(regs, sf->fpu_save); + err |= restore_fpu_state(regs, fpu_save); /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __get_user(set.sig[0], &sf->info.si_mask); - err |= copy_from_user(&set.sig[1], &sf->extramask, - (_NSIG_WORDS-1) * sizeof(unsigned int)); + err |= __copy_from_user(&set.sig[1], &sf->extramask, + (_NSIG_WORDS-1) * sizeof(unsigned int)); if (err) goto segv_and_exit; @@ -270,8 +275,6 @@ return; segv_and_exit: - /* Ugh, we need to grab master lock in these rare cases ;-( */ - lock_kernel(); do_exit(SIGSEGV); } @@ -305,8 +308,8 @@ */ err |= __get_user(set.sig[0], &scptr->sigc_mask); /* Note that scptr + 1 points to extramask */ - err |= copy_from_user(&set.sig[1], scptr + 1, - (_NSIG_WORDS - 1) * sizeof(unsigned int)); + err |= __copy_from_user(&set.sig[1], scptr + 1, + (_NSIG_WORDS - 1) * sizeof(unsigned int)); if (err) goto segv_and_exit; @@ -352,7 +355,7 @@ (((unsigned long) sf) & 0x03)) goto segv; - err = get_user(pc, &sf->regs.pc); + err = __get_user(pc, &sf->regs.pc); err |= __get_user(npc, &sf->regs.npc); err |= ((pc | npc) & 0x03); @@ -366,8 +369,8 @@ err |= __get_user(fpu_save, &sf->fpu_save); if(fpu_save) - err |= restore_fpu_state(regs, &sf->fpu_state); - err |= copy_from_user(&set, &sf->mask, sizeof(sigset_t)); + err |= restore_fpu_state(regs, fpu_save); + err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); @@ -459,13 +462,13 @@ for(window = 0; window < current->tss.w_saved; window++) { sc->sigc_spbuf[window] = (char *)current->tss.rwbuf_stkptrs[window]; - err |= copy_to_user(&sc->sigc_wbuf[window], - ¤t->tss.reg_window[window], - sizeof(struct reg_window)); + err |= __copy_to_user(&sc->sigc_wbuf[window], + ¤t->tss.reg_window[window], + sizeof(struct reg_window)); } else - err |= copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], - sizeof(struct reg_window)); + err |= __copy_to_user(sframep, (char *)regs->u_regs[UREG_FP], + sizeof(struct reg_window)); current->tss.w_saved = 0; /* So process is allowed to execute. */ err |= __put_user(signr, &sframep->sig_num); @@ -490,11 +493,8 @@ return; sigill_and_return: - /* Ugh, we need to grab master lock in these rare cases ;-( */ - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -520,13 +520,13 @@ regs->psr &= ~(PSR_EF); } #endif - err |= copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], - (sizeof(unsigned long) * 32)); + err |= __copy_to_user(&fpu->si_float_regs[0], ¤t->tss.float_regs[0], + (sizeof(unsigned long) * 32)); err |= __put_user(current->tss.fsr, &fpu->si_fsr); err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth); if (current->tss.fpqdepth != 0) - err |= copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], - ((sizeof(unsigned long) + + err |= __copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0], + ((sizeof(unsigned long) + (sizeof(unsigned long *)))*16)); current->used_math = 0; return err; @@ -560,7 +560,9 @@ } /* 2. Save the current process state */ - err = copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs)); + err = __copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs)); + + err |= __put_user(0, &sf->extra_size); if (current->used_math) { err |= save_fpu_state(regs, &sf->fpu_state); @@ -572,8 +574,8 @@ err |= __put_user(oldset->sig[0], &sf->info.si_mask); err |= __copy_to_user(sf->extramask, &oldset->sig[1], (_NSIG_WORDS - 1) * sizeof(unsigned int)); - err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP], - sizeof (struct reg_window)); + err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], + sizeof (struct reg_window)); if (err) goto sigsegv; @@ -606,10 +608,8 @@ return; sigill_and_return: - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -620,7 +620,7 @@ struct rt_signal_frame *sf; int sigframe_size; unsigned int psr; - int i, err; + int err; synchronize_user_stack(); sigframe_size = RT_ALIGNEDSZ; @@ -632,15 +632,16 @@ if(current->tss.w_saved != 0) goto sigill; - err = put_user(regs->pc, &sf->regs.pc); + err = __put_user(regs->pc, &sf->regs.pc); err |= __put_user(regs->npc, &sf->regs.npc); err |= __put_user(regs->y, &sf->regs.y); psr = regs->psr; if(current->used_math) psr |= PSR_EF; err |= __put_user(psr, &sf->regs.psr); - for(i = 0; i < 16; i++) - err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs)); + err |= __put_user(0, &sf->extra_size); + if(psr & PSR_EF) { err |= save_fpu_state(regs, &sf->fpu_state); err |= __put_user(&sf->fpu_state, &sf->fpu_save); @@ -654,8 +655,8 @@ err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); - err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP], - sizeof (struct reg_window)); + err |= __copy_to_user(sf, (char *) regs->u_regs [UREG_FP], + sizeof (struct reg_window)); if (err) goto sigsegv; @@ -685,10 +686,8 @@ return; sigill: - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -717,7 +716,7 @@ } /* Start with a clean frame pointer and fill it */ - err = clear_user(sfp, sizeof (*sfp)); + err = __clear_user(sfp, sizeof (*sfp)); /* Setup convenience variables */ si = &sfp->si; @@ -746,8 +745,8 @@ err |= __put_user(regs->y, &((*gr) [SVR4_Y])); /* Copy g [1..7] and o [0..7] registers */ - err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); - err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &uc->stack.sp); @@ -775,9 +774,9 @@ */ for(window = 0; window < current->tss.w_saved; window++) { err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]); - err |= copy_to_user(&gw->win [window], - ¤t->tss.reg_window [window], - sizeof (svr4_rwindow_t)); + err |= __copy_to_user(&gw->win [window], + ¤t->tss.reg_window [window], + sizeof (svr4_rwindow_t)); err |= __put_user(0, gw->winptr [window]); } @@ -819,10 +818,8 @@ return; sigill_and_return: - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -839,6 +836,8 @@ goto sigsegv_and_return; err = clear_user(uc, sizeof (*uc)); + if (err) + return -EFAULT; /* Setup convenience variables */ mc = &uc->mcontext; @@ -860,8 +859,8 @@ err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ - err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); - err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); + err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7); + err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &uc->stack.sp); @@ -874,7 +873,6 @@ return (err ? -EFAULT : 0); sigsegv_and_return: - lock_kernel(); do_exit(SIGSEGV); } @@ -950,14 +948,13 @@ regs->psr |= (psr & PSR_ICC); /* Restore g[1..7] and o[0..7] registers */ - err |= copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], + err |= __copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7); - err |= copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], + err |= __copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8); return (err ? -EFAULT : 0); sigsegv_and_return: - lock_kernel(); do_exit(SIGSEGV); } @@ -1110,7 +1107,9 @@ case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) + if(current->binfmt && + current->binfmt->core_dump && + current->binfmt->core_dump(signr, regs)) exit_code |= 0x80; unlock_kernel(); } diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v2.1.126/linux/arch/sparc/kernel/smp.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/smp.c Tue Oct 27 09:52:20 1998 @@ -64,6 +64,9 @@ /* Kernel spinlock */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +/* Used to make bitops atomic */ +unsigned char bitops_spinlock = 0; + volatile unsigned long ipi_count; volatile int smp_process_available=0; diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c --- v2.1.126/linux/arch/sparc/kernel/sparc_ksyms.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sparc_ksyms.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc_ksyms.c,v 1.70 1998/09/17 11:04:55 jj Exp $ +/* $Id: sparc_ksyms.c,v 1.72 1998/10/22 15:15:08 ecd Exp $ * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,10 @@ extern void dump_thread(struct pt_regs *, struct user *); +#ifdef __SMP__ +extern spinlock_t kernel_flag; +#endif + /* One thing to note is that the way the symbols of the mul/div * support routines are named is a mess, they all start with * a '.' which makes it a bitch to export, here is the trick: @@ -87,33 +91,21 @@ EXPORT_SYMBOL(sparc_cpu_model); EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor); #ifdef SPIN_LOCK_DEBUG -EXPORT_SYMBOL(_spin_lock); -EXPORT_SYMBOL(_spin_unlock); +EXPORT_SYMBOL(_do_spin_lock); +EXPORT_SYMBOL(_do_spin_unlock); EXPORT_SYMBOL(_spin_trylock); -EXPORT_SYMBOL(_spin_lock_irq); -EXPORT_SYMBOL(_spin_unlock_irq); -EXPORT_SYMBOL(_spin_lock_irqsave); -EXPORT_SYMBOL(_spin_unlock_irqrestore); -EXPORT_SYMBOL(_read_lock); -EXPORT_SYMBOL(_read_unlock); -EXPORT_SYMBOL(_read_lock_irq); -EXPORT_SYMBOL(_read_unlock_irq); -EXPORT_SYMBOL(_read_lock_irqsave); -EXPORT_SYMBOL(_read_unlock_irqrestore); -EXPORT_SYMBOL(_write_lock); -EXPORT_SYMBOL(_write_unlock); -EXPORT_SYMBOL(_write_lock_irq); -EXPORT_SYMBOL(_write_unlock_irq); -EXPORT_SYMBOL(_write_lock_irqsave); -EXPORT_SYMBOL(_write_unlock_irqrestore); +EXPORT_SYMBOL(_do_read_lock); +EXPORT_SYMBOL(_do_read_unlock); +EXPORT_SYMBOL(_do_write_lock); +EXPORT_SYMBOL(_do_write_unlock); #else EXPORT_SYMBOL_PRIVATE(_rw_read_enter); EXPORT_SYMBOL_PRIVATE(_rw_read_exit); EXPORT_SYMBOL_PRIVATE(_rw_write_enter); #endif -EXPORT_SYMBOL(__sparc_bh_counter); #ifdef __SMP__ #ifdef DEBUG_IRQLOCK +EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_cli); @@ -142,14 +134,19 @@ EXPORT_SYMBOL_PRIVATE(_clear_le_bit); /* IRQ implementation. */ -EXPORT_SYMBOL(local_irq_count); #ifdef __SMP__ +EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(global_irq_holder); EXPORT_SYMBOL(global_irq_lock); EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(sparc_bh_lock); EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(synchronize_bh); #endif +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); EXPORT_SYMBOL(udelay); EXPORT_SYMBOL(mstk48t02_regs); diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sun4d_irq.c linux/arch/sparc/kernel/sun4d_irq.c --- v2.1.126/linux/arch/sparc/kernel/sun4d_irq.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sun4d_irq.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sun4d_irq.c,v 1.15 1998/09/29 09:46:12 davem Exp $ +/* $Id: sun4d_irq.c,v 1.17 1998/10/18 03:31:03 davem Exp $ * arch/sparc/kernel/sun4d_irq.c: * SS1000/SC2000 interrupt handling. * @@ -438,8 +438,13 @@ int cpu; /* Map the User Timer registers. */ - sun4d_timers = sparc_alloc_io(BW_LOCAL_BASE+BW_TIMER_LIMIT, 0, +#ifdef __SMP__ + sun4d_timers = sparc_alloc_io(CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT, 0, + PAGE_SIZE, "user timer", 0xf, 0x0); +#else + sun4d_timers = sparc_alloc_io(CSR_BASE(0)+BW_TIMER_LIMIT, 0, PAGE_SIZE, "user timer", 0xf, 0x0); +#endif sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); master_l10_counter = &sun4d_timers->l10_cur_count; diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v2.1.126/linux/arch/sparc/kernel/sunos_ioctl.c Thu Apr 23 20:21:30 1998 +++ linux/arch/sparc/kernel/sunos_ioctl.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.30 1998/01/21 06:17:32 ecd Exp $ +/* $Id: sunos_ioctl.c,v 1.31 1998/10/25 19:31:04 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -218,7 +218,7 @@ } #if 0 - if (cmd & 0xff00 == ('k' << 8)){ + if ((cmd & 0xff00) == ('k' << 8)) { printk ("[[KBIO: %8.8x\n", (unsigned int) cmd); } #endif diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v2.1.126/linux/arch/sparc/kernel/sys_sparc.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sys_sparc.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.48 1998/09/07 09:19:34 davem Exp $ +/* $Id: sys_sparc.c,v 1.49 1998/10/11 06:57:53 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -181,6 +181,7 @@ struct file * file = NULL; unsigned long retval = -EBADF; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); @@ -214,6 +215,7 @@ fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.1.126/linux/arch/sparc/kernel/sys_sunos.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/kernel/sys_sunos.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.92 1998/08/31 03:40:53 davem Exp $ +/* $Id: sys_sunos.c,v 1.94 1998/10/12 06:15:04 jj Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,7 @@ struct file * file = NULL; unsigned long retval, ret_type; + down(¤t->mm->mmap_sem); lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { @@ -128,6 +129,7 @@ fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -147,6 +149,7 @@ unsigned long rlim; unsigned long newbrk, oldbrk; + down(¤t->mm->mmap_sem); lock_kernel(); if(ARCH_SUN4C_SUN4) { if(brk >= 0x20000000 && brk < 0xe0000000) { @@ -213,6 +216,7 @@ retval = 0; out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -579,20 +583,16 @@ asmlinkage int sunos_uname(struct sunos_utsname *name) { - int ret = -EFAULT; - + int ret; down(&uts_sem); - if(!name) - goto out; - if(copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1)) - goto out; - copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); - put_user('\0', &name->nname[8]); - copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); - ret = 0; -out: + ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + if (!ret) { + ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= __put_user('\0', &name->nname[8]); + ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); + ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); + ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); + } up(&uts_sem); return ret; } @@ -843,7 +843,7 @@ strncpy (linux_nfs_mount.hostname, the_name, 254); linux_nfs_mount.hostname [255] = 0; putname (the_name); - + dev = get_unnamed_dev (); ret = do_mount (dev, "", dir_name, "nfs", linux_flags, &linux_nfs_mount); @@ -860,6 +860,9 @@ int ret = -EINVAL; char *dev_fname = 0; + if (!capable (CAP_SYS_ADMIN)) + return -EPERM; + lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/bitops.S linux/arch/sparc/lib/bitops.S --- v2.1.126/linux/arch/sparc/lib/bitops.S Sun Jan 26 02:07:09 1997 +++ linux/arch/sparc/lib/bitops.S Tue Oct 27 09:52:20 1998 @@ -26,12 +26,26 @@ wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 or %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -48,12 +62,26 @@ wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 andn %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -70,12 +98,26 @@ wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ld [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ld [%g1], %g7 xor %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + st %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f st %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -92,12 +134,26 @@ wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ldub [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ldub [%g1], %g7 or %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + stb %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f stb %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: @@ -113,12 +169,26 @@ wr %g3, PSR_PIL, %psr nop; nop; nop 1: - ldub [%g1], %g7 +#ifdef __SMP__ + set C_LABEL(bitops_spinlock), %g5 +2: ldstub [%g5], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 2b ! Nope... +#endif + ldub [%g1], %g7 andn %g7, %g2, %g5 - andcc %g3, PSR_PIL, %g0 and %g7, %g2, %g2 +#ifdef __SMP__ + stb %g5, [%g1] + set C_LABEL(bitops_spinlock), %g5 + andcc %g3, PSR_PIL, %g0 + bne 1f + stb %g0, [%g5] +#else + andcc %g3, PSR_PIL, %g0 bne 1f stb %g5, [%g1] +#endif wr %g3, 0x0, %psr nop; nop; nop 1: diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/debuglocks.c linux/arch/sparc/lib/debuglocks.c --- v2.1.126/linux/arch/sparc/lib/debuglocks.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc/lib/debuglocks.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.3 1998/09/29 09:46:22 davem Exp $ +/* $Id: debuglocks.c,v 1.5 1998/10/14 09:19:04 jj Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -120,29 +120,17 @@ if(val) { while(rw->lock & 0xff) { if (!--stuck) { - show(str, (spinlock_t *)rw, caller); - stuck = INIT_STUCK; - } - barrier(); - } - goto wlock_again; - } -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); - if(val) { - while(rw->lock & 0xff00) { - if (!--stuck) { show_read(str, rw, caller); stuck = INIT_STUCK; } barrier(); } - goto clock_again; + goto wlock_again; } - (*((unsigned short *)&rw->lock))++; + rw->reader_pc[cpu] = caller; barrier(); - (*(((unsigned short *)&rw->lock)+1)) = 0; + rw->lock++; } #undef INIT_STUCK @@ -157,22 +145,22 @@ STORE_CALLER(caller); -clock_again: - __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock))); +wlock_again: + __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); if(val) { - while(rw->lock & 0xff00) { + while(rw->lock & 0xff) { if (!--stuck) { show_read(str, rw, caller); stuck = INIT_STUCK; } barrier(); } - goto clock_again; + goto wlock_again; } - (*((unsigned short *)&rw->lock))--; + rw->reader_pc[cpu] = 0; barrier(); - (*(((unsigned char *)&rw->lock)+2))=0; + rw->lock -= 0x1ff; } #undef INIT_STUCK @@ -190,7 +178,8 @@ wlock_again: __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock))); if(val) { - while(rw->lock & 0xff) { +wlock_wait: + while(rw->lock) { if (!--stuck) { show_write(str, rw, caller); stuck = INIT_STUCK; @@ -199,14 +188,15 @@ } goto wlock_again; } - rw->owner_pc = (cpu & 3) | (caller & ~3); - while(rw->lock & ~0xff) { - if (!--stuck) { - show_write(str, rw, caller); - stuck = INIT_STUCK; - } + + if (rw->lock & ~0xff) { + *(((unsigned char *)&rw->lock)+3) = 0; barrier(); + goto wlock_wait; } + + barrier(); + rw->owner_pc = (cpu & 3) | (caller & ~3); } void _do_write_unlock(rwlock_t *rw) diff -u --recursive --new-file v2.1.126/linux/arch/sparc/lib/locks.S linux/arch/sparc/lib/locks.S --- v2.1.126/linux/arch/sparc/lib/locks.S Thu Aug 6 14:06:30 1998 +++ linux/arch/sparc/lib/locks.S Tue Oct 27 09:52:20 1998 @@ -1,7 +1,9 @@ -/* $Id: locks.S,v 1.13 1998/07/30 11:29:28 davem Exp $ +/* $Id: locks.S,v 1.15 1998/10/14 09:18:55 jj Exp $ * locks.S: SMP low-level lock primitives on Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #include @@ -43,52 +45,48 @@ ldstub [%g1 + 3], %g2 b ___rw_read_enter_spin_on_wlock ldub [%g1 + 3], %g2 +___rw_read_exit_spin_on_wlock: + orcc %g2, 0x0, %g0 + be,a ___rw_read_exit + ldstub [%g1 + 3], %g2 + b ___rw_read_exit_spin_on_wlock + ldub [%g1 + 3], %g2 ___rw_write_enter_spin_on_wlock: orcc %g2, 0x0, %g0 be,a ___rw_write_enter ldstub [%g1 + 3], %g2 b ___rw_write_enter_spin_on_wlock - ldub [%g1 + 3], %g2 + ld [%g1], %g2 .globl ___rw_read_enter ___rw_read_enter: orcc %g2, 0x0, %g0 bne,a ___rw_read_enter_spin_on_wlock ldub [%g1 + 3], %g2 -1: - ldstub [%g1 + 2], %g7 - orcc %g7, 0x0, %g0 - bne 1b - ldsh [%g1], %g2 + ld [%g1], %g2 add %g2, 1, %g2 - sth %g2, [%g1] - sth %g0, [%g1 + 2] + st %g2, [%g1] retl mov %g4, %o7 - /* We must be careful here to not blow away wlock. */ .globl ___rw_read_exit -___rw_read_exit_spin: - ldstub [%g1 + 2], %g2 ___rw_read_exit: orcc %g2, 0x0, %g0 - bne ___rw_read_exit_spin - ldsh [%g1], %g7 - sub %g7, 1, %g7 - sth %g7, [%g1] - stb %g0, [%g1 + 2] + bne,a ___rw_read_exit_spin_on_wlock + ldub [%g1 + 3], %g2 + ld [%g1], %g2 + sub %g2, 0x1ff, %g2 + st %g2, [%g1] retl mov %g4, %o7 .globl ___rw_write_enter ___rw_write_enter: orcc %g2, 0x0, %g0 - bne,a ___rw_write_enter_spin_on_wlock - ldub [%g1 + 3], %g2 - ld [%g1], %g2 -1: - andncc %g2, 0xff, %g0 - bne,a 1b + bne ___rw_write_enter_spin_on_wlock ld [%g1], %g2 + andncc %g2, 0xff, %g0 + bne,a ___rw_write_enter_spin_on_wlock + stb %g0, [%g1 + 3] retl mov %g4, %o7 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.1.126/linux/arch/sparc64/Makefile Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/Makefile Tue Oct 27 09:52:20 1998 @@ -1,21 +1,28 @@ -# $Id: Makefile,v 1.29 1998/09/16 12:25:20 jj Exp $ +# $Id: Makefile,v 1.33 1998/10/19 07:04:02 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the # 64-bit Sparc. # -# Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) # # If the solaris /bin/sh wasn't so broken, I wouldn't need the following # line... SHELL =/bin/bash -CC = sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include +CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include +CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi) IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) +ifneq ($(CC_HAS_ARGS),y) +MAKEOVERRIDES := $(shell echo "$(MAKEOVERRIDES)" | sed 's CC=$(CC) CC=$(CC)\\\ -D__KERNEL__\\\ -I$(TOPDIR)/include ') +override CC := $(CC) -D__KERNEL__ -I$(TOPDIR)/include +endif + ifneq ($(NEW_GAS),y) AS = sparc64-linux-as LD = sparc64-linux-ld @@ -28,7 +35,6 @@ endif ELFTOAOUT = elftoaout - # # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. @@ -40,6 +46,16 @@ else CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare +endif + +# Uncomment this to get spinlock/rwlock debugging on SMP. +# DEBUG_SPINLOCK = 1 + +ifdef SMP + ifdef DEBUG_SPINLOCK + CFLAGS += -DSPIN_LOCK_DEBUG + AFLAGS += -DSPIN_LOCK_DEBUG + endif endif LINKFLAGS = -T arch/sparc64/vmlinux.lds diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.1.126/linux/arch/sparc64/defconfig Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/defconfig Tue Oct 27 09:52:20 1998 @@ -27,6 +27,7 @@ CONFIG_PROM_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_MATROX is not set CONFIG_FB_SBUS=y CONFIG_FB_CREATOR=y CONFIG_FB_CGSIX=y @@ -86,10 +87,11 @@ CONFIG_BINFMT_MISC=m CONFIG_BINFMT_JAVA=m CONFIG_SOLARIS_EMUL=m -CONFIG_PARPORT=y -CONFIG_PARPORT_AX=y +CONFIG_PARPORT=m +CONFIG_PARPORT_AX=m +CONFIG_PARPORT_LOWLEVEL_MODULE=y # CONFIG_PARPORT_OTHER is not set -CONFIG_PRINTER=y +CONFIG_PRINTER=m CONFIG_PRINTER_READBACK=y CONFIG_ENVCTRL=m @@ -122,11 +124,9 @@ # Networking options # CONFIG_PACKET=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -# CONFIG_NETLINK_DEV is not set +# CONFIG_NETLINK is not set # CONFIG_FIREWALL is not set -CONFIG_NET_ALIAS=y +# CONFIG_NET_ALIAS is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -136,8 +136,7 @@ # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -CONFIG_IP_ALIAS=y -# CONFIG_ARPD is not set +# CONFIG_IP_ALIAS is not set # CONFIG_SYN_COOKIES is not set # @@ -165,18 +164,7 @@ # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set # CONFIG_CPU_IS_SLOW is not set -CONFIG_NET_SCHED=y -CONFIG_NETLINK=y -CONFIG_RTNETLINK=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_CSZ=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -# CONFIG_NET_QOS is not set -# CONFIG_NET_CLS is not set +# CONFIG_NET_SCHED is not set # # SCSI support @@ -249,7 +237,7 @@ CONFIG_HAPPYMEAL=y CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m -CONFIG_DE4X5=y +CONFIG_DE4X5=m CONFIG_VORTEX=m # @@ -258,18 +246,19 @@ # CONFIG_QUOTA is not set CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -CONFIG_ISO9660_FS=y +CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set CONFIG_FAT_FS=m CONFIG_MSDOS_FS=m # CONFIG_UMSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_VFAT_FS=m CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_NFSD=m +# CONFIG_NFSD_SUN is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_CODA_FS is not set +CONFIG_CODA_FS=m CONFIG_SMB_FS=m CONFIG_SMB_WIN95=y CONFIG_NCP_FS=m @@ -292,8 +281,7 @@ CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_ADFS_FS is not set -CONFIG_QNX4FS_FS=m -# CONFIG_QNX4FS_RW is not set +# CONFIG_QNX4FS_FS is not set # CONFIG_MAC_PARTITION is not set CONFIG_NLS=y diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile --- v2.1.126/linux/arch/sparc64/kernel/Makefile Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/kernel/Makefile Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.40 1998/09/17 11:05:03 jj Exp $ +# $Id: Makefile,v 1.41 1998/10/11 06:58:14 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -89,6 +89,8 @@ @echo "" >> asm_offsets.h @echo "#else /* __SMP__ */" >> asm_offsets.h @echo "" >> asm_offsets.h + @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h + @echo "" >> asm_offsets.h @echo "#include " > tmp.c $(CC) -D__SMP__ -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @@ -110,6 +112,31 @@ # ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c + @echo "" >> asm_offsets.h + @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h + @echo "" >> asm_offsets.h + @echo "#include " > tmp.c + $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i + @echo "/* Automatically generated. Do not edit. */" > check_asm.c + @echo "#include " >> check_asm.c + @echo 'struct task_struct _task;' >> check_asm.c + @echo 'struct mm_struct _mm;' >> check_asm.c + @echo 'struct thread_struct _thread;' >> check_asm.c + @echo 'int main(void) {' >> check_asm.c + $(SH) ./check_asm.sh task tmp.i check_asm.c + $(SH) ./check_asm.sh mm tmp.i check_asm.c + $(SH) ./check_asm.sh thread tmp.i check_asm.c + @echo 'return 0; }' >> check_asm.c + @rm -f tmp.[ci] + #$(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -o check_asm check_asm.c + # Until we can do this natively, a hack has to take place + $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c + $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s + @rm -f check_asm.s + # + ./check_asm >> asm_offsets.h + @rm -f check_asm check_asm.c + @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h @echo "" >> asm_offsets.h @echo "#endif /* __SMP__ */" >> asm_offsets.h @echo "" >> asm_offsets.h diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.126/linux/arch/sparc64/kernel/entry.S Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/kernel/entry.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.90 1998/09/25 01:09:05 davem Exp $ +/* $Id: entry.S,v 1.91 1998/10/07 01:27:08 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -730,7 +730,7 @@ mov %l5, %o7 ret_from_syscall: /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in - * %o7 for us. + * %o7 for us. Check performance counter stuff too. */ andn %o7, 0x100, %o7 sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags] @@ -739,7 +739,13 @@ membar #StoreStore | #LoadStore stb %g0, [%o4 + %lo(scheduler_lock)] #endif - b,pt %xcc, ret_sys_call + andcc %o7, 0x200, %g0 + be,pt %icc, 1f + nop + ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7 + wr %g0, %o7, %pcr + wr %g0, %g0, %pic +1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 sparc_exit: rdpr %otherwin, %g1 rdpr %pstate, %g2 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S --- v2.1.126/linux/arch/sparc64/kernel/head.S Thu Aug 6 14:06:30 1998 +++ linux/arch/sparc64/kernel/head.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $ +/* $Id: head.S,v 1.54 1998/10/06 20:48:30 ecd Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -379,6 +379,9 @@ sethi %hi(ivector_to_mask), %g5 or %g5, %lo(ivector_to_mask), %g1 /* IVECTOR table */ mov 0x40, %g2 /* INTR data 0 register */ + + /* Kill PROM timer */ + wr %g0, 0, %tick_cmpr /* Ok, we're done setting up all the state our trap mechanims needs, * now get back into normal globals and let the PROM know what is up. diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.126/linux/arch/sparc64/kernel/ioctl32.c Mon Oct 5 13:13:37 1998 +++ linux/arch/sparc64/kernel/ioctl32.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.52 1998/09/25 17:09:22 jj Exp $ +/* $Id: ioctl32.c,v 1.53 1998/10/26 08:01:01 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1532,8 +1532,9 @@ error = loop_status(fd, cmd, arg); goto out; - case AUTOFS_IOC_SETTIMEOUT: - error = rw_long(fd, cmd, arg); +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) + case AUTOFS_IOC_SETTIMEOUT32: + error = rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); goto out; case PIO_FONTX: diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.1.126/linux/arch/sparc64/kernel/irq.c Thu Aug 6 14:06:30 1998 +++ linux/arch/sparc64/kernel/irq.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $ +/* $Id: irq.c,v 1.66 1998/10/21 15:02:25 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,7 @@ #include #include /* XXX ADD add_foo_randomness() calls... -DaveM */ #include +#include #include #include @@ -208,7 +209,7 @@ 13, /* Audio Record */ 14, /* Audio Playback */ 15, /* PowerFail */ - 9, /* Keyboard/Mouse/Serial */ + 3, /* second SCSI */ 11, /* Floppy */ 2, /* Spare Hardware */ 9, /* Keyboard */ @@ -573,22 +574,18 @@ restore_flags(flags); } -/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu - * structure for cache reasons. +/* Only uniprocessor needs this IRQ/BH locking depth, on SMP it + * lives in the per-cpu structure for cache reasons. */ #ifndef __SMP__ unsigned int local_irq_count; -#endif - -#ifndef __SMP__ -int __sparc64_bh_counter = 0; +unsigned int local_bh_count; #define irq_enter(cpu, irq) (local_irq_count++) #define irq_exit(cpu, irq) (local_irq_count--) - #else - -atomic_t __sparc64_bh_counter = ATOMIC_INIT(0); +atomic_t global_bh_lock = ATOMIC_INIT(0); +spinlock_t global_bh_count = SPIN_LOCK_UNLOCKED; /* Who has global_irq_lock. */ unsigned char global_irq_holder = NO_PROC_ID; @@ -596,136 +593,163 @@ /* This protects IRQ's. */ spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED; -/* This protects BH software state (masks, things like that). */ -spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; - /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -static unsigned long previous_irqholder; +#define irq_enter(cpu, irq) \ +do { hardirq_enter(cpu); \ + spin_unlock_wait(&global_irq_lock); \ +} while(0) +#define irq_exit(cpu, irq) hardirq_exit(cpu) -#undef INIT_STUCK -#define INIT_STUCK 100000000 +static void show(char * str) +{ + int cpu = smp_processor_id(); -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } + printk("\n%s, CPU %d:\n", str, cpu); + printk("irq: %d [%d %d]\n", + atomic_read(&global_irq_count), + cpu_data[0].irq_count, cpu_data[1].irq_count); + printk("bh: %d [%d %d]\n", + (spin_is_locked(&global_bh_count) ? 1 : 0), + cpu_data[0].bh_count, cpu_data[1].bh_count); +} + +#define MAXCOUNT 100000000 + +static inline void wait_on_bh(void) +{ + int count = MAXCOUNT; + do { + if(!--count) { + show("wait_on_bh"); + count = 0; + } + membar("#LoadLoad"); + } while(spin_is_locked(&global_bh_count)); +} -static inline void wait_on_irq(int cpu, unsigned long where) -{ - int stuck = INIT_STUCK; - int local_count = local_irq_count; +#define SYNC_OTHER_ULTRAS(x) udelay(x+1) - while(local_count != atomic_read(&global_irq_count)) { - atomic_sub(local_count, &global_irq_count); - spin_unlock(&global_irq_lock); +static inline void wait_on_irq(int cpu) +{ + int count = MAXCOUNT; + for(;;) { + membar("#LoadLoad"); + if (!atomic_read (&global_irq_count)) { + if (local_bh_count || ! spin_is_locked(&global_bh_count)) + break; + } + spin_unlock (&global_irq_lock); + membar("#StoreLoad | #StoreStore"); for(;;) { - STUCK; - membar("#StoreLoad | #LoadLoad"); + if (!--count) { + show("wait_on_irq"); + count = ~0; + } + __sti(); + SYNC_OTHER_ULTRAS(cpu); + __cli(); if (atomic_read(&global_irq_count)) continue; - if (*((volatile unsigned char *)&global_irq_lock)) + if (spin_is_locked (&global_irq_lock)) + continue; + if (!local_bh_count && spin_is_locked (&global_bh_count)) continue; - membar("#LoadLoad | #LoadStore"); if (spin_trylock(&global_irq_lock)) break; } - atomic_add(local_count, &global_irq_count); } } -#undef INIT_STUCK -#define INIT_STUCK 10000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} +void synchronize_bh(void) +{ + if (spin_is_locked (&global_bh_count) && !in_interrupt()) + wait_on_bh(); +} -static inline void get_irqlock(int cpu, unsigned long where) +void synchronize_irq(void) { - int stuck = INIT_STUCK; + if (atomic_read(&global_irq_count)) { + cli(); + sti(); + } +} - if (!spin_trylock(&global_irq_lock)) { - membar("#StoreLoad | #LoadLoad"); +static inline void get_irqlock(int cpu) +{ + if (! spin_trylock(&global_irq_lock)) { if ((unsigned char) cpu == global_irq_holder) return; do { - do { - STUCK; + while (spin_is_locked (&global_irq_lock)) membar("#LoadLoad"); - } while(*((volatile unsigned char *)&global_irq_lock)); - } while (!spin_trylock(&global_irq_lock)); + } while(! spin_trylock(&global_irq_lock)); } - wait_on_irq(cpu, where); + wait_on_irq(cpu); global_irq_holder = cpu; - previous_irqholder = where; } void __global_cli(void) { - int cpu = smp_processor_id(); - unsigned long where; + unsigned long flags; - __asm__ __volatile__("mov %%i7, %0" : "=r" (where)); - __cli(); - get_irqlock(cpu, where); + __save_flags(flags); + if(flags == 0) { + int cpu = smp_processor_id(); + __cli(); + if (! local_irq_count) + get_irqlock(cpu); + } } void __global_sti(void) { - release_irqlock(smp_processor_id()); - __sti(); -} + int cpu = smp_processor_id(); -void __global_restore_flags(unsigned long flags) -{ - if (flags & 1) { - __global_cli(); - } else { - if (global_irq_holder == (unsigned char) smp_processor_id()) { - global_irq_holder = NO_PROC_ID; - spin_unlock(&global_irq_lock); - } - if (!(flags & 2)) - __sti(); - } + if (! local_irq_count) + release_irqlock(cpu); + __sti(); } -#undef INIT_STUCK -#define INIT_STUCK 200000000 - -#undef STUCK -#define STUCK \ -if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} - -void irq_enter(int cpu, int irq) +unsigned long __global_save_flags(void) { - int stuck = INIT_STUCK; + unsigned long flags, local_enabled, retval; - hardirq_enter(cpu); - while (*((volatile unsigned char *)&global_irq_lock)) { - if ((unsigned char) cpu == global_irq_holder) - printk("irq_enter: Frosted Lucky Charms, " - "they're magically delicious!\n"); - STUCK; - membar("#LoadLoad"); + __save_flags(flags); + local_enabled = ((flags == 0) ? 1 : 0); + retval = 2 + local_enabled; + if (! local_irq_count) { + if (local_enabled) + retval = 1; + if (global_irq_holder == (unsigned char) smp_processor_id()) + retval = 0; } + return retval; } -void irq_exit(int cpu, int irq) -{ - hardirq_exit(cpu); - release_irqlock(cpu); -} - -void synchronize_irq(void) +void __global_restore_flags(unsigned long flags) { - int local_count = local_irq_count; - unsigned long flags; - - if (local_count != atomic_read(&global_irq_count)) { - save_and_cli(flags); - restore_flags(flags); + switch (flags) { + case 0: + __global_cli(); + break; + case 1: + __global_sti(); + break; + case 2: + __cli(); + break; + case 3: + __sti(); + break; + default: + { + unsigned long pc; + __asm__ __volatile__("mov %%i7, %0" : "=r" (pc)); + printk("global_restore_flags: Bogon flags(%016lx) caller %016lx\n", + flags, pc); + } } } @@ -787,7 +811,7 @@ /* * Check for TICK_INT on level 14 softint. */ - if ((irq == 14) && get_softint() & (1UL << 0)) + if ((irq == 14) && (get_softint() & (1UL << 0))) irq = 0; #endif clear_softint(1 << irq); @@ -1004,12 +1028,15 @@ /* Called from smp_commence, when we know how many cpus are in the system * and can have device IRQ's directed at them. */ +/* #define SMP_IRQ_VERBOSE */ void distribute_irqs(void) { unsigned long flags; int cpu, level; +#ifdef SMP_IRQ_VERBOSE printk("SMP: redistributing interrupts...\n"); +#endif save_and_cli(flags); cpu = 0; for(level = 0; level < NR_IRQS; level++) { @@ -1020,16 +1047,18 @@ struct ino_bucket *bucket = (struct ino_bucket *)p->mask; unsigned int *imap = __imap(bucket); unsigned int val; - unsigned long tid = __cpu_logical_map[cpu] << 9; + unsigned long tid = __cpu_logical_map[cpu] << 26; val = *imap; *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); +#ifdef SMP_IRQ_VERBOSE printk("SMP: Redirecting IGN[%x] INO[%x] " "to cpu %d [%s]\n", (val & SYSIO_IMAP_IGN) >> 6, (val & SYSIO_IMAP_INO), cpu, p->name); +#endif cpu++; if (cpu >= NR_CPUS || __cpu_logical_map[cpu] == -1) @@ -1114,12 +1143,17 @@ __initfunc(void init_IRQ(void)) { - int i; + static int called = 0; + + if (called == 0) { + int i; - map_prom_timers(); - kill_prom_timer(); - for(i = 0; i < NUM_IVECS; i++) - ivector_to_mask[i] = 0; + called = 1; + map_prom_timers(); + kill_prom_timer(); + for(i = 0; i < NUM_IVECS; i++) + ivector_to_mask[i] = 0; + } /* We need to clear any IRQ's pending in the soft interrupt * registers, a spurious one could be left around from the diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.126/linux/arch/sparc64/kernel/process.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/process.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.75 1998/09/23 02:05:15 davem Exp $ +/* $Id: process.c,v 1.82 1998/10/19 21:52:23 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -71,13 +71,16 @@ { current->priority = 0; while(1) { + struct task_struct *p; + check_pgt_cache(); run_task_queue(&tq_scheduler); - barrier(); current->counter = 0; - if(current->need_resched) + if (current->need_resched != 0 || + ((p = init_task.next_run) != NULL && + (p->processor == smp_processor_id() || + (p->tss.flags & SPARC_FLAG_NEWCHILD) != 0))) schedule(); - barrier(); } } @@ -386,12 +389,32 @@ else current->tss.utraps[0]--; } + + /* Turn off performance counters if on. */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + write_pcr(0); + } } void flush_thread(void) { + if (!(current->tss.flags & SPARC_FLAG_KTHREAD)) + flush_user_windows(); current->tss.w_saved = 0; + /* Turn off performance counters if on. */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + write_pcr(0); + } + /* No new signal delivery by default. */ current->tss.new_signal = 0; current->tss.fpsaved[0] = 0; @@ -399,18 +422,14 @@ /* Now, this task is no longer a kernel thread. */ current->tss.current_ds = USER_DS; if(current->tss.flags & SPARC_FLAG_KTHREAD) { - extern spinlock_t scheduler_lock; - current->tss.flags &= ~SPARC_FLAG_KTHREAD; /* exec_mmap() set context to NO_CONTEXT, here is * where we grab a new one. */ - spin_lock(&scheduler_lock); current->mm->cpu_vm_mask = 0; activate_context(current); current->mm->cpu_vm_mask = (1UL<tss.flags & SPARC_FLAG_32BIT) __asm__ __volatile__("stxa %%g0, [%0] %1" @@ -524,7 +543,6 @@ current->tss.w_saved = 0; return; barf: - lock_kernel(); do_exit(SIGILL); } @@ -552,7 +570,19 @@ p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; p->tss.fpsaved[0] = 0; + p->mm->segments = (void *) 0; if(regs->tstate & TSTATE_PRIV) { + /* Special case, if we are spawning a kernel thread from + * a userspace task (via KMOD, NFS, or similar) we must + * disable performance counters in the child because the + * address space and protection realm are changing. + */ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { + p->tss.user_cntd0 = + p->tss.user_cntd1 = NULL; + p->tss.pcr_reg = 0; + p->tss.flags &= ~(SPARC_FLAG_PERFCTR); + } p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD); p->tss.current_ds = KERNEL_DS; diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c --- v2.1.126/linux/arch/sparc64/kernel/psycho.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/psycho.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.64 1998/09/01 07:24:24 jj Exp $ +/* $Id: psycho.c,v 1.65 1998/10/20 14:41:28 ecd Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -1639,17 +1639,8 @@ return; } - /* See if we find a matching interrupt-map entry. */ - if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { - pdev->irq = psycho_irq_build(pbm, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif /* See if fully specified already (ie. for onboard devices like hme) */ - } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { + if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { pdev->irq = psycho_irq_build(pbm, pdev, prom_irq); #ifdef FIXUP_IRQ_DEBUG dprintf("fully specified prom_irq[%x] pdev->irq[%x]", @@ -1663,6 +1654,15 @@ #ifdef FIXUP_IRQ_DEBUG dprintf("partially specified prom_irq[%x] pdev->irq[%x]", prom_irq, pdev->irq); +#endif + /* See if we find a matching interrupt-map entry. */ + } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { + pdev->irq = psycho_irq_build(pbm, pdev, + (pbm->parent->upa_portid << 6) + | prom_irq); +#ifdef FIXUP_IRQ_DEBUG + dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); #endif } else { unsigned int bus, slot, line; diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.1.126/linux/arch/sparc64/kernel/ptrace.c Thu Aug 6 14:06:30 1998 +++ linux/arch/sparc64/kernel/ptrace.c Tue Oct 27 09:52:20 1998 @@ -43,6 +43,12 @@ repeat: pgdir = pgd_offset(vma->vm_mm, addr); + + /* Seems non-intuitive but the page copy/clear routines always + * check current's value. + */ + current->mm->segments = (void *) (addr & PAGE_SIZE); + if (pgd_none(*pgdir)) { handle_mm_fault(tsk, vma, addr, write); goto repeat; @@ -574,7 +580,11 @@ goto out; } #endif - if(!(child = find_task_by_pid(pid))) { + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + read_unlock(&tasklist_lock); + + if(!child) { pt_error_return(regs, ESRCH); goto out; } @@ -604,9 +614,13 @@ } child->flags |= PF_PTRACED; if(child->p_pptr != current) { + unsigned long flags; + + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = current; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); } send_sig(SIGSTOP, child, 1); pt_succ_return(regs, 0); @@ -781,11 +795,12 @@ cregs->tnpc = npc; } cregs->y = y; - for(i = 1; i < 16; i++) + for(i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } + } pt_succ_return(regs, 0); goto out; } @@ -814,11 +829,12 @@ cregs->tnpc = tnpc; } cregs->y = y; - for(i = 1; i < 16; i++) + for(i = 1; i < 16; i++) { if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { pt_error_return(regs, EFAULT); goto out; } + } pt_succ_return(regs, 0); goto out; } @@ -1055,23 +1071,29 @@ pt_succ_return(regs, 0); goto out; } - wake_up_process(child); child->exit_code = SIGKILL; + wake_up_process(child); pt_succ_return(regs, 0); goto out; } case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + unsigned long flags; + if ((unsigned long) data > _NSIG) { pt_error_return(regs, EIO); goto out; } child->flags &= ~(PF_PTRACED|PF_TRACESYS); - wake_up_process(child); child->exit_code = data; + + write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); child->p_pptr = child->p_opptr; SET_LINKS(child); + write_unlock_irqrestore(&tasklist_lock, flags); + + wake_up_process(child); pt_succ_return(regs, 0); goto out; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S --- v2.1.126/linux/arch/sparc64/kernel/rtrap.S Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/rtrap.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.40 1998/09/23 02:05:18 davem Exp $ +/* $Id: rtrap.S,v 1.44 1998/10/21 22:27:22 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -46,13 +46,15 @@ ldub [%l6 + %o0], %l2 sub %l5, 2, %l5 add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1 - andcc %l2, FPRS_FEF, %g0 + andcc %l2, (FPRS_FEF|FPRS_DU), %g0 be,pt %icc, 2f and %l2, FPRS_DL, %l6 + andcc %l2, FPRS_FEF, %g0 + be,pn %icc, 5f + sll %o0, 3, %o5 rd %fprs, %g5 wr %g5, FPRS_FEF, %fprs ldub [%o1 + %o0], %g5 - sll %o0, 3, %o5 add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1 membar #StoreLoad | #LoadLoad sll %o0, 8, %o2 @@ -130,25 +132,49 @@ nop lduw [%g6 + AOFF_task_sigpending], %l0 check_signal: brz,a,pt %l0, check_user_wins - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + nop clr %o0 mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 -check_user_wins:brz,pt %o2, 1f + + /* We must not take any traps between here and the actual + * return to user-space. If we do we risk having windows + * saved to the thread struct between the test and the + * actual return from trap. --DaveM + */ +check_user_wins: + wrpr %l7, 0x0, %pstate + lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %l6 + wrpr %l7, PSTATE_IE, %pstate call fault_in_user_windows add %sp, STACK_BIAS + REGWIN_SZ, %o0 - + /* It is OK to leave interrupts on now because if + * fault_in_user_windows has returned it has left us + * with a clean user stack state. + */ 1: #if 0 call rtrap_check add %sp, STACK_BIAS + REGWIN_SZ, %o0 #endif + lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5 + andcc %l5, 0x200, %g0 + be,pt %xcc, 1f + nop + + /* Don't forget to preserve user window invariants. */ + wrpr %l7, PSTATE_IE, %pstate + call update_perfctrs + nop + ba,a,pt %xcc, check_user_wins + +1: andcc %l1, %l6, %g0 be,pt %xcc, rt_continue stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only @@ -159,5 +185,17 @@ andn %l1, %l6, %l1 ba,pt %xcc, rt_continue+4 lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 + +5: wr %g0, FPRS_FEF, %fprs + membar #StoreLoad | #LoadLoad + sll %o0, 8, %o2 + add %g6, AOFF_task_fpregs+0x80, %o3 + add %g6, AOFF_task_fpregs+0xc0, %o4 + ldda [%o3 + %o2] ASI_BLK_P, %f32 + ldda [%o4 + %o2] ASI_BLK_P, %f48 +1: membar #Sync + wr %g0, FPRS_DU, %fprs + ba,pt %xcc, rt_continue + stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] #undef PTREGS_OFF diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.1.126/linux/arch/sparc64/kernel/setup.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/setup.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.32 1998/09/24 03:21:37 davem Exp $ +/* $Id: setup.c,v 1.37 1998/10/14 15:49:09 ecd Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -62,38 +62,207 @@ * prints out pretty messages and returns. */ -extern unsigned long sparc64_ttable_tl0; #if CONFIG_SUN_CONSOLE void (*prom_palette)(int); #endif asmlinkage void sys_sync(void); /* it's really int */ +static void +prom_console_write(struct console *con, const char *s, unsigned n) +{ + prom_printf("%s", s); +} + +static struct console prom_console = { + "prom", + prom_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_CONSDEV | CON_ENABLED, + -1, + 0, + NULL +}; + +#define PROM_TRUE -1 +#define PROM_FALSE 0 + /* Pretty sick eh? */ -void prom_sync_me(long *args) +int prom_callback(long *args) { - unsigned long prom_tba, flags; + struct console *cons, *saved_console = NULL; + unsigned long flags; + char *cmd; + + if (!args) + return -1; + if (!(cmd = (char *)args[0])) + return -1; save_and_cli(flags); - __asm__ __volatile__("flushw; rdpr %%tba, %0\n\t" : "=r" (prom_tba)); - __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0)); - -#ifdef CONFIG_SUN_CONSOLE - if (prom_palette) - prom_palette (1); -#endif - prom_printf("PROM SYNC COMMAND...\n"); - show_free_areas(); - if(current->pid != 0) { - sti(); - sys_sync(); - cli(); + cons = console_drivers; + while (cons) { + unregister_console(cons); + cons->flags &= ~(CON_PRINTBUFFER); + cons->next = saved_console; + saved_console = cons; + cons = console_drivers; } - prom_printf("Returning to prom\n"); + register_console(&prom_console); + if (!strcmp(cmd, "sync")) { + prom_printf("PROM `%s' command...\n", cmd); + show_free_areas(); + if(current->pid != 0) { + sti(); + sys_sync(); + cli(); + } + args[2] = 0; + args[args[1] + 3] = -1; + prom_printf("Returning to PROM\n"); + } else if (!strcmp(cmd, "va>tte-data")) { + unsigned long ctx, va; + unsigned long tte = 0; + long res = PROM_FALSE; + + ctx = args[3]; + va = args[4]; + if (ctx) { + /* + * Find process owning ctx, lookup mapping. + */ + struct task_struct *p; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + for_each_task(p) + if (p->tss.ctx == ctx) + break; + if (p->tss.ctx != ctx) + goto done; + + pgdp = pgd_offset(p->mm, va); + if (pgd_none(*pgdp)) + goto done; + pmdp = pmd_offset(pgdp, va); + if (pmd_none(*pmdp)) + goto done; + ptep = pte_offset(pmdp, va); + if (!pte_present(*ptep)) + goto done; + tte = pte_val(*ptep); + res = PROM_TRUE; + goto done; + } - __asm__ __volatile__("flushw; wrpr %0, 0x0, %%tba\n\t" : : "r" (prom_tba)); - restore_flags(flags); + if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) { + /* + * Locked down tlb entry 63. + */ + tte = spitfire_get_dtlb_data(63); + res = PROM_TRUE; + goto done; + } + + if (va < PGDIR_SIZE) { + /* + * vmalloc or prom_inherited mapping. + */ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + + pgdp = pgd_offset_k(va); + if (pgd_none(*pgdp)) + goto done; + pmdp = pmd_offset(pgdp, va); + if (pmd_none(*pmdp)) + goto done; + ptep = pte_offset(pmdp, va); + if (!pte_present(*ptep)) + goto done; + tte = pte_val(*ptep); + res = PROM_TRUE; + goto done; + } + + if (va < PAGE_OFFSET) { + /* + * No mappings here. + */ + goto done; + } - return; + if (va & (1UL << 40)) { + /* + * I/O page. + */ + + tte = (__pa(va) & _PAGE_PADDR) | + _PAGE_VALID | _PAGE_SZ4MB | + _PAGE_E | _PAGE_P | _PAGE_W; + res = PROM_TRUE; + goto done; + } + + /* + * Normal page. + */ + tte = (__pa(va) & _PAGE_PADDR) | + _PAGE_VALID | _PAGE_SZ4MB | + _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W; + res = PROM_TRUE; + + done: + if (res == PROM_TRUE) { + args[2] = 3; + args[args[1] + 3] = 0; + args[args[1] + 4] = res; + args[args[1] + 5] = tte; + } else { + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = res; + } + } else if (!strcmp(cmd, ".soft1")) { + unsigned long tte; + + tte = args[3]; + prom_printf("%lx:\"%s%s%s%s%s\" ", + (tte & _PAGE_SOFT) >> 7, + tte & _PAGE_MODIFIED ? "M" : "-", + tte & _PAGE_ACCESSED ? "A" : "-", + tte & _PAGE_READ ? "W" : "-", + tte & _PAGE_WRITE ? "R" : "-", + tte & _PAGE_PRESENT ? "P" : "-"); + + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = PROM_TRUE; + } else if (!strcmp(cmd, ".soft2")) { + unsigned long tte; + + tte = args[3]; + prom_printf("%lx ", (tte & _PAGE_SOFT2) >> 50); + + args[2] = 2; + args[args[1] + 3] = 0; + args[args[1] + 4] = PROM_TRUE; + } else { + prom_printf("unknown PROM `%s' command...\n", cmd); + } + unregister_console(&prom_console); + while (saved_console) { + cons = saved_console; + saved_console = cons->next; + register_console(cons); + } + restore_flags(flags); + return 0; } extern void rs_kgdb_hook(int tty_num); /* sparc/serial.c */ @@ -250,28 +419,6 @@ extern struct consw sun_serial_con; -#ifdef PROM_DEBUG_CONSOLE -static void -prom_console_write(struct console *con, const char *s, unsigned n) -{ - prom_printf("%s", s); -} - -static struct console prom_console = { - "prom", - prom_console_write, - NULL, - NULL, - NULL, - NULL, - NULL, - CON_PRINTBUFFER, - -1, - 0, - NULL -}; -#endif - __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { @@ -279,10 +426,6 @@ unsigned long lowest_paddr, end_of_phys_memory = 0; int total, i; -#ifdef PROM_DEBUG_CONSOLE - register_console(&prom_console); -#endif - /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); strcpy(saved_command_line, *cmdline_p); @@ -316,7 +459,13 @@ } } } - prom_setsync(prom_sync_me); + prom_setcallback(prom_callback); + prom_feval(": linux-va>tte-data 2 \" va>tte-data\" $callback drop ; " + "' linux-va>tte-data to va>tte-data"); + prom_feval(": linux-.soft1 1 \" .soft1\" $callback 2drop ; " + "' linux-.soft1 to .soft1"); + prom_feval(": linux-.soft2 1 \" .soft2\" $callback 2drop ; " + "' linux-.soft2 to .soft2"); /* In paging_init() we tip off this value to see if we need * to change init_mm.pgd to point to the real alias mapping. @@ -439,8 +588,6 @@ extern int smp_bogo(char *); extern int mmu_info(char *); -unsigned long dcache_aliases_found = 0; - int get_cpuinfo(char *buffer) { int cpuid=smp_processor_id(); @@ -454,7 +601,6 @@ "type\t\t: sun4u\n" "ncpus probed\t: %d\n" "ncpus active\t: %d\n" - "d-aliases\t: %lu\n" #ifndef __SMP__ "BogoMips\t: %lu.%02lu\n" #endif @@ -462,7 +608,7 @@ sparc_cpu_type[cpuid], sparc_fpu_type[cpuid], prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff, - linux_num_cpus, smp_num_cpus, dcache_aliases_found + linux_num_cpus, smp_num_cpus #ifndef __SMP__ , loops_per_sec/500000, (loops_per_sec/5000) % 100 #endif diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.1.126/linux/arch/sparc64/kernel/signal.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/signal.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.37 1998/09/25 01:09:22 davem Exp $ +/* $Id: signal.c,v 1.38 1998/10/16 03:19:04 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -53,7 +53,7 @@ unsigned char fenab; int err; - __asm__ __volatile__("flushw"); + flush_user_windows(); if(tp->w_saved || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok((unsigned long)ucp, sizeof(*ucp)))) diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.126/linux/arch/sparc64/kernel/signal32.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/signal32.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.44 1998/09/25 01:09:17 davem Exp $ +/* $Id: signal32.c,v 1.47 1998/10/13 09:07:40 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -76,6 +76,9 @@ /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; unsigned extramask[_NSIG_WORDS32 - 1]; + unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; __siginfo_fpu_t fpu_state; }; @@ -87,6 +90,9 @@ /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; stack_t32 stack; + unsigned extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */ + /* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */ + siginfo_extra_v8plus_t v8plus; __siginfo_fpu_t fpu_state; }; @@ -209,7 +215,7 @@ unsigned pc, npc, fpu_save; sigset_t set; unsigned seta[_NSIG_WORDS32]; - int err; + int err, i; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; @@ -232,24 +238,18 @@ err = __get_user(regs->y, &sf->info.si_regs.y); err |= __get_user(psr, &sf->info.si_regs.psr); - err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]); - err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]); - err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]); - err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]); - err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]); - err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]); - err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]); - err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]); - err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]); - err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]); - err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]); - err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]); - err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]); - err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); - err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { + err |= __get_user(i, &sf->v8plus.g_upper[0]); + if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + } + } /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); err |= __get_user(fpu_save, &sf->fpu_save); @@ -273,7 +273,6 @@ return; segv: - lock_kernel(); do_exit(SIGSEGV); } @@ -329,12 +328,11 @@ err |= __get_user(psr, &scptr->sigc_psr); if (err) goto segv; - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); return; segv: - lock_kernel(); do_exit(SIGSEGV); } @@ -346,7 +344,7 @@ sigset_t set; sigset_t32 seta; stack_t st; - int err; + int err, i; synchronize_user_stack(); regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; @@ -369,25 +367,19 @@ /* 2. Restore the state */ err = __get_user(regs->y, &sf->regs.y); err |= __get_user(psr, &sf->regs.psr); - - err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); - err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); - err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); - err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); - err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); - err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); - err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); - err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); - err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); - err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); - err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); - err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); - err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); - err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); - err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); + + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(regs->u_regs[i], &sf->regs.u_regs[i]); + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) { + err |= __get_user(i, &sf->v8plus.g_upper[0]); + if (i == SIGINFO_EXTRA_V8PLUS_MAGIC) { + for (i = UREG_G1; i <= UREG_I7; i++) + err |= __get_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); + } + } /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); err |= __get_user(fpu_save, &sf->fpu_save); @@ -417,7 +409,6 @@ spin_unlock_irq(¤t->sigmask_lock); return; segv: - lock_kernel(); do_exit(SIGSEGV); } @@ -472,7 +463,6 @@ /* Don't change signal code and address, so that * post mortem debuggers can have a look. */ - lock_kernel (); do_exit(SIGILL); } @@ -544,7 +534,6 @@ return; sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -614,6 +603,10 @@ err |= __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]); + err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); + err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); + for (i = 1; i < 16; i++) + err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); @@ -682,10 +675,8 @@ return; sigill: - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -717,7 +708,6 @@ #ifdef DEBUG_SIGNALS printk ("Invalid stack frame\n"); #endif - lock_kernel (); do_exit(SIGILL); } @@ -833,7 +823,6 @@ return; sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -850,7 +839,6 @@ if (current->tss.w_saved){ printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved); - lock_kernel(); do_exit (SIGSEGV); } err = clear_user(uc, sizeof (*uc)); @@ -968,7 +956,7 @@ regs->tnpc = npc | 1; err |= __get_user(regs->y, &((*gr) [SVR4_Y])); err |= __get_user(psr, &((*gr) [SVR4_PSR])); - regs->tstate &= ~(TSTATE_ICC); + regs->tstate &= ~(TSTATE_ICC|TSTATE_XCC); regs->tstate |= psr_to_tstate_icc(psr); #if 0 if(psr & PSR_EF) @@ -984,7 +972,6 @@ return -EINTR; sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -1034,6 +1021,10 @@ err |= __put_user(psr, &sf->regs.psr); for (i = 0; i < 16; i++) err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]); + err |= __put_user(sizeof(siginfo_extra_v8plus_t), &sf->extra_size); + err |= __put_user(SIGINFO_EXTRA_V8PLUS_MAGIC, &sf->v8plus.g_upper[0]); + for (i = 1; i < 16; i++) + err |= __put_user(((u32 *)regs->u_regs)[2*i], &sf->v8plus.g_upper[i]); if (psr & PSR_EF) { err |= save_fpu_state32(regs, &sf->fpu_state); @@ -1107,10 +1098,8 @@ return; sigill: - lock_kernel(); do_exit(SIGILL); sigsegv: - lock_kernel(); do_exit(SIGSEGV); } @@ -1304,14 +1293,19 @@ case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) + if(current->binfmt && + current->binfmt->core_dump && + current->binfmt->core_dump(signr, regs)) exit_code |= 0x80; unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); - show_regs (regs); + /* On SMP we are only interested in the current + * CPU's registers. + */ + __show_regs (regs); #ifdef DEBUG_SIGNALS_TLB do { extern void sparc_ultra_dump_itlb(void); diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.1.126/linux/arch/sparc64/kernel/smp.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/smp.c Tue Oct 27 09:52:20 1998 @@ -41,7 +41,9 @@ struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); -static unsigned char boot_cpu_id __initdata = 0; +/* Please don't make this initdata!!! --DaveM */ +static unsigned char boot_cpu_id = 0; + static int smp_activated = 0; volatile int cpu_number_map[NR_CPUS]; @@ -82,12 +84,16 @@ __initfunc(void smp_store_cpu_info(int id)) { - cpu_data[id].udelay_val = loops_per_sec; cpu_data[id].irq_count = 0; + cpu_data[id].bh_count = 0; + /* multiplier and counter set by + smp_setup_percpu_timer() */ + cpu_data[id].udelay_val = loops_per_sec; + cpu_data[id].pgcache_size = 0; + cpu_data[id].pte_cache = NULL; cpu_data[id].pgdcache_size = 0; cpu_data[id].pgd_cache = NULL; - cpu_data[id].pte_cache = NULL; } extern void distribute_irqs(void); @@ -137,6 +143,11 @@ __asm__ __volatile__("membar #Sync\n\t" "flush %%g6" : : : "memory"); + /* Clear this or we will die instantly when we + * schedule back to this idler... + */ + current->tss.flags &= ~(SPARC_FLAG_NEWCHILD); + while(!smp_processors_ready) membar("#LoadLoad"); } @@ -396,6 +407,8 @@ { u32 ctx = mm->context & 0x3ff; + start &= PAGE_MASK; + end &= PAGE_MASK; if(mm == current->mm && atomic_read(&mm->count) == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) goto local_flush_and_out; @@ -404,8 +417,6 @@ smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); local_flush_and_out: - start &= PAGE_MASK; - end &= PAGE_MASK; __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); } @@ -413,6 +424,7 @@ { u32 ctx = mm->context & 0x3ff; + page &= PAGE_MASK; if(mm == current->mm && atomic_read(&mm->count) == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) goto local_flush_and_out; @@ -433,11 +445,11 @@ smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); local_flush_and_out: - __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT); + __flush_tlb_page(ctx, page, SECONDARY_CONTEXT); } /* CPU capture. */ -#define CAPTURE_DEBUG +/* #define CAPTURE_DEBUG */ extern unsigned long xcall_capture; static atomic_t smp_capture_depth = ATOMIC_INIT(0); @@ -446,37 +458,42 @@ void smp_capture(void) { - int result = atomic_add_return(1, &smp_capture_depth); + if (smp_processors_ready) { + int result = atomic_add_return(1, &smp_capture_depth); - membar("#StoreStore | #LoadStore"); - if(result == 1) { - int ncpus = smp_num_cpus; + membar("#StoreStore | #LoadStore"); + if(result == 1) { + int ncpus = smp_num_cpus; #ifdef CAPTURE_DEBUG - printk("CPU[%d]: Sending penguins to jail...", smp_processor_id()); + printk("CPU[%d]: Sending penguins to jail...", + smp_processor_id()); #endif - penguins_are_doing_time = 1; - membar("#StoreStore | #LoadStore"); - atomic_inc(&smp_capture_registry); - smp_cross_call(&xcall_capture, 0, 0, 0); - while(atomic_read(&smp_capture_registry) != ncpus) - membar("#LoadLoad"); + penguins_are_doing_time = 1; + membar("#StoreStore | #LoadStore"); + atomic_inc(&smp_capture_registry); + smp_cross_call(&xcall_capture, 0, 0, 0); + while(atomic_read(&smp_capture_registry) != ncpus) + membar("#LoadLoad"); #ifdef CAPTURE_DEBUG - printk("done\n"); + printk("done\n"); #endif + } } } void smp_release(void) { - if(atomic_dec_and_test(&smp_capture_depth)) { + if(smp_processors_ready) { + if(atomic_dec_and_test(&smp_capture_depth)) { #ifdef CAPTURE_DEBUG - printk("CPU[%d]: Giving pardon to imprisoned penguins\n", - smp_processor_id()); + printk("CPU[%d]: Giving pardon to imprisoned penguins\n", + smp_processor_id()); #endif - penguins_are_doing_time = 0; - membar("#StoreStore | #StoreLoad"); - atomic_dec(&smp_capture_registry); + penguins_are_doing_time = 0; + membar("#StoreStore | #StoreLoad"); + atomic_dec(&smp_capture_registry); + } } } @@ -539,8 +556,12 @@ if(!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { - extern void irq_enter(int, int); - extern void irq_exit(int, int); +/* XXX Keep this in sync with irq.c --DaveM */ +#define irq_enter(cpu, irq) \ +do { hardirq_enter(cpu); \ + spin_unlock_wait(&global_irq_lock); \ +} while(0) +#define irq_exit(cpu, irq) hardirq_exit(cpu) irq_enter(cpu, 0); kstat.irqs[cpu][0]++; @@ -548,6 +569,9 @@ timer_tick_interrupt(regs); irq_exit(cpu, 0); + +#undef irq_enter +#undef irq_exit } if(current->pid) { diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.126/linux/arch/sparc64/kernel/sparc64_ksyms.c Fri Oct 9 13:27:06 1998 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.42 1998/10/05 03:18:50 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.48 1998/10/20 03:09:08 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -13,8 +13,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -55,7 +57,6 @@ extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long); void _sigpause_common (unsigned int set, struct pt_regs *); -extern void *__bzero_1page(void *); extern void *__bzero(void *, size_t); extern void *__bzero_noasi(void *, size_t); extern void *__memscan_zero(void *, size_t); @@ -63,6 +64,7 @@ extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); extern __kernel_size_t __strlen(const char *); +extern __kernel_size_t strlen(const char *); extern char saved_command_line[]; extern char *getname32(u32 name); extern void linux_sparc_syscall(void); @@ -87,6 +89,17 @@ #ifdef __SMP__ extern spinlock_t scheduler_lock; +extern spinlock_t kernel_flag; +extern int smp_num_cpus; +#ifdef SPIN_LOCK_DEBUG +extern void _do_spin_lock (spinlock_t *lock, char *str); +extern void _do_spin_unlock (spinlock_t *lock); +extern int _spin_trylock (spinlock_t *lock); +extern void _do_read_lock(rwlock_t *rw, char *str); +extern void _do_read_unlock(rwlock_t *rw, char *str); +extern void _do_write_lock(rwlock_t *rw, char *str); +extern void _do_write_unlock(rwlock_t *rw); +#endif #endif /* One thing to note is that the way the symbols of the mul/div @@ -102,19 +115,46 @@ /* used by various drivers */ #ifdef __SMP__ +/* Kernel wide locking */ EXPORT_SYMBOL(scheduler_lock); +EXPORT_SYMBOL(kernel_flag); + +/* Software-IRQ BH locking */ EXPORT_SYMBOL(global_bh_lock); +EXPORT_SYMBOL(global_bh_count); +EXPORT_SYMBOL(synchronize_bh); + +/* Hard IRQ locking */ EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(global_irq_lock); +EXPORT_SYMBOL(global_irq_count); EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(cpu_data); EXPORT_SYMBOL_PRIVATE(global_cli); EXPORT_SYMBOL_PRIVATE(global_sti); +EXPORT_SYMBOL_PRIVATE(global_save_flags); EXPORT_SYMBOL_PRIVATE(global_restore_flags); + +/* Per-CPU information table */ +EXPORT_SYMBOL(cpu_data); + +/* Misc SMP information */ +EXPORT_SYMBOL(smp_num_cpus); + +/* Spinlock debugging library, optional. */ +#ifdef SPIN_LOCK_DEBUG +EXPORT_SYMBOL(_do_spin_lock); +EXPORT_SYMBOL(_do_spin_unlock); +EXPORT_SYMBOL(_spin_trylock); +EXPORT_SYMBOL(_do_read_lock); +EXPORT_SYMBOL(_do_read_unlock); +EXPORT_SYMBOL(_do_write_lock); +EXPORT_SYMBOL(_do_write_unlock); +#endif + #else EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(local_bh_count); #endif -EXPORT_SYMBOL_PRIVATE(_lock_kernel); -EXPORT_SYMBOL_PRIVATE(_unlock_kernel); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); @@ -124,7 +164,6 @@ EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); -EXPORT_SYMBOL(__sparc64_bh_counter); EXPORT_SYMBOL(sparc_ultra_unmapioaddr); EXPORT_SYMBOL(mmu_get_scsi_sgl); EXPORT_SYMBOL(mmu_get_scsi_one); @@ -185,6 +224,9 @@ /* sparc library symbols */ EXPORT_SYMBOL(bcopy); EXPORT_SYMBOL(__strlen); +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 +EXPORT_SYMBOL(strlen); +#endif EXPORT_SYMBOL(strnlen); EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strncpy); @@ -220,7 +262,7 @@ /* Special internal versions of library functions. */ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); -EXPORT_SYMBOL(__bzero_1page); +EXPORT_SYMBOL(clear_page); EXPORT_SYMBOL(__bzero); EXPORT_SYMBOL(__memscan_zero); EXPORT_SYMBOL(__memscan_generic); diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c --- v2.1.126/linux/arch/sparc64/kernel/sys_sparc.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/sys_sparc.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.22 1998/09/25 01:09:27 davem Exp $ +/* $Id: sys_sparc.c,v 1.25 1998/10/21 03:21:15 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -25,6 +25,7 @@ #include #include #include +#include /* XXX Make this per-binary type, this way we can detect the type of * XXX a binary. Every Sparc executable calls this very early on. @@ -151,6 +152,7 @@ struct file * file = NULL; unsigned long retval = -EBADF; + down(¤t->mm->mmap_sem); lock_kernel(); if (!(flags & MAP_ANONYMOUS)) { file = fget(fd); @@ -189,6 +191,7 @@ fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -377,4 +380,106 @@ } return ret; +} + +/* Invoked by rtrap code to update performance counters in + * user space. + */ +asmlinkage void +update_perfctrs(void) +{ + unsigned long pic, tmp; + + read_pic(pic); + tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); + __put_user(tmp, current->tss.user_cntd0); + tmp = (current->tss.kernel_cntd1 += (pic >> 32)); + __put_user(tmp, current->tss.user_cntd1); + reset_pic(); +} + +asmlinkage int +sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long arg2) +{ + int err = 0; + + switch(opcode) { + case PERFCTR_ON: + current->tss.pcr_reg = arg2; + current->tss.user_cntd0 = (u64 *) arg0; + current->tss.user_cntd1 = (u64 *) arg1; + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + write_pcr(arg2); + reset_pic(); + current->tss.flags |= SPARC_FLAG_PERFCTR; + break; + + case PERFCTR_OFF: + err = -EINVAL; + if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) { + current->tss.user_cntd0 = + current->tss.user_cntd1 = NULL; + current->tss.pcr_reg = 0; + write_pcr(0); + current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + err = 0; + } + break; + + case PERFCTR_READ: { + unsigned long pic, tmp; + + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + read_pic(pic); + tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); + err |= __put_user(tmp, current->tss.user_cntd0); + tmp = (current->tss.kernel_cntd1 += (pic >> 32)); + err |= __put_user(tmp, current->tss.user_cntd1); + reset_pic(); + break; + } + + case PERFCTR_CLRPIC: + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + reset_pic(); + break; + + case PERFCTR_SETPCR: { + u64 *user_pcr = (u64 *)arg0; + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + err |= __get_user(current->tss.pcr_reg, user_pcr); + write_pcr(current->tss.pcr_reg); + current->tss.kernel_cntd0 = + current->tss.kernel_cntd1 = 0; + reset_pic(); + break; + } + + case PERFCTR_GETPCR: { + u64 *user_pcr = (u64 *)arg0; + if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + err = -EINVAL; + break; + } + err |= __put_user(current->tss.pcr_reg, user_pcr); + break; + } + + default: + err = -EINVAL; + break; + }; + return err; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.126/linux/arch/sparc64/kernel/sys_sparc32.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/sys_sparc32.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.95 1998/09/07 09:20:50 davem Exp $ +/* $Id: sys_sparc32.c,v 1.98 1998/10/26 20:01:11 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -224,9 +224,6 @@ __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch; - unsigned short shm_npages; - u32 shm_pages; - u32 attaches; }; /* @@ -1394,7 +1391,7 @@ else if(is_smb) do_smb_super_data_conv((void *)data_page); else - panic("Tell DaveM he fucked up..."); + panic("The problem is here..."); old_fs = get_fs(); set_fs(KERNEL_DS); err = sys_mount((char *)dev_page, (char *)dir_page, @@ -2707,10 +2704,53 @@ /* Query various bits about modules. */ -extern long get_mod_name(const char *user_name, char **buf); -extern void put_mod_name(char *buf); -extern struct module *find_module(const char *name); -extern struct module kernel_module; +static inline long +get_mod_name(const char *user_name, char **buf) +{ + unsigned long page; + long retval; + + if ((unsigned long)user_name >= TASK_SIZE + && !segment_eq(get_fs (), KERNEL_DS)) + return -EFAULT; + + page = __get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + retval = strncpy_from_user((char *)page, user_name, PAGE_SIZE); + if (retval > 0) { + if (retval < PAGE_SIZE) { + *buf = (char *)page; + return retval; + } + retval = -ENAMETOOLONG; + } else if (!retval) + retval = -EINVAL; + + free_page(page); + return retval; +} + +static inline void +put_mod_name(char *buf) +{ + free_page((unsigned long)buf); +} + +static __inline__ struct module *find_module(const char *name) +{ + struct module *mod; + + for (mod = module_list; mod ; mod = mod->next) { + if (mod->flags & MOD_DELETED) + continue; + if (!strcmp(mod->name, name)) + break; + } + + return mod; +} static int qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) @@ -2720,7 +2760,7 @@ nmod = space = 0; - for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) { + for (mod = module_list; mod->next != NULL; mod = mod->next, ++nmod) { len = strlen(mod->name)+1; if (len > bufsize) goto calc_space_needed; @@ -2738,7 +2778,7 @@ calc_space_needed: space += len; - while ((mod = mod->next) != &kernel_module) + while ((mod = mod->next)->next != NULL) space += strlen(mod->name)+1; if (put_user(space, ret)) @@ -2752,7 +2792,7 @@ { size_t i, space, len; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) if (put_user(0, ret)) @@ -2796,7 +2836,7 @@ size_t nrefs, space, len; struct module_ref *ref; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) if (put_user(0, ret)) @@ -2898,7 +2938,7 @@ { int error = 0; - if (mod == &kernel_module) + if (mod->next == NULL) return -EINVAL; if (sizeof(struct module_info32) <= bufsize) { @@ -2926,9 +2966,11 @@ int err; lock_kernel(); - if (name_user == 0) - mod = &kernel_module; - else { + if (name_user == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; mod->next != NULL; mod = mod->next) + ; + } else { long namelen; char *name; @@ -2937,9 +2979,11 @@ goto out; } err = -ENOENT; - if (namelen == 0) - mod = &kernel_module; - else if ((mod = find_module(name)) == NULL) { + if (namelen == 0) { + /* This finds "kernel_module" which is not exported. */ + for(mod = module_list; mod->next != NULL; mod = mod->next) + ; + } else if ((mod = find_module(name)) == NULL) { put_mod_name(name); goto out; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.1.126/linux/arch/sparc64/kernel/sys_sunos32.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/sys_sunos32.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.18 1998/08/31 03:41:01 davem Exp $ +/* $Id: sys_sunos32.c,v 1.22 1998/10/26 20:01:13 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -68,6 +68,7 @@ struct file *file = NULL; unsigned long retval, ret_type; + down(¤t->mm->mmap_sem); lock_kernel(); current->personality |= PER_BSD; if(flags & MAP_NORESERVE) { @@ -117,6 +118,7 @@ fput(file); out: unlock_kernel(); + up(¤t->mm->mmap_sem); return (u32) retval; } @@ -131,6 +133,7 @@ unsigned long rlim; unsigned long newbrk, oldbrk, brk = (unsigned long) baddr; + down(¤t->mm->mmap_sem); lock_kernel(); if (brk < current->mm->end_code) goto out; @@ -178,6 +181,7 @@ retval = 0; out: unlock_kernel(); + up(¤t->mm->mmap_sem); return retval; } @@ -538,27 +542,17 @@ char mach[9]; }; -asmlinkage int sunos_uname(u32 u_name) +asmlinkage int sunos_uname(struct sunos_utsname *name) { - struct sunos_utsname *name = (struct sunos_utsname *)A(u_name); - int ret = -EFAULT; + int ret; down(&uts_sem); - if(!name) - goto out; - if(copy_to_user(&name->sname[0], - &system_utsname.sysname[0], - sizeof(name->sname) - 1)) - goto out; - copy_to_user(&name->nname[0], - &system_utsname.nodename[0], - sizeof(name->nname) - 1); - put_user('\0', &name->nname[8]); - copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); - ret = 0; -out: + ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= put_user('\0', &name->nname[8]); + ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); + ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); + ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); up(&uts_sem); return ret; } @@ -837,6 +831,8 @@ int ret = -EINVAL; char *dev_fname = 0; + if (!capable (CAP_SYS_ADMIN)) + return -EPERM; lock_kernel(); /* We don't handle the integer fs type */ if ((flags & SMNT_NEWTYPE) == 0) @@ -1211,9 +1207,6 @@ __kernel_ipc_pid_t32 shm_cpid; __kernel_ipc_pid_t32 shm_lpid; unsigned short shm_nattch; - unsigned short shm_npages; - u32 shm_pages; - u32 attaches; }; static inline int sunos_shmid_get(struct shmid_ds32 *user, @@ -1230,8 +1223,7 @@ __get_user(kern->shm_ctime, &user->shm_ctime) || __get_user(kern->shm_cpid, &user->shm_cpid) || __get_user(kern->shm_lpid, &user->shm_lpid) || - __get_user(kern->shm_nattch, &user->shm_nattch) || - __get_user(kern->shm_npages, &user->shm_npages)) + __get_user(kern->shm_nattch, &user->shm_nattch)) return -EFAULT; return 0; } @@ -1250,8 +1242,7 @@ __put_user(kern->shm_ctime, &user->shm_ctime) || __put_user(kern->shm_cpid, &user->shm_cpid) || __put_user(kern->shm_lpid, &user->shm_lpid) || - __put_user(kern->shm_nattch, &user->shm_nattch) || - __put_user(kern->shm_npages, &user->shm_npages)) + __put_user(kern->shm_nattch, &user->shm_nattch)) return -EFAULT; return 0; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S --- v2.1.126/linux/arch/sparc64/kernel/systbls.S Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/systbls.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.49 1998/09/13 04:30:32 davem Exp $ +/* $Id: systbls.S,v 1.50 1998/10/07 01:27:27 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -20,7 +20,7 @@ /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod -/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek +/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice @@ -79,7 +79,7 @@ /*0*/ .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod -/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek +/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_perfctr, sys_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S --- v2.1.126/linux/arch/sparc64/kernel/trampoline.S Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/kernel/trampoline.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $ +/* $Id: trampoline.S,v 1.6 1998/10/11 06:58:23 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -27,6 +27,7 @@ stxa %g1, [%g0] ASI_LSU_CONTROL membar #Sync wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate + wr %g0, 0, %fprs wrpr %g0, 15, %pil sethi %uhi(PAGE_OFFSET), %g4 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c --- v2.1.126/linux/arch/sparc64/kernel/traps.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/traps.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.54 1998/09/25 01:09:02 davem Exp $ +/* $Id: traps.c,v 1.55 1998/10/11 06:58:22 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -661,7 +661,7 @@ #ifndef __SMP__ unsigned node = linux_cpus[get_cpuid()].prom_node; #else -#error SMP not supported on sparc64 yet +#error cache_flush_trap not supported on sparc64/SMP yet #endif #if 0 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/kernel/unaligned.c linux/arch/sparc64/kernel/unaligned.c --- v2.1.126/linux/arch/sparc64/kernel/unaligned.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/kernel/unaligned.c Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.11 1998/09/22 03:24:52 davem Exp $ +/* $Id: unaligned.c,v 1.13 1998/10/07 22:43:13 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -58,9 +58,10 @@ { unsigned int tmp; - if (((insn >> 19) & 0xf) == 14) - return 8; /* stx* */ - tmp = (insn >> 19) & 3; + tmp = ((insn >> 19) & 0xf); + if (tmp == 11 || tmp == 14) /* ldx/stx */ + return 8; + tmp &= 3; if(!tmp) return 4; else if(tmp == 3) diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile --- v2.1.126/linux/arch/sparc64/lib/Makefile Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/lib/Makefile Tue Oct 27 09:52:20 1998 @@ -1,10 +1,10 @@ -# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $ +# $Id: Makefile,v 1.18 1998/10/13 09:07:24 davem Exp $ # Makefile for Sparc library files.. # CFLAGS := $(CFLAGS) -OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \ +OBJS = PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o @@ -16,10 +16,10 @@ VISbzero.o: VISbzero.S VIS.h .S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o dep: diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S --- v2.1.126/linux/arch/sparc64/lib/VIScopy.S Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/lib/VIScopy.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $ +/* $Id: VIScopy.S,v 1.19 1998/10/19 21:52:19 davem Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -480,7 +480,7 @@ vis01:FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_SYNC(o0, f48) membar #Sync FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_JUMP(o0, f48, finish_f0) membar #Sync vis02:FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0) STORE_SYNC(o0, f48) membar #Sync - FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, check_finish_f16) add %o2, %g3, %g7 + FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_JUMP(o0, f48, finish_f16) membar #Sync vis03:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) STORE_SYNC(o0, f48) membar #Sync FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) STORE_JUMP(o0, f48, finish_f32) membar #Sync VISLOOP_PAD @@ -569,18 +569,7 @@ finish_f10: FINISH_VISCHUNK(o0, f10, f12, g3) finish_f12: FINISH_VISCHUNK(o0, f12, f14, g3) finish_f14: UNEVEN_VISCHUNK(o0, f14, f0, g3) -/* This is a special hack to speed up 8K page copy */ -check_finish_f16: - andcc %g1, 7, %g0 - bne,pn %icc, finish_f16 - cmp %g7, 0x40 - bne,pn %icc, finish_f16 - FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) - membar #Sync - EXVIS1(STBLK %f48, [%o0] ASIBLK) - b,pt %xcc, vis_ret -finish_f16: membar #Sync - FINISH_VISCHUNK(o0, f16, f18, g3) +finish_f16: FINISH_VISCHUNK(o0, f16, f18, g3) finish_f18: FINISH_VISCHUNK(o0, f18, f20, g3) finish_f20: FINISH_VISCHUNK(o0, f20, f22, g3) finish_f22: FINISH_VISCHUNK(o0, f22, f24, g3) diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/VISsave.S linux/arch/sparc64/lib/VISsave.S --- v2.1.126/linux/arch/sparc64/lib/VISsave.S Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/lib/VISsave.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj Exp $ +/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $ * VISsave.S: Code for saving FPU register state for * VIS routines. One should not call this directly, * but use macros provided in . @@ -76,11 +76,13 @@ sll %g1, 5, %g1 add %g6, AOFF_task_fpregs+0xc0, %g3 + wr %g0, FPRS_FEF, %fprs membar #StoreStore | #LoadStore stda %f32, [%g2 + %g1] ASI_BLK_P stda %f48, [%g3 + %g1] ASI_BLK_P membar #Sync jmpl %g7 + %g0, %g0 + nop .align 32 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S --- v2.1.126/linux/arch/sparc64/lib/blockops.S Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/lib/blockops.S Tue Oct 27 09:52:20 1998 @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $ +/* $Id: blockops.S,v 1.16 1998/10/20 03:09:04 jj Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,9 @@ #include "VIS.h" #include +#include +#include +#include #define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \ fmovd %reg0, %f48; fmovd %reg1, %f50; \ @@ -14,12 +17,47 @@ fmovd %reg4, %f56; fmovd %reg5, %f58; \ fmovd %reg6, %f60; fmovd %reg7, %f62; +#define TLBTEMP_BASE (8 * 1024 * 1024) +#define DCACHE_SIZE (PAGE_SIZE * 2) +#define TLBTEMP_ENT1 (61 << 3) +#define TLBTEMP_ENT2 (62 << 3) +#define TLBTEMP_ENTSZ (1 << 3) + .text .align 32 .globl copy_page .type copy_page,@function copy_page: /* %o0=dest, %o1=src */ VISEntry + ldx [%g6 + AOFF_task_mm], %o2 + sub %o0, %g4, %g1 + sethi %uhi(_PAGE_VALID), %g3 + sub %o1, %g4, %g2 + sllx %g3, 32, %g3 + ldx [%o2 + AOFF_mm_segments], %o0 + or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 + or %g1, %g3, %g1 + or %g2, %g3, %g2 + mov TLB_TAG_ACCESS, %o2 + sethi %hi(TLBTEMP_BASE), %o3 + sethi %hi(DCACHE_SIZE), %o1 + add %o0, %o3, %o0 + add %o0, %o1, %o1 + sethi %hi(TLBTEMP_ENT1), %o3 + rdpr %pstate, %g3 + wrpr %g3, PSTATE_IE, %pstate + ldxa [%o3] ASI_DTLB_TAG_READ, %o4 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %o5 + stxa %o0, [%o2] ASI_DMMU + stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + add %o3, (TLBTEMP_ENTSZ), %o3 + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 + stxa %o1, [%o2] ASI_DMMU + stxa %g2, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + membar #LoadStore | #StoreStore | #StoreLoad ldda [%o1] ASI_BLK_P, %f0 add %o1, 0x40, %o1 @@ -50,15 +88,44 @@ stda %f0, [%o0] ASI_BLK_P add %o0, 0x40, %o0 stda %f16, [%o0] ASI_BLK_P - membar #StoreStore | #StoreLoad + membar #Sync + VISExit + + mov TLB_TAG_ACCESS, %o2 + stxa %g5, [%o2] ASI_DMMU + stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + sub %o3, (TLBTEMP_ENTSZ), %o3 + stxa %o4, [%o2] ASI_DMMU + stxa %o5, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync jmpl %o7 + 0x8, %g0 - VISExit + wrpr %g3, 0x0, %pstate .align 32 - .globl __bzero_1page - .type __bzero_1page,@function -__bzero_1page: /* %o0=dest */ + .globl clear_page + .type clear_page,@function +clear_page: /* %o0=dest */ VISEntryHalf + ldx [%g6 + AOFF_task_mm], %o2 + sub %o0, %g4, %g1 + sethi %uhi(_PAGE_VALID), %g3 + sllx %g3, 32, %g3 + or %g3, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W), %g3 + ldx [%o2 + AOFF_mm_segments], %o0 + or %g1, %g3, %g1 + mov TLB_TAG_ACCESS, %o2 + sethi %hi(TLBTEMP_BASE), %o3 + add %o0, %o3, %o0 + sethi %hi(TLBTEMP_ENT2), %o3 + rdpr %pstate, %g3 + wrpr %g3, PSTATE_IE, %pstate + ldxa [%o3] ASI_DTLB_TAG_READ, %g5 + ldxa [%o3] ASI_DTLB_DATA_ACCESS, %g7 + stxa %o0, [%o2] ASI_DMMU + stxa %g1, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + fzero %f0 ! FPA Group mov 32, %o1 ! IEU0 fzero %f2 ! FPA Group @@ -79,6 +146,11 @@ subcc %o1, 1, %o1 ! IEU1 bne,pt %icc, 1b ! CTI add %o0, 0x100, %o0 ! IEU0 Group - membar #StoreStore | #StoreLoad ! LSU Group - jmpl %o7 + 0x8, %g0 ! CTI Group brk forced - VISExitHalf + membar #Sync ! LSU Group + VISExitHalf + + stxa %g5, [%o2] ASI_DMMU + stxa %g7, [%o3] ASI_DTLB_DATA_ACCESS + membar #Sync + jmpl %o7 + 0x8, %g0 + wrpr %g3, 0x0, %pstate diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/debuglocks.c linux/arch/sparc64/lib/debuglocks.c --- v2.1.126/linux/arch/sparc64/lib/debuglocks.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/debuglocks.c Tue Oct 27 09:52:20 1998 @@ -0,0 +1,278 @@ +/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $ + * debuglocks.c: Debugging versions of SMP locking primitives. + * + * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) + */ + +#include +#include +#include +#include + +#ifdef __SMP__ + +/* To enable this code, just define SPIN_LOCK_DEBUG in asm/spinlock.h */ +#ifdef SPIN_LOCK_DEBUG + +#define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC)) + +static inline void show (char *str, spinlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n", + str, lock, cpu, (unsigned int) caller, + lock->owner_pc, lock->owner_cpu); +} + +static inline void show_read (char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n", + str, lock, cpu, (unsigned int) caller, + lock->writer_pc, lock->writer_cpu); +} + +static inline void show_write (char *str, rwlock_t *lock, unsigned long caller) +{ + int cpu = smp_processor_id(); + + printk("%s(%p) CPU#%d stuck at %08x\n", + str, lock, cpu, (unsigned int) caller); + printk("Writer: PC(%08x):CPU(%x)\n", + lock->writer_pc, lock->writer_cpu); + printk("Readers: 0[%08x] 1[%08x] 2[%08x] 4[%08x]\n", + lock->reader_pc[0], lock->reader_pc[1], + lock->reader_pc[2], lock->reader_pc[3]); +} + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +void _do_spin_lock(spinlock_t *lock, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +again: + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (val) + : "r" (&(lock->lock)) + : "memory"); + membar("#StoreLoad | #StoreStore"); + if (val) { + while (lock->lock) { + if (!--stuck) { + show(str, lock, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + goto again; + } + lock->owner_pc = ((unsigned int)caller); + lock->owner_cpu = cpu; +} + +int _spin_trylock(spinlock_t *lock) +{ + unsigned long val, caller; + int cpu = smp_processor_id(); + + GET_CALLER(caller); + __asm__ __volatile__("ldstub [%1], %0" + : "=r" (val) + : "r" (&(lock->lock)) + : "memory"); + membar("#StoreLoad | #StoreStore"); + if (!val) { + lock->owner_pc = ((unsigned int)caller); + lock->owner_cpu = cpu; + } + return val == 0; +} + +void _do_spin_unlock(spinlock_t *lock) +{ + lock->owner_pc = 0; + lock->owner_cpu = NO_PROC_ID; + membar("#StoreStore | #LoadStore"); + lock->lock = 0; +} + +/* Keep INIT_STUCK the same... */ + +void _do_read_lock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +wlock_again: + /* Wait for any writer to go away. */ + while (((long)(rw->lock)) < 0) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + /* Try once to increment the counter. */ + __asm__ __volatile__(" + ldx [%0], %%g5 + brlz,a,pn %%g5, 2f + mov 1, %0 + add %%g5, 1, %%g7 + casx [%0], %%g5, %%g7 + sub %%g5, %%g7, %0 +2:" : "=r" (val) + : "0" (&(rw->lock)) + : "g5", "g7", "memory"); + membar("#StoreLoad | #StoreStore"); + if (val) + goto wlock_again; + rw->reader_pc[cpu] = ((unsigned int)caller); +} + +void _do_read_unlock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); + + /* Drop our identity _first_. */ + rw->reader_pc[cpu] = 0; +runlock_again: + /* Spin trying to decrement the counter using casx. */ + __asm__ __volatile__(" + ldx [%0], %%g5 + sub %%g5, 1, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + sub %%g5, %%g7, %0 +" : "=r" (val) + : "0" (&(rw->lock)) + : "g5", "g7", "memory"); + if (val) { + if (!--stuck) { + show_read(str, rw, caller); + stuck = INIT_STUCK; + } + goto runlock_again; + } +} + +void _do_write_lock (rwlock_t *rw, char *str) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + int cpu = smp_processor_id(); + + GET_CALLER(caller); +wlock_again: + /* Spin while there is another writer. */ + while (((long)rw->lock) < 0) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + + /* Try to acuire the write bit. */ + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 + ldx [%0], %%g5 + brlz,pn %%g5, 1f + or %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + ba,pt %%xcc, 2f + sub %%g5, %%g7, %0 +1: mov 1, %0 +2:" : "=r" (val) + : "0" (&(rw->lock)) + : "g3", "g5", "g7", "memory"); + if (val) { + /* We couldn't get the write bit. */ + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + goto wlock_again; + } + if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) { + /* Readers still around, drop the write + * lock, spin, and try again. + */ + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 +1: ldx [%0], %%g5 + andn %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + cmp %%g5, %%g7 + bne,pn %%xcc, 1b + membar #StoreLoad | #StoreStore" + : /* no outputs */ + : "r" (&(rw->lock)) + : "g3", "g5", "g7", "cc", "memory"); + while(rw->lock != 0) { + if (!--stuck) { + show_write(str, rw, caller); + stuck = INIT_STUCK; + } + membar("#LoadLoad"); + } + goto wlock_again; + } + + /* We have it, say who we are. */ + rw->writer_pc = ((unsigned int)caller); + rw->writer_cpu = cpu; +} + +void _do_write_unlock(rwlock_t *rw) +{ + unsigned long caller, val; + int stuck = INIT_STUCK; + + GET_CALLER(caller); + + /* Drop our identity _first_ */ + rw->writer_pc = 0; + rw->writer_cpu = NO_PROC_ID; +wlock_again: + __asm__ __volatile__(" + mov 1, %%g3 + sllx %%g3, 63, %%g3 + ldx [%0], %%g5 + andn %%g5, %%g3, %%g7 + casx [%0], %%g5, %%g7 + membar #StoreLoad | #StoreStore + sub %%g5, %%g7, %0 +" : "=r" (val) + : "0" (&(rw->lock)) + : "g3", "g5", "g7", "memory"); + if (val) { + if (!--stuck) { + show_write("write_unlock", rw, caller); + stuck = INIT_STUCK; + } + goto wlock_again; + } +} + +#endif /* SPIN_LOCK_DEBUG */ +#endif /* __SMP__ */ diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/locks.S linux/arch/sparc64/lib/locks.S --- v2.1.126/linux/arch/sparc64/lib/locks.S Sat Aug 16 09:51:09 1997 +++ linux/arch/sparc64/lib/locks.S Wed Dec 31 16:00:00 1969 @@ -1,76 +0,0 @@ -/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $ - * locks.S: SMP low-level lock primitives on Sparc64. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include - - .text - .align 32 - -___lk_busy_spin: - ldub [%g1 + 0], %g2 - brnz,pt %g2, ___lk_busy_spin - membar #LoadLoad - b,pt %xcc, 1f - ldstub [%g1 + 0], %g2 - - .globl ___lock_kernel -___lock_kernel: - addcc %g2, -1, %g2 - rdpr %pil, %g3 - bcs,a,pn %icc, 9f - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr %g0, 15, %pil - ldstub [%g1 + 0], %g2 -1: brnz,pn %g2, ___lk_busy_spin - membar #StoreLoad | #StoreStore - lduw [%g6 + AOFF_task_processor], %g2 - stb %g2, [%g1 + 1] -2: mov -1, %g2 - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr %g3, 0, %pil -9: jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - - .globl ___lock_reacquire_kernel -___lock_reacquire_kernel: - rdpr %pil, %g3 - wrpr %g0, 15, %pil - stw %g2, [%g6 + AOFF_task_lock_depth] - ldstub [%g1 + 0], %g2 -1: brz,pt %g2, 3f - membar #StoreLoad | #StoreStore -2: ldub [%g1 + 0], %g2 - brnz,pt %g2, 2b - membar #LoadLoad - b,pt %xcc, 1b - ldstub [%g1 + 0], %g2 -3: lduw [%g6 + AOFF_task_processor], %g2 - stb %g2, [%g1 + 1] - wrpr %g3, 0, %pil - jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - -#undef NO_PROC_ID -#define NO_PROC_ID 0xff - - .globl ___unlock_kernel -___unlock_kernel: - addcc %g2, 1, %g2 - rdpr %pil, %g3 - bne,a,pn %icc, 1f - stw %g2, [%g6 + AOFF_task_lock_depth] - wrpr 15, %pil - mov NO_PROC_ID, %g2 - stb %g2, [%g1 + 1] - membar #StoreStore | #LoadStore - stb %g0, [%g1 + 0] - stw %g0, [%g6 + AOFF_task_lock_depth] - wrpr %g3, 0, %pil -1: jmpl %o7 + 0x8, %g0 - mov %g5, %o7 - diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/lib/strlen.S linux/arch/sparc64/lib/strlen.S --- v2.1.126/linux/arch/sparc64/lib/strlen.S Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/lib/strlen.S Tue Oct 27 09:52:20 1998 @@ -9,7 +9,8 @@ #define HI_MAGIC 0x80808080 .align 32 - .global __strlen + .global strlen, __strlen +strlen: __strlen: mov %o0, %o1 andcc %o0, 3, %g0 diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/math-emu/Makefile linux/arch/sparc64/math-emu/Makefile --- v2.1.126/linux/arch/sparc64/math-emu/Makefile Thu Apr 23 20:21:32 1998 +++ linux/arch/sparc64/math-emu/Makefile Tue Oct 27 09:52:20 1998 @@ -16,10 +16,4 @@ fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o \ fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o -.S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s - -.S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o - include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.126/linux/arch/sparc64/mm/fault.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/mm/fault.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.24 1998/09/22 03:27:33 davem Exp $ +/* $Id: fault.c,v 1.25 1998/10/19 21:52:26 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -154,6 +154,7 @@ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } + current->mm->segments = (void *) (address & PAGE_SIZE); handle_mm_fault(current, vma, address, write); up(&mm->mmap_sem); return; diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c --- v2.1.126/linux/arch/sparc64/mm/init.c Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/mm/init.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.98 1998/09/28 06:18:39 davem Exp $ +/* $Id: init.c,v 1.103 1998/10/20 03:09:12 jj Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -45,7 +45,6 @@ int do_check_pgt_cache(int low, int high) { - struct page *page, *page2; int freed = 0; if(pgtable_cache_size > high) { @@ -60,6 +59,7 @@ } #ifndef __SMP__ if (pgd_cache_size > high / 4) { + struct page *page, *page2; for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) { if ((unsigned long)page->pprev_hash == 3) { if (page2) @@ -537,7 +537,7 @@ if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PMD_TABLE_SIZE); - clear_page(pmdp); + memset(pmdp, 0, PAGE_SIZE); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, vaddr); @@ -591,12 +591,17 @@ } static int prom_ditlb_set = 0; -int prom_itlb_ent, prom_dtlb_ent; -unsigned long prom_itlb_tag, prom_itlb_data; -unsigned long prom_dtlb_tag, prom_dtlb_data; +struct prom_tlb_entry { + int tlb_ent; + unsigned long tlb_tag; + unsigned long tlb_data; +}; +struct prom_tlb_entry prom_itlb[8], prom_dtlb[8]; void prom_world(int enter) { + int i; + if (!prom_ditlb_set) return; if (enter) { @@ -604,29 +609,44 @@ __flush_nucleus_vptes(); /* Install PROM world. */ - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(62, prom_dtlb_data); - membar("#Sync"); - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + membar("#Sync"); + } + + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, prom_itlb_data); - membar("#Sync"); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + membar("#Sync"); + } + } } else { - __asm__ __volatile__("stxa %%g0, [%0] %1" + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(62, 0x0UL); - membar("#Sync"); - __asm__ __volatile__("stxa %%g0, [%0] %1" + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, 0x0UL); + membar("#Sync"); + } + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, 0x0UL); - membar("#Sync"); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, 0x0UL); + membar("#Sync"); + } + } } } @@ -640,8 +660,8 @@ * it (conveniently) fails to mention any of these in the * translations property. The only ones that matter are * the locked PROM tlb entries, so we impose the following - * irrecovable rule on the PROM, it is allowed 1 locked - * entry in the ITLB and 1 in the DTLB. + * irrecovable rule on the PROM, it is allowed 8 locked + * entries in the ITLB and 8 in the DTLB. * * Supposedly the upper 16GB of the address space is * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED @@ -650,17 +670,23 @@ * systems to coordinate mmu mappings is also COMPLETELY * UNDOCUMENTED!!!!!! Thanks S(t)un! */ + if (save_p) { + for(i = 0; i < 8; i++) { + prom_dtlb[i].tlb_ent = -1; + prom_itlb[i].tlb_ent = -1; + } + } for(i = 0; i < 63; i++) { unsigned long data; data = spitfire_get_dtlb_data(i); - if(!dtlb_seen && (data & _PAGE_L)) { + if(data & _PAGE_L) { unsigned long tag = spitfire_get_dtlb_tag(i); if(save_p) { - prom_dtlb_ent = i; - prom_dtlb_tag = tag; - prom_dtlb_data = data; + prom_dtlb[dtlb_seen].tlb_ent = i; + prom_dtlb[dtlb_seen].tlb_tag = tag; + prom_dtlb[dtlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); @@ -668,18 +694,22 @@ spitfire_put_dtlb_data(i, 0x0UL); membar("#Sync"); - dtlb_seen = 1; - if(itlb_seen) + dtlb_seen++; + if(dtlb_seen > 7) break; } + } + for(i = 0; i < 63; i++) { + unsigned long data; + data = spitfire_get_itlb_data(i); - if(!itlb_seen && (data & _PAGE_L)) { + if(data & _PAGE_L) { unsigned long tag = spitfire_get_itlb_tag(i); if(save_p) { - prom_itlb_ent = i; - prom_itlb_tag = tag; - prom_itlb_data = data; + prom_itlb[itlb_seen].tlb_ent = i; + prom_itlb[itlb_seen].tlb_tag = tag; + prom_itlb[itlb_seen].tlb_data = data; } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); @@ -687,15 +717,8 @@ spitfire_put_itlb_data(i, 0x0UL); membar("#Sync"); - /* Re-install it. */ - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(62, data); - membar("#Sync"); - itlb_seen = 1; - if(dtlb_seen) + itlb_seen++; + if(itlb_seen > 7) break; } } @@ -706,19 +729,29 @@ /* Give PROM back his world, done during reboots... */ void prom_reload_locked(void) { - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(prom_dtlb_ent, prom_dtlb_data); - membar("#Sync"); - - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_IMMU)); - membar("#Sync"); - spitfire_put_itlb_data(prom_itlb_ent, prom_itlb_data); - membar("#Sync"); + int i; + + for (i = 0; i < 8; i++) { + if (prom_dtlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(prom_dtlb[i].tlb_ent, + prom_dtlb[i].tlb_data); + membar("#Sync"); + } + + if (prom_itlb[i].tlb_ent != -1) { + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb[i].tlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(prom_itlb[i].tlb_ent, + prom_itlb[i].tlb_data); + membar("#Sync"); + } + } } void __flush_dcache_range(unsigned long start, unsigned long end) @@ -844,7 +877,7 @@ pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pmd) { - clear_page(pmd); + memset(pmd, 0, PAGE_SIZE); pgd_set(pgd, pmd); return pmd + offset; } @@ -857,7 +890,7 @@ pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pte) { - clear_page(pte); + memset(pte, 0, PAGE_SIZE); pmd_set(pmd, pte); return pte + offset; } @@ -875,13 +908,13 @@ pgdp = pgd_offset(init_task.mm, start); if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PAGE_SIZE); - clear_page(pmdp); + memset(pmdp, 0, PAGE_SIZE); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, start); if (pmd_none(*pmdp)) { ptep = sparc_init_alloc(&mempool, PAGE_SIZE); - clear_page(ptep); + memset(ptep, 0, PAGE_SIZE); pmd_set(pmdp, ptep); } start = (start + PMD_SIZE) & PMD_MASK; diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S --- v2.1.126/linux/arch/sparc64/mm/ultra.S Mon Oct 5 13:13:38 1998 +++ linux/arch/sparc64/mm/ultra.S Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.27 1998/09/28 06:18:42 davem Exp $ +/* $Id: ultra.S,v 1.29 1998/10/22 03:05:51 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -125,34 +125,39 @@ retl wrpr %g1, 0x0, %pstate - /* Unfortunately, it is necessary. */ - .globl flush_page_to_ram -flush_page_to_ram: /* %o0 = page */ - rdpr %pstate, %g5 - wrpr %g5, PSTATE_IE, %pstate - sethi %hi(dcache_aliases_found), %g1 - ldx [%g1 + %lo(dcache_aliases_found)], %g2 - sub %o0, %g4, %o0 ! Get phys_page - clr %o2 ! This dcache area begin - sethi %hi(1<<14), %o1 ! This dcache area end -1: ldxa [%o2] ASI_DCACHE_TAG, %o3 - andcc %o3, 0x3, %g0 ! Valid bits set? - be,pn %xcc, 2f ! Nope, skip this one - andn %o3, 0x3, %o3 ! Mask out valid bits - sllx %o3, (13 - 2), %o3 ! Shift into physaddr - cmp %o3, %o0 ! Match? - bne,pt %xcc, 2f ! Nope, skip to next + .align 32 + .globl flush_icache_page +flush_icache_page: /* %o0 = phys_page */ + sethi %hi(1 << 13), %o2 ! I-cache valid/set bit + srlx %o0, 5, %o0 ! phys-addr comparitor + clr %o1 ! I-cache address +1: ldda [%o1] ASI_IC_TAG, %o4 + andcc %o5, %o2, %g0 + be,pn %xcc, 2f + andn %o5, %o2, %o5 + cmp %o5, %o0 + + be,pn %xcc, iflush1 +2: ldda [%o1 + %o2] ASI_IC_TAG, %o4 +4: andcc %o5, %o2, %g0 + be,pn %xcc, 3f + andn %o5, %o2, %o5 + cmp %o5, %o0 + be,pn %xcc, iflush2 nop - stxa %g0, [%o2] ASI_DCACHE_TAG - membar #Sync - add %g2, 1, %g2 ! Increment alias counter -2: add %o2, (1<<5), %o2 ! 32-bytes per full line - cmp %o2, %o1 + +3: add %o1, 0x20, %o1 + cmp %o1, %o2 bne,pt %xcc, 1b nop - stx %g2, [%g1 + %lo(dcache_aliases_found)] retl - wrpr %g5, 0x0, %pstate + nop +iflush1:stxa %g0, [%o1] ASI_IC_TAG + membar #Sync + ba,a,pt %xcc, 4b +iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG + membar #Sync + ba,a,pt %xcc, 3b #ifdef __SMP__ /* These are all called by the slaves of a cross call, at diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c --- v2.1.126/linux/arch/sparc64/prom/misc.c Thu Aug 6 14:06:31 1998 +++ linux/arch/sparc64/prom/misc.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $ +/* $Id: misc.c,v 1.13 1998/10/13 14:03:49 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -40,25 +40,18 @@ /* Drop into the prom, with the chance to continue with the 'go' * prom command. */ -/* XXX Fix the pre and post calls as it locks up my Ultra at the moment -DaveM */ void prom_cmdline(void) { - extern void kernel_enter_debugger(void); - /* extern void install_obp_ticker(void); */ - /* extern void install_linux_ticker(void); */ unsigned long flags; - /* kernel_enter_debugger(); */ #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (1); #endif - /* install_obp_ticker(); */ - save_flags(flags); cli(); + __save_and_cli(flags); p1275_cmd ("enter", P1275_INOUT(0,0)); - restore_flags(flags); - /* install_linux_ticker(); */ + __restore_flags(flags); #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) prom_palette (0); @@ -78,7 +71,7 @@ /* Set prom sync handler to call function 'funcp'. */ void -prom_setsync(sync_func_t funcp) +prom_setcallback(callback_func_t funcp) { if(!funcp) return; p1275_cmd ("set-callback", P1275_ARG(0,P1275_ARG_IN_FUNCTION)| diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c --- v2.1.126/linux/arch/sparc64/prom/p1275.c Fri May 8 23:14:46 1998 +++ linux/arch/sparc64/prom/p1275.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $ +/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -15,9 +15,10 @@ #include #include #include +#include struct { - long prom_sync_routine; /* 0x00 */ + long prom_callback; /* 0x00 */ void (*prom_cif_handler)(long *); /* 0x08 */ unsigned long prom_cif_stack; /* 0x10 */ unsigned long prom_args [23]; /* 0x18 */ @@ -31,29 +32,262 @@ __asm__ __volatile__ (" mov %0, %%o0 ldx [%%o0 + 0x010], %%o1 ! prom_cif_stack - save %%o1, -0xc0, %%sp + save %%o1, -0x190, %%sp ldx [%%i0 + 0x008], %%l2 ! prom_cif_handler rdpr %%pstate, %%l4 - mov %%g4, %%l0 - mov %%g6, %%l1 - wrpr %%l4, %1, %%pstate ! turn on address masking + wrpr %%g0, 0x15, %%pstate ! save alternate globals + stx %%g1, [%%sp + 2047 + 0x0b0] + stx %%g2, [%%sp + 2047 + 0x0b8] + stx %%g3, [%%sp + 2047 + 0x0c0] + stx %%g4, [%%sp + 2047 + 0x0c8] + stx %%g5, [%%sp + 2047 + 0x0d0] + stx %%g6, [%%sp + 2047 + 0x0d8] + stx %%g7, [%%sp + 2047 + 0x0e0] + wrpr %%g0, 0x814, %%pstate ! save interrupt globals + stx %%g1, [%%sp + 2047 + 0x0e8] + stx %%g2, [%%sp + 2047 + 0x0f0] + stx %%g3, [%%sp + 2047 + 0x0f8] + stx %%g4, [%%sp + 2047 + 0x100] + stx %%g5, [%%sp + 2047 + 0x108] + stx %%g6, [%%sp + 2047 + 0x110] + stx %%g7, [%%sp + 2047 + 0x118] + wrpr %%g0, 0x14, %%pstate ! save normal globals + stx %%g1, [%%sp + 2047 + 0x120] + stx %%g2, [%%sp + 2047 + 0x128] + stx %%g3, [%%sp + 2047 + 0x130] + stx %%g4, [%%sp + 2047 + 0x138] + stx %%g5, [%%sp + 2047 + 0x140] + stx %%g6, [%%sp + 2047 + 0x148] + stx %%g7, [%%sp + 2047 + 0x150] + wrpr %%g0, 0x414, %%pstate ! save mmu globals + stx %%g1, [%%sp + 2047 + 0x158] + stx %%g2, [%%sp + 2047 + 0x160] + stx %%g3, [%%sp + 2047 + 0x168] + stx %%g4, [%%sp + 2047 + 0x170] + stx %%g5, [%%sp + 2047 + 0x178] + stx %%g6, [%%sp + 2047 + 0x180] + stx %%g7, [%%sp + 2047 + 0x188] + mov %%g1, %%l0 ! also save to locals, so we can handle + mov %%g2, %%l1 ! tlb faults later on, when accessing + mov %%g3, %%l3 ! the stack. + mov %%g7, %%l5 + wrpr %%l4, %1, %%pstate ! turn off interrupts call %%l2 add %%i0, 0x018, %%o0 ! prom_args - wrpr %%l4, 0, %%pstate ! put pstate back - mov %%l0, %%g4 + wrpr %%g0, 0x414, %%pstate ! restore mmu globals + mov %%l0, %%g1 + mov %%l1, %%g2 + mov %%l3, %%g3 + mov %%l5, %%g7 + wrpr %%g0, 0x14, %%pstate ! restore normal globals + ldx [%%sp + 2047 + 0x120], %%g1 + ldx [%%sp + 2047 + 0x128], %%g2 + ldx [%%sp + 2047 + 0x130], %%g3 + ldx [%%sp + 2047 + 0x138], %%g4 + ldx [%%sp + 2047 + 0x140], %%g5 + ldx [%%sp + 2047 + 0x148], %%g6 + ldx [%%sp + 2047 + 0x150], %%g7 + wrpr %%g0, 0x814, %%pstate ! restore interrupt globals + ldx [%%sp + 2047 + 0x0e8], %%g1 + ldx [%%sp + 2047 + 0x0f0], %%g2 + ldx [%%sp + 2047 + 0x0f8], %%g3 + ldx [%%sp + 2047 + 0x100], %%g4 + ldx [%%sp + 2047 + 0x108], %%g5 + ldx [%%sp + 2047 + 0x110], %%g6 + ldx [%%sp + 2047 + 0x118], %%g7 + wrpr %%g0, 0x15, %%pstate ! restore alternate globals + ldx [%%sp + 2047 + 0x0b0], %%g1 + ldx [%%sp + 2047 + 0x0b8], %%g2 + ldx [%%sp + 2047 + 0x0c0], %%g3 + ldx [%%sp + 2047 + 0x0c8], %%g4 + ldx [%%sp + 2047 + 0x0d0], %%g5 + ldx [%%sp + 2047 + 0x0d8], %%g6 + ldx [%%sp + 2047 + 0x0e0], %%g7 + wrpr %%l4, 0, %%pstate ! restore original pstate ret - restore %%l1, 0, %%g6 - save %%sp, -0xc0, %%sp ! If you change the offset of the save - rdpr %%pstate, %%l4 ! here, please change the 0x8038 - andn %%l4, %1, %%l3 ! constant below as well - wrpr %%l3, %%pstate - ldx [%%o0 + 0x000], %%l2 + restore + " : : "r" (&p1275buf), "i" (PSTATE_IE)); +} + +void prom_cif_callback(void) +{ + __asm__ __volatile__ (" + mov %0, %%o1 + save %%sp, -0x270, %%sp + rdpr %%pstate, %%l4 + wrpr %%g0, 0x15, %%pstate ! save PROM alternate globals + stx %%g1, [%%sp + 2047 + 0x0b0] + stx %%g2, [%%sp + 2047 + 0x0b8] + stx %%g3, [%%sp + 2047 + 0x0c0] + stx %%g4, [%%sp + 2047 + 0x0c8] + stx %%g5, [%%sp + 2047 + 0x0d0] + stx %%g6, [%%sp + 2047 + 0x0d8] + stx %%g7, [%%sp + 2047 + 0x0e0] + ! restore Linux alternate globals + ldx [%%sp + 2047 + 0x190], %%g1 + ldx [%%sp + 2047 + 0x198], %%g2 + ldx [%%sp + 2047 + 0x1a0], %%g3 + ldx [%%sp + 2047 + 0x1a8], %%g4 + ldx [%%sp + 2047 + 0x1b0], %%g5 + ldx [%%sp + 2047 + 0x1b8], %%g6 + ldx [%%sp + 2047 + 0x1c0], %%g7 + wrpr %%g0, 0x814, %%pstate ! save PROM interrupt globals + stx %%g1, [%%sp + 2047 + 0x0e8] + stx %%g2, [%%sp + 2047 + 0x0f0] + stx %%g3, [%%sp + 2047 + 0x0f8] + stx %%g4, [%%sp + 2047 + 0x100] + stx %%g5, [%%sp + 2047 + 0x108] + stx %%g6, [%%sp + 2047 + 0x110] + stx %%g7, [%%sp + 2047 + 0x118] + ! restore Linux interrupt globals + ldx [%%sp + 2047 + 0x1c8], %%g1 + ldx [%%sp + 2047 + 0x1d0], %%g2 + ldx [%%sp + 2047 + 0x1d8], %%g3 + ldx [%%sp + 2047 + 0x1e0], %%g4 + ldx [%%sp + 2047 + 0x1e8], %%g5 + ldx [%%sp + 2047 + 0x1f0], %%g6 + ldx [%%sp + 2047 + 0x1f8], %%g7 + wrpr %%g0, 0x14, %%pstate ! save PROM normal globals + stx %%g1, [%%sp + 2047 + 0x120] + stx %%g2, [%%sp + 2047 + 0x128] + stx %%g3, [%%sp + 2047 + 0x130] + stx %%g4, [%%sp + 2047 + 0x138] + stx %%g5, [%%sp + 2047 + 0x140] + stx %%g6, [%%sp + 2047 + 0x148] + stx %%g7, [%%sp + 2047 + 0x150] + ! restore Linux normal globals + ldx [%%sp + 2047 + 0x200], %%g1 + ldx [%%sp + 2047 + 0x208], %%g2 + ldx [%%sp + 2047 + 0x210], %%g3 + ldx [%%sp + 2047 + 0x218], %%g4 + ldx [%%sp + 2047 + 0x220], %%g5 + ldx [%%sp + 2047 + 0x228], %%g6 + ldx [%%sp + 2047 + 0x230], %%g7 + wrpr %%g0, 0x414, %%pstate ! save PROM mmu globals + stx %%g1, [%%sp + 2047 + 0x158] + stx %%g2, [%%sp + 2047 + 0x160] + stx %%g3, [%%sp + 2047 + 0x168] + stx %%g4, [%%sp + 2047 + 0x170] + stx %%g5, [%%sp + 2047 + 0x178] + stx %%g6, [%%sp + 2047 + 0x180] + stx %%g7, [%%sp + 2047 + 0x188] + ! restore Linux mmu globals + ldx [%%sp + 2047 + 0x238], %%o0 + ldx [%%sp + 2047 + 0x240], %%o1 + ldx [%%sp + 2047 + 0x248], %%l2 + ldx [%%sp + 2047 + 0x250], %%l3 + ldx [%%sp + 2047 + 0x258], %%l5 + ldx [%%sp + 2047 + 0x260], %%l6 + ldx [%%sp + 2047 + 0x268], %%l7 + ! switch to Linux tba + sethi %%hi(sparc64_ttable_tl0), %%l1 + rdpr %%tba, %%l0 ! save PROM tba + mov %%o0, %%g1 + mov %%o1, %%g2 + mov %%l2, %%g3 + mov %%l3, %%g4 + mov %%l5, %%g5 + mov %%l6, %%g6 + mov %%l7, %%g7 + wrpr %%l1, %%tba ! install Linux tba + wrpr %%l4, 0, %%pstate ! restore PSTATE + call prom_world + mov %%g0, %%o0 + ldx [%%i1 + 0x000], %%l2 call %%l2 - nop + mov %%i0, %%o0 + mov %%o0, %%l1 + call prom_world + or %%g0, 1, %%o0 + wrpr %%g0, 0x14, %%pstate ! interrupts off + ! restore PROM mmu globals + ldx [%%sp + 2047 + 0x158], %%o0 + ldx [%%sp + 2047 + 0x160], %%o1 + ldx [%%sp + 2047 + 0x168], %%l2 + ldx [%%sp + 2047 + 0x170], %%l3 + ldx [%%sp + 2047 + 0x178], %%l5 + ldx [%%sp + 2047 + 0x180], %%l6 + ldx [%%sp + 2047 + 0x188], %%l7 + wrpr %%g0, 0x414, %%pstate ! restore PROM mmu globals + mov %%o0, %%g1 + mov %%o1, %%g2 + mov %%l2, %%g3 + mov %%l3, %%g4 + mov %%l5, %%g5 + mov %%l6, %%g6 + mov %%l7, %%g7 + wrpr %%l0, %%tba ! restore PROM tba + wrpr %%g0, 0x14, %%pstate ! restore PROM normal globals + ldx [%%sp + 2047 + 0x120], %%g1 + ldx [%%sp + 2047 + 0x128], %%g2 + ldx [%%sp + 2047 + 0x130], %%g3 + ldx [%%sp + 2047 + 0x138], %%g4 + ldx [%%sp + 2047 + 0x140], %%g5 + ldx [%%sp + 2047 + 0x148], %%g6 + ldx [%%sp + 2047 + 0x150], %%g7 + wrpr %%g0, 0x814, %%pstate ! restore PROM interrupt globals + ldx [%%sp + 2047 + 0x0e8], %%g1 + ldx [%%sp + 2047 + 0x0f0], %%g2 + ldx [%%sp + 2047 + 0x0f8], %%g3 + ldx [%%sp + 2047 + 0x100], %%g4 + ldx [%%sp + 2047 + 0x108], %%g5 + ldx [%%sp + 2047 + 0x110], %%g6 + ldx [%%sp + 2047 + 0x118], %%g7 + wrpr %%g0, 0x15, %%pstate ! restore PROM alternate globals + ldx [%%sp + 2047 + 0x0b0], %%g1 + ldx [%%sp + 2047 + 0x0b8], %%g2 + ldx [%%sp + 2047 + 0x0c0], %%g3 + ldx [%%sp + 2047 + 0x0c8], %%g4 + ldx [%%sp + 2047 + 0x0d0], %%g5 + ldx [%%sp + 2047 + 0x0d8], %%g6 + ldx [%%sp + 2047 + 0x0e0], %%g7 wrpr %%l4, 0, %%pstate ret - restore - " : : "r" (&p1275buf), "i" (0 /* PSTATE_AM */)); + restore %%l1, 0, %%o0 + " : : "r" (&p1275buf), "i" (PSTATE_PRIV)); +} + +/* We need some SMP protection here. But be careful as + * prom callback code can call into here too, this is why + * the counter is needed. -DaveM + */ +static int prom_entry_depth = 0; +#ifdef __SMP__ +static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; +extern void smp_capture(void); +extern void smp_release(void); +#endif + +static __inline__ unsigned long prom_get_lock(void) +{ + unsigned long flags; + + __save_and_cli(flags); + if (prom_entry_depth == 0) { + spin_lock(&prom_entry_lock); + +#if 1 /* DEBUGGING */ + if (prom_entry_depth != 0) + panic("prom_get_lock"); +#endif +#ifdef __SMP__ + smp_capture(); +#endif + } + prom_entry_depth++; + + return flags; +} + +static __inline__ void prom_release_lock(unsigned long flags) +{ + if (--prom_entry_depth == 0) { +#ifdef __SMP__ + smp_release(); +#endif + spin_unlock(&prom_entry_lock); + } + __restore_flags(flags); } long p1275_cmd (char *service, long fmt, ...) @@ -66,13 +300,15 @@ long ctx = 0; p = p1275buf.prom_buffer; - __save_and_cli(flags); ctx = spitfire_get_primary_context (); if (ctx) { flushw_user (); spitfire_set_primary_context (0); } - p1275buf.prom_args[0] = (unsigned long)p; /* service */ + + flags = prom_get_lock(); + + p1275buf.prom_args[0] = (unsigned long)p; /* service */ strcpy (p, service); p = (char *)(((long)(strchr (p, 0) + 8)) & ~7); p1275buf.prom_args[1] = nargs = (fmt & 0x0f); /* nargs */ @@ -82,7 +318,9 @@ for (i = 0; i < nargs; i++, attrs >>= 3) { switch (attrs & 0x7) { case P1275_ARG_NUMBER: - p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break; + p1275buf.prom_args[i + 3] = + (unsigned)va_arg(list, long); + break; case P1275_ARG_IN_STRING: strcpy (p, va_arg(list, char *)); p1275buf.prom_args[i + 3] = (unsigned long)p; @@ -111,16 +349,16 @@ p += 32; break; case P1275_ARG_IN_FUNCTION: - p1275buf.prom_args[i + 3] = (unsigned long)prom_cif_interface + 0x38; - p1275buf.prom_sync_routine = va_arg(list, long); break; + p1275buf.prom_args[i + 3] = + (unsigned long)prom_cif_callback; + p1275buf.prom_callback = va_arg(list, long); + break; } } va_end(list); prom_world(1); - prom_cif_interface(); - prom_world(0); attrs = fmt >> 8; @@ -128,11 +366,14 @@ for (i = 0; i < nargs; i++, attrs >>= 3) { switch (attrs & 0x7) { case P1275_ARG_NUMBER: - (void) va_arg(list, long); break; + (void) va_arg(list, long); + break; case P1275_ARG_IN_STRING: - (void) va_arg(list, char *); break; + (void) va_arg(list, char *); + break; case P1275_ARG_IN_FUNCTION: - (void) va_arg(list, long); break; + (void) va_arg(list, long); + break; case P1275_ARG_IN_BUF: (void) va_arg(list, char *); (void) va_arg(list, long); @@ -152,10 +393,12 @@ } va_end(list); x = p1275buf.prom_args [nargs + 3]; - + + prom_release_lock(flags); + if (ctx) spitfire_set_primary_context (ctx); - __restore_flags(flags); + return x; } diff -u --recursive --new-file v2.1.126/linux/arch/sparc64/solaris/Makefile linux/arch/sparc64/solaris/Makefile --- v2.1.126/linux/arch/sparc64/solaris/Makefile Thu Apr 23 20:21:32 1998 +++ linux/arch/sparc64/solaris/Makefile Tue Oct 27 09:52:21 1998 @@ -15,10 +15,10 @@ endif .S.s: - $(CPP) -D__ASSEMBLY__ $(CPPFLAGS) -ansi $< -o $*.s + $(CPP) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi $< -o $*.s .S.o: - $(CC) -D__ASSEMBLY__ $(CPPFLAGS) -ansi -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) $(CPPFLAGS) -ansi -c $< -o $*.o ifneq ($(CONFIG_SOLARIS_EMUL),y) do_it_all: diff -u --recursive --new-file v2.1.126/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v2.1.126/linux/drivers/block/floppy.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/floppy.c Fri Nov 6 12:33:25 1998 @@ -1740,12 +1740,14 @@ if(do_print) print_result("unexpected interrupt", inr); if (inr == 0){ + int max_sensei = 4; do { output_byte(FD_SENSEI); inr = result(); if(do_print) print_result("sensei", inr); - } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); + max_sensei--; + } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2 && max_sensei); } if (handler) { int cpu = smp_processor_id(); diff -u --recursive --new-file v2.1.126/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.126/linux/drivers/block/ide-cd.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/ide-cd.c Sat Oct 31 10:17:22 1998 @@ -3,6 +3,7 @@ * linux/drivers/block/ide-cd.c * Copyright (C) 1994, 1995, 1996 scott snyder * Copyright (C) 1996-1998 Erik Andersen + * Copyright (C) 1998 Jens Axboe and Chris Zwilling * * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. @@ -221,9 +222,13 @@ * 4.15 Aug 25, 1998 -- Updated ide-cd.h to respect mechine endianess, * patch thanks to "Eddie C. Dost" * + * 4.50 Oct 19, 1998 -- New maintainers! + * Jens Axboe + * Chris Zwilling + * *************************************************************************/ -#define IDECD_VERSION "4.15" +#define IDECD_VERSION "4.50" #include #include @@ -1290,8 +1295,7 @@ void cdrom_sleep (int time) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + time; - schedule (); + schedule_timeout(time); } static @@ -2632,7 +2636,7 @@ if (was_locked) (void) cdrom_lockdoor (drive, 1, NULL); - return stat; + return slot; } } diff -u --recursive --new-file v2.1.126/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h --- v2.1.126/linux/drivers/block/ide-cd.h Thu Sep 17 17:53:35 1998 +++ linux/drivers/block/ide-cd.h Sat Nov 7 11:28:46 1998 @@ -4,6 +4,7 @@ * linux/drivers/block/ide_modes.h * * Copyright (C) 1996 Erik Andersen + * Copyright (C) 1998 Jens Axboe and Chris Zwilling */ #include diff -u --recursive --new-file v2.1.126/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.1.126/linux/drivers/block/loop.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/block/loop.c Mon Oct 26 09:57:55 1998 @@ -27,7 +27,6 @@ #include -#include #include #include #include diff -u --recursive --new-file v2.1.126/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.126/linux/drivers/block/md.c Fri Oct 9 13:27:07 1998 +++ linux/drivers/block/md.c Sat Oct 31 10:37:14 1998 @@ -1139,8 +1139,7 @@ while (blocksize*j/(jiffies-starttime+1)*HZ/1024 > SPEED_LIMIT) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies+1; - schedule(); + schedule_timeout(1); } /* diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pcd.c linux/drivers/block/paride/pcd.c --- v2.1.126/linux/drivers/block/paride/pcd.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/paride/pcd.c Wed Nov 4 10:03:01 1998 @@ -559,8 +559,7 @@ static void pcd_sleep( int cs ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + cs; - schedule(); + schedule_timeout(cs); } static int pcd_reset( int unit ) diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pf.c linux/drivers/block/paride/pf.c --- v2.1.126/linux/drivers/block/paride/pf.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/paride/pf.c Wed Nov 4 10:04:43 1998 @@ -660,8 +660,7 @@ static void pf_sleep( int cs ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + cs; - schedule(); + schedule_timeout(cs); } diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c --- v2.1.126/linux/drivers/block/paride/pg.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/paride/pg.c Wed Nov 4 10:04:29 1998 @@ -357,8 +357,7 @@ static void pg_sleep( int cs ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + cs; - schedule(); + schedule_timeout(cs); } static int pg_wait( int unit, int go, int stop, int tmo, char * msg ) diff -u --recursive --new-file v2.1.126/linux/drivers/block/paride/pt.c linux/drivers/block/paride/pt.c --- v2.1.126/linux/drivers/block/paride/pt.c Mon Oct 5 13:13:38 1998 +++ linux/drivers/block/paride/pt.c Wed Nov 4 10:05:12 1998 @@ -464,8 +464,7 @@ static void pt_sleep( int cs ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + cs; - schedule(); + schedule_timeout(cs); } static int pt_poll_dsc( int unit, int pause, int tmo, char *msg ) diff -u --recursive --new-file v2.1.126/linux/drivers/block/swim3.c linux/drivers/block/swim3.c --- v2.1.126/linux/drivers/block/swim3.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/block/swim3.c Thu Nov 5 09:58:39 1998 @@ -740,8 +740,7 @@ break; } current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); } fs->ejected = 1; release_drive(fs); @@ -807,8 +806,7 @@ break; } current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); } if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0)) @@ -911,8 +909,7 @@ if (signal_pending(current)) break; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); } ret = swim3_readbit(fs, SEEK_COMPLETE) == 0 || swim3_readbit(fs, DISK_IN) == 0; diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c --- v2.1.126/linux/drivers/cdrom/cdrom.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/cdrom/cdrom.c Sat Oct 24 10:43:47 1998 @@ -1,6 +1,7 @@ /* linux/drivers/cdrom/cdrom.c. Copyright (c) 1996, 1997 David A. van Leeuwen. Copyright (c) 1997, 1998 Erik Andersen + Copyright (c) 1998 Jens Axboe and Chris Zwilling May be copied or modified under the terms of the GNU General Public License. See linux/COPYING for more information. @@ -86,10 +87,15 @@ Thanks to Grant R. Guenther for spotting this bug. -- Made a few things more pedanticly correct. + 2.50 Oct 19, 1998 - Jens Axboe + -- New maintainers! Erik was too busy to continue the work on the driver, + so now Chris Zwilling and Jens Axboe + will do their best to follow in his footsteps + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 2.14" -#define VERSION "Id: cdrom.c 2.14 1998/08/17 erik" +#define REVISION "Revision: 2.50" +#define VERSION "Id: cdrom.c 2.50 1998/10/19" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/cdu31a.c linux/drivers/cdrom/cdu31a.c --- v2.1.126/linux/drivers/cdrom/cdu31a.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/cdrom/cdu31a.c Wed Nov 4 12:09:43 1998 @@ -409,8 +409,7 @@ if (cdu31a_irq <= 0) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies; - schedule(); + schedule_timeout(0); } else /* Interrupt driven */ { @@ -753,8 +752,7 @@ } current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 2*HZ; - schedule(); + schedule_timeout(2*HZ); sony_get_toc(); } @@ -1012,8 +1010,7 @@ { num_retries++; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/10; /* Wait .1 seconds on retries */ - schedule(); + schedule_timeout(HZ/10); /* Wait .1 seconds on retries */ goto retry_cd_operation; } diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/gscd.c linux/drivers/cdrom/gscd.c --- v2.1.126/linux/drivers/cdrom/gscd.c Wed Aug 26 11:37:36 1998 +++ linux/drivers/cdrom/gscd.c Sat Oct 31 10:28:25 1998 @@ -66,6 +66,7 @@ #define gscd_port gscd /* for compatible parameter passing with "insmod" */ #include "gscd.h" +static int gscd_blocksizes[1] = {512}; static int gscdPresent = 0; @@ -1060,6 +1061,7 @@ } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + blksize_size[MAJOR_NR] = gscd_blocksizes; read_ahead[MAJOR_NR] = 4; disk_state = 0; diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/mcd.c linux/drivers/cdrom/mcd.c --- v2.1.126/linux/drivers/cdrom/mcd.c Tue Jun 23 10:01:22 1998 +++ linux/drivers/cdrom/mcd.c Wed Nov 4 12:09:43 1998 @@ -1100,8 +1100,7 @@ return -EIO; /* drive doesn't respond */ if ((st & MST_READY) == 0) { /* no disk? wait a sec... */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; - schedule(); + schedule_timeout(HZ); } } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS); diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c --- v2.1.126/linux/drivers/cdrom/mcdx.c Thu Feb 12 20:56:05 1998 +++ linux/drivers/cdrom/mcdx.c Wed Nov 4 14:52:21 1998 @@ -794,8 +794,7 @@ * allowed! */ if (current->pid == 0) { while (jiffies < tout) { - current->timeout = jiffies; - schedule(); + schedule_timeout(0); } } else { current->timeout = tout; @@ -1247,6 +1246,7 @@ { int border; int done = 0; + long timeout; if (stuffp->audio) { xwarn("Attempt to read from audio CD.\n"); @@ -1281,13 +1281,12 @@ do { - current->timeout = jiffies + 5 * HZ; while (stuffp->busy) { - interruptible_sleep_on(&stuffp->busyq); + timeout = interruptible_sleep_on_timeout(&stuffp->busyq, 5*HZ); if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); } - else if (current->timeout == 0) { xtrace(XFER, "timeout\n"); } + else if (!timeout) { xtrace(XFER, "timeout\n"); } else if (signal_pending(current)) { xtrace(XFER, "signal\n"); } else continue; diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/sbpcd.c linux/drivers/cdrom/sbpcd.c --- v2.1.126/linux/drivers/cdrom/sbpcd.c Thu Sep 17 17:53:35 1998 +++ linux/drivers/cdrom/sbpcd.c Wed Nov 4 12:09:43 1998 @@ -843,8 +843,7 @@ { sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + time; - schedule(); + schedule_timeout(time); sti(); } /*==========================================================================*/ diff -u --recursive --new-file v2.1.126/linux/drivers/cdrom/sonycd535.c linux/drivers/cdrom/sonycd535.c --- v2.1.126/linux/drivers/cdrom/sonycd535.c Wed Aug 26 11:37:36 1998 +++ linux/drivers/cdrom/sonycd535.c Thu Nov 5 21:36:12 1998 @@ -62,26 +62,24 @@ * This interface is (unfortunately) a polled interface. This is * because most Sony interfaces are set up with DMA and interrupts * disables. Some (like mine) do not even have the capability to - * handle interrupts or DMA. For this reason you will see a lot of + * handle interrupts or DMA. For this reason you will see a bit of * the following: * - * retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; - * while ((retry_count > jiffies) && (! state = TASK_INTERRUPTIBLE; - current->timeout = jiffies; - schedule(); + schedule_timeout(0); } else { /* Interrupt driven */ cli(); enable_interrupts(); @@ -370,12 +365,13 @@ static int read_result_reg(Byte *data_ptr) { - int retry_count; + unsigned long snap; int read_status; - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (jiffies < retry_count) { - if (((read_status = inb(read_status_reg)) & SONY535_RESULT_NOT_READY_BIT) == 0) { + snap = jiffies; + while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { + read_status = inb(read_status_reg); + if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { #if DEBUG > 1 printk(CDU535_MESSAGE_NAME ": read_result_reg(): readStatReg = 0x%x\n", read_status); @@ -599,7 +595,7 @@ Byte cmd_buff[7]; int i; int read_status; - int retry_count; + unsigned long snap; Byte *data_buff; int sector_count = 0; @@ -618,8 +614,9 @@ /* read back the data one block at a time */ while (0 < n_blocks--) { /* wait for data to be ready */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (jiffies < retry_count) { + int data_valid = 0; + snap = jiffies; + while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { read_status = inb(read_status_reg); if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { read_exec_status(status); @@ -630,11 +627,12 @@ data_buff = buff[sector_count++]; for (i = 0; i < block_size; i++) *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ + data_valid = 1; break; /* exit the timeout loop */ } sony_sleep(); /* data not ready, sleep a while */ } - if (retry_count <= jiffies) + if (!data_valid) return TIME_OUT; /* if we reach this stage */ } @@ -893,8 +891,7 @@ if (readStatus == BAD_STATUS) { /* Sleep for a while, then retry */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + RETRY_FOR_BAD_STATUS; - schedule(); + schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); } #if DEBUG > 0 printk(CDU535_MESSAGE_NAME @@ -1493,7 +1490,8 @@ Byte cmd_buff[3]; Byte ret_buff[2]; Byte status[2]; - int retry_count; + unsigned long snap; + int got_result = 0; int tmp_irq; int i; @@ -1525,21 +1523,22 @@ } /* look for the CD-ROM, follows the procedure in the DOS driver */ inb(select_unit_reg); - retry_count = jiffies + 2 * HZ; - while (jiffies < retry_count) - sony_sleep(); /* wait for 40 18 Hz ticks (from DOS driver) */ + /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ + schedule_timeout((HZ+17)*40/18); inb(result_reg); outb(0, read_status_reg); /* does a reset? */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (jiffies < retry_count) { + snap = jiffies; + while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { select_unit(0); - if (inb(result_reg) != 0xff) + if (inb(result_reg) != 0xff) { + got_result = 1; break; + } sony_sleep(); } - if ((jiffies < retry_count) && (check_drive_status() != TIME_OUT)) { + if (got_result && (check_drive_status() != TIME_OUT)) { /* CD-ROM drive responded -- get the drive configuration */ cmd_buff[0] = SONY535_INQUIRY; if (do_sony_cmd(cmd_buff, 1, status, diff -u --recursive --new-file v2.1.126/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.126/linux/drivers/char/Makefile Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/Makefile Tue Oct 27 09:52:21 1998 @@ -240,12 +240,6 @@ endif endif -ifeq ($(CONFIG_SUN_OPENPROMIO),y) -else - ifeq ($(CONFIG_SUN_OPENPROMIO),m) - endif -endif - ifeq ($(CONFIG_WDT),y) L_OBJS += wdt.o else diff -u --recursive --new-file v2.1.126/linux/drivers/char/bw-qcam.c linux/drivers/char/bw-qcam.c --- v2.1.126/linux/drivers/char/bw-qcam.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/bw-qcam.c Sat Oct 31 11:03:24 1998 @@ -214,8 +214,7 @@ if(runs++>1000) { current->state=TASK_INTERRUPTIBLE; - current->timeout = jiffies+HZ/10; - schedule(); + schedule_timeout(HZ/10); } if(runs>1050) return -1; @@ -232,8 +231,7 @@ if(runs++>1000) { current->state=TASK_INTERRUPTIBLE; - current->timeout = jiffies+HZ/10; - schedule(); + schedule_timeout(HZ/10); } if(runs++>1050) /* 5 seconds */ return -1; @@ -263,8 +261,7 @@ if(runs++>1000) { current->state=TASK_INTERRUPTIBLE; - current->timeout = jiffies+HZ/10; - schedule(); + schedule_timeout(HZ/10); } if(runs++>1050) /* 5 seconds */ return 0; diff -u --recursive --new-file v2.1.126/linux/drivers/char/c-qcam.c linux/drivers/char/c-qcam.c --- v2.1.126/linux/drivers/char/c-qcam.c Tue Aug 18 22:02:03 1998 +++ linux/drivers/char/c-qcam.c Sat Oct 31 11:04:24 1998 @@ -58,8 +58,7 @@ if (qcam_ready1(qcam) == value) return 0; current->state=TASK_INTERRUPTIBLE; - current->timeout = jiffies+HZ/10; - schedule(); + schedule_timeout(HZ/10); } /* Probably somebody pulled the plug out. Not much we can do. */ @@ -85,8 +84,7 @@ if (qcam_ready2(qcam) == value) return 0; current->state=TASK_INTERRUPTIBLE; - current->timeout = jiffies+HZ/10; - schedule(); + schedule_timeout(HZ/10); } /* Probably somebody pulled the plug out. Not much we can do. */ diff -u --recursive --new-file v2.1.126/linux/drivers/char/console.c linux/drivers/char/console.c --- v2.1.126/linux/drivers/char/console.c Fri Oct 9 13:27:07 1998 +++ linux/drivers/char/console.c Mon Nov 2 13:21:42 1998 @@ -2415,7 +2415,7 @@ } printk("Console: switching "); if (!deflt) - printk("consoles %d-%d ", first, last); + printk("consoles %d-%d ", first+1, last+1); if (j >= 0) printk("to %s %s %dx%d\n", vc_cons[j].d->vc_can_do_color ? "colour" : "mono", @@ -2564,7 +2564,7 @@ return; if (console_blanked) { timer_table[BLANK_TIMER].fn = unblank_screen; - timer_table[BLANK_TIMER].expires = 0; + timer_table[BLANK_TIMER].expires = jiffies; /* Now */ timer_active |= 1<state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) @@ -2604,8 +2603,7 @@ /* Run one more char cycle */ current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + (char_time * 5); - schedule(); + schedule_timeout(char_time * 5); current->state = TASK_RUNNING; #ifdef CY_DEBUG_WAIT_UNTIL_SENT printk("Clean (jiff=%lu)...done\n", jiffies); @@ -2737,8 +2735,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } diff -u --recursive --new-file v2.1.126/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c --- v2.1.126/linux/drivers/char/dsp56k.c Wed Aug 26 11:37:36 1998 +++ linux/drivers/char/dsp56k.c Sat Oct 31 11:05:37 1998 @@ -63,8 +63,7 @@ #define wait_some(n) \ { \ current->state = TASK_INTERRUPTIBLE; \ - current->timeout = jiffies + n; \ - schedule(); \ + schedule_timeout(n); \ } #define handshake(count, maxio, timeout, ENABLE, f) \ diff -u --recursive --new-file v2.1.126/linux/drivers/char/epca.c linux/drivers/char/epca.c --- v2.1.126/linux/drivers/char/epca.c Sun Jun 7 11:16:29 1998 +++ linux/drivers/char/epca.c Sat Oct 31 11:05:53 1998 @@ -647,8 +647,7 @@ if (ch->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ch->close_delay; - schedule(); + schedule_timeout(ch->close_delay); } wake_up_interruptible(&ch->open_wait); diff -u --recursive --new-file v2.1.126/linux/drivers/char/esp.c linux/drivers/char/esp.c --- v2.1.126/linux/drivers/char/esp.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/esp.c Sat Oct 31 11:06:21 1998 @@ -2147,8 +2147,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -2182,8 +2181,7 @@ (serial_in(info, UART_ESI_STAT2) != 0xff)) { current->state = TASK_INTERRUPTIBLE; current->counter = 0; - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; diff -u --recursive --new-file v2.1.126/linux/drivers/char/ftape/lowlevel/fdc-io.c linux/drivers/char/ftape/lowlevel/fdc-io.c --- v2.1.126/linux/drivers/char/ftape/lowlevel/fdc-io.c Sun Jun 7 11:16:29 1998 +++ linux/drivers/char/ftape/lowlevel/fdc-io.c Wed Nov 4 09:56:37 1998 @@ -389,6 +389,7 @@ sigset_t old_sigmask; static int resetting = 0; TRACE_FUN(ft_t_fdc_dma); + long timeout; #if LINUX_VERSION_CODE >= KERNEL_VER(2,0,16) if (waitqueue_active(&ftape_wait_intr)) { @@ -400,8 +401,7 @@ } #endif /* timeout time will be up to USPT microseconds too long ! */ - current->timeout = jiffies + (1000 * time + FT_USPT - 1) / FT_USPT; - current->state = TASK_INTERRUPTIBLE; + timeout = (1000 * time + FT_USPT - 1) / FT_USPT; spin_lock_irq(¤t->sigmask_lock); old_sigmask = current->blocked; @@ -409,9 +409,10 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); + current->state = TASK_INTERRUPTIBLE; add_wait_queue(&ftape_wait_intr, &wait); - while (!ft_interrupt_seen && current->state != TASK_RUNNING) { - schedule(); /* sets TASK_RUNNING on timeout */ + while (!ft_interrupt_seen && (current->state == TASK_INTERRUPTIBLE)) { + timeout = schedule_timeout(timeout); } spin_lock_irq(¤t->sigmask_lock); @@ -433,7 +434,6 @@ */ current->state = TASK_RUNNING; if (ft_interrupt_seen) { /* woken up by interrupt */ - current->timeout = 0; /* interrupt hasn't cleared this */ ft_interrupt_seen = 0; TRACE_EXIT 0; } diff -u --recursive --new-file v2.1.126/linux/drivers/char/ftape/lowlevel/ftape-io.c linux/drivers/char/ftape/lowlevel/ftape-io.c --- v2.1.126/linux/drivers/char/ftape/lowlevel/ftape-io.c Tue Dec 2 09:33:16 1997 +++ linux/drivers/char/ftape/lowlevel/ftape-io.c Wed Nov 4 09:57:43 1998 @@ -89,17 +89,18 @@ /* Time too small for scheduler, do a busy wait ! */ ftape_udelay(time); } else { + long timeout; unsigned long flags; unsigned int ticks = (time + FT_USPT - 1) / FT_USPT; TRACE(ft_t_any, "%d msec, %d ticks", time/1000, ticks); - current->timeout = jiffies + ticks; + timeout = ticks; current->state = TASK_INTERRUPTIBLE; save_flags(flags); sti(); do { while (current->state != TASK_RUNNING) { - schedule(); + timeout = schedule_timeout(timeout); } /* Mmm. Isn't current->blocked == 0xffffffff ? */ @@ -108,7 +109,7 @@ "awoken by non-blocked signal :-("); break; /* exit on signal */ } - } while (current->timeout > 0); + } while (timeout); restore_flags(flags); } TRACE_EXIT; diff -u --recursive --new-file v2.1.126/linux/drivers/char/istallion.c linux/drivers/char/istallion.c --- v2.1.126/linux/drivers/char/istallion.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/istallion.c Sat Oct 31 11:07:22 1998 @@ -1292,8 +1292,7 @@ #endif if (len > 0) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + len; - schedule(); + schedule_timeout(len); current->state = TASK_RUNNING; } } @@ -2252,7 +2251,8 @@ { stlibrd_t *brdp; stliport_t *portp; - long arg, savestate, savetime; + long arg; + /* long savestate, savetime; */ #if DEBUG printk("stli_breakctl(tty=%x,state=%d)\n", (int) tty, state); @@ -2272,15 +2272,18 @@ /* * Due to a bug in the tty send_break() code we need to preserve * the current process state and timeout... - */ savetime = current->timeout; savestate = current->state; + */ arg = (state == -1) ? BREAKON : BREAKOFF; stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0); +/* + * current->timeout = savetime; current->state = savestate; + */ } /*****************************************************************************/ diff -u --recursive --new-file v2.1.126/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.126/linux/drivers/char/lp.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/lp.c Sat Nov 7 10:56:05 1998 @@ -162,17 +162,17 @@ lp_table[minor].irq_missed = 1; } -static __inline__ void lp_schedule(int minor) +static __inline__ void lp_schedule(int minor, long timeout) { struct pardevice *dev = lp_table[minor].dev; register unsigned long int timeslip = (jiffies - dev->time); if ((timeslip > dev->timeslice) && (dev->port->waithead != NULL)) { lp_parport_release(minor); lp_table[minor].irq_missed = 1; - schedule (); + schedule_timeout(timeout); lp_parport_claim(minor); } else - schedule(); + schedule_timeout(timeout); } static int lp_reset(int minor) @@ -269,9 +269,8 @@ { if (LP_POLLED(minor) || LP_PREEMPTED(minor)) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + LP_TIMEOUT_POLLED; lp_parport_release(minor); - schedule(); + schedule_timeout(LP_TIMEOUT_POLLED); lp_parport_claim(minor); lp_table[minor].irq_missed = 1; } @@ -381,8 +380,7 @@ printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp->runchars, LP_TIME(minor)); #endif current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + LP_TIME(minor); - lp_schedule (minor); + lp_schedule(minor, LP_TIME(minor)); } else { cli(); if (LP_PREEMPTED(minor)) @@ -399,8 +397,7 @@ } if (!lp_table[minor].irq_detected) { - current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; - interruptible_sleep_on(&lp->wait_q); + interruptible_sleep_on_timeout(&lp->wait_q, LP_TIMEOUT_INTERRUPT); } sti(); } @@ -535,8 +532,7 @@ return -EINTR; } current->state=TASK_INTERRUPTIBLE; - current->timeout=jiffies + LP_TIME(minor); - schedule (); + schedule_timeout(LP_TIME(minor)); } counter=0; diff -u --recursive --new-file v2.1.126/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.126/linux/drivers/char/mem.c Mon Oct 5 13:13:39 1998 +++ linux/drivers/char/mem.c Tue Oct 27 09:52:21 1998 @@ -35,6 +35,9 @@ void dmasound_init(void); #endif #endif +#ifdef CONFIG_SPARCAUDIO +extern int sparcaudio_init(void); +#endif #ifdef CONFIG_ISDN int isdn_init(void); #endif @@ -570,6 +573,9 @@ #ifdef CONFIG_DMASOUND dmasound_init(); #endif +#endif +#ifdef CONFIG_SPARCAUDIO + sparcaudio_init(); #endif #ifdef CONFIG_JOYSTICK /* diff -u --recursive --new-file v2.1.126/linux/drivers/char/msp3400.c linux/drivers/char/msp3400.c --- v2.1.126/linux/drivers/char/msp3400.c Thu Aug 20 17:05:15 1998 +++ linux/drivers/char/msp3400.c Sat Oct 31 10:17:22 1998 @@ -554,8 +554,7 @@ UNLOCK_I2C_BUS(msp->bus); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/25; - schedule(); + schedule_timeout(HZ/25); if (signal_pending(current)) goto done; if (msp->restart) { @@ -589,8 +588,7 @@ UNLOCK_I2C_BUS(msp->bus); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/25; - schedule(); + schedule_timeout(HZ/25); if (signal_pending(current)) goto done; if (msp->restart) { @@ -715,8 +713,7 @@ /* wait 1 sec */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; - schedule(); + schedule_timeout(HZ); if (signal_pending(current)) goto done; if (msp->restart) { diff -u --recursive --new-file v2.1.126/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.126/linux/drivers/char/n_tty.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/n_tty.c Sat Oct 31 10:17:22 1998 @@ -419,7 +419,7 @@ char buf[64]; tty->num_overrun++; - if (tty->overrun_time < (jiffies - HZ)) { + if (time_before(tty->overrun_time, jiffies - HZ)) { printk("%s: %d input overrun(s)\n", tty_name(tty, buf), tty->num_overrun); tty->overrun_time = jiffies; @@ -872,6 +872,7 @@ int minimum, time; ssize_t retval = 0; ssize_t size; + long timeout; do_it_again: @@ -900,7 +901,7 @@ } minimum = time = 0; - current->timeout = (unsigned long) -1; + timeout = MAX_SCHEDULE_TIMEOUT; if (!tty->icanon) { time = (HZ / 10) * TIME_CHAR(tty); minimum = MIN_CHAR(tty); @@ -911,9 +912,9 @@ (tty->minimum_to_wake > minimum)) tty->minimum_to_wake = minimum; } else { - current->timeout = 0; + timeout = 0; if (time) { - current->timeout = time + jiffies; + timeout = time; time = 0; } tty->minimum_to_wake = minimum = 1; @@ -949,7 +950,7 @@ } if (tty_hung_up_p(file)) break; - if (!current->timeout) + if (!timeout) break; if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; @@ -960,7 +961,7 @@ break; } enable_bh(TQUEUE_BH); - schedule(); + timeout = schedule_timeout(timeout); disable_bh(TQUEUE_BH); continue; } @@ -1021,7 +1022,7 @@ if (b - buf >= minimum) break; if (time) - current->timeout = time + jiffies; + timeout = time; } enable_bh(TQUEUE_BH); remove_wait_queue(&tty->read_wait, &wait); @@ -1030,7 +1031,6 @@ tty->minimum_to_wake = minimum; current->state = TASK_RUNNING; - current->timeout = 0; size = b - buf; if (size) { retval = size; diff -u --recursive --new-file v2.1.126/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c --- v2.1.126/linux/drivers/char/pc_keyb.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/pc_keyb.c Tue Nov 3 23:10:00 1998 @@ -56,7 +56,7 @@ static void kbd_write(int address, int data); -static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; +spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; /* used only by send_data - set by keyboard_interrupt */ static volatile unsigned char reply_expected = 0; @@ -904,10 +904,18 @@ static int __init psaux_init(void) { +#if 0 + /* + * Don't bother with the BIOS flag: even if we don't have + * a mouse connected at bootup we may still want to connect + * one later, and we don't want to just let the BIOS tell + * us that it has no mouse.. + */ if (aux_device_present != 0xaa) return -EIO; printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n"); +#endif misc_register(&psaux_mouse); queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); memset(queue, 0, sizeof(*queue)); diff -u --recursive --new-file v2.1.126/linux/drivers/char/pcxx.c linux/drivers/char/pcxx.c --- v2.1.126/linux/drivers/char/pcxx.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/char/pcxx.c Thu Nov 5 09:58:43 1998 @@ -633,8 +633,7 @@ if(info->blocked_open) { if(info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } diff -u --recursive --new-file v2.1.126/linux/drivers/char/qpmouse.c linux/drivers/char/qpmouse.c --- v2.1.126/linux/drivers/char/qpmouse.c Fri Oct 23 22:01:20 1998 +++ linux/drivers/char/qpmouse.c Sat Oct 31 10:43:36 1998 @@ -245,8 +245,7 @@ if (inb_p(qp_status)&(QP_RX_FULL)) inb_p(qp_data); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (5*HZ + 99) / 100; - schedule(); + schedule_timeout((5*HZ + 99) / 100); retries++; } return !(retries==MAX_RETRIES); diff -u --recursive --new-file v2.1.126/linux/drivers/char/radio-sf16fmi.c linux/drivers/char/radio-sf16fmi.c --- v2.1.126/linux/drivers/char/radio-sf16fmi.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/radio-sf16fmi.c Thu Nov 5 09:58:43 1998 @@ -43,7 +43,7 @@ * 92.7400017 -> 92.75 */ #define RSF16_ENCODE(x) ((x)/800+214) -#define RSF16_MINFREQ 88*16000 +#define RSF16_MINFREQ 87*16000 #define RSF16_MAXFREQ 108*16000 static void outbits(int bits, unsigned int data, int port) @@ -64,27 +64,31 @@ } } -static void fmi_mute(int port) +static inline void fmi_mute(int port) { outb(0x00, port); } -static void fmi_unmute(int port) +static inline void fmi_unmute(int port) { outb(0x08, port); } -static int fmi_setfreq(struct fmi_device *dev, unsigned long freq) +static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq) { int myport = dev->port; outbits(16, RSF16_ENCODE(freq), myport); outbits(8, 0xC0, myport); - /* we should wait here... */ + /* it is better than udelay(140000), isn't it? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/7); + /* ignore signals, we really should restore volume */ + if (dev->curvol) fmi_unmute(myport); return 0; } -static int fmi_getsigstr(struct fmi_device *dev) +static inline int fmi_getsigstr(struct fmi_device *dev) { int val; int res; @@ -93,10 +97,16 @@ val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ outb(val, myport); outb(val | 0x10, myport); - udelay(140000); + /* it is better than udelay(140000), isn't it? */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/7); + /* do not do it..., 140ms is very looong time to get signal in real program + if (signal_pending(current)) + return -EINTR; + */ res = (int)inb(myport+1); outb(val, myport); - return (res & 2) ? 0 : 1; + return (res & 2) ? 0 : 0xFFFF; } static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) @@ -136,7 +146,7 @@ v.rangehigh = RSF16_MAXFREQ/mult; v.flags=fmi->flags; v.mode=VIDEO_MODE_AUTO; - v.signal=0xFFFF*fmi_getsigstr(fmi); + v.signal = fmi_getsigstr(fmi); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; diff -u --recursive --new-file v2.1.126/linux/drivers/char/riscom8.c linux/drivers/char/riscom8.c --- v2.1.126/linux/drivers/char/riscom8.c Thu May 7 22:51:49 1998 +++ linux/drivers/char/riscom8.c Thu Nov 5 09:58:43 1998 @@ -1172,8 +1172,7 @@ timeout = jiffies+HZ; while(port->IER & IER_TXEMPTY) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + port->timeout; - schedule(); + schedule_timeout(port->timeout); if (jiffies > timeout) break; } @@ -1189,8 +1188,7 @@ if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + port->close_delay; - schedule(); + schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); } diff -u --recursive --new-file v2.1.126/linux/drivers/char/rocket.c linux/drivers/char/rocket.c --- v2.1.126/linux/drivers/char/rocket.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/char/rocket.c Thu Nov 5 09:58:43 1998 @@ -1181,8 +1181,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } else { @@ -1269,10 +1268,9 @@ static void send_break( struct r_port * info, int duration) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; cli(); sSendBreak(&info->channel); - schedule(); + schedule_timeout(duration); sClrBreak(&info->channel); sti(); } @@ -1666,8 +1664,7 @@ #endif current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + check_time; - schedule(); + schedule_timeout(check_time); if (signal_pending(current)) break; } diff -u --recursive --new-file v2.1.126/linux/drivers/char/saa5249.c linux/drivers/char/saa5249.c --- v2.1.126/linux/drivers/char/saa5249.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/saa5249.c Thu Nov 5 09:58:43 1998 @@ -242,8 +242,7 @@ recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + delay; - schedule(); + schedule_timeout(delay); spin_lock_irq(¤t->sigmask_lock); current->blocked = oldblocked; diff -u --recursive --new-file v2.1.126/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.126/linux/drivers/char/serial.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/char/serial.c Tue Nov 3 22:05:25 1998 @@ -1653,6 +1653,8 @@ return -EPERM; state->flags = ((state->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); + info->flags = ((state->flags & ~ASYNC_USR_MASK) | + (info->flags & ASYNC_USR_MASK)); state->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } @@ -1660,8 +1662,9 @@ new_serial.irq = irq_cannonicalize(new_serial.irq); if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) || - (new_serial.type < PORT_UNKNOWN) || - (new_serial.type > PORT_MAX)) { + (new_serial.baud_base == 0) || (new_serial.type < PORT_UNKNOWN) || + (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || + (new_serial.type == PORT_STARTECH)) { return -EINVAL; } @@ -2291,8 +2294,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -2346,8 +2348,7 @@ #endif current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) diff -u --recursive --new-file v2.1.126/linux/drivers/char/serial167.c linux/drivers/char/serial167.c --- v2.1.126/linux/drivers/char/serial167.c Fri Oct 9 13:27:08 1998 +++ linux/drivers/char/serial167.c Thu Nov 5 09:58:43 1998 @@ -1952,8 +1952,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } diff -u --recursive --new-file v2.1.126/linux/drivers/char/specialix.c linux/drivers/char/specialix.c --- v2.1.126/linux/drivers/char/specialix.c Thu May 7 22:51:49 1998 +++ linux/drivers/char/specialix.c Thu Nov 5 09:58:43 1998 @@ -58,6 +58,8 @@ * Made many more debug printk's a compile time option. * Revision 1.8: Jul 1 1997 * port to linux-2.1.43 kernel. + * Revision 1.9: Oct 9 1998 + * Added stuff for the IO8+/PCI version. . * */ @@ -87,6 +89,7 @@ #include #include #include +#include /* ************************************************************** */ @@ -173,7 +176,6 @@ #define SPECIALIX_TYPE_NORMAL 1 #define SPECIALIX_TYPE_CALLOUT 2 -static struct specialix_board * IRQ_to_board[16] = { NULL, } ; static struct tty_driver specialix_driver, specialix_callout_driver; static int specialix_refcount = 0; static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT] = { NULL, }; @@ -331,17 +333,22 @@ extern inline void sx_request_io_range(struct specialix_board * bp) { - request_region(bp->base, SX_IO_SPACE, "specialix IO8+" ); + request_region(bp->base, + bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE, + "specialix IO8+" ); } extern inline void sx_release_io_range(struct specialix_board * bp) { - release_region(bp->base, SX_IO_SPACE); + release_region(bp->base, + bp->flags&SX_BOARD_IS_PCI?SX_PCI_IO_SPACE:SX_IO_SPACE); } /* Must be called with enabled interrupts */ +/* Ugly. Very ugly. Don't use this for anything else than initialization + code */ extern inline void sx_long_delay(unsigned long delay) { unsigned long i; @@ -357,6 +364,8 @@ int virq; int i; + if (bp->flags & SX_BOARD_IS_PCI) + return 1; switch (bp->irq) { /* In the same order as in the docs... */ case 15: virq = 0;break; @@ -484,9 +493,14 @@ printk (KERN_DEBUG "sx%d: DSR lines are: %02x, rts lines are: %02x\n", board_No(bp), val1, val2); #endif - if (val1 != 0xb2) { - printk(KERN_INFO "sx%d: specialix IO8+ ID at 0x%03x not found.\n", - board_No(bp), bp->base); + /* They managed to switch the bit order between the docs and + the IO8+ card. The new PCI card now conforms to old docs. + They changed the PCI docs to reflect the situation on the + old card. */ + val2 = (bp->flags & SX_BOARD_IS_PCI)?0x4d : 0xb2; + if (val1 != val2) { + printk(KERN_INFO "sx%d: specialix IO8+ ID %02x at 0x%03x not found (%02x).\n", + board_No(bp), val2, bp->base, val1); return 1; } @@ -868,7 +882,7 @@ unsigned long loop = 0; int saved_reg; - bp = IRQ_to_board[irq]; + bp = dev_id; if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) { #ifdef SPECIALIX_DEBUG @@ -924,6 +938,25 @@ * Routines for open & close processing. */ +void turn_ints_off (struct specialix_board *bp) +{ + if (bp->flags & SX_BOARD_IS_PCI) { + /* This was intended for enabeling the interrupt on the + * PCI card. However it seems that it's already enabled + * and as PCI interrupts can be shared, there is no real + * reason to have to turn it off. */ + } + (void) sx_in_off (bp, 0); /* Turn off interrupts. */ +} + +void turn_ints_on (struct specialix_board *bp) +{ + if (bp->flags & SX_BOARD_IS_PCI) { + /* play with the PCI chip. See comment above. */ + } + (void) sx_in (bp, 0); /* Turn ON interrupts. */ +} + /* Called with disabled interrupts */ extern inline int sx_setup_board(struct specialix_board * bp) @@ -933,14 +966,12 @@ if (bp->flags & SX_BOARD_ACTIVE) return 0; - error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", NULL); + error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp); if (error) return error; - IRQ_to_board[bp->irq] = bp; - (void) sx_in (bp, 0); /* Turn ON interrupts. */ - + turn_ints_on (bp); bp->flags |= SX_BOARD_ACTIVE; MOD_INC_USE_COUNT; @@ -956,11 +987,13 @@ bp->flags &= ~SX_BOARD_ACTIVE; - free_irq(bp->irq, NULL); - (void) sx_in_off (bp, 0); /* Turn off interrupts. */ +#if SPECIALIX_DEBUG > 2 + printk ("Freeing IRQ%d for board %d.\n", bp->irq, board_No (bp)); +#endif + free_irq(bp->irq, bp); + + turn_ints_off (bp); - IRQ_to_board[bp->irq] = NULL; - MOD_DEC_USE_COUNT; } @@ -1045,12 +1078,14 @@ /* Page 48 of version 2.0 of the CL-CD1865 databook */ if (tmp >= 12) { printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n" - "Performance degradation is possible.\n", + "Performance degradation is possible.\n" + "Read specialix.txt for more info.\n", port_No (port), tmp); } else { printk (KERN_INFO "sx%d: Baud rate divisor is %ld. \n" "Warning: overstressing Cirrus chip. " - "This might not work.\n", + "This might not work.\n" + "Read specialix.txt for more info.\n", port_No (port), tmp); } } @@ -1516,8 +1551,7 @@ timeout = jiffies+HZ; while(port->IER & IER_TXEMPTY) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + port->timeout; - schedule(); + schedule_timeout(port->timeout); if (jiffies > timeout) { printk (KERN_INFO "Timeout waiting for close\n"); break; @@ -1536,8 +1570,7 @@ if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + port->close_delay; - schedule(); + schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); } @@ -2153,7 +2186,6 @@ return 1; } init_bh(SPECIALIX_BH, do_specialix_bh); - memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); memset(&specialix_driver, 0, sizeof(specialix_driver)); specialix_driver.magic = TTY_DRIVER_MAGIC; specialix_driver.name = "ttyW"; @@ -2265,7 +2297,7 @@ int i; int found = 0; - printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997.\n"); + printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n"); printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n"); #ifdef CONFIG_SPECIALIX_RTSCTS printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n"); @@ -2280,6 +2312,35 @@ if (sx_board[i].base && !sx_probe(&sx_board[i])) found++; +#ifdef CONFIG_PCI + if (pci_present()) { + struct pci_dev *pdev = NULL; + unsigned int tint; + + i=0; + while (i <= SX_NBOARD) { + if (sx_board[i].flags & SX_BOARD_PRESENT) { + i++; + continue; + } + pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX, + PCI_DEVICE_ID_SPECIALIX_IO8, + pdev); + if (!pdev) break; + + sx_board[i].irq = pdev->irq; + + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2, &tint); + /* Mask out the fact that it's IO-space */ + sx_board[i].base = tint & PCI_BASE_ADDRESS_IO_MASK; + + sx_board[i].flags |= SX_BOARD_IS_PCI; + if (!sx_probe(&sx_board[i])) + found ++; + } + } +#endif + if (!found) { sx_release_drivers(); printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n"); @@ -2296,7 +2357,8 @@ /* * You can setup up to 4 boards. - * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. + * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter. + * You should specify the IRQs too in that case "irq=....,...". * * More than 4 boards in one computer is not possible, as the card can * only use 4 different interrupts. diff -u --recursive --new-file v2.1.126/linux/drivers/char/specialix_io8.h linux/drivers/char/specialix_io8.h --- v2.1.126/linux/drivers/char/specialix_io8.h Tue Mar 10 10:03:31 1998 +++ linux/drivers/char/specialix_io8.h Wed Oct 28 22:04:05 1998 @@ -43,9 +43,16 @@ #ifdef __KERNEL__ -#define SX_NBOARD 4 +/* You can have max 4 ISA cards in one PC, and I recommend not much +more than a few PCI versions of the card. */ + +#define SX_NBOARD 8 + /* NOTE: Specialix decoder recognizes 4 addresses, but only two are used.... */ #define SX_IO_SPACE 4 +/* The PCI version decodes 8 addresses, but still only 2 are used. */ +#define SX_PCI_IO_SPACE 8 + /* eight ports per board. */ #define SX_NPORT 8 #define SX_BOARD(line) ((line) / SX_NPORT) @@ -93,6 +100,7 @@ #define SX_BOARD_PRESENT 0x00000001 #define SX_BOARD_ACTIVE 0x00000002 +#define SX_BOARD_IS_PCI 0x00000004 struct specialix_port { diff -u --recursive --new-file v2.1.126/linux/drivers/char/stallion.c linux/drivers/char/stallion.c --- v2.1.126/linux/drivers/char/stallion.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/char/stallion.c Thu Nov 5 09:58:43 1998 @@ -1072,8 +1072,7 @@ #endif if (len > 0) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + len; - schedule(); + schedule_timeout(len); current->state = TASK_RUNNING; } } diff -u --recursive --new-file v2.1.126/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c --- v2.1.126/linux/drivers/char/tpqic02.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/char/tpqic02.c Thu Nov 5 09:58:43 1998 @@ -588,9 +588,10 @@ /* not ready and no exception && timeout not expired yet */ while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffiestimeout = jiffies + 3*HZ/10; /* nap 0.30 sec between checks, */ current->state = TASK_INTERRUPTIBLE; - schedule(); /* but could be woken up earlier by signals... */ + /* nap 0.30 sec between checks, */ + /* but could be woken up earlier by signals... */ + schedule_timeout(3*HZ/10); } /* don't use jiffies for this test because it may have changed by now */ diff -u --recursive --new-file v2.1.126/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.126/linux/drivers/char/tty_io.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/char/tty_io.c Sat Oct 31 10:17:22 1998 @@ -1623,11 +1623,10 @@ static int send_break(struct tty_struct *tty, int duration) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; tty->driver.break_ctl(tty, -1); if (!signal_pending(current)) - schedule(); + schedule_timeout(duration); tty->driver.break_ctl(tty, 0); if (signal_pending(current)) return -EINTR; @@ -2046,7 +2045,10 @@ return kmem_start; } -static struct tty_driver dev_tty_driver, dev_syscons_driver, dev_ptmx_driver; +static struct tty_driver dev_tty_driver, dev_syscons_driver; +#ifdef CONFIG_UNIX98_PTYS +static struct tty_driver dev_ptmx_driver; +#endif #ifdef CONFIG_VT static struct tty_driver dev_console_driver; #endif diff -u --recursive --new-file v2.1.126/linux/drivers/char/tty_ioctl.c linux/drivers/char/tty_ioctl.c --- v2.1.126/linux/drivers/char/tty_ioctl.c Tue Mar 17 22:18:14 1998 +++ linux/drivers/char/tty_ioctl.c Sat Oct 31 10:17:22 1998 @@ -40,7 +40,7 @@ #define TERMIOS_WAIT 2 #define TERMIOS_TERMIO 4 -void tty_wait_until_sent(struct tty_struct * tty, int timeout) +void tty_wait_until_sent(struct tty_struct * tty, long timeout) { struct wait_queue wait = { current, NULL }; @@ -53,10 +53,8 @@ return; add_wait_queue(&tty->write_wait, &wait); current->counter = 0; /* make us low-priority */ - if (timeout) - current->timeout = timeout + jiffies; - else - current->timeout = (unsigned) -1; + if (!timeout) + timeout = MAX_SCHEDULE_TIMEOUT; do { #ifdef TTY_DEBUG_WAIT_UNTIL_SENT printk("waiting %s...(%d)\n", tty_name(tty, buf), @@ -67,15 +65,10 @@ goto stop_waiting; if (!tty->driver.chars_in_buffer(tty)) break; - schedule(); - } while (current->timeout); - if (tty->driver.wait_until_sent) { - if (current->timeout == -1) - timeout = 0; - else - timeout = current->timeout - jiffies; + timeout = schedule_timeout(timeout); + } while (timeout); + if (tty->driver.wait_until_sent) tty->driver.wait_until_sent(tty, timeout); - } stop_waiting: current->state = TASK_RUNNING; remove_wait_queue(&tty->write_wait, &wait); diff -u --recursive --new-file v2.1.126/linux/drivers/char/tuner.c linux/drivers/char/tuner.c --- v2.1.126/linux/drivers/char/tuner.c Wed Aug 26 11:37:37 1998 +++ linux/drivers/char/tuner.c Sat Oct 31 10:17:22 1998 @@ -142,8 +142,7 @@ if (debug) { UNLOCK_I2C_BUS(t->bus); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/10; - schedule(); + schedule_timeout(HZ/10); LOCK_I2C_BUS(t->bus); if (tuner_islocked (t)) diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/act2000/act2000_isa.c linux/drivers/isdn/act2000/act2000_isa.c --- v2.1.126/linux/drivers/isdn/act2000/act2000_isa.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/isdn/act2000/act2000_isa.c Thu Nov 5 09:58:43 1998 @@ -61,8 +61,7 @@ { sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + t; - schedule(); + schedule_timeout(t); sti(); } diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/avmb1/b1capi.c linux/drivers/isdn/avmb1/b1capi.c --- v2.1.126/linux/drivers/isdn/avmb1/b1capi.c Wed Apr 1 20:11:49 1998 +++ linux/drivers/isdn/avmb1/b1capi.c Thu Nov 5 09:58:43 1998 @@ -965,9 +965,8 @@ while (card->cardstate != CARD_RUNNING) { - current->timeout = jiffies + HZ / 10; /* 0.1 sec */ current->state = TASK_INTERRUPTIBLE; - schedule(); + schedule_timeout(HZ/10); /* 0.1 sec */ if (signal_pending(current)) return -EINTR; diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/arcofi.c linux/drivers/isdn/hisax/arcofi.c --- v2.1.126/linux/drivers/isdn/hisax/arcofi.c Wed Apr 1 20:11:50 1998 +++ linux/drivers/isdn/hisax/arcofi.c Thu Nov 5 09:58:43 1998 @@ -40,8 +40,7 @@ while (cnt && !test_bit(HW_MON1_TX_END, &cs->HW_Flags)) { cnt--; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ } restore_flags(flags); sprintf(tmp, "arcofi tout %d", cnt); diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/asuscom.c linux/drivers/isdn/hisax/asuscom.c --- v2.1.126/linux/drivers/isdn/hisax/asuscom.c Wed Apr 1 20:11:50 1998 +++ linux/drivers/isdn/hisax/asuscom.c Thu Nov 5 09:58:43 1998 @@ -201,12 +201,10 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); byteout(cs->hw.asus.adr, 0); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); restore_flags(flags); } diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/diva.c linux/drivers/isdn/hisax/diva.c --- v2.1.126/linux/drivers/isdn/hisax/diva.c Wed Apr 1 20:11:50 1998 +++ linux/drivers/isdn/hisax/diva.c Thu Nov 5 09:58:43 1998 @@ -241,13 +241,11 @@ cs->hw.diva.ctrl_reg = 0; /* Reset On */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ if (cs->subtyp == DIVA_ISA) cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; else diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/elsa.c linux/drivers/isdn/hisax/elsa.c --- v2.1.126/linux/drivers/isdn/hisax/elsa.c Wed Apr 1 20:11:50 1998 +++ linux/drivers/isdn/hisax/elsa.c Thu Nov 5 09:58:44 1998 @@ -450,12 +450,10 @@ sti(); writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); schedule(); restore_flags(flags); @@ -658,8 +656,7 @@ } else return(0); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (110 * HZ) / 1000; /* Timeout 110ms */ - schedule(); + schedule_timeout((110*HZ)/1000); /* Timeout 110ms */ restore_flags(flags); cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/isdnl1.c linux/drivers/isdn/hisax/isdnl1.c --- v2.1.126/linux/drivers/isdn/hisax/isdnl1.c Wed Apr 1 20:11:50 1998 +++ linux/drivers/isdn/hisax/isdnl1.c Sat Oct 31 10:37:14 1998 @@ -639,8 +639,7 @@ sti(); current->state = TASK_INTERRUPTIBLE; /* Timeout 10ms */ - current->timeout = jiffies + (10 * HZ) / 1000; - schedule(); + schedule_timeout((10 * HZ) / 1000); restore_flags(flags); printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], cs->irq, kstat_irqs(cs->irq)); diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/netjet.c linux/drivers/isdn/hisax/netjet.c --- v2.1.126/linux/drivers/isdn/hisax/netjet.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/hisax/netjet.c Thu Nov 5 09:58:44 1998 @@ -971,13 +971,11 @@ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (10 * HZ) / 1000; /* Timeout 10ms */ - schedule(); + schedule_timeout((10*HZ)/1000); /* Timeout 10ms */ restore_flags(flags); cs->hw.njet.auxd = 0; cs->hw.njet.dmactrl = 0; diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/sedlbauer.c linux/drivers/isdn/hisax/sedlbauer.c --- v2.1.126/linux/drivers/isdn/hisax/sedlbauer.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/hisax/sedlbauer.c Thu Nov 5 09:58:44 1998 @@ -242,12 +242,10 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); restore_flags(flags); } } diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/sportster.c linux/drivers/isdn/hisax/sportster.c --- v2.1.126/linux/drivers/isdn/hisax/sportster.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/hisax/sportster.c Thu Nov 5 09:58:44 1998 @@ -165,13 +165,11 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); restore_flags(flags); } diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/teleint.c linux/drivers/isdn/hisax/teleint.c --- v2.1.126/linux/drivers/isdn/hisax/teleint.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/hisax/teleint.c Thu Nov 5 09:58:44 1998 @@ -246,13 +246,11 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 3; - schedule(); + schedule_timeout(3); cs->hw.hfc.cirm &= ~HFC_RESET; byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); restore_flags(flags); } diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/hisax/teles3c.c linux/drivers/isdn/hisax/teles3c.c --- v2.1.126/linux/drivers/isdn/hisax/teles3c.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/hisax/teles3c.c Thu Nov 5 09:58:44 1998 @@ -79,13 +79,11 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 3; - schedule(); + schedule_timeout(3); cs->hw.hfcD.cirm = HFCD_MEM8K; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); cs->hw.hfcD.cirm |= HFCD_INTB; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* INT B */ cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); @@ -136,8 +134,7 @@ save_flags(flags); sti(); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (80*HZ)/1000; - schedule(); + schedule_timeout((80*HZ)/1000); cs->hw.hfcD.ctmt |= HFCD_TIM800; cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v2.1.126/linux/drivers/isdn/icn/icn.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/isdn/icn/icn.c Thu Nov 5 09:58:44 1998 @@ -914,8 +914,7 @@ printk(KERN_DEBUG "Loader %d TO?\n", cardnumber); #endif current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); + schedule_timeout(ICN_BOOT_TIMEOUT1); } else { #ifdef BOOT_DEBUG printk(KERN_DEBUG "Loader %d OK\n", cardnumber); @@ -941,8 +940,7 @@ printk(KERN_DEBUG "SLEEP(%d)\n",slsec); \ while (slsec) { \ current->state = TASK_INTERRUPTIBLE; \ - current->timeout = jiffies + HZ; \ - schedule(); \ + schedule_timeout(HZ); \ slsec--; \ } \ } @@ -1104,8 +1102,7 @@ return -EIO; } current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 10; - schedule(); + schedule_timeout(10); } } writeb(0x20, &sbuf_n); @@ -1129,8 +1126,7 @@ printk(KERN_DEBUG "Proto TO?\n"); #endif current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); + schedule_timeout(ICN_BOOT_TIMEOUT1); } else { if ((card->secondhalf) || (!card->doubleS0)) { #ifdef BOOT_DEBUG @@ -1425,11 +1421,9 @@ if (!card->leased) { card->leased = 1; while (card->ptype == ISDN_PTYPE_UNKNOWN) { - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); + schedule_timeout(ICN_BOOT_TIMEOUT1); } - current->timeout = jiffies + ICN_BOOT_TIMEOUT1; - schedule(); + schedule_timeout(ICN_BOOT_TIMEOUT1); sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n", (a & 1)?'1':'C', (a & 2)?'2':'C'); i = icn_writecmd(cbuf, strlen(cbuf), 0, card); diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v2.1.126/linux/drivers/isdn/isdn_tty.c Wed Apr 1 20:11:51 1998 +++ linux/drivers/isdn/isdn_tty.c Sat Oct 31 10:37:14 1998 @@ -1820,9 +1820,8 @@ timeout = jiffies + HZ; while (!(info->lsr & UART_LSR_TEMT)) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 20; - schedule(); - if (jiffies > timeout) + schedule_timeout(20); + if (time_after(jiffies,timeout)) break; } } @@ -1837,8 +1836,7 @@ tty->closing = 0; if (info->blocked_open) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 50; - schedule(); + schedule_timeout(50); wake_up_interruptible(&info->open_wait); } info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE | diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/isdnloop/isdnloop.c linux/drivers/isdn/isdnloop/isdnloop.c --- v2.1.126/linux/drivers/isdn/isdnloop/isdnloop.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/isdn/isdnloop/isdnloop.c Sat Oct 31 10:37:14 1998 @@ -1179,11 +1179,9 @@ if (!card->leased) { card->leased = 1; while (card->ptype == ISDN_PTYPE_UNKNOWN) { - current->timeout = jiffies + 10; - schedule(); + schedule_timeout(10); } - current->timeout = jiffies + 10; - schedule(); + schedule_timeout(10); sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); printk(KERN_INFO diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/sc/init.c linux/drivers/isdn/sc/init.c --- v2.1.126/linux/drivers/isdn/sc/init.c Wed Apr 1 20:11:52 1998 +++ linux/drivers/isdn/sc/init.c Thu Nov 5 09:58:44 1998 @@ -165,8 +165,7 @@ pr_debug("Doing a SAFE probe reset\n"); outb(0xFF, io[b] + RESET_OFFSET); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + milliseconds(10000); - schedule(); + schedule_timeout(milliseconds(10000)); } pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b], ram[b] == 0 ? "will" : "won't"); @@ -514,8 +513,7 @@ */ outb(PRI_BASEPG_VAL, pgport); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; - schedule(); + schedule_timeout(HZ); sig = readl(rambase + SIG_OFFSET); pr_debug("Looking for a signature, got 0x%x\n", sig); #if 0 @@ -535,8 +533,7 @@ */ outb(BRI_BASEPG_VAL, pgport); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; - schedule(); + schedule_timeout(HZ); sig = readl(rambase + SIG_OFFSET); pr_debug("Looking for a signature, got 0x%x\n", sig); #if 0 @@ -571,8 +568,7 @@ x = 0; while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); x++; } if(x == 100) { diff -u --recursive --new-file v2.1.126/linux/drivers/isdn/sc/message.c linux/drivers/isdn/sc/message.c --- v2.1.126/linux/drivers/isdn/sc/message.c Wed Apr 1 20:11:52 1998 +++ linux/drivers/isdn/sc/message.c Thu Nov 5 09:58:44 1998 @@ -267,8 +267,7 @@ /* wait for the response */ while (tries < timeout) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); pr_debug("SAR waiting..\n"); diff -u --recursive --new-file v2.1.126/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c --- v2.1.126/linux/drivers/macintosh/macserial.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/macintosh/macserial.c Thu Nov 5 09:58:44 1998 @@ -1264,8 +1264,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -1301,8 +1300,7 @@ while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && ((orig_jiffies + timeout) < jiffies)) diff -u --recursive --new-file v2.1.126/linux/drivers/macintosh/mediabay.c linux/drivers/macintosh/mediabay.c --- v2.1.126/linux/drivers/macintosh/mediabay.c Fri May 8 23:14:47 1998 +++ linux/drivers/macintosh/mediabay.c Thu Nov 5 09:58:44 1998 @@ -184,8 +184,7 @@ prev = media_bay_id; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); + schedule_timeout(1); if (signal_pending(current)) return 0; } diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c --- v2.1.126/linux/drivers/misc/parport_ieee1284.c Tue Jul 21 00:15:31 1998 +++ linux/drivers/misc/parport_ieee1284.c Sat Oct 31 10:17:22 1998 @@ -34,8 +34,7 @@ schedule(); } current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies+4; - schedule(); /* wait for 40ms */ + schedule_timeout(HZ/25); /* wait for 40ms */ status = parport_read_status(port); return ((status & mask) == result)?0:1; } diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c --- v2.1.126/linux/drivers/misc/parport_pc.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/misc/parport_pc.c Mon Oct 26 13:42:53 1998 @@ -7,6 +7,8 @@ * Andrea Arcangeli * * based on work by Grant Guenther and Phil Blundell. + * + * Cleaned up include files - Russell King */ /* This driver should work with any hardware that is broadly compatible @@ -557,12 +559,12 @@ static int irq_probe_ECP(struct parport *pb) { int irqs, i; - + sti(); irqs = probe_irq_on(); - parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ - parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ + parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */ + parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */ /* If Full FIFO sure that WriteIntrThresold is generated */ for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++) diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_procfs.c linux/drivers/misc/parport_procfs.c --- v2.1.126/linux/drivers/misc/parport_procfs.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/misc/parport_procfs.c Mon Oct 26 13:42:53 1998 @@ -8,16 +8,11 @@ * * based on work by Grant Guenther * and Philip Blundell + * + * Cleaned up include files - Russell King */ -#include -#include -#include -#include -#include -#include -#include - +#include #include #include #include @@ -26,6 +21,11 @@ #include #include #include +#include + +#include +#include +#include struct proc_dir_entry *base = NULL; diff -u --recursive --new-file v2.1.126/linux/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c --- v2.1.126/linux/drivers/misc/parport_share.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/misc/parport_share.c Tue Oct 27 10:32:29 1998 @@ -105,7 +105,7 @@ tmp->ops = ops; tmp->number = portnum; memset (&tmp->probe_info, 0, sizeof (struct parport_device_info)); - spin_lock_init(&tmp->cad_lock); + tmp->cad_lock = RW_LOCK_UNLOCKED; spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->pardevice_lock); diff -u --recursive --new-file v2.1.126/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v2.1.126/linux/drivers/net/3c509.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/3c509.c Mon Oct 26 13:45:22 1998 @@ -34,6 +34,7 @@ v1.10 4/21/97 Fixed module code so that multiple cards may be detected, other cleanups. -djb Andrea Arcangeli: Upgraded to Donald Becker's version 1.12. + Rick Payne: Fixed SMP race condition */ static char *version = "3c509.c:1.12 6/4/97 becker@cesdis.gsfc.nasa.gov\n"; @@ -59,6 +60,7 @@ #include #include /* for udelay() */ +#include #include #include @@ -122,6 +124,7 @@ struct el3_private { struct enet_statistics stats; struct device *next_dev; + spinlock_t lock; /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; @@ -401,6 +404,9 @@ outw(RxReset, ioaddr + EL3_CMD); outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); + /* Set the spinlock before grabbing IRQ! */ + ((struct el3_private *)dev->priv)->lock = (spinlock_t) SPIN_LOCK_UNLOCKED; + if (request_irq(dev->irq, &el3_interrupt, 0, "3c509", dev)) { return -EAGAIN; } @@ -520,6 +526,11 @@ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { + unsigned long flags; + + /* Spin on the lock, until we're clear of an IRQ */ + spin_lock_irqsave(&lp->lock, flags); + /* Put out the doubleword header... */ outw(skb->len, ioaddr + TX_FIFO); outw(0x00, ioaddr + TX_FIFO); @@ -536,6 +547,8 @@ } else /* Interrupt us when the FIFO has room for max-sized packet. */ outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); + + spin_unlock_irqrestore(&lp->lock, flags); } dev_kfree_skb (skb); @@ -560,6 +573,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *)dev_id; + struct el3_private *lp; int ioaddr, status; int i = INTR_WORK; @@ -568,6 +582,9 @@ return; } + lp = (struct el3_private *)dev->priv; + spin_lock(&lp->lock); + if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; @@ -629,7 +646,7 @@ printk("%s: exiting interrupt, status %4.4x.\n", dev->name, inw(ioaddr + EL3_STATUS)); } - + spin_unlock(&lp->lock); dev->interrupt = 0; return; } diff -u --recursive --new-file v2.1.126/linux/drivers/net/bmac.c linux/drivers/net/bmac.c --- v2.1.126/linux/drivers/net/bmac.c Sat Sep 5 16:46:40 1998 +++ linux/drivers/net/bmac.c Tue Oct 27 09:57:19 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #include "bmac.h" #define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) @@ -30,15 +31,6 @@ /* switch to use multicast code lifted from sunhme driver */ #define SUNHME_MULTICAST -/* a bunch of constants for the "Heathrow" interrupt controller. - These really should be in an include file somewhere */ -#define IoBaseHeathrow ((unsigned *)0xf3000000) -#define HeathrowFCR 0x0038 /* FCR offset from Heathrow Base Address */ -#define fcrEnetEnabledBits 0x60000000 /* mask to enable Enet Xcvr/Controller */ -#define fcrResetEnetCell 0x80000000 /* mask used to reset Enet cell */ -#define fcrClearResetEnetCell 0x7fffffff /* mask used to clear reset Enet cell */ -#define fcrDisableEnet 0x1fffffff /* mask to disable Enet Xcvr/Controller */ - #define N_RX_RING 64 #define N_TX_RING 32 #define MAX_TX_ACTIVE 1 @@ -122,6 +114,7 @@ }; struct device *bmac_devs = NULL; +static int is_bmac_plus; #if 0 /* @@ -157,8 +150,6 @@ static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs); static void bmac_set_timeout(struct device *dev); static void bmac_tx_timeout(unsigned long data); -static void bmac_reset_chip(struct device *dev); -static void bmac_init_registers(struct device *dev); static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length, int dummy); static int bmac_output(struct sk_buff *skb, struct device *dev); static void bmac_start(struct device *dev); @@ -240,34 +231,86 @@ struct bmac_data *bp = (struct bmac_data *) dev->priv; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; - volatile unsigned *heathrowFCR; - unsigned int fcrValue; dbdma_reset(rd); dbdma_reset(td); - heathrowFCR = (unsigned *)((unsigned char *)IoBaseHeathrow + HeathrowFCR); + feature_set(FEATURE_BMac_IO_enable); + udelay(10000); + feature_set(FEATURE_BMac_reset); + udelay(10000); + feature_clear(FEATURE_BMac_reset); + udelay(10000); +} - fcrValue = in_le32(heathrowFCR); +#define MIFDELAY udelay(500) - fcrValue &= fcrDisableEnet; /* clear out Xvr and Controller Bit */ - out_le32(heathrowFCR, fcrValue); - udelay(50000); +static unsigned int +bmac_mif_readbits(struct device *dev, int nb) +{ + unsigned int val = 0; - fcrValue |= fcrResetEnetCell; /* set bit to reset them */ - out_le32(heathrowFCR, fcrValue); - udelay(50000); - - fcrValue &= fcrDisableEnet; - out_le32(heathrowFCR, fcrValue); - udelay(50000); - - fcrValue |= fcrEnetEnabledBits; - out_le32(heathrowFCR, fcrValue); - udelay(50000); - - out_le32(heathrowFCR, fcrValue); - udelay(50000); + while (--nb >= 0) { + bmwrite(dev, MIFCSR, 0); + MIFDELAY; + if (bmread(dev, MIFCSR) & 8) + val |= 1 << nb; + bmwrite(dev, MIFCSR, 1); + MIFDELAY; + } + bmwrite(dev, MIFCSR, 0); + MIFDELAY; + bmwrite(dev, MIFCSR, 1); + MIFDELAY; + return val; +} + +static void +bmac_mif_writebits(struct device *dev, unsigned int val, int nb) +{ + int b; + + while (--nb >= 0) { + b = (val & (1 << nb))? 6: 4; + bmwrite(dev, MIFCSR, b); + MIFDELAY; + bmwrite(dev, MIFCSR, b|1); + MIFDELAY; + } +} + +static unsigned int +bmac_mif_read(struct device *dev, unsigned int addr) +{ + unsigned int val; + + bmwrite(dev, MIFCSR, 4); + MIFDELAY; + bmac_mif_writebits(dev, ~0U, 32); + bmac_mif_writebits(dev, 6, 4); + bmac_mif_writebits(dev, addr, 10); + bmwrite(dev, MIFCSR, 2); + MIFDELAY; + bmwrite(dev, MIFCSR, 1); + MIFDELAY; + val = bmac_mif_readbits(dev, 17); + bmwrite(dev, MIFCSR, 4); + MIFDELAY; + printk(KERN_DEBUG "bmac_mif_read(%x) -> %x\n", addr, val); + return val; +} + +static void +bmac_mif_write(struct device *dev, unsigned int addr, unsigned int val) +{ + bmwrite(dev, MIFCSR, 4); + MIFDELAY; + bmac_mif_writebits(dev, ~0U, 32); + bmac_mif_writebits(dev, 5, 4); + bmac_mif_writebits(dev, addr, 10); + bmac_mif_writebits(dev, 2, 2); + bmac_mif_writebits(dev, val, 16); + bmac_mif_writebits(dev, 3, 2); } static void @@ -280,14 +323,23 @@ /* XXDEBUG(("bmac: enter init_registers\n")); */ + bmwrite(dev, RXRST, RxResetValue); bmwrite(dev, TXRST, TxResetBit); + i = 100; do { + --i; + udelay(10000); regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */ - } while (regValue & TxResetBit); + } while ((regValue & TxResetBit) && i > 0); + + if (!is_bmac_plus) { + regValue = bmread(dev, XCVRIF); + regValue |= ClkBit | SerialMode | COLActiveLow; + bmwrite(dev, XCVRIF, regValue); + udelay(10000); + } - bmwrite(dev, RXRST, RxResetValue); - bmwrite(dev, XCVRIF, ClkBit | SerialMode | COLActiveLow); bmwrite(dev, RSEED, (unsigned short)0x1968); regValue = bmread(dev, XIFC); @@ -366,18 +418,30 @@ /* enable rx dma channel */ dbdma_continue(rd); + + oldConfig = bmread(dev, TXCFG); + bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); /* turn on rx plus any other bits already on (promiscuous possibly) */ oldConfig = bmread(dev, RXCFG); bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); - - oldConfig = bmread(dev, TXCFG); - bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); + udelay(20000); } static int bmac_init_chip(struct device *dev) { + if (is_bmac_plus && bmac_mif_read(dev, 2) == 0x7810) { + if (bmac_mif_read(dev, 4) == 0xa1) { + bmac_mif_write(dev, 0, 0x1000); + } else { + bmac_mif_write(dev, 4, 0xa1); + bmac_mif_write(dev, 0, 0x1200); + } + /* XXX debugging */ + bmac_mif_read(dev, 0); + bmac_mif_read(dev, 4); + } bmac_init_registers(dev); return 1; } @@ -1144,8 +1208,16 @@ unsigned char *addr; static struct device_node *all_bmacs = NULL, *next_bmac; - if (all_bmacs == NULL) - all_bmacs = next_bmac = find_devices("bmac"); + if (all_bmacs == NULL) { + all_bmacs = find_devices("bmac"); + is_bmac_plus = 0; + if (all_bmacs == NULL) { + all_bmacs = find_compatible_devices("network", "bmac+"); + if (all_bmacs) + is_bmac_plus = 1; + } + next_bmac = all_bmacs; + } bmacs = next_bmac; if (bmacs == NULL) return -ENODEV; next_bmac = bmacs->next; @@ -1157,7 +1229,7 @@ bmacs->full_name); return -EINVAL; } - + if (dev == NULL) { dev = init_etherdev(NULL, PRIV_BYTES); bmac_devs = dev; /*KLUDGE!!*/ diff -u --recursive --new-file v2.1.126/linux/drivers/net/cs89x0.c linux/drivers/net/cs89x0.c --- v2.1.126/linux/drivers/net/cs89x0.c Mon Feb 23 18:12:05 1998 +++ linux/drivers/net/cs89x0.c Thu Nov 5 09:58:44 1998 @@ -403,8 +403,7 @@ /* wait 30 ms */ current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 3; - schedule(); + schedule_timeout(30*HZ/1000); if (lp->chip_type != CS8900) { /* Hardware problem requires PNP registers to be reconfigured after a reset */ diff -u --recursive --new-file v2.1.126/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.126/linux/drivers/net/de4x5.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/de4x5.c Sat Oct 24 09:23:14 1998 @@ -972,7 +972,7 @@ static void srom_repair(struct device *dev, int card); static int test_bad_enet(struct device *dev, int status); static int an_exception(struct bus_type *lp); -#if !defined(__sparc_v9__) && !defined(__powerpc__) +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) static void eisa_probe(struct device *dev, u_long iobase); #endif static void pci_probe(struct device *dev, u_long iobase); @@ -1021,7 +1021,7 @@ #endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; -#if !defined(__sparc_v9__) && !defined(__powerpc__) +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; static int lastEISA = 0; #else @@ -1095,7 +1095,7 @@ { u_long iobase = dev->base_addr; -#if !defined(__sparc_v9__) && !defined(__powerpc__) +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) eisa_probe(dev, iobase); #endif if (lastEISA == MAX_EISA_SLOTS) { @@ -2028,7 +2028,7 @@ return; } -#if !defined(__sparc_v9__) && !defined(__powerpc__) +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) /* ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. @@ -2096,7 +2096,7 @@ return; } -#endif /* !(__sparc_v9__) && !(__powerpc__) */ +#endif /* !(__sparc_v9__) && !(__powerpc__) && !defined(__alpha__) */ /* ** PCI bus I/O device probe @@ -5826,7 +5826,7 @@ u_int class = DE4X5_CLASS_CODE; u_int device; -#if !defined(__sparc_v9__) && !defined(__powerpc__) +#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__) char name[DE4X5_STRLEN]; u_long iobase = 0x1000; diff -u --recursive --new-file v2.1.126/linux/drivers/net/eepro100.c linux/drivers/net/eepro100.c --- v2.1.126/linux/drivers/net/eepro100.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/eepro100.c Sat Oct 24 08:53:15 1998 @@ -1384,7 +1384,7 @@ data[3] = mdio_read(ioaddr, data[0], data[1]); return 0; case SIOCDEVPRIVATE+2: /* Write the specified MII register */ - if (!suser()) + if (!capable(CAP_NET_ADMIN)) return -EPERM; mdio_write(ioaddr, data[0], data[1], data[2]); return 0; diff -u --recursive --new-file v2.1.126/linux/drivers/net/ne2.c linux/drivers/net/ne2.c --- v2.1.126/linux/drivers/net/ne2.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/ne2.c Mon Oct 26 09:57:56 1998 @@ -55,7 +55,6 @@ "ne2.c:v0.90 Oct 14 1998 David Weinehall \n"; #include -#include #include #include diff -u --recursive --new-file v2.1.126/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v2.1.126/linux/drivers/net/ppp.c Fri Oct 9 13:27:09 1998 +++ linux/drivers/net/ppp.c Sat Oct 31 10:17:23 1998 @@ -507,7 +507,6 @@ if (file->f_flags & O_NONBLOCK) break; - current->timeout = 0; interruptible_sleep_on(&ppp->read_wait); err = -EINTR; if (signal_pending(current)) diff -u --recursive --new-file v2.1.126/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.1.126/linux/drivers/net/sktr.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/net/sktr.c Thu Nov 5 09:58:44 1998 @@ -1526,12 +1526,11 @@ { long tmp; - tmp = jiffies + time/(1000000/HZ); + tmp = time/(1000000/HZ); do { - current->timeout = tmp; current->state = TASK_INTERRUPTIBLE; - schedule(); - } while(tmp > jiffies); + tmp = schedule_timeout(tmp); + } while(tmp); return; } diff -u --recursive --new-file v2.1.126/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.1.126/linux/drivers/net/tlan.c Tue Aug 18 22:02:04 1998 +++ linux/drivers/net/tlan.c Mon Nov 2 09:11:58 1998 @@ -25,6 +25,11 @@ * Microchip Technology, 24C01A/02A/04A Data Sheet * available in PDF format from www.microchip.com * + * Change History + * + * Tigran Aivazian : TLan_PciProbe() now uses + * new PCI BIOS interface. + * ********************************************************************/ @@ -32,7 +37,6 @@ #include "tlan.h" -#include #include #include #include @@ -152,7 +156,7 @@ }; -static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * ); +static int TLan_PciProbe( u8 *, u8 *, u8 *, u32 *, u32 * ); static int TLan_Init( struct device * ); static int TLan_Open(struct device *dev); static int TLan_StartTx(struct sk_buff *, struct device *); @@ -269,7 +273,6 @@ extern int init_module(void) { TLanPrivateInfo *priv; - u8 bus; struct device *dev; size_t dev_size; u8 dfn; @@ -296,7 +299,7 @@ dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo); - while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ) ) ) { + while ( ( found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ) ) ) { dev = (struct device *) kmalloc( dev_size, GFP_KERNEL ); if ( dev == NULL ) { printk( "TLAN: Could not allocate memory for device.\n" ); @@ -417,10 +420,10 @@ TLanPrivateInfo *priv; static int pad_allocated = 0; int found; - u8 bus, dfn, irq, rev; + u8 dfn, irq, rev; u32 io_base, index; - found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &index ); + found = TLan_PciProbe( &dfn, &irq, &rev, &io_base, &index ); if ( ! found ) { return -ENODEV; @@ -502,8 +505,6 @@ * Returns: * 1 if another TLAN card was found, 0 if not. * Parms: - * pci_bus The PCI bus the card was found - * on. * pci_dfn The PCI whatever the card was * found at. * pci_irq The IRQ of the found adapter. @@ -522,33 +523,26 @@ * **************************************************************/ -int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) +int TLan_PciProbe(u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) { static int dl_index = 0; - static int pci_index = 0; - - int not_found; - u8 pci_latency; + static struct pci_dev * pdev = NULL; u16 pci_command; int reg; - if ( ! pcibios_present() ) { + if ( ! pci_present() ) { printk( "TLAN: PCI Bios not present.\n" ); return 0; } for (; TLanAdapterList[dl_index].vendorId != 0; dl_index++) { - not_found = pcibios_find_device( + pdev = pci_find_device( TLanAdapterList[dl_index].vendorId, - TLanAdapterList[dl_index].deviceId, - pci_index, - pci_bus, - pci_dfn - ); + TLanAdapterList[dl_index].deviceId, pdev); - if ( ! not_found ) { + if ( pdev ) { TLAN_DBG( TLAN_DEBUG_GNRL, @@ -557,19 +551,14 @@ TLanAdapterList[dl_index].deviceId ); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); - pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); - pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base); - pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 0x10) { - pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); - TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: Setting latency timer to max.\n"); - } + *pci_irq = pdev->irq; + *pci_io_base = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; + *pci_dfn = pdev->devfn; + pci_read_config_byte ( pdev, PCI_REVISION_ID, pci_rev); + pci_read_config_word ( pdev, PCI_COMMAND, &pci_command); for ( reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg +=4 ) { - pcibios_read_config_dword( *pci_bus, *pci_dfn, reg, pci_io_base); + pci_read_config_dword( pdev, reg, pci_io_base); if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; TLAN_DBG( TLAN_DEBUG_GNRL, "TLAN: IO mapping is available at %x.\n", *pci_io_base); @@ -582,12 +571,7 @@ if ( *pci_io_base == 0 ) printk("TLAN: IO mapping not available, ignoring device.\n"); - if ( ! ( pci_command & PCI_COMMAND_MASTER ) ) { - pcibios_write_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, pci_command | PCI_COMMAND_MASTER ); - printk( "TLAN: Activating PCI bus mastering for this device.\n" ); - } - - pci_index++; + pci_set_master(pdev); if ( *pci_io_base ) { *dl_ix = dl_index; @@ -595,7 +579,7 @@ } } else { - pci_index = 0; + pdev = NULL; } } diff -u --recursive --new-file v2.1.126/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c --- v2.1.126/linux/drivers/pci/oldproc.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/pci/oldproc.c Wed Oct 28 22:04:05 1998 @@ -400,6 +400,7 @@ DEVICE( LITEON, LITEON_LNE100TX,"LNE100TX"), DEVICE( NP, NP_PCI_FDDI, "NP-PCI"), DEVICE( ATT, ATT_L56XMF, "L56xMF"), + DEVICE( SPECIALIX, SPECIALIX_IO8, "IO8+/PCI"), DEVICE( SPECIALIX, SPECIALIX_XIO, "XIO/SIO host"), DEVICE( SPECIALIX, SPECIALIX_RIO, "RIO host"), DEVICE( AURAVISION, AURAVISION_VXP524,"VXP524"), diff -u --recursive --new-file v2.1.126/linux/drivers/pnp/parport_probe.c linux/drivers/pnp/parport_probe.c --- v2.1.126/linux/drivers/pnp/parport_probe.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/pnp/parport_probe.c Thu Nov 5 21:25:24 1998 @@ -76,7 +76,7 @@ Byte |= (z<<4); if (temp) *(temp++) = Byte; - if (count++ == length) + if (++count == length) temp = NULL; /* Does the error line indicate end of data? */ if ((parport_read_status(port) & LP_PERRORP) == @@ -105,9 +105,8 @@ switch (parport_ieee1284_nibble_mode_ok(port, 4)) { case 1: current->state=TASK_INTERRUPTIBLE; - current->timeout=jiffies+1; - schedule(); /* HACK: wait 10ms because printer seems to - * ack wrong */ + /* HACK: wait 10ms because printer seems to ack wrong */ + schedule_timeout((HZ+99)/100); result = read_polled(port, buffer, len); break; case 0: diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c --- v2.1.126/linux/drivers/sbus/char/pcikbd.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/pcikbd.c Thu Nov 5 09:58:44 1998 @@ -1,4 +1,4 @@ -/* $Id: pcikbd.c,v 1.22 1998/09/21 05:06:45 jj Exp $ +/* $Id: pcikbd.c,v 1.23 1998/10/07 11:35:24 jj Exp $ * pcikbd.c: Ultra/AX PC keyboard support. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -36,13 +36,6 @@ #else #define PCI_KB_NAME "keyboard" #define PCI_MS_NAME "mouse" -/* - * XXX. - * Gleb defines check_region and request_region here. - * This looks suspicios because he neglects to call - * sparc_alloc_io, but the conflict with sparc_alloc_io is what - * causes problems. - */ #endif #include "pcikbd.h" @@ -517,7 +510,7 @@ for_each_ebusdev(edev, ebus) { if(!strcmp(edev->prom_name, "8042")) { for_each_edevchild(edev, child) { - if (!strcmp(child->prom_name, "kb_ps2")) + if (!strcmp(child->prom_name, PCI_KB_NAME)) goto found; } } @@ -698,8 +691,7 @@ == AUX_STAT_OBF) pcimouse_inb(pcimouse_iobase + KBD_DATA_REG); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + (5*HZ + 99) / 100; - schedule(); + schedule_timeout((5*HZ + 99)/100); retries++; } return (retries < MAX_RETRIES); diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c --- v2.1.126/linux/drivers/sbus/char/sab82532.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/sab82532.c Thu Nov 5 09:58:44 1998 @@ -1,4 +1,4 @@ -/* $Id: sab82532.c,v 1.23 1998/09/16 03:20:25 ecd Exp $ +/* $Id: sab82532.c,v 1.26 1998/10/25 06:46:41 ecd Exp $ * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -88,6 +88,7 @@ "V(0x08)", "V(0x09)", "V(0x0a)", "V(0x0b)", "V(0x0c)", "V(0x0d)", "V(0x0e)", "V(0x0f)" }; +static char serial_version[16]; /* * tmp_buf is used as a temporary buffer by sab82532_write. We need to @@ -505,7 +506,7 @@ #endif } if ((info->regs->r.pvr & info->pvr_dsr_bit) ^ info->dsr) { - info->dsr = info->regs->r.pvr & info->pvr_dsr_bit; + info->dsr = (info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : 1; info->icount.dsr++; modem_change++; #if 0 @@ -786,6 +787,12 @@ */ sab82532_init_line(info); + if (info->tty->termios->c_cflag & CBAUD) { + info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); + info->regs->rw.mode |= SAB82532_MODE_RTS; + info->regs->rw.pvr &= ~(info->pvr_dtr_bit); + } + /* * Finally, enable interrupts */ @@ -951,8 +958,9 @@ ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); - if (ebrg_table[i].baud) - info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + info->baud = ebrg_table[i].baud; + if (info->baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; else info->timeout = 0; info->timeout += HZ / 50; /* Add .02 seconds of slop */ @@ -1278,7 +1286,9 @@ { unsigned int result; - result = ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS) + result = ((info->regs->r.mode & SAB82532_MODE_RTS) ? + ((info->regs->r.mode & SAB82532_MODE_FRTS) ? 0 : TIOCM_RTS) + : TIOCM_RTS) | ((info->regs->r.pvr & info->pvr_dtr_bit) ? 0 : TIOCM_DTR) | ((info->regs->r.vstr & SAB82532_VSTR_CD) ? 0 : TIOCM_CAR) | ((info->regs->r.pvr & info->pvr_dsr_bit) ? 0 : TIOCM_DSR) @@ -1619,8 +1629,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -1664,8 +1673,7 @@ while (info->xmit_cnt || !info->all_sent) { current->state = TASK_INTERRUPTIBLE; current->counter = 0; - current->timeout = jiffies + char_time; - schedule(); + schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && (orig_jiffies + timeout) < jiffies) @@ -1952,9 +1960,11 @@ * /proc fs routines.... */ -static int inline line_info(char *buf, struct tty_struct *tty) +static __inline__ int +line_info(char *buf, struct sab82532 *info) { - struct sab82532 *info = (struct sab82532 *)tty->driver_data; + unsigned long flags; + char stat_buf[30]; int ret; ret = sprintf(buf, "%d: uart:SAB82532 ", info->line); @@ -1972,8 +1982,8 @@ ret += sprintf(buf+ret, "V?.? "); break; } - ret += sprintf(buf+ret, "port:%lX irq:%d", - (unsigned long)info->regs, info->irq); + ret += sprintf(buf+ret, "port:%lX irq:%s", + (unsigned long)info->regs, __irq_itoa(info->irq)); if (!info->regs) { ret += sprintf(buf+ret, "\n"); @@ -1983,20 +1993,57 @@ /* * Figure out the current RS-232 lines */ + stat_buf[0] = 0; + stat_buf[1] = 0; + save_flags(flags); cli(); + if (info->regs->r.mode & SAB82532_MODE_RTS) { + if (!(info->regs->r.mode & SAB82532_MODE_FRTS)) + strcat(stat_buf, "|RTS"); + } else { + strcat(stat_buf, "|RTS"); + } + if (info->regs->r.star & SAB82532_STAR_CTS) + strcat(stat_buf, "|CTS"); + if (!(info->regs->r.pvr & info->pvr_dtr_bit)) + strcat(stat_buf, "|DTR"); + if (!(info->regs->r.pvr & info->pvr_dsr_bit)) + strcat(stat_buf, "|DSR"); + if (!(info->regs->r.vstr & SAB82532_VSTR_CD)) + strcat(stat_buf, "|CD"); + restore_flags(flags); + + if (info->baud) + ret += sprintf(buf+ret, " baud:%d", info->baud); + + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); + + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); - ret += sprintf(buf+ret, "\n"); + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + + /* + * Last thing is the RS-232 status lines. + */ + ret += sprintf(buf+ret, " %s\n", stat_buf + 1); return ret; } int sab82532_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.23 $"); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, sab82532_table[i]); + struct sab82532 *info = sab82532_chain; + off_t begin = 0; + int len = 0; + + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (info = sab82532_chain; info && len < 4000; info = info->next) { + len += line_info(page + len, info); if (len+begin > off+count) goto done; if (len+begin < off) { @@ -2089,13 +2136,14 @@ __initfunc(static inline void show_serial_version(void)) { - char *revision = "$Revision: 1.23 $"; + char *revision = "$Revision: 1.26 $"; char *version, *p; version = strchr(revision, ' '); - p = strchr(++version, ' '); + strcpy(serial_version, ++version); + p = strchr(serial_version, ' '); *p = '\0'; - printk("SAB82532 serial driver version %s\n", version); + printk("SAB82532 serial driver version %s\n", serial_version); } /* @@ -2456,8 +2504,9 @@ ebrg = ebrg_table[i].n; ebrg |= (ebrg_table[i].m << 6); - if (ebrg_table[i].baud) - info->timeout = (info->xmit_fifo_size * HZ * bits) / ebrg_table[i].baud; + info->baud = ebrg_table[i].baud; + if (info->baud) + info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud; else info->timeout = 0; info->timeout += HZ / 50; /* Add .02 seconds of slop */ @@ -2490,6 +2539,7 @@ info->regs->rw.mode &= ~(SAB82532_MODE_FRTS); info->regs->rw.mode |= SAB82532_MODE_FCTS; } + info->regs->rw.pvr &= ~(info->pvr_dtr_bit); info->regs->rw.mode |= SAB82532_MODE_RAC; restore_flags(flags); diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c --- v2.1.126/linux/drivers/sbus/char/su.c Thu Aug 6 14:06:32 1998 +++ linux/drivers/sbus/char/su.c Thu Nov 5 09:58:44 1998 @@ -1,69 +1,164 @@ -/* $Id: su.c,v 1.10 1998/05/29 06:00:26 ecd Exp $ - * su.c: Small serial driver for keyboard/mouse interface on Ultra/AX +/* $Id: su.c,v 1.12 1998/10/25 04:24:52 ecd Exp $ + * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Coypright (C) 1998 Pete Zaitcev (zaitcev@metabyte.com) * - * This is mainly a very stripped down version of drivers/char/serial.c, + * This is mainly a variation of drivers/char/serial.c, * credits go to authors mentioned therein. */ +/* + * Configuration section. + */ +#define SERIAL_PARANOIA_CHECK +#define CONFIG_SERIAL_NOPAUSE_IO /* Unused on sparc */ +#define SERIAL_DO_RESTART + +/* Set of debugging defines */ + +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW +#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT +#undef SERIAL_DEBUG_THROTTLE + +#define RS_ISR_PASS_LIMIT 256 + +/* + * 0x20 is sun4m thing, Dave Redman heritage. + * See arch/sparc/kernel/irq.c. + */ +#define IRQ_4M(n) ((n)|0x20) + +#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) +#define DBG_CNT(s) \ +do { \ + printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + kdevname(tty->device), (info->flags), serial_refcount, \ + info->count,tty->count,s); \ +} while (0); +#else +#define DBG_CNT(s) +#endif + +/* + * End of serial driver configuration section. + */ +#include +#include #include #include +#include #include +#include +#include #include #include #include +#include #include #include +#include #include #include +#include +#ifdef CONFIG_SERIAL_CONSOLE +#include +#include +#endif +#include +#include #include #include #include #include +#include +#include #include "sunserial.h" #include "sunkbd.h" #include "sunmouse.h" -static char *serial_name = "kbd/mouse serial driver"; -static char *serial_version = "1.0"; - -/* Set of debugging defines */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN - /* We are on a NS PC87303 clocked with 24.0 MHz, which results * in a UART clock of 1.8462 MHz. */ #define BAUD_BASE (1846200 / 16) +#ifdef CONFIG_SERIAL_CONSOLE +extern int serial_console; +static struct console sercons; +int su_serial_console_init(void); +#endif + +/* + * serial.c saves memory when it allocates async_info upon first open. + * We have parts of state structure together because we do call startup + * for keyboard and mouse. + */ struct su_struct { int magic; unsigned long port; int baud_base; - int type; + int type; /* Hardware type: e.g. 16550 */ int irq; int flags; - unsigned char IER; - unsigned char MCR; int line; int cflag; + int kbd_node; int ms_node; + int port_node; + char name[16]; -}; -static struct su_struct su_table[] = { - { 0, 0, BAUD_BASE, PORT_UNKNOWN }, - { 0, 0, BAUD_BASE, PORT_UNKNOWN } + int xmit_fifo_size; + int custom_divisor; + unsigned short close_delay; + unsigned short closing_wait; /* time to wait before closing */ + + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int quot; + int x_char; /* xon/xoff character */ + int IER; /* Interrupt Enable Register */ + int MCR; /* Modem control register */ + unsigned long event; + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct wait_queue *open_wait; + struct wait_queue *close_wait; + struct wait_queue *delta_msr_wait; + + int count; + struct async_icount icount; + struct termios normal_termios, callout_termios; + unsigned long last_active; /* For async_struct, to be */ }; -#define NR_PORTS (sizeof(su_table) / sizeof(struct su_struct)) +static char *serial_name = "PCIO serial driver"; +static char *serial_version = "1.1"; + +static DECLARE_TASK_QUEUE(tq_serial); + +static struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 -static void autoconfig(struct su_struct * info); +static void autoconfig(struct su_struct *info); static void change_speed(struct su_struct *info); +static void su_wait_until_sent(struct tty_struct *tty, int timeout); /* * Here we define the default xmit fifo size used for each type of @@ -83,12 +178,52 @@ { 0, 0} }; + +#define NR_PORTS 4 + +static struct su_struct su_table[NR_PORTS]; +static struct tty_struct *serial_table[NR_PORTS]; +static struct termios *serial_termios[NR_PORTS]; +static struct termios *serial_termios_locked[NR_PORTS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + /* - * This is used to figure out the divisor speeds and the timeouts + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the copy_from_user blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; +static unsigned char *tmp_buf; +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct su_struct *info, + kdev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%s) in %s\n"; + static const char *badinfo = + "Warning: null su_struct for (%s) in %s\n"; + + if (!info) { + printk(badinfo, kdevname(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, kdevname(device), routine); + return 1; + } +#endif + return 0; +} + +#ifdef __sparc_v9__ static inline unsigned int su_inb(struct su_struct *info, unsigned long offset) @@ -102,19 +237,117 @@ outb(value, info->port + offset); } +#else + +static inline +unsigned int su_inb(struct su_struct *info, unsigned long offset) +{ + return (unsigned int)(*(volatile unsigned char *)(info->port + offset)); +} + static inline void -receive_chars(struct su_struct *info, struct pt_regs *regs) +su_outb(struct su_struct *info, unsigned long offset, int value) +{ + /* + * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are + * connected with a gate then go to SlavIO. When IRQ4 goes tristated + * gate gives logical one. Since we use level triggered interrupts + * we have lockup and watchdog reset. We cannot mask IRQ because + * keyboard shares IRQ with us (Bob Smelik: I would not hire you). + * P3: Assure that OUT2 never goes down. + */ + if (offset == UART_MCR) value |= UART_MCR_OUT2; + *(volatile unsigned char *)(info->port + offset) = value; +} + +#endif + +#define serial_in(info, off) su_inb(info, off) +#define serial_inp(info, off) su_inb(info, off) +#define serial_out(info, off, val) su_outb(info, off, val) +#define serial_outp(info, off, val) su_outb(info, off, val) + +/* + * ------------------------------------------------------------ + * su_stop() and su_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void su_stop(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_stop")) + return; + + save_flags(flags); cli(); + if (info->IER & UART_IER_THRI) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + restore_flags(flags); +} + +static void su_start(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + restore_flags(flags); +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * su_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static __inline__ void +su_sched_event(struct su_struct *info, int event) +{ + info->event |= 1 << event; + queue_task(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +static __inline__ void +receive_kbd_ms_chars(struct su_struct *info, struct pt_regs *regs) { unsigned char status = 0; unsigned char ch; do { - ch = su_inb(info, UART_RX); - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, status); -#endif - + ch = serial_inp(info, UART_RX); if (info->kbd_node) { if(ch == SUNKBD_RESET) { l1a_state.kbd_id = 1; @@ -142,11 +375,206 @@ } while (status & UART_LSR_DR); } +static __inline__ void +receive_serial_chars(struct su_struct *info, int *status, struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch; + int ignored = 0; + struct async_icount *icount; + + icount = &info->icount; + do { + ch = serial_inp(info, UART_RX); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.char_buf_ptr = ch; + icount->rx++; + +#ifdef SERIAL_DEBUG_INTR + printk("DR%02x:%02x...", ch, *status); +#endif + *tty->flip.flag_buf_ptr = 0; + if (*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE)) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + icount->brk++; + } else if (*status & UART_LSR_PE) + icount->parity++; + else if (*status & UART_LSR_FE) + icount->frame++; + if (*status & UART_LSR_OE) + icount->overrun++; + + /* + * Now check to see if character should be + * ignored, and mask off conditions which + * should be ignored. + */ + if (*status & info->ignore_status_mask) { + if (++ignored > 100) + break; + goto ignore_char; + } + *status &= info->read_status_mask; + + if (*status & (UART_LSR_BI)) { +#ifdef SERIAL_DEBUG_INTR + printk("handling break...."); +#endif + *tty->flip.flag_buf_ptr = TTY_BREAK; + if (info->flags & ASYNC_SAK) + do_SAK(tty); + } else if (*status & UART_LSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & UART_LSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + if (*status & UART_LSR_OE) { + /* + * Overrun is special, since it's + * reported immediately, and doesn't + * affect the current character + */ + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + tty->flip.count++; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + } + } + } + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + ignore_char: + *status = serial_inp(info, UART_LSR); + } while (*status & UART_LSR_DR); + tty_flip_buffer_push(tty); +} + +static __inline__ void +transmit_chars(struct su_struct *info, int *intr_done) +{ + int count; + + if (info->x_char) { + serial_outp(info, UART_TX, info->x_char); + info->icount.tx++; + info->x_char = 0; + if (intr_done) + *intr_done = 0; + return; + } + if ((info->xmit_cnt <= 0) || info->tty->stopped || + info->tty->hw_stopped) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + return; + } + + count = info->xmit_fifo_size; + do { + serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->icount.tx++; + if (--info->xmit_cnt <= 0) + break; + } while (--count > 0); + + if (info->xmit_cnt < WAKEUP_CHARS) + su_sched_event(info, RS_EVENT_WRITE_WAKEUP); + +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + if (intr_done) + *intr_done = 0; + + if (info->xmit_cnt <= 0) { + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +static __inline__ void +check_modem_status(struct su_struct *info) +{ + int status; + struct async_icount *icount; + + status = serial_in(info, UART_MSR); + + if (status & UART_MSR_ANY_DELTA) { + icount = &info->icount; + /* update input line counters */ + if (status & UART_MSR_TERI) + icount->rng++; + if (status & UART_MSR_DDSR) + icount->dsr++; + if (status & UART_MSR_DDCD) { + icount->dcd++; +#ifdef CONFIG_HARD_PPS + if ((info->flags & ASYNC_HARDPPS_CD) && + (status & UART_MSR_DCD)) + hardpps(); +#endif + } + if (status & UART_MSR_DCTS) + icount->cts++; + wake_up_interruptible(&info->delta_msr_wait); + } + + if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + wake_up_interruptible(&info->open_wait); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("doing serial hangup..."); +#endif + if (info->tty) + tty_hangup(info->tty); + } + } + if (info->flags & ASYNC_CTS_FLOW) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + su_sched_event(info, RS_EVENT_WRITE_WAKEUP); + return; + } + } else { + if (!(status & UART_MSR_CTS)) { +#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + info->IER &= ~UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + } + } +} + /* - * This is the serial driver's generic interrupt routine + * This is the kbd/mouse serial driver's interrupt routine */ static void -su_interrupt(int irq, void *dev_id, struct pt_regs * regs) +su_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct su_struct *info = (struct su_struct *)dev_id; unsigned char status; @@ -154,52 +582,171 @@ #ifdef SERIAL_DEBUG_INTR printk("su_interrupt(%s)...", __irq_itoa(irq)); #endif + if (!info) + return; - if (su_inb(info, UART_IIR) & UART_IIR_NO_INT) + if (serial_in(info, UART_IIR) & UART_IIR_NO_INT) return; - status = su_inb(info, UART_LSR); + status = serial_inp(info, UART_LSR); #ifdef SERIAL_DEBUG_INTR printk("status = %x...", status); #endif if (status & UART_LSR_DR) - receive_chars(info, regs); + receive_kbd_ms_chars(info, regs); + +#ifdef SERIAL_DEBUG_INTR + printk("end.\n"); +#endif +} + +/* + * This is the serial driver's generic interrupt routine + */ +static void +su_serial_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + int status; + struct su_struct *info; + int pass_counter = 0; + +#ifdef SERIAL_DEBUG_INTR + printk("su_interrupt(%s)...", __irq_itoa(irq)); +#endif + info = (struct su_struct *)dev_id; + if (!info || !info->tty) + return; + + do { + status = serial_inp(info, UART_LSR); +#ifdef SERIAL_DEBUG_INTR + printk("status = %x...", status); +#endif + if (status & UART_LSR_DR) + receive_serial_chars(info, &status, regs); + check_modem_status(info); + if (status & UART_LSR_THRE) + transmit_chars(info, 0); + + if (pass_counter++ > RS_ISR_PASS_LIMIT) { +#if 0 + printk("rs loop break\n"); +#endif + break; /* Prevent infinite loops */ + } + } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); + + info->last_active = jiffies; #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif } +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * su_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using su_sched_event(), and they get done here. + */ +static void +do_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void +do_softint(void *private_) +{ + struct su_struct *info = (struct su_struct *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + static int -startup(struct su_struct * info) +startup(struct su_struct *info) { unsigned long flags; int retval=0; + unsigned long page; - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - goto errout; - } + save_flags(flags); + if (info->tty) { + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + cli(); + + if (info->flags & ASYNC_INITIALIZED) { + free_page(page); + goto errout; + } - if (!info->port || !info->type) { - goto errout; + if (info->port == 0 || info->type == PORT_UNKNOWN) { + set_bit(TTY_IO_ERROR, &info->tty->flags); + free_page(page); + goto errout; + } + if (info->xmit_buf) + free_page(page); + else + info->xmit_buf = (unsigned char *) page; } + cli(); #ifdef SERIAL_DEBUG_OPEN - printk("starting up su%d (irq %s)...", info->line, - __irq_itoa(info->irq)); + printk("starting up ttys%d (irq %d)...", info->line, state->irq); #endif - if (info->type == PORT_16750) - su_outb(info, UART_IER, 0); + if (uart_config[info->type].flags & UART_STARTECH) { + /* Wake up UART */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, 0); + serial_outp(info, UART_EFR, 0); + serial_outp(info, UART_LCR, 0); + } + + if (info->type == PORT_16750) { + /* Wake up UART */ + serial_outp(info, UART_IER, 0); + } /* * Clear the FIFO buffers and disable them * (they will be reenabled in change_speed()) */ if (uart_config[info->type].flags & UART_CLEAR_FIFO) - su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); /* @@ -207,47 +754,84 @@ * if it is, then bail out, because there's likely no UART * here. */ - if (su_inb(info, UART_LSR) == 0xff) { - retval = -ENODEV; + if (serial_inp(info, UART_LSR) == 0xff) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + } else + retval = -ENODEV; goto errout; } - + /* * Allocate the IRQ if necessary */ - retval = request_irq(info->irq, su_interrupt, SA_SHIRQ, - info->name, info); - if (retval) + if (info->kbd_node || info->ms_node) { + retval = request_irq(info->irq, su_kbd_ms_interrupt, + SA_SHIRQ, info->name, info); + } else { + retval = request_irq(info->irq, su_serial_interrupt, + SA_SHIRQ, info->name, info); + } + if (retval) { + if (capable(CAP_SYS_ADMIN)) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + retval = 0; + } goto errout; + } /* * Clear the interrupt registers. */ - su_inb(info, UART_RX); - su_inb(info, UART_IIR); - su_inb(info, UART_MSR); + (void) serial_inp(info, UART_RX); + (void) serial_inp(info, UART_IIR); + (void) serial_inp(info, UART_MSR); /* * Now, initialize the UART */ - su_outb(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - info->MCR = UART_MCR_OUT2; - su_outb(info, UART_MCR, info->MCR); + info->MCR = 0; + if (info->tty && info->tty->termios->c_cflag & CBAUD) + info->MCR = UART_MCR_DTR | UART_MCR_RTS; + if (info->irq != 0) + info->MCR |= UART_MCR_OUT2; + serial_outp(info, UART_MCR, info->MCR); /* * Finally, enable interrupts */ - info->IER = UART_IER_RLSI | UART_IER_RDI; - su_outb(info, UART_IER, info->IER); /* enable interrupts */ - + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ + /* * And clear the interrupt registers again for luck. */ - su_inb(info, UART_LSR); - su_inb(info, UART_RX); - su_inb(info, UART_IIR); - su_inb(info, UART_MSR); + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up the tty->alt_speed kludge + */ + if (info->tty) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) + info->tty->alt_speed = 460800; + } /* * and set the speed of the serial port @@ -257,38 +841,135 @@ info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return 0; - + errout: restore_flags(flags); return retval; } /* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. */ static void -change_speed(struct su_struct *info) +shutdown(struct su_struct *info) { - unsigned char cval, fcr = 0; - int quot = 0; - unsigned long flags; - int i; + unsigned long flags; - /* byte size and parity */ - switch (info->cflag & CSIZE) { - case CS5: cval = 0x00; break; - case CS6: cval = 0x01; break; - case CS7: cval = 0x02; break; - case CS8: cval = 0x03; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: cval = 0x00; break; - } - if (info->cflag & CSTOPB) { - cval |= 0x04; + if (!(info->flags & ASYNC_INITIALIZED)) + return; + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free the irq + * here so the queue might never be waken up + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ, if necessary + */ + free_irq(info->irq, info); + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; } - if (info->cflag & PARENB) { + + info->IER = 0; + serial_outp(info, UART_IER, 0x00); /* disable all intrs */ + info->MCR &= ~UART_MCR_OUT2; + + /* disable break condition */ + serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + serial_outp(info, UART_MCR, info->MCR); + + /* disable FIFO's */ + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + (void)serial_in(info, UART_RX); /* read data port to reset things */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + if (uart_config[info->type].flags & UART_STARTECH) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, UART_EFR_ECB); + serial_outp(info, UART_IER, UART_IERX_SLEEP); + serial_outp(info, UART_LCR, 0); + } + if (info->type == PORT_16750) { + /* Arrange to enter sleep mode */ + serial_outp(info, UART_IER, UART_IERX_SLEEP); + } + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +static __inline__ int +su_get_baud_rate(struct su_struct *info) +{ + static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 + }; + int i; + + if (info->tty) + return tty_get_baud_rate(info->tty); + + i = info->cflag & CBAUD; + if (i & CBAUDEX) { + i &= ~(CBAUDEX); + if (i < 1 || i > 4) + info->cflag &= ~(CBAUDEX); + else + i += 15; + } + return baud_table[i]; +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void +change_speed(struct su_struct *info) +{ + int quot = 0, baud; + unsigned int cval, fcr = 0; + int bits; + unsigned long flags; + + if (!info->kbd_node && !info->ms_node) { + if (!info->tty || !info->tty->termios) + return; + if (!info->port) + return; + info->cflag = info->tty->termios->c_cflag; + } + + /* byte size and parity */ + switch (info->cflag & CSIZE) { + case CS5: cval = 0x00; bits = 7; break; + case CS6: cval = 0x01; bits = 8; break; + case CS7: cval = 0x02; bits = 9; break; + case CS8: cval = 0x03; bits = 10; break; + /* Never happens, but GCC is too dumb to figure it out */ + default: cval = 0x00; bits = 7; break; + } + if (info->cflag & CSTOPB) { + cval |= 0x04; + bits++; + } + if (info->cflag & PARENB) { cval |= UART_LCR_PARITY; + bits++; } if (!(info->cflag & PARODD)) cval |= UART_LCR_EPAR; @@ -297,101 +978,1195 @@ cval |= UART_LCR_SPAR; #endif - /* Determine divisor based on baud rate */ - i = info->cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 4) - info->cflag &= ~CBAUDEX; + /* Determine divisor based on baud rate */ + baud = su_get_baud_rate(info); + if (baud == 38400 && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + quot = info->custom_divisor; + else { + if (baud == 134) + /* Special case since 134 is really 134.5 */ + quot = (2 * info->baud_base / 269); + else if (baud) + quot = info->baud_base / baud; + } + /* If the quotient is ever zero, default to 9600 bps */ + if (!quot) + quot = info->baud_base / 9600; + info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / info->baud_base); + info->timeout += HZ/50; /* Add .02 seconds of slop */ + + /* Set up FIFO's */ + if (uart_config[info->type].flags & UART_USE_FIFO) { + if ((info->baud_base / quot) < 9600) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } + if (info->type == PORT_16750) + fcr |= UART_FCR7_64BYTE; + + /* CTS flow control flag and modem status interrupts */ + info->IER &= ~UART_IER_MSI; + if (info->flags & ASYNC_HARDPPS_CD) + info->IER |= UART_IER_MSI; + if (info->cflag & CRTSCTS) { + info->flags |= ASYNC_CTS_FLOW; + info->IER |= UART_IER_MSI; + } else + info->flags &= ~ASYNC_CTS_FLOW; + if (info->cflag & CLOCAL) + info->flags &= ~ASYNC_CHECK_CD; + else { + info->flags |= ASYNC_CHECK_CD; + info->IER |= UART_IER_MSI; + } + serial_out(info, UART_IER, info->IER); + + /* + * Set up parity check flag + */ + if (info->tty) { +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | + UART_LSR_DR; + if (I_INPCK(info->tty)) + info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) + info->read_status_mask |= UART_LSR_BI; + + /* + * Characters to ignore + */ + info->ignore_status_mask = 0; + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (I_IGNBRK(info->tty)) { + info->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignore parity and break indicators, ignore + * overruns too. (For real raw support). + */ + if (I_IGNPAR(info->tty)) + info->ignore_status_mask |= UART_LSR_OE; + } + /* + * !!! ignore all characters if CREAD is not set + */ + if ((info->cflag & CREAD) == 0) + info->ignore_status_mask |= UART_LSR_DR; + } + + save_flags(flags); cli(); + if (uart_config[info->type].flags & UART_STARTECH) { + serial_outp(info, UART_LCR, 0xBF); + serial_outp(info, UART_EFR, + (info->cflag & CRTSCTS) ? UART_EFR_CTS : 0); + } + serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ + if (info->type == PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + serial_outp(info, UART_LCR, cval); /* reset DLAB */ + if (info->type != PORT_16750) + serial_outp(info, UART_FCR, fcr); /* set fcr */ + restore_flags(flags); + info->quot = quot; +} + +static void +su_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_put_char")) + return; + + if (!tty || !info->xmit_buf) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { + restore_flags(flags); + return; + } + + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= SERIAL_XMIT_SIZE-1; + info->xmit_cnt++; + restore_flags(flags); +} + +static void su_put_char_kbd(unsigned char c) +{ + struct su_struct *info = su_table; + int lsr; + + if (!info->kbd_node) + ++info; + if (!info) + return; + + do { + lsr = serial_in(info, UART_LSR); + } while (!(lsr & UART_LSR_THRE)); + + /* Send the character out. */ + su_outb(info, UART_TX, c); +} + +static void +su_change_mouse_baud(int baud) +{ + struct su_struct *info = su_table; + + if (!info->ms_node) + ++info; + if (!info) + return; + + info->cflag &= ~(CBAUDEX | CBAUD); + switch(baud) { + case 1200: + info->cflag |= B1200; + break; + case 2400: + info->cflag |= B2400; + break; + case 4800: + info->cflag |= B4800; + break; + case 9600: + info->cflag |= B9600; + break; + default: + printk("su_change_mouse_baud: unknown baud rate %d, " + "defaulting to 1200\n", baud); + info->cflag |= 1200; + break; + } + change_speed(info); +} + +static void +su_flush_chars(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + save_flags(flags); cli(); + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + restore_flags(flags); +} + +static int +su_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, ret = 0; + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_write")) + return 0; + + if (!tty || !info->xmit_buf || !tmp_buf) + return 0; + + save_flags(flags); + if (from_user) { + down(&tmp_buf_sem); + while (1) { + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + c -= copy_from_user(tmp_buf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + cli(); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + up(&tmp_buf_sem); + } else { + while (1) { + cli(); + c = MIN(count, + MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) { + restore_flags(flags); + break; + } + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = ((info->xmit_head + c) & + (SERIAL_XMIT_SIZE-1)); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + ret += c; + } + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->IER & UART_IER_THRI)) { + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } + return ret; +} + +static int +su_write_room(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "su_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int +su_chars_in_buffer(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "su_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void +su_flush_buffer(struct tty_struct *tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "su_flush_buffer")) + return; + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void +su_send_xchar(struct tty_struct *tty, char ch) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "su_send_char")) + return; + + info->x_char = ch; + if (ch) { + /* Make sure transmit interrupts are on */ + info->IER |= UART_IER_THRI; + serial_out(info, UART_IER, info->IER); + } +} + +/* + * ------------------------------------------------------------ + * su_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void +su_throttle(struct tty_struct * tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "su_throttle")) + return; + + if (I_IXOFF(tty)) + su_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + info->MCR &= ~UART_MCR_RTS; + + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +} + +static void +su_unthrottle(struct tty_struct * tty) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "su_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + su_send_xchar(tty, START_CHAR(tty)); + } + if (tty->termios->c_cflag & CRTSCTS) + info->MCR |= UART_MCR_RTS; + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); +} + +/* + * ------------------------------------------------------------ + * su_ioctl() and friends + * ------------------------------------------------------------ + */ + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int +get_lsr_info(struct su_struct * info, unsigned int *value) +{ + unsigned char status; + unsigned int result; + + cli(); + status = serial_in(info, UART_LSR); + sti(); + result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); + return put_user(result,value); +} + + +static int +get_modem_info(struct su_struct * info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + + control = info->MCR; + cli(); + status = serial_in(info, UART_MSR); + sti(); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) +#ifdef TIOCM_OUT1 + | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) + | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) +#endif + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + return put_user(result,value); +} + +static int +set_modem_info(struct su_struct * info, unsigned int cmd, unsigned int *value) +{ + int error; + unsigned int arg; + + error = get_user(arg, value); + if (error) + return error; + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + info->MCR |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR |= UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR |= UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR |= UART_MCR_OUT2; +#endif + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + info->MCR &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + info->MCR &= ~UART_MCR_DTR; +#ifdef TIOCM_OUT1 + if (arg & TIOCM_OUT1) + info->MCR &= ~UART_MCR_OUT1; + if (arg & TIOCM_OUT2) + info->MCR &= ~UART_MCR_OUT2; +#endif + break; + case TIOCMSET: + info->MCR = ((info->MCR & ~(UART_MCR_RTS | +#ifdef TIOCM_OUT1 + UART_MCR_OUT1 | + UART_MCR_OUT2 | +#endif + UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) +#ifdef TIOCM_OUT1 + | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) + | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) +#endif + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); + break; + default: + return -EINVAL; + } + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); + return 0; +} + +/* + * su_break() --- routine which turns the break handling on or off + */ +static void +su_break(struct tty_struct *tty, int break_state) +{ + struct su_struct * info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "su_break")) + return; + + if (!info->port) + return; + save_flags(flags); cli(); + if (break_state == -1) + serial_out(info, UART_LCR, + serial_inp(info, UART_LCR) | UART_LCR_SBC); + else + serial_out(info, UART_LCR, + serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + restore_flags(flags); +} + +static int +su_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct su_struct * info = (struct su_struct *)tty->driver_data; + struct async_icount cprev, cnow; /* kernel counter temps */ + struct serial_icounter_struct *p_cuser; /* user space */ + + if (serial_paranoia_check(info, tty->device, "su_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, (unsigned int *) arg); + +#if 0 + case TIOCSERGSTRUCT: + if (copy_to_user((struct async_struct *) arg, + info, sizeof(struct async_struct))) + return -EFAULT; + return 0; +#endif + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + cli(); + /* note the counters on entry */ + cprev = info->icount; + sti(); + while (1) { + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; + cli(); + cnow = info->icount; /* atomic copy */ + sti(); + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + cli(); + cnow = info->icount; + sti(); + p_cuser = (struct serial_icounter_struct *) arg; + error = put_user(cnow.cts, &p_cuser->cts); + if (error) return error; + error = put_user(cnow.dsr, &p_cuser->dsr); + if (error) return error; + error = put_user(cnow.rng, &p_cuser->rng); + if (error) return error; + error = put_user(cnow.dcd, &p_cuser->dcd); + if (error) return error; + return 0; + + default: + return -ENOIOCTLCMD; + } + /* return 0; */ /* Trigger warnings is fall through by a chance. */ +} + +static void +su_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + + if ( (tty->termios->c_cflag == old_termios->c_cflag) + && ( RELEVANT_IFLAG(tty->termios->c_iflag) + == RELEVANT_IFLAG(old_termios->c_iflag))) + return; + + change_speed(info); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && + !(tty->termios->c_cflag & CBAUD)) { + info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); + } + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && + (tty->termios->c_cflag & CBAUD)) { + info->MCR |= UART_MCR_DTR; + if (!(tty->termios->c_cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) { + info->MCR |= UART_MCR_RTS; + } + cli(); + serial_out(info, UART_MCR, info->MCR); + sti(); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + su_start(tty); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * ------------------------------------------------------------ + * su_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void +su_close(struct tty_struct *tty, struct file * filp) +{ + struct su_struct *info = (struct su_struct *)tty->driver_data; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "su_close")) + return; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + DBG_CNT("before DEC-hung"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + +#ifdef SERIAL_DEBUG_OPEN + printk("su_close ttys%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("su_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("su_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) { + DBG_CNT("before DEC-2"); + MOD_DEC_USE_COUNT; + restore_flags(flags); + return; + } + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + info->IER &= ~UART_IER_RLSI; + info->read_status_mask &= ~UART_LSR_DR; + if (info->flags & ASYNC_INITIALIZED) { + serial_out(info, UART_IER, info->IER); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + su_wait_until_sent(tty, info->timeout); + } + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; + restore_flags(flags); +} + +/* + * su_wait_until_sent() --- wait until the transmitter is empty + */ +static void +su_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct su_struct * info = (struct su_struct *)tty->driver_data; + unsigned long orig_jiffies, char_time; + int lsr; + + if (serial_paranoia_check(info, tty->device, "su_wait_until_sent")) + return; + + if (info->type == PORT_UNKNOWN) + return; + + orig_jiffies = jiffies; + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout) + char_time = MIN(char_time, timeout); +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("In su_wait_until_sent(%d) check=%lu...", timeout, char_time); + printk("jiff=%lu...", jiffies); +#endif + while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...", lsr, jiffies); +#endif + current->state = TASK_INTERRUPTIBLE; + current->counter = 0; /* make us low-priority */ + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (timeout && ((orig_jiffies + timeout) < jiffies)) + break; + } + current->state = TASK_RUNNING; +#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT + printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); +#endif +} + +/* + * su_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +static void +su_hangup(struct tty_struct *tty) +{ + struct su_struct * info = (struct su_struct *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "su_hangup")) + return; + + su_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * su_open() and friends + * ------------------------------------------------------------ + */ +static int +block_til_ready(struct tty_struct *tty, struct file * filp, + struct su_struct *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ASYNC_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * su_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + info->line, info->count); +#endif + cli(); + if (!tty_hung_up_p(filp)) + info->count--; + sti(); + info->blocked_open++; + while (1) { + cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + (tty->termios->c_cflag & CBAUD)) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +static int +su_open(struct tty_struct *tty, struct file * filp) +{ + struct su_struct *info; + int retval, line; + unsigned long page; + + line = MINOR(tty->device) - tty->driver.minor_start; + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + info = su_table + line; + if (serial_paranoia_check(info, tty->device, "su_open")) + return -ENODEV; + info->count++; + +#ifdef SERIAL_DEBUG_OPEN + printk("su_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); +#endif + tty->driver_data = info; + info->tty = tty; + info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + if (tmp_buf) + free_page(page); else - i += 15; + tmp_buf = (unsigned char *) page; } - if (!quot) { - if (baud_table[i] == 134) - /* Special case since 134 is really 134.5 */ - quot = (2 * info->baud_base / 269); - else if (baud_table[i]) - quot = info->baud_base / baud_table[i]; - /* If the quotient is ever zero, default to 1200 bps */ - if (!quot) - quot = info->baud_base / 1200; + + /* + * If the port is the middle of closing, bail out now + */ + if (tty_hung_up_p(filp) || + (info->flags & ASYNC_CLOSING)) { + if (info->flags & ASYNC_CLOSING) + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + return ((info->flags & ASYNC_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS); +#else + return -EAGAIN; +#endif } + + /* + * Start up serial port + */ + retval = startup(info); + if (retval) + return retval; - /* Set up FIFO's */ - if (uart_config[info->type].flags & UART_USE_FIFO) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + MOD_INC_USE_COUNT; + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("su_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } - su_outb(info, UART_IER, info->IER); + if ((info->count == 1) && + (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_speed(info); + } +#ifdef CONFIG_SERIAL_CONSOLE + if (sercons.cflag && sercons.index == line) { + tty->termios->c_cflag = sercons.cflag; + sercons.cflag = 0; + change_speed(info); + } +#endif + info->session = current->session; + info->pgrp = current->pgrp; - save_flags(flags); cli(); - su_outb(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - su_outb(info, UART_DLL, quot & 0xff); /* LS of divisor */ - su_outb(info, UART_DLM, quot >> 8); /* MS of divisor */ - if (info->type == PORT_16750) - su_outb(info, UART_FCR, fcr); /* set fcr */ - su_outb(info, UART_LCR, cval); /* reset DLAB */ - if (info->type != PORT_16750) - su_outb(info, UART_FCR, fcr); /* set fcr */ - restore_flags(flags); +#ifdef SERIAL_DEBUG_OPEN + printk("su_open ttys%d successful...", info->line); +#endif + return 0; } -static void -su_put_char(unsigned char c) +/* + * /proc fs routines.... + */ +static __inline__ int +line_info(char *buf, struct su_struct *info) { - struct su_struct *info = su_table; - int lsr; + char stat_buf[30], control, status; + int ret; - if (!info->kbd_node) - ++info; + ret = sprintf(buf, "%d: uart:%s port:%X irq:%s", + info->line, uart_config[info->type].name, + (int)info->port, __irq_itoa(info->irq)); + + if (info->port == 0 || info->type == PORT_UNKNOWN) { + ret += sprintf(buf+ret, "\n"); + return ret; + } - do { - lsr = inb(info->port + UART_LSR); - } while (!(lsr & UART_LSR_THRE)); + /* + * Figure out the current RS-232 lines + */ + cli(); + status = serial_in(info, UART_MSR); + control = info ? info->MCR : serial_in(info, UART_MCR); + sti(); + + stat_buf[0] = 0; + stat_buf[1] = 0; + if (control & UART_MCR_RTS) + strcat(stat_buf, "|RTS"); + if (status & UART_MSR_CTS) + strcat(stat_buf, "|CTS"); + if (control & UART_MCR_DTR) + strcat(stat_buf, "|DTR"); + if (status & UART_MSR_DSR) + strcat(stat_buf, "|DSR"); + if (status & UART_MSR_DCD) + strcat(stat_buf, "|CD"); + if (status & UART_MSR_RI) + strcat(stat_buf, "|RI"); + + if (info->quot) { + ret += sprintf(buf+ret, " baud:%d", + info->baud_base / info->quot); + } + + ret += sprintf(buf+ret, " tx:%d rx:%d", + info->icount.tx, info->icount.rx); + + if (info->icount.frame) + ret += sprintf(buf+ret, " fe:%d", info->icount.frame); - /* Send the character out. */ - su_outb(info, UART_TX, c); + if (info->icount.parity) + ret += sprintf(buf+ret, " pe:%d", info->icount.parity); + + if (info->icount.brk) + ret += sprintf(buf+ret, " brk:%d", info->icount.brk); + + if (info->icount.overrun) + ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); + + /* + * Last thing is the RS-232 status lines + */ + ret += sprintf(buf+ret, " %s\n", stat_buf+1); + return ret; } -static void -su_change_mouse_baud(int baud) +int su_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) { - struct su_struct *info = su_table; - - if (!info->ms_node) - ++info; - if (!info) - return; + int i, len = 0; + off_t begin = 0; - info->cflag &= ~(CBAUDEX | CBAUD); - switch(baud) { - case 1200: - info->cflag |= B1200; - break; - case 2400: - info->cflag |= B2400; - break; - case 4800: - info->cflag |= B4800; - break; - case 9600: - info->cflag |= B9600; - break; - default: - printk("su_change_mouse_baud: unknown baud rate %d, " - "defaulting to 1200\n", baud); - info->cflag |= 1200; - break; + len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); + for (i = 0; i < NR_PORTS && len < 4000; i++) { + len += line_info(page + len, &su_table[i]); + if (len+begin > off+count) + goto done; + if (len+begin < off) { + begin += len; + len = 0; + } } - change_speed(info); + *eof = 1; +done: + if (off >= len+begin) + return 0; + *start = page + (begin-off); + return ((count < begin+len-off) ? count : begin+len-off); } /* + * --------------------------------------------------------------------- + * su_init() and friends + * + * su_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this * driver. */ -static inline void -show_su_version(void) +static __inline__ +void show_su_version(void) { printk(KERN_INFO "%s version %s\n", serial_name, serial_version); } @@ -407,10 +2182,15 @@ autoconfig(struct su_struct *info) { unsigned char status1, status2, scratch, scratch2; +#ifdef __sparc_v9__ struct linux_ebus_device *dev = 0; struct linux_ebus *ebus; +#else + struct linux_prom_registers reg0; +#endif unsigned long flags; +#ifdef __sparc_v9__ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { if (!strncmp(dev->prom_name, "su", 2)) { @@ -430,9 +2210,29 @@ return; info->irq = dev->irqs[0]; +#else + if (!info->port_node) + return; + + if (prom_getproperty(info->port_node, "reg", + (char *)®0, sizeof(reg0)) == -1) { + prom_printf("su: no \"reg\" property\n"); + return; + } + prom_apply_obio_ranges(®0, 1); + if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr, + 0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) { + prom_printf("su: cannot map\n"); + return; + } + /* + * There is no intr property on MrCoffee, so hardwire it. Krups? + */ + info->irq = IRQ_4M(13); +#endif #ifdef DEBUG_SERIAL_OPEN - printk("Found 'su' at %016lx IRQ %d,%x\n", dev->base_address[0], + printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0], __irq_itoa(dev->irqs[0])); #endif @@ -449,33 +2249,35 @@ * 0x80 is a non-existent port; which should be safe since * include/asm/io.h also makes this assumption. */ - scratch = su_inb(info, UART_IER); + scratch = serial_in(info, UART_IER); su_outb(info, UART_IER, 0); - scratch2 = su_inb(info, UART_IER); + scratch2 = serial_in(info, UART_IER); su_outb(info, UART_IER, scratch); if (scratch2) { restore_flags(flags); return; /* We failed; there's nothing here */ } - scratch = su_inb(info, UART_MCR); +#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */ + scratch = serial_in(info, UART_MCR); su_outb(info, UART_MCR, UART_MCR_LOOP | scratch); - scratch2 = su_inb(info, UART_MSR); + scratch2 = serial_in(info, UART_MSR); su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = su_inb(info, UART_MSR) & 0xF0; + status1 = serial_in(info, UART_MSR) & 0xF0; su_outb(info, UART_MCR, scratch); su_outb(info, UART_MSR, scratch2); if (status1 != 0x90) { restore_flags(flags); return; } +#endif - scratch2 = su_inb(info, UART_LCR); + scratch2 = serial_in(info, UART_LCR); su_outb(info, UART_LCR, 0xBF); /* set up for StarTech test */ su_outb(info, UART_EFR, 0); /* EFR is the same as FCR */ su_outb(info, UART_LCR, 0); su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = su_inb(info, UART_IIR) >> 6; + scratch = serial_in(info, UART_IIR) >> 6; switch (scratch) { case 0: info->type = PORT_16450; @@ -528,21 +2330,27 @@ if ((status1 != 0xa5) || (status2 != 0x5a)) info->type = PORT_8250; } + info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size; if (info->type == PORT_UNKNOWN) { restore_flags(flags); return; } - sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd"); + if (info->kbd_node || info->ms_node) + sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd"); + else + strcpy(info->name, "su(serial)"); + +#ifdef __sparc_v9__ request_region(info->port, 8, info->name); +#endif /* * Reset the UART. */ su_outb(info, UART_MCR, 0x00); - su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); + su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); su_inb(info, UART_RX); restore_flags(flags); @@ -551,19 +2359,117 @@ /* * The serial driver boot-time initialization code! */ -__initfunc(int su_init(void)) +__initfunc(int su_serial_init(void)) { int i; struct su_struct *info; - + + init_bh(SERIAL_BH, do_serial_bh); show_su_version(); + /* Initialize the tty_driver structure */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.driver_name = "su"; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NR_PORTS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = su_open; + serial_driver.close = su_close; + serial_driver.write = su_write; + serial_driver.put_char = su_put_char; + serial_driver.flush_chars = su_flush_chars; + serial_driver.write_room = su_write_room; + serial_driver.chars_in_buffer = su_chars_in_buffer; + serial_driver.flush_buffer = su_flush_buffer; + serial_driver.ioctl = su_ioctl; + serial_driver.throttle = su_throttle; + serial_driver.unthrottle = su_unthrottle; + serial_driver.send_xchar = su_send_xchar; + serial_driver.set_termios = su_set_termios; + serial_driver.stop = su_stop; + serial_driver.start = su_start; + serial_driver.hangup = su_hangup; + serial_driver.break_ctl = su_break; + serial_driver.wait_until_sent = su_wait_until_sent; + serial_driver.read_proc = su_read_proc; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + callout_driver.read_proc = 0; + callout_driver.proc_entry = 0; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register regular su\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout su\n"); + for (i = 0, info = su_table; i < NR_PORTS; i++, info++) { info->line = i; + info->type = PORT_UNKNOWN; + info->baud_base = BAUD_BASE; + /* info->flags = 0; */ + info->custom_divisor = 0; + info->close_delay = 5*HZ/10; + info->closing_wait = 30*HZ; + info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->icount.cts = info->icount.dsr = + info->icount.rng = info->icount.dcd = 0; + info->icount.rx = info->icount.tx = 0; + info->icount.frame = info->icount.parity = 0; + info->icount.overrun = info->icount.brk = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->cflag = serial_driver.init_termios.c_cflag; + + autoconfig(info); + if (info->type == PORT_UNKNOWN) + continue; + + printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n", + info->name, info->port, __irq_itoa(info->irq), + uart_config[info->type].name); + } + + return 0; +} + +__initfunc(int su_kbd_ms_init(void)) +{ + int i; + struct su_struct *info; + + show_su_version(); + + for (i = 0, info = su_table; i < 2; i++, info++) { + info->line = i; + info->type = PORT_UNKNOWN; + info->baud_base = BAUD_BASE; + if (info->kbd_node) - info->cflag = B1200 | CS8 | CREAD; + info->cflag = B1200 | CS8 | CLOCAL | CREAD; else - info->cflag = B4800 | CS8 | CREAD; + info->cflag = B4800 | CS8 | CLOCAL | CREAD; autoconfig(info); if (info->type == PORT_UNKNOWN) @@ -575,7 +2481,7 @@ startup(info); if (info->kbd_node) - keyboard_zsinit(su_put_char); + keyboard_zsinit(su_put_char_kbd); else sun_mouse_zsinit(); } @@ -592,6 +2498,33 @@ int len; /* + * Find su on MrCoffee. We return OK code if find any. + * Then su_init finds every one and initializes them. + * We do this early because MrCoffee got no aliases. + */ + node = prom_getchild(prom_root_node); + if ((node = prom_searchsiblings(node, "obio")) != 0) { + if ((sunode = prom_getchild(node)) != 0) { + if ((sunode = prom_searchsiblings(sunode, "su")) != 0) { + info->port_node = sunode; +#ifdef CONFIG_SERIAL_CONSOLE + /* + * Console must be initiated after the generic + * initialization. + * sunserial_setinitfunc inverts order, so + * call this before next one. + */ + sunserial_setinitfunc(memory_start, + su_serial_console_init); +#endif + sunserial_setinitfunc(memory_start, + su_serial_init); + return 0; + } + } + } + + /* * Get the nodes for keyboard and mouse from 'aliases'... */ node = prom_getchild(prom_root_node); @@ -619,7 +2552,9 @@ * Find matching EBus nodes... */ node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "pci"); + if ((node = prom_searchsiblings(node, "pci")) == 0) { + return -ENODEV; /* Plain sparc */ + } /* * Check for SUNW,sabre on Ultra 5/10/AXi. @@ -668,7 +2603,7 @@ /* * Found everything we need? */ - if (devices == NR_PORTS) + if (devices == 2) goto found; sunode = prom_getsibling(sunode); @@ -687,7 +2622,7 @@ return -ENODEV; found: - sunserial_setinitfunc(memory_start, su_init); + sunserial_setinitfunc(memory_start, su_kbd_ms_init); rs_ops.rs_change_mouse_baud = su_change_mouse_baud; sunkbd_setinitfunc(memory_start, sun_kbd_init); kbd_ops.compute_shiftstate = sun_compute_shiftstate; @@ -695,9 +2630,266 @@ kbd_ops.getledstate = sun_getledstate; kbd_ops.setkeycode = sun_setkeycode; kbd_ops.getkeycode = sun_getkeycode; +#ifdef CONFIG_PCI sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, sun_func_buf, sun_func_table, sun_funcbufsize, sun_funcbufleft, sun_accent_table, sun_accent_table_size); +#endif + return 0; +} + +/* + * ------------------------------------------------------------ + * Serial console driver + * ------------------------------------------------------------ + */ +#ifdef CONFIG_SERIAL_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Wait for transmitter & holding register to empty + */ +static __inline__ void +wait_for_xmitr(struct su_struct *info) +{ + int lsr; + unsigned int tmout = 1000000; + + do { + lsr = su_inb(info, UART_LSR); + if (--tmout == 0) + break; + } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + */ +static void +serial_console_write(struct console *co, const char *s, + unsigned count) +{ + struct su_struct *info; + int ier; + unsigned i; + + info = su_table + co->index; + /* + * First save the IER then disable the interrupts + */ + ier = su_inb(info, UART_IER); + su_outb(info, UART_IER, 0x00); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(info); + + /* + * Send the character out. + * If a LF, also do CR... + */ + su_outb(info, UART_TX, *s); + if (*s == 10) { + wait_for_xmitr(info); + su_outb(info, UART_TX, 13); + } + } + + /* + * Finally, Wait for transmitter & holding register to empty + * and restore the IER + */ + wait_for_xmitr(info); + su_outb(info, UART_IER, ier); +} + +/* + * Receive character from the serial port + */ +static int +serial_console_wait_key(struct console *co) +{ + struct su_struct *info; + int ier; + int lsr; + int c; + + info = su_table + co->index; + + /* + * First save the IER then disable the interrupts so + * that the real driver for the port does not get the + * character. + */ + ier = su_inb(info, UART_IER); + su_outb(info, UART_IER, 0x00); + + do { + lsr = su_inb(info, UART_LSR); + } while (!(lsr & UART_LSR_DR)); + c = su_inb(info, UART_RX); + + /* + * Restore the interrupts + */ + su_outb(info, UART_IER, ier); + + return c; +} + +static kdev_t +serial_console_device(struct console *c) +{ + return MKDEV(TTY_MAJOR, 64 + c->index); +} + +/* + * Setup initial baud/bits/parity. We do two things here: + * - construct a cflag setting for the first su_open() + * - initialize the serial port + * Return non-zero if we didn't find a serial port. + */ +__initfunc(static int serial_console_setup(struct console *co, char *options)) +{ + struct su_struct *info; + unsigned cval; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int cflag = CREAD | HUPCL | CLOCAL; + int quot = 0; + char *s; + + if (options) { + baud = simple_strtoul(options, NULL, 10); + s = options; + while(*s >= '0' && *s <= '9') + s++; + if (*s) parity = *s++; + if (*s) bits = *s - '0'; + } + + /* + * Now construct a cflag setting. + */ + switch(baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 57600: + cflag |= B57600; + break; + case 115200: + cflag |= B115200; + break; + case 9600: + default: + cflag |= B9600; + break; + } + switch(bits) { + case 7: + cflag |= CS7; + break; + default: + case 8: + cflag |= CS8; + break; + } + switch(parity) { + case 'o': case 'O': + cflag |= PARODD; + break; + case 'e': case 'E': + cflag |= PARENB; + break; + } + co->cflag = cflag; + + /* + * Divisor, bytesize and parity + */ + info = su_table + co->index; + quot = BAUD_BASE / baud; + cval = cflag & (CSIZE | CSTOPB); +#if defined(__powerpc__) || defined(__alpha__) + cval >>= 8; +#else /* !__powerpc__ && !__alpha__ */ + cval >>= 4; +#endif /* !__powerpc__ && !__alpha__ */ + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + + /* + * Disable UART interrupts, set DTR and RTS high + * and set speed. + */ + su_outb(info, UART_IER, 0); + su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + su_outb(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + su_outb(info, UART_DLL, quot & 0xff); /* LS of divisor */ + su_outb(info, UART_DLM, quot >> 8); /* MS of divisor */ + su_outb(info, UART_LCR, cval); /* reset DLAB */ + info->quot = quot; + + /* + * If we read 0xff from the LSR, there is no UART here. + */ + if (su_inb(info, UART_LSR) == 0xff) + return -1; + + return 0; +} + +static struct console sercons = { + "ttyS", + serial_console_write, + NULL, + serial_console_device, + serial_console_wait_key, + NULL, + serial_console_setup, + CON_PRINTBUFFER, + -1, + 0, + NULL +}; + +/* + * Register console. + */ +__initfunc(int su_serial_console_init(void)) +{ + extern int con_is_present(void); + + if (con_is_present()) + return 0; + if (serial_console == 0) + return 0; + if (su_table[0].port == 0 || su_table[0].port_node == 0) + return 0; + sercons.index = 0; + register_console(&sercons); return 0; } + +#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/su32.c linux/drivers/sbus/char/su32.c --- v2.1.126/linux/drivers/sbus/char/su32.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/su32.c Wed Dec 31 16:00:00 1969 @@ -1,3565 +0,0 @@ -/* $Id: su32.c,v 1.1 1998/09/18 10:45:32 jj Exp $ - * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI - * - * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Coypright (C) 1998 Pete Zaitcev (zaitcev@metabyte.com) - * - * This is mainly a variation of drivers/char/serial.c, - * credits go to authors mentioned therein. - */ - -/* - * Configuration section. - */ -#define SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO /* Unused on sparc */ -#define SERIAL_DO_RESTART - -#if 1 -/* Normally these defines are controlled by the autoconf.h */ - -#undef CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_SHARE_IRQ /* Must be enabled for MrCoffee. */ -#undef CONFIG_SERIAL_DETECT_IRQ /* code is removed from su.c */ -#undef CONFIG_SERIAL_MULTIPORT -#endif - -/* Sanity checks */ - -#ifdef CONFIG_SERIAL_MULTIPORT -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#endif - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT -#undef SERIAL_DEBUG_THROTTLE - -/* */ - -#define RS_STROBE_TIME (10*HZ) -#define RS_ISR_PASS_LIMIT 256 - -#ifdef __sparc_v9__ -#define IRQ_4M(n) (n) -#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT) -#else -/* 0x20 is sun4m thing, Dave Redman heritage. See arch/sparc/kernel/irq.c. */ -#define IRQ_4M(n) ((n)|0x20) -/* Interrupts must be shared on MrCoffee. */ -#define IRQ_T(info) SA_SHIRQ -#endif - -#define SERIAL_INLINE - -#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) -#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) -#else -#define DBG_CNT(s) -#endif - -/* - * End of serial driver configuration section. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SERIAL_CONSOLE -#include -#include -#endif -#include - -#include -#include -#include -#include -#include -#include -#include -#if 0 /* P3: Needed if we to support /sbin/setserial. */ -#include -#endif - -#include "sunserial.h" -#include "sunkbd.h" -#include "sunmouse.h" - -/* We are on a NS PC87303 clocked with 24.0 MHz, which results - * in a UART clock of 1.8462 MHz. - */ -#define BAUD_BASE (1846200 / 16) - -#ifdef CONFIG_SERIAL_CONSOLE -extern int serial_console; -static struct console sercons; -int su_serial_console_init(void); -#endif - -/* - * serial.c saves memory when it allocates async_info upon first open. - * We have parts of state structure together because we do call startup - * for keyboard and mouse. - */ -struct su_struct { - int magic; - unsigned long port; - int baud_base; - int type; /* Hardware type: e.g. 16550 */ - int irq; - int flags; - int line; - int cflag; - - /* XXX Unify. */ - int kbd_node; - int ms_node; - int port_node; - - char name[16]; - - int xmit_fifo_size; - int custom_divisor; - unsigned short close_delay; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int quot; - int x_char; /* xon/xoff character */ - int IER; /* Interrupt Enable Register */ - int MCR; /* Modem control register */ - unsigned long event; - int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - struct tq_struct tqueue; - struct wait_queue *open_wait; - struct wait_queue *close_wait; - struct wait_queue *delta_msr_wait; - - struct su_struct *next_port; - struct su_struct *prev_port; - - int count; - struct async_icount icount; - struct termios normal_termios, callout_termios; - unsigned long last_active; /* For async_struct, to be */ -}; - -#if 0 /* P3: became unused after surgery. */ -/* - * This is used to figure out the divisor speeds and the timeouts - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 }; -#endif - -#ifdef SERIAL_INLINE -#define _INLINE_ inline -#endif - -static char *serial_name = "Serial driver"; -static char *serial_version = "4.25.s1"; - -static DECLARE_TASK_QUEUE(tq_serial); - -static struct tty_driver serial_driver, callout_driver; -static int serial_refcount; - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* - * IRQ_timeout - How long the timeout should be for each IRQ - * should be after the IRQ has been active. - */ -static struct su_struct *IRQ_ports[NR_IRQS]; -#ifdef CONFIG_SERIAL_MULTIPORT -static struct rs_multiport_struct rs_multiport[NR_IRQS]; -#endif -static int IRQ_timeout[NR_IRQS]; - -static void autoconfig(struct su_struct *info); -static void change_speed(struct su_struct *info); -static void su_wait_until_sent(struct tty_struct *tty, int timeout); - -/* - * Here we define the default xmit fifo size used for each type of - * UART - */ -static struct serial_uart_config uart_config[] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "cirrus", 1, 0 }, - { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, - { 0, 0} -}; - - -#define NR_PORTS 4 - -static struct su_struct su_table[NR_PORTS]; -static struct tty_struct *serial_table[NR_PORTS]; -static struct termios *serial_termios[NR_PORTS]; -static struct termios *serial_termios_locked[NR_PORTS]; - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static struct semaphore tmp_buf_sem = MUTEX; - -static inline int serial_paranoia_check(struct su_struct *info, - kdev_t device, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null su_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, kdevname(device), routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, kdevname(device), routine); - return 1; - } -#endif - return 0; -} - -#ifdef __sparc_v9__ - -static inline -unsigned int su_inb(struct su_struct *info, unsigned long offset) -{ - return inb(info->port + offset); -} - -static inline void -su_outb(struct su_struct *info, unsigned long offset, int value) -{ - outb(value, info->port + offset); -} - -#else - -static inline -unsigned int su_inb(struct su_struct *info, unsigned long offset) -{ - return (unsigned int)(*(volatile unsigned char *)(info->port + offset)); -} - -static inline void -su_outb(struct su_struct *info, unsigned long offset, int value) -{ - /* - * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are - * connected with a gate then go to SlavIO. When IRQ4 goes tristated - * gate gives logical one. Since we use level triggered interrupts - * we have lockup and watchdog reset. We cannot mask IRQ because - * keyboard shares IRQ with us (Bob Smelik: I would not hire you). - * P3: Assure that OUT2 never goes down. - */ - if (offset == UART_MCR) value |= UART_MCR_OUT2; - *(volatile unsigned char *)(info->port + offset) = value; -} - -#endif - -#define serial_in(info, off) su_inb(info, off) -#define serial_inp(info, off) su_inb(info, off) -#define serial_out(info, off, val) su_outb(info, off, val) -#define serial_outp(info, off, val) su_outb(info, off, val) - -/* - * ------------------------------------------------------------ - * su_stop() and su_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void su_stop(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_stop")) - return; - - save_flags(flags); cli(); - if (info->IER & UART_IER_THRI) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - restore_flags(flags); -} - -static void su_start(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_start")) - return; - - save_flags(flags); cli(); - if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - restore_flags(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * su_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static _INLINE_ void su_sched_event(struct su_struct *info, int event) -{ - info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); -} - -static _INLINE_ void receive_chars(struct su_struct *info, int *status, - struct pt_regs *regs) -{ - struct tty_struct *tty = info->tty; - unsigned char ch; - int ignored = 0; - struct async_icount *icount; - - icount = &info->icount; - do { - ch = serial_inp(info, UART_RX); - if (info->kbd_node) { - if(ch == SUNKBD_RESET) { - l1a_state.kbd_id = 1; - l1a_state.l1_down = 0; - } else if(l1a_state.kbd_id) { - l1a_state.kbd_id = 0; - } else if(ch == SUNKBD_L1) { - l1a_state.l1_down = 1; - } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { - l1a_state.l1_down = 0; - } else if(ch == SUNKBD_A && l1a_state.l1_down) { - /* whee... */ - batten_down_hatches(); - /* Continue execution... */ - l1a_state.l1_down = 0; - l1a_state.kbd_id = 0; - return; - } - sunkbd_inchar(ch, regs); - } else { - sun_mouse_inbyte(ch); - } - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - *tty->flip.char_buf_ptr = ch; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, *status); -#endif - *tty->flip.flag_buf_ptr = 0; - if (*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE)) { - /* - * For statistics only - */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - icount->brk++; - } else if (*status & UART_LSR_PE) - icount->parity++; - else if (*status & UART_LSR_FE) - icount->frame++; - if (*status & UART_LSR_OE) - icount->overrun++; - - /* - * Now check to see if character should be - * ignored, and mask off conditions which - * should be ignored. - */ - if (*status & info->ignore_status_mask) { - if (++ignored > 100) - break; - goto ignore_char; - } - *status &= info->read_status_mask; - - if (*status & (UART_LSR_BI)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (*status & UART_LSR_PE) - *tty->flip.flag_buf_ptr = TTY_PARITY; - else if (*status & UART_LSR_FE) - *tty->flip.flag_buf_ptr = TTY_FRAME; - if (*status & UART_LSR_OE) { - /* - * Overrun is special, since it's - * reported immediately, and doesn't - * affect the current character - */ - if (tty->flip.count < TTY_FLIPBUF_SIZE) { - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - } - } - } - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - ignore_char: - *status = serial_inp(info, UART_LSR); - } while (*status & UART_LSR_DR); - tty_flip_buffer_push(tty); -} - -static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done) -{ - int count; - - if (info->x_char) { - serial_outp(info, UART_TX, info->x_char); - info->icount.tx++; - info->x_char = 0; - if (intr_done) - *intr_done = 0; - return; - } - if ((info->xmit_cnt <= 0) || info->tty->stopped || - info->tty->hw_stopped) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - return; - } - - count = info->xmit_fifo_size; - do { - serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]); - info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); - info->icount.tx++; - if (--info->xmit_cnt <= 0) - break; - } while (--count > 0); - - if (info->xmit_cnt < WAKEUP_CHARS) - su_sched_event(info, RS_EVENT_WRITE_WAKEUP); - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif - if (intr_done) - *intr_done = 0; - - if (info->xmit_cnt <= 0) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } -} - -static _INLINE_ void check_modem_status(struct su_struct *info) -{ - int status; - struct async_icount *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { -#ifdef SERIAL_DEBUG_OPEN - printk("doing serial hangup..."); -#endif - if (info->tty) - tty_hangup(info->tty); - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - su_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} - -#ifdef CONFIG_SERIAL_SHARE_IRQ -/* - * This is the serial driver's generic interrupt routine - */ -static void su_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - struct su_struct *info; - int pass_counter = 0; - struct su_struct *end_mark = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct su_multiport_struct *multi; -#endif - -#ifdef SERIAL_DEBUG_INTR - printk("su_interrupt(%s)...", __irq_itoa(irq)); -#endif - - info = IRQ_ports[irq]; - if (!info) - return; - -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - do { - if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { - if (!end_mark) - end_mark = info; - goto next; - } - end_mark = 0; - - info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - - next: - info = info->next_port; - if (!info) { - info = IRQ_ports[irq]; - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("rs loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - continue; - } - } while (end_mark != info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n", - info->irq, first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} -#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ - - -/* - * This is the serial driver's interrupt routine for a single port - */ -static void su_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - int pass_counter = 0; - struct su_struct * info; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct rs_multiport_struct *multi; -#endif - -#ifdef SERIAL_DEBUG_INTR - printk("su_interrupt_single(%d) int=%x ...", irq, - serial_inp(&su_table[0], UART_IIR)); -#endif - - info = IRQ_ports[irq]; - if (!info || !info->tty) - return; - -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - do { - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("su_single loop break.\n"); -#endif - break; - } - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); - info->last_active = jiffies; -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (single) irq %s: 0x%x, 0x%x\n", - __irq_itoa(info->irq), first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - -#ifdef CONFIG_SERIAL_MULTIPORT -/* - * This is the serial driver's for multiport boards - */ -static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - struct su_struct * info; - int pass_counter = 0; - int first_multi= 0; - struct rs_multiport_struct *multi; - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_multi(%d)...", irq); -#endif - - info = IRQ_ports[irq]; - if (!info) - return; - multi = &rs_multiport[irq]; - if (!multi->port1) { - /* Should never happen */ - printk("rs_interrupt_multi: NULL port1!\n"); - return; - } - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); - - while (1) { - if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) - goto next; - - info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - - next: - info = info->next_port; - if (info) - continue; - - info = IRQ_ports[irq]; - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 1 - printk("rs_multi loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - if (multi->port_monitor) - printk("rs port monitor irq %d: 0x%x, 0x%x\n", - info->irq, first_multi, - inb(multi->port_monitor)); - if ((inb(multi->port1) & multi->mask1) != multi->match1) - continue; - if (!multi->port2) - break; - if ((inb(multi->port2) & multi->mask2) != multi->match2) - continue; - if (!multi->port3) - break; - if ((inb(multi->port3) & multi->mask3) != multi->match3) - continue; - if (!multi->port4) - break; - if ((inb(multi->port4) & multi->mask4) == multi->match4) - continue; - break; - } -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} -#endif - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * su_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using su_sched_event(), and they get done here. - */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) -{ - struct su_struct *info = (struct su_struct *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); - } -} - -/* - * This subroutine is called when the RS_TIMER goes off. It is used - * by the serial driver to handle ports that do not have an interrupt - * (irq=0). This doesn't work very well for 16450's, but gives barely - * passable results for a 16550A. (Although at the expense of much - * CPU overhead). - */ -static void su_timer(void) -{ - static unsigned long last_strobe = 0; - struct su_struct *info; - unsigned int i; - - if ((jiffies - last_strobe) >= RS_STROBE_TIME) { - for (i=1; i < NR_IRQS; i++) { - info = IRQ_ports[i]; - if (!info) - continue; - cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - if (info->next_port) { - do { - serial_out(info, UART_IER, 0); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - info = info->next_port; - } while (info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[i].port1) - rs_interrupt_multi(i, NULL, NULL); - else -#endif - su_interrupt(i, NULL, NULL); - } else -#endif /* CONFIG_SERIAL_SHARE_IRQ */ - su_interrupt_single(i, NULL, NULL); - sti(); - } - } - last_strobe = jiffies; - timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME; - timer_active |= 1 << RS_TIMER; - - if (IRQ_ports[0]) { - cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - su_interrupt(0, NULL, NULL); -#else - su_interrupt_single(0, NULL, NULL); -#endif - sti(); - - timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2; - } -} - -/* - * --------------------------------------------------------------- - * Low level utility subroutines for the serial driver: routines to - * figure out the appropriate timeout for an interrupt chain, routines - * to initialize and startup a serial port, and routines to shutdown a - * serial port. Useful stuff like that. - * --------------------------------------------------------------- - */ - -/* - * This routine figures out the correct timeout for a particular IRQ. - * It uses the smallest timeout of all of the serial ports in a - * particular interrupt chain. Now only used for IRQ 0.... - */ -static void figure_IRQ_timeout(int irq) -{ - struct su_struct *info; - int timeout = 60*HZ; /* 60 seconds === a long time :-) */ - - info = IRQ_ports[irq]; - if (!info) { - IRQ_timeout[irq] = 60*HZ; - return; - } - while (info) { - if (info->timeout < timeout) - timeout = info->timeout; - info = info->next_port; - } - if (!irq) - timeout = timeout / 2; - IRQ_timeout[irq] = timeout ? timeout : 1; -} - -static int startup(struct su_struct *info) -{ - unsigned long flags; - int retval=0; - void (*handler)(int, void *, struct pt_regs *); - unsigned long page; -#ifdef CONFIG_SERIAL_MANY_PORTS - unsigned short ICP; -#endif - - page = get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (info->port == 0 || info->type == PORT_UNKNOWN) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - goto errout; - } - if (info->xmit_buf) - free_page(page); - else - info->xmit_buf = (unsigned char *) page; - - if (uart_config[info->type].flags & UART_STARTECH) { - /* Wake up UART */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - serial_outp(info, UART_IER, 0); - serial_outp(info, UART_EFR, 0); - serial_outp(info, UART_LCR, 0); - } - - if (info->type == PORT_16750) { - /* Wake up UART */ - serial_outp(info, UART_IER, 0); - } - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - if (uart_config[info->type].flags & UART_CLEAR_FIFO) - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - - /* - * At this point there's no way the LSR could still be 0xFF; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (serial_inp(info, UART_LSR) == 0xff) { - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - } else - retval = -ENODEV; - goto errout; - } - - /* - * Allocate the IRQ if necessary - */ - if (info->irq && (!IRQ_ports[info->irq] || - !IRQ_ports[info->irq]->next_port)) { - if (IRQ_ports[info->irq]) { -#ifdef CONFIG_SERIAL_SHARE_IRQ - free_irq(IRQ_4M(info->irq), info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[info->irq].port1) - handler = rs_interrupt_multi; - else -#endif - handler = su_interrupt; -#else - retval = -EBUSY; - goto errout; -#endif /* CONFIG_SERIAL_SHARE_IRQ */ - } else - handler = su_interrupt_single; - - retval = request_irq(IRQ_4M(info->irq), handler, IRQ_T(info), - "serial", info); - if (retval) { - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); - retval = 0; - } - goto errout; - } - } - - /* - * Insert serial port into IRQ chain. - */ - info->prev_port = 0; - info->next_port = IRQ_ports[info->irq]; - if (info->next_port) - info->next_port->prev_port = info; - IRQ_ports[info->irq] = info; - figure_IRQ_timeout(info->irq); - - /* - * Clear the interrupt registers. - */ - /* (void) serial_inp(info, UART_LSR); */ /* (see above) */ - (void) serial_inp(info, UART_RX); - (void) serial_inp(info, UART_IIR); - (void) serial_inp(info, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - - info->MCR = 0; - if (info->tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - if (info->irq == 0) - info->MCR |= UART_MCR_OUT1; - } else -#endif - { - if (info->irq != 0) - info->MCR |= UART_MCR_OUT2; - } -#if defined(__alpha__) && !defined(CONFIG_PCI) - /* - * DEC did something gratutiously wrong.... - */ - info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2; -#endif - serial_outp(info, UART_MCR, info->MCR); - - /* - * Finally, enable interrupts - */ - info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - serial_outp(info, UART_IER, info->IER); /* enable interrupts */ - -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* Enable interrupts on the AST Fourport board */ - ICP = (info->port & 0xFE0) | 0x01F; - outb_p(0x80, ICP); - (void) inb_p(ICP); - } -#endif - - /* - * And clear the interrupt registers again for luck. - */ - (void)serial_inp(info, UART_LSR); - (void)serial_inp(info, UART_RX); - (void)serial_inp(info, UART_IIR); - (void)serial_inp(info, UART_MSR); - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - /* - * Set up serial timers... - */ - timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; - timer_active |= 1 << RS_TIMER; - - /* - * Set up the tty->alt_speed kludge - */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - } - - /* - * and set the speed of the serial port - */ - change_speed(info); - - info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); - return 0; - -errout: - restore_flags(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct su_struct *info) -{ - unsigned long flags; - int retval; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - save_flags(flags); cli(); /* Disable interrupts */ - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - wake_up_interruptible(&info->delta_msr_wait); - - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[info->irq] = info->next_port; - figure_IRQ_timeout(info->irq); - - /* - * Free the IRQ, if necessary - */ - if (info->irq && (!IRQ_ports[info->irq] || - !IRQ_ports[info->irq]->next_port)) { - if (IRQ_ports[info->irq]) { - free_irq(IRQ_4M(info->irq), info); - retval = request_irq(IRQ_4M(info->irq), - su_interrupt_single, IRQ_T(info), "serial", info); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(IRQ_4M(info->irq), info); - } - - if (info->xmit_buf) { - free_page((unsigned long) info->xmit_buf); - info->xmit_buf = 0; - } - - info->IER = 0; - serial_outp(info, UART_IER, 0x00); /* disable all intrs */ -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - (void) inb((info->port & 0xFE0) | 0x01F); - info->MCR |= UART_MCR_OUT1; - } else -#endif - info->MCR &= ~UART_MCR_OUT2; -#if defined(__alpha__) && !defined(CONFIG_PCI) - /* - * DEC did something gratutiously wrong.... - */ - info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2; -#endif - - /* disable break condition */ - serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); - - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - serial_outp(info, UART_MCR, info->MCR); - - /* disable FIFO's */ - serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - (void)serial_in(info, UART_RX); /* read data port to reset things */ - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - if (uart_config[info->type].flags & UART_STARTECH) { - /* Arrange to enter sleep mode */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - serial_outp(info, UART_IER, UART_IERX_SLEEP); - serial_outp(info, UART_LCR, 0); - } - if (info->type == PORT_16750) { - /* Arrange to enter sleep mode */ - serial_outp(info, UART_IER, UART_IERX_SLEEP); - } - info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct su_struct *info) -{ - unsigned short port; - int quot = 0, baud_base, baud; - unsigned cflag, cval, fcr = 0; - int bits; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; - if (!(port = info->port)) - return; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: cval = 0x00; bits = 7; break; - case CS6: cval = 0x01; bits = 8; break; - case CS7: cval = 0x02; bits = 9; break; - case CS8: cval = 0x03; bits = 10; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: cval = 0x00; bits = 7; break; - } - if (cflag & CSTOPB) { - cval |= 0x04; - bits++; - } - if (cflag & PARENB) { - cval |= UART_LCR_PARITY; - bits++; - } - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(info->tty); - baud_base = info->baud_base; - if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->custom_divisor; - else { - if (baud == 134) - /* Special case since 134 is really 134.5 */ - quot = (2*baud_base / 269); - else if (baud) - quot = baud_base / baud; - } - /* If the quotient is ever zero, default to 9600 bps */ - if (!quot) - quot = baud_base / 9600; - info->quot = quot; - info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - /* Set up FIFO's */ - if (uart_config[info->type].flags & UART_USE_FIFO) { - if ((info->baud_base / quot) < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - } - if (info->type == PORT_16750) - fcr |= UART_FCR7_64BYTE; - - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); - - /* - * Set up parity check flag - */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->tty)) - info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) - info->read_status_mask |= UART_LSR_BI; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (I_IGNBRK(info->tty)) { - info->ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= UART_LSR_OE; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->ignore_status_mask |= UART_LSR_DR; - save_flags(flags); cli(); - if (uart_config[info->type].flags & UART_STARTECH) { - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, - (cflag & CRTSCTS) ? UART_EFR_CTS : 0); - } - serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ - if (info->type == PORT_16750) - serial_outp(info, UART_FCR, fcr); /* set fcr */ - serial_outp(info, UART_LCR, cval); /* reset DLAB */ - if (info->type != PORT_16750) - serial_outp(info, UART_FCR, fcr); /* set fcr */ - restore_flags(flags); - info->quot = quot; -} - -static void su_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_put_char")) - return; - - if (!tty || !info->xmit_buf) - return; - - save_flags(flags); cli(); - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { - restore_flags(flags); - return; - } - - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= SERIAL_XMIT_SIZE-1; - info->xmit_cnt++; - restore_flags(flags); -} - -static void su_put_char_kbd(unsigned char c) -{ - struct su_struct *info; - int i; - int lsr; - - for (i = 0, info = su_table; i < NR_PORTS; i++, info++) { - if (info->kbd_node != 0) - break; - } - if (i >= NR_PORTS) { - /* XXX P3: I would put a printk here but it may flood. */ - return; - } - - do { - lsr = serial_in(info, UART_LSR); - } while (!(lsr & UART_LSR_THRE)); - - /* Send the character out. */ - su_outb(info, UART_TX, c); -} - -static void su_change_mouse_baud(int baud) -{ - struct su_struct *info = su_table; - int i; - - for (i = 0, info = su_table; i < NR_PORTS; i++, info++) - if (info->kbd_node != 0) break; - if (i >= NR_PORTS) return; - - info->cflag &= ~(CBAUDEX | CBAUD); - switch(baud) { - case 1200: - info->cflag |= B1200; - break; - case 2400: - info->cflag |= B2400; - break; - case 4800: - info->cflag |= B4800; - break; - case 9600: - info->cflag |= B9600; - break; - default: - printk("su_change_mouse_baud: unknown baud rate %d, " - "defaulting to 1200\n", baud); - info->cflag |= 1200; - break; - } - change_speed(info); -} - -static void su_flush_chars(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_flush_chars")) - return; - - if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || - !info->xmit_buf) - return; - - save_flags(flags); cli(); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - restore_flags(flags); -} - -static int su_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, ret = 0; - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_write")) - return 0; - - if (!tty || !info->xmit_buf || !tmp_buf) - return 0; - - save_flags(flags); - if (from_user) { - down(&tmp_buf_sem); - while (1) { - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) - break; - - c -= copy_from_user(tmp_buf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - cli(); - c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); - info->xmit_head = ((info->xmit_head + c) & - (SERIAL_XMIT_SIZE-1)); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - ret += c; - } - up(&tmp_buf_sem); - } else { - while (1) { - cli(); - c = MIN(count, - MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, - SERIAL_XMIT_SIZE - info->xmit_head)); - if (c <= 0) { - restore_flags(flags); - break; - } - memcpy(info->xmit_buf + info->xmit_head, buf, c); - info->xmit_head = ((info->xmit_head + c) & - (SERIAL_XMIT_SIZE-1)); - info->xmit_cnt += c; - restore_flags(flags); - buf += c; - count -= c; - ret += c; - } - } - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && - !(info->IER & UART_IER_THRI)) { - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - return ret; -} - -static int su_write_room(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - int ret; - - if (serial_paranoia_check(info, tty->device, "su_write_room")) - return 0; - ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; - if (ret < 0) - ret = 0; - return ret; -} - -static int su_chars_in_buffer(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "su_chars_in_buffer")) - return 0; - return info->xmit_cnt; -} - -static void su_flush_buffer(struct tty_struct *tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "su_flush_buffer")) - return; - cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); - wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void su_send_xchar(struct tty_struct *tty, char ch) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "su_send_char")) - return; - - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } -} - -/* - * ------------------------------------------------------------ - * su_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void su_throttle(struct tty_struct * tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "su_throttle")) - return; - - if (I_IXOFF(tty)) - su_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); -} - -static void su_unthrottle(struct tty_struct * tty) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "su_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - su_send_xchar(tty, START_CHAR(tty)); - } - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); -} - -/* - * ------------------------------------------------------------ - * su_ioctl() and friends - * ------------------------------------------------------------ - */ - -#if 0 -static int get_serial_info(struct su_struct * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = info->port; - tmp.irq = info->irq; - tmp.flags = info->flags; - tmp.xmit_fifo_size = info->xmit_fifo_size; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = info->custom_divisor; - tmp.hub6 = 0; - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct su_struct * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct serial_state old_state, *state; - unsigned int i,change_irq,change_port; - int retval = 0; - - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - old_state = *state; - - change_irq = new_serial.irq != state->irq; - change_port = (new_serial.port != state->port); - - if (!capable(CAP_SYS_ADMIN)) { - if (change_irq || change_port || - (new_serial.baud_base != state->baud_base) || - (new_serial.type != state->type) || - (new_serial.close_delay != state->close_delay) || - (new_serial.xmit_fifo_size != state->xmit_fifo_size) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (state->flags & ~ASYNC_USR_MASK))) - return -EPERM; - state->flags = ((state->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - state->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - new_serial.irq = irq_cannonicalize(new_serial.irq); - - if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) || - (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) { - return -EINVAL; - } - - /* Make sure address is not already in use */ - if (new_serial.type) { - for (i = 0 ; i < NR_PORTS; i++) - if ((state != &su_table[i]) && - (su_table[i].port == new_serial.port) && - su_table[i].type) - return -EADDRINUSE; - } - - if ((change_port || change_irq) && (state->count > 1)) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - state->baud_base = new_serial.baud_base; - state->flags = ((state->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | - (info->flags & ASYNC_INTERNAL_FLAGS)); - state->custom_divisor = new_serial.custom_divisor; - state->type = new_serial.type; - state->close_delay = new_serial.close_delay * HZ/100; - state->closing_wait = new_serial.closing_wait * HZ/100; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - info->xmit_fifo_size = state->xmit_fifo_size = - new_serial.xmit_fifo_size; - - release_region(state->port,8); - if (change_port || change_irq) { - /* - * We need to shutdown the serial port at the old - * port/irq combination. - */ - shutdown(info); - state->irq = new_serial.irq; - info->port = state->port = new_serial.port; - info->hub6 = state->hub6 = new_serial.hub6; - } - if (state->type != PORT_UNKNOWN) - request_region(state->port,8,"serial(set)"); - -check_and_exit: - if (!state->port || !state->type) - return 0; - if (state->type != old_state.type) - info->xmit_fifo_size = state->xmit_fifo_size = - uart_config[state->type].dfl_xmit_fifo_size; - if (state->flags & ASYNC_INITIALIZED) { - if (((old_state.flags & ASYNC_SPD_MASK) != - (state->flags & ASYNC_SPD_MASK)) || - (old_state.custom_divisor != state->custom_divisor)) { - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - change_speed(info); - } - } else - retval = startup(info); - return retval; -} -#endif - - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct su_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - - cli(); - status = serial_in(info, UART_LSR); - sti(); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); -} - - -static int get_modem_info(struct su_struct * info, unsigned int *value) -{ - unsigned char control, status; - unsigned int result; - - control = info->MCR; - cli(); - status = serial_in(info, UART_MSR); - sti(); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - return put_user(result,value); -} - -static int set_modem_info(struct su_struct * info, unsigned int cmd, - unsigned int *value) -{ - int error; - unsigned int arg; - - error = get_user(arg, value); - if (error) - return error; - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - info->MCR |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR |= UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; -#endif - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - break; - case TIOCMSET: - info->MCR = ((info->MCR & ~(UART_MCR_RTS | -#ifdef TIOCM_OUT1 - UART_MCR_OUT1 | - UART_MCR_OUT2 | -#endif - UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) -#ifdef TIOCM_OUT1 - | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) - | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) -#endif - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - break; - default: - return -EINVAL; - } - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); - return 0; -} - -#if 0 -static int do_autoconfig(struct su_struct * info) -{ - int retval; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (info->state->count > 1) - return -EBUSY; - - shutdown(info); - - autoconfig(info->state); - if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0)) - info->state->irq = detect_uart_irq(info->state); - - retval = startup(info); - if (retval) - return retval; - return 0; -} -#endif - -/* - * su_break() --- routine which turns the break handling on or off - */ -static void su_break(struct tty_struct *tty, int break_state) -{ - struct su_struct * info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "su_break")) - return; - - if (!info->port) - return; - save_flags(flags); cli(); - if (break_state == -1) - serial_out(info, UART_LCR, - serial_inp(info, UART_LCR) | UART_LCR_SBC); - else - serial_out(info, UART_LCR, - serial_inp(info, UART_LCR) & ~UART_LCR_SBC); - restore_flags(flags); -} - -#ifdef CONFIG_SERIAL_MULTIPORT -static int get_multiport_struct(struct su_struct * info, - struct serial_multiport_struct *retinfo) -{ - struct serial_multiport_struct ret; - struct rs_multiport_struct *multi; - - multi = &rs_multiport[info->state->irq]; - - ret.port_monitor = multi->port_monitor; - - ret.port1 = multi->port1; - ret.mask1 = multi->mask1; - ret.match1 = multi->match1; - - ret.port2 = multi->port2; - ret.mask2 = multi->mask2; - ret.match2 = multi->match2; - - ret.port3 = multi->port3; - ret.mask3 = multi->mask3; - ret.match3 = multi->match3; - - ret.port4 = multi->port4; - ret.mask4 = multi->mask4; - ret.match4 = multi->match4; - - ret.irq = info->state->irq; - - if (copy_to_user(retinfo,&ret,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_multiport_struct(struct su_struct * info, - struct serial_multiport_struct *in_multi) -{ - struct serial_multiport_struct new_multi; - struct rs_multiport_struct *multi; - struct serial_state *state; - int was_multi, now_multi; - int retval; - void (*handler)(int, void *, struct pt_regs *); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - state = info->state; - - if (copy_from_user(&new_multi, in_multi, - sizeof(struct serial_multiport_struct))) - return -EFAULT; - - if (new_multi.irq != state->irq || state->irq == 0 || - !IRQ_ports[state->irq]) - return -EINVAL; - - multi = &rs_multiport[state->irq]; - was_multi = (multi->port1 != 0); - - multi->port_monitor = new_multi.port_monitor; - - if (multi->port1) - release_region(multi->port1,1); - multi->port1 = new_multi.port1; - multi->mask1 = new_multi.mask1; - multi->match1 = new_multi.match1; - if (multi->port1) - request_region(multi->port1,1,"serial(multiport1)"); - - if (multi->port2) - release_region(multi->port2,1); - multi->port2 = new_multi.port2; - multi->mask2 = new_multi.mask2; - multi->match2 = new_multi.match2; - if (multi->port2) - request_region(multi->port2,1,"serial(multiport2)"); - - if (multi->port3) - release_region(multi->port3,1); - multi->port3 = new_multi.port3; - multi->mask3 = new_multi.mask3; - multi->match3 = new_multi.match3; - if (multi->port3) - request_region(multi->port3,1,"serial(multiport3)"); - - if (multi->port4) - release_region(multi->port4,1); - multi->port4 = new_multi.port4; - multi->mask4 = new_multi.mask4; - multi->match4 = new_multi.match4; - if (multi->port4) - request_region(multi->port4,1,"serial(multiport4)"); - - now_multi = (multi->port1 != 0); - - if (IRQ_ports[state->irq]->next_port && - (was_multi != now_multi)) { - free_irq(IRQ_4M(state->irq), info); - if (now_multi) - handler = rs_interrupt_multi; - else - handler = su_interrupt; - - retval = request_irq(IRQ_4M(state->irq), handler, IRQ_T(info), - "serial", info); - if (retval) { - printk("Couldn't reallocate serial interrupt " - "driver!!\n"); - } - } - - return 0; -} -#endif - -static int su_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int error; - struct su_struct * info = (struct su_struct *)tty->driver_data; - struct async_icount cprev, cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ - - if (serial_paranoia_check(info, tty->device, "su_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); -#if 0 - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERCONFIG: - return do_autoconfig(info); -#endif - - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); - -#if 0 - case TIOCSERGSTRUCT: - if (copy_to_user((struct async_struct *) arg, - info, sizeof(struct async_struct))) - return -EFAULT; - return 0; -#endif - -#ifdef CONFIG_SERIAL_MULTIPORT - case TIOCSERGETMULTI: - return get_multiport_struct(info, - (struct serial_multiport_struct *) arg); - case TIOCSERSETMULTI: - return set_multiport_struct(info, - (struct serial_multiport_struct *) arg); -#endif - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - cli(); - /* note the counters on entry */ - cprev = info->icount; - sti(); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - cli(); - cnow = info->icount; /* atomic copy */ - sti(); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - cli(); - cnow = info->icount; - sti(); - p_cuser = (struct serial_icounter_struct *) arg; - error = put_user(cnow.cts, &p_cuser->cts); - if (error) return error; - error = put_user(cnow.dsr, &p_cuser->dsr); - if (error) return error; - error = put_user(cnow.rng, &p_cuser->rng); - if (error) return error; - error = put_user(cnow.dcd, &p_cuser->dcd); - if (error) return error; - return 0; - - default: - return -ENOIOCTLCMD; - } - /* return 0; */ /* Trigger warnings is fall through by a chance. */ -} - -static void su_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - - if ( (tty->termios->c_cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - change_speed(info); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { - info->MCR |= UART_MCR_RTS; - } - cli(); - serial_out(info, UART_MCR, info->MCR); - sti(); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - su_start(tty); - } - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * su_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void su_close(struct tty_struct *tty, struct file * filp) -{ - struct su_struct *info = (struct su_struct *)tty->driver_data; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->device, "su_close")) - return; - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("su_close ttys%d, count = %d\n", info->line, info->count); -#endif - if ((tty->count == 1) && (info->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("su_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - if (--info->count < 0) { - printk("su_close: bad serial port count for ttys%d: %d\n", - info->line, info->count); - info->count = 0; - } - if (info->count) { - DBG_CNT("before DEC-2"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - info->flags |= ASYNC_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->IER &= ~UART_IER_RLSI; - info->read_status_mask &= ~UART_LSR_DR; - if (info->flags & ASYNC_INITIALIZED) { - serial_out(info, UART_IER, info->IER); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - su_wait_until_sent(tty, info->timeout); - } - shutdown(info); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - info->event = 0; - info->tty = 0; - if (info->blocked_open) { - if (info->close_delay) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; - restore_flags(flags); -} - -/* - * su_wait_until_sent() --- wait until the transmitter is empty - */ -static void su_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct su_struct * info = (struct su_struct *)tty->driver_data; - unsigned long orig_jiffies, char_time; - int lsr; - - if (serial_paranoia_check(info, tty->device, "su_wait_until_sent")) - return; - - if (info->type == PORT_UNKNOWN) - return; - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout) - char_time = MIN(char_time, timeout); -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In su_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif - current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ - current->timeout = jiffies + char_time; - schedule(); - if (signal_pending(current)) - break; - if (timeout && ((orig_jiffies + timeout) < jiffies)) - break; - } - current->state = TASK_RUNNING; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * su_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void su_hangup(struct tty_struct *tty) -{ - struct su_struct * info = (struct su_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "su_hangup")) - return; - - su_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); - info->tty = 0; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * su_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct su_struct *info) -{ - struct wait_queue wait = { current, NULL }; - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * su_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - info->line, info->count); -#endif - cli(); - if (!tty_hung_up_p(filp)) - info->count--; - sti(); - info->blocked_open++; - while (1) { - cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - sti(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, info->count); -#endif - schedule(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, info->count); -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int su_open(struct tty_struct *tty, struct file * filp) -{ - struct su_struct *info; - int retval, line; - unsigned long page; - - line = MINOR(tty->device) - tty->driver.minor_start; - if ((line < 0) || (line >= NR_PORTS)) - return -ENODEV; - info = su_table + line; - if (serial_paranoia_check(info, tty->device, "su_open")) - return -ENODEV; - info->count++; - -#ifdef SERIAL_DEBUG_OPEN - printk("su_open %s%d, count = %d\n", tty->driver.name, info->line, - info->count); -#endif - tty->driver_data = info; - info->tty = tty; - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - if (!tmp_buf) { - page = get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - - /* - * If the port is the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) - return retval; - - MOD_INC_USE_COUNT; - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("su_open returning after block_til_ready with %d\n", - retval); -#endif - return retval; - } - - if ((info->count == 1) && - (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; - change_speed(info); - } -#ifdef CONFIG_SERIAL_CONSOLE - if (sercons.cflag && sercons.index == line) { - tty->termios->c_cflag = sercons.cflag; - sercons.cflag = 0; - change_speed(info); - } -#endif - info->session = current->session; - info->pgrp = current->pgrp; - -#ifdef SERIAL_DEBUG_OPEN - printk("su_open ttys%d successful...", info->line); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static inline int line_info(char *buf, struct su_struct *info) -{ - char stat_buf[30], control, status; - int ret; - - ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", - info->line, uart_config[info->type].name, - (int)info->port, info->irq); - - if (info->port == 0 || info->type == PORT_UNKNOWN) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - - /* - * Figure out the current RS-232 lines - */ - cli(); - status = serial_in(info, UART_MSR); - control = info ? info->MCR : serial_in(info, UART_MCR); - sti(); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - info->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - info->icount.tx, info->icount.rx); - - if (info->icount.frame) - ret += sprintf(buf+ret, " fe:%d", info->icount.frame); - - if (info->icount.parity) - ret += sprintf(buf+ret, " pe:%d", info->icount.parity); - - if (info->icount.brk) - ret += sprintf(buf+ret, " brk:%d", info->icount.brk); - - if (info->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", info->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); - return ret; -} - -int su_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - len += line_info(page + len, &su_table[i]); - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (begin-off); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * su_init() and friends - * - * su_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static _INLINE_ void show_su_version(void) -{ - printk(KERN_INFO "%s version %s with", serial_name, serial_version); -#ifdef CONFIG_SERIAL_MANY_PORTS - printk(" MANY_PORTS"); -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_MULTIPORT - printk(" MULTIPORT"); -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_SHARE_IRQ - printk(" SHARE_IRQ"); -#endif -#define SERIAL_OPT -#ifdef CONFIG_SERIAL_DETECT_IRQ - printk(" DETECT_IRQ"); -#endif -#ifdef SERIAL_OPT - printk(" enabled\n"); -#else - printk(" no serial options enabled\n"); -#endif -#undef SERIAL_OPT -} - -/* - * This routine is called by su_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void -autoconfig(struct su_struct *info) -{ - unsigned char status1, status2, scratch, scratch2; -#ifdef __sparc_v9__ - struct linux_ebus_device *dev = 0; - struct linux_ebus *ebus; -#else - struct linux_prom_registers reg0; -#endif - unsigned long flags; - -#ifdef __sparc_v9__ - for_each_ebus(ebus) { - for_each_ebusdev(dev, ebus) { - if (!strncmp(dev->prom_name, "su", 2)) { - if (dev->prom_node == info->kbd_node) - goto ebus_done; - if (dev->prom_node == info->ms_node) - goto ebus_done; - } - } - } -ebus_done: - if (!dev) - return; - - info->port = dev->base_address[0]; - if (check_region(info->port, 8)) - return; - - info->irq = dev->irqs[0]; - -#ifdef DEBUG_SERIAL_OPEN - printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0], - __irq_itoa(dev->irqs[0])); -#endif - -#else - if (info->port_node == 0) { - return; - } - if (prom_getproperty(info->port_node, "reg", - (char *)®0, sizeof(reg0)) == -1) { - prom_printf("su: no \"reg\" property\n"); - return; - } - prom_apply_obio_ranges(®0, 1); - if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr, - 0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) { - prom_printf("su: cannot map\n"); - return; - } - /* - * There is no intr property on MrCoffee, so hardwire it. Krups? - */ - info->irq = 13; -#endif - - info->magic = SERIAL_MAGIC; - - save_flags(flags); cli(); - - /* - * Do a simple existence test first; if we fail this, there's - * no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against false - * positives due to ISA bus float. The assumption is that - * 0x80 is a non-existent port; which should be safe since - * include/asm/io.h also makes this assumption. - */ - scratch = serial_in(info, UART_IER); - su_outb(info, UART_IER, 0); - scratch2 = serial_in(info, UART_IER); - su_outb(info, UART_IER, scratch); - if (scratch2) { - restore_flags(flags); - return; /* We failed; there's nothing here */ - } - -#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */ - scratch = serial_in(info, UART_MCR); - su_outb(info, UART_MCR, UART_MCR_LOOP | scratch); - scratch2 = serial_in(info, UART_MSR); - su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_in(info, UART_MSR) & 0xF0; - su_outb(info, UART_MCR, scratch); - su_outb(info, UART_MSR, scratch2); - if (status1 != 0x90) { - restore_flags(flags); - return; - } -#endif - - scratch2 = serial_in(info, UART_LCR); - su_outb(info, UART_LCR, 0xBF); /* set up for StarTech test */ - su_outb(info, UART_EFR, 0); /* EFR is the same as FCR */ - su_outb(info, UART_LCR, 0); - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(info, UART_IIR) >> 6; - switch (scratch) { - case 0: - info->type = PORT_16450; - break; - case 1: - info->type = PORT_UNKNOWN; - break; - case 2: - info->type = PORT_16550; - break; - case 3: - info->type = PORT_16550A; - break; - } - if (info->type == PORT_16550A) { - /* Check for Startech UART's */ - su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB); - if (su_inb(info, UART_EFR) == 0) { - info->type = PORT_16650; - } else { - su_outb(info, UART_LCR, 0xBF); - if (su_inb(info, UART_EFR) == 0) - info->type = PORT_16650V2; - } - } - if (info->type == PORT_16550A) { - /* Check for TI 16750 */ - su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB); - su_outb(info, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = su_inb(info, UART_IIR) >> 5; - if (scratch == 7) { - su_outb(info, UART_LCR, 0); - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = su_inb(info, UART_IIR) >> 5; - if (scratch == 6) - info->type = PORT_16750; - } - su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO); - } - su_outb(info, UART_LCR, scratch2); - if (info->type == PORT_16450) { - scratch = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, 0xa5); - status1 = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, 0x5a); - status2 = su_inb(info, UART_SCR); - su_outb(info, UART_SCR, scratch); - - if ((status1 != 0xa5) || (status2 != 0x5a)) - info->type = PORT_8250; - } - info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size; - - if (info->type == PORT_UNKNOWN) { - restore_flags(flags); - return; - } - -#ifdef __sparc_v9__ - sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd"); - request_region(info->port, 8, info->name); -#else - strcpy(info->name, "su(serial)"); -#endif - - /* - * Reset the UART. - */ - su_outb(info, UART_MCR, 0x00); - su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - su_inb(info, UART_RX); - - restore_flags(flags); -} - -/* - * The serial driver boot-time initialization code! - */ -__initfunc(int su_init(void)) -{ - int i; - struct su_struct *info; - extern void atomwide_serial_init (void); - extern void dualsp_serial_init (void); - -#ifdef CONFIG_ATOMWIDE_SERIAL - atomwide_serial_init (); -#endif -#ifdef CONFIG_DUALSP_SERIAL - dualsp_serial_init (); -#endif - - init_bh(SERIAL_BH, do_serial_bh); - timer_table[RS_TIMER].fn = su_timer; - timer_table[RS_TIMER].expires = 0; - - for (i = 0; i < NR_IRQS; i++) { - IRQ_ports[i] = 0; - IRQ_timeout[i] = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - memset(&rs_multiport[i], 0, - sizeof(struct rs_multiport_struct)); -#endif - } -#if 0 /* Must be shared with keyboard on MrCoffee. */ -#ifdef CONFIG_SERIAL_CONSOLE - /* - * The interrupt of the serial console port - * can't be shared. - */ - if (sercons.flags & CON_CONSDEV) { - for(i = 0; i < NR_PORTS; i++) - if (i != sercons.index && - su_table[i].irq == su_table[sercons.index].irq) - su_table[i].irq = 0; - } -#endif -#endif - show_su_version(); - - /* Initialize the tty_driver structure */ - - memset(&serial_driver, 0, sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver.driver_name = "su"; - serial_driver.name = "ttyS"; - serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW; - serial_driver.refcount = &serial_refcount; - serial_driver.table = serial_table; - serial_driver.termios = serial_termios; - serial_driver.termios_locked = serial_termios_locked; - - serial_driver.open = su_open; - serial_driver.close = su_close; - serial_driver.write = su_write; - serial_driver.put_char = su_put_char; - serial_driver.flush_chars = su_flush_chars; - serial_driver.write_room = su_write_room; - serial_driver.chars_in_buffer = su_chars_in_buffer; - serial_driver.flush_buffer = su_flush_buffer; - serial_driver.ioctl = su_ioctl; - serial_driver.throttle = su_throttle; - serial_driver.unthrottle = su_unthrottle; - serial_driver.send_xchar = su_send_xchar; - serial_driver.set_termios = su_set_termios; - serial_driver.stop = su_stop; - serial_driver.start = su_start; - serial_driver.hangup = su_hangup; - serial_driver.break_ctl = su_break; - serial_driver.wait_until_sent = su_wait_until_sent; - serial_driver.read_proc = su_read_proc; - - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - - if (tty_register_driver(&serial_driver)) - panic("Couldn't register regular su\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout su\n"); - - for (i = 0, info = su_table; i < NR_PORTS; i++, info++) { - info->magic = SSTATE_MAGIC; - info->line = i; - info->type = PORT_UNKNOWN; - info->baud_base = BAUD_BASE; - /* info->flags = 0; */ - info->custom_divisor = 0; - info->close_delay = 5*HZ/10; - info->closing_wait = 30*HZ; - info->callout_termios = callout_driver.init_termios; - info->normal_termios = serial_driver.init_termios; - info->icount.cts = info->icount.dsr = - info->icount.rng = info->icount.dcd = 0; - info->icount.rx = info->icount.tx = 0; - info->icount.frame = info->icount.parity = 0; - info->icount.overrun = info->icount.brk = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - - if (info->kbd_node) - info->cflag = B1200 | CS8 | CREAD; - else if (info->ms_node) - info->cflag = B4800 | CS8 | CREAD; - else - info->cflag = B9600 | CS8 | CREAD; - - autoconfig(info); - if (info->type == PORT_UNKNOWN) - continue; - - printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n", - info->name, info->port, __irq_itoa(info->irq), - uart_config[info->type].name); - - /* - * We want startup here because we want mouse and keyboard - * working without opening. On SPARC console will work - * without startup. - */ - if (info->kbd_node) { - startup(info); - keyboard_zsinit(su_put_char_kbd); - } else if (info->ms_node) { - startup(info); - sun_mouse_zsinit(); - } - } - - return 0; -} - -__initfunc(int su_probe (unsigned long *memory_start)) -{ - struct su_struct *info = su_table; - int node, enode, tnode, sunode; - int kbnode = 0, msnode = 0; - int devices = 0; - char prop[128]; - int len; - - /* - * Find su on MrCoffee. We return OK code if find any. - * Then su_init finds every one and initializes them. - * We do this early because MrCoffee got no aliases. - */ - node = prom_getchild(prom_root_node); - if ((node = prom_searchsiblings(node, "obio")) != 0) { - if ((sunode = prom_getchild(node)) != 0) { - if ((sunode = prom_searchsiblings(sunode, "su")) != 0) { - info->port_node = sunode; -#ifdef CONFIG_SERIAL_CONSOLE - /* - * Console must be initiated after the generic initialization. - * sunserial_setinitfunc inverts order, so call this before next one. - */ - sunserial_setinitfunc(memory_start, su_serial_console_init); -#endif - sunserial_setinitfunc(memory_start, su_init); - return 0; - } - } - } - - /* - * Get the nodes for keyboard and mouse from 'aliases'... - */ - node = prom_getchild(prom_root_node); - node = prom_searchsiblings(node, "aliases"); - if (!node) - return -ENODEV; - - len = prom_getproperty(node, "keyboard", prop, sizeof(prop)); - if (len > 0) { - prop[len] = 0; - kbnode = prom_finddevice(prop); - } - if (!kbnode) - return -ENODEV; - - len = prom_getproperty(node, "mouse", prop, sizeof(prop)); - if (len > 0) { - prop[len] = 0; - msnode = prom_finddevice(prop); - } - if (!msnode) - return -ENODEV; - - /* - * Find matching EBus nodes... - */ - node = prom_getchild(prom_root_node); - if ((node = prom_searchsiblings(node, "pci")) == 0) { - return -ENODEV; /* Plain sparc */ - } - - /* - * Check for SUNW,sabre on Ultra 5/10/AXi. - */ - len = prom_getproperty(node, "model", prop, sizeof(prop)); - if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) { - node = prom_getchild(node); - node = prom_searchsiblings(node, "pci"); - } - - /* - * For each PCI bus... - */ - while (node) { - enode = prom_getchild(node); - enode = prom_searchsiblings(enode, "ebus"); - - /* - * For each EBus on this PCI... - */ - while (enode) { - sunode = prom_getchild(enode); - tnode = prom_searchsiblings(sunode, "su"); - if (!tnode) - tnode = prom_searchsiblings(sunode, "su_pnp"); - sunode = tnode; - - /* - * For each 'su' on this EBus... - */ - while (sunode) { - /* - * Does it match? - */ - if (sunode == kbnode) { - info->kbd_node = sunode; - ++info; - ++devices; - } - if (sunode == msnode) { - info->ms_node = sunode; - ++info; - ++devices; - } - - /* - * Found everything we need? - */ - if (devices == NR_PORTS) - goto found; - - sunode = prom_getsibling(sunode); - tnode = prom_searchsiblings(sunode, "su"); - if (!tnode) - tnode = prom_searchsiblings(sunode, - "su_pnp"); - sunode = tnode; - } - enode = prom_getsibling(enode); - enode = prom_searchsiblings(enode, "ebus"); - } - node = prom_getsibling(node); - node = prom_searchsiblings(node, "pci"); - } - return -ENODEV; - -found: - sunserial_setinitfunc(memory_start, su_init); - rs_ops.rs_change_mouse_baud = su_change_mouse_baud; - sunkbd_setinitfunc(memory_start, sun_kbd_init); - kbd_ops.compute_shiftstate = sun_compute_shiftstate; - kbd_ops.setledstate = sun_setledstate; - kbd_ops.getledstate = sun_getledstate; - kbd_ops.setkeycode = sun_setkeycode; - kbd_ops.getkeycode = sun_getkeycode; -#ifdef CONFIG_PCI - sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, - sun_func_buf, sun_func_table, - sun_funcbufsize, sun_funcbufleft, - sun_accent_table, sun_accent_table_size); -#endif - return 0; -} - -#if 0 -#ifdef MODULE -int init_module(void) -{ - return su_init(); /* rs_init? su_probe? XXX */ -} - -void cleanup_module(void) -{ - unsigned long flags; - int e1, e2; - int i; - - /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - save_flags(flags); - cli(); - timer_active &= ~(1 << RS_TIMER); - timer_table[RS_TIMER].fn = NULL; - timer_table[RS_TIMER].expires = 0; - remove_bh(SERIAL_BH); - if ((e1 = tty_unregister_driver(&serial_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", - e2); - restore_flags(flags); - - for (i = 0; i < NR_PORTS; i++) { - if (su_table[i].type != PORT_UNKNOWN) - release_region(su_table[i].port, 8); - } - if (tmp_buf) { - free_page((unsigned long) tmp_buf); - tmp_buf = NULL; - } -} -#endif /* MODULE */ -#endif /* deadwood */ - -/* - * ------------------------------------------------------------ - * Serial console driver - * ------------------------------------------------------------ - */ -#ifdef CONFIG_SERIAL_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct su_struct *info) -{ - int lsr; - unsigned int tmout = 1000000; - - do { - lsr = su_inb(info, UART_LSR); - if (--tmout == 0) - break; - } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - */ -static void serial_console_write(struct console *co, const char *s, - unsigned count) -{ - struct su_struct *info; - int ier; - unsigned i; - - info = su_table + co->index; - /* - * First save the IER then disable the interrupts - */ - ier = su_inb(info, UART_IER); - su_outb(info, UART_IER, 0x00); - - /* - * Now, do each character - */ - for (i = 0; i < count; i++, s++) { - wait_for_xmitr(info); - - /* - * Send the character out. - * If a LF, also do CR... - */ - su_outb(info, UART_TX, *s); - if (*s == 10) { - wait_for_xmitr(info); - su_outb(info, UART_TX, 13); - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - wait_for_xmitr(info); - su_outb(info, UART_IER, ier); -} - -/* - * Receive character from the serial port - */ -static int serial_console_wait_key(struct console *co) -{ - struct su_struct *info; - int ier; - int lsr; - int c; - - info = su_table + co->index; - - /* - * First save the IER then disable the interrupts so - * that the real driver for the port does not get the - * character. - */ - ier = su_inb(info, UART_IER); - su_outb(info, UART_IER, 0x00); - - do { - lsr = su_inb(info, UART_LSR); - } while (!(lsr & UART_LSR_DR)); - c = su_inb(info, UART_RX); - - /* - * Restore the interrupts - */ - su_outb(info, UART_IER, ier); - - return c; -} - -static kdev_t serial_console_device(struct console *c) -{ - return MKDEV(TTY_MAJOR, 64 + c->index); -} - -/* - * Setup initial baud/bits/parity. We do two things here: - * - construct a cflag setting for the first su_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -__initfunc(static int serial_console_setup(struct console *co, char *options)) -{ - struct su_struct *info; - unsigned cval; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int cflag = CREAD | HUPCL | CLOCAL; - int quot = 0; - char *s; - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while(*s >= '0' && *s <= '9') - s++; - if (*s) parity = *s++; - if (*s) bits = *s - '0'; - } - - /* - * Now construct a cflag setting. - */ - switch(baud) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - case 9600: - default: - cflag |= B9600; - break; - } - switch(bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; - } - switch(parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - - /* - * Divisor, bytesize and parity - */ - info = su_table + co->index; - quot = BAUD_BASE / baud; - cval = cflag & (CSIZE | CSTOPB); -#if defined(__powerpc__) || defined(__alpha__) - cval >>= 8; -#else /* !__powerpc__ && !__alpha__ */ - cval >>= 4; -#endif /* !__powerpc__ && !__alpha__ */ - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * Disable UART interrupts, set DTR and RTS high - * and set speed. - */ - su_outb(info, UART_IER, 0); - su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); - su_outb(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - su_outb(info, UART_DLL, quot & 0xff); /* LS of divisor */ - su_outb(info, UART_DLM, quot >> 8); /* MS of divisor */ - su_outb(info, UART_LCR, cval); /* reset DLAB */ - info->quot = quot; - - /* - * If we read 0xff from the LSR, there is no UART here. - */ - if (su_inb(info, UART_LSR) == 0xff) - return -1; - - return 0; -} - -static struct console sercons = { - "ttyS", - serial_console_write, - NULL, - serial_console_device, - serial_console_wait_key, - NULL, - serial_console_setup, - CON_PRINTBUFFER, - -1, - 0, - NULL -}; - -/* - * Register console. - */ -__initfunc(int su_serial_console_init(void)) -{ - extern int con_is_present(void); - - if (con_is_present()) - return 0; - if (serial_console == 0) - return 0; - if (su_table[0].port == 0 || su_table[0].port_node == 0) - return 0; - sercons.index = 0; - register_console(&sercons); - return 0; -} - -#endif /* CONFIG_SERIAL_CONSOLE */ diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c --- v2.1.126/linux/drivers/sbus/char/sunserial.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/sunserial.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: sunserial.c,v 1.66 1998/09/21 05:48:48 jj Exp $ +/* $Id: sunserial.c,v 1.67 1998/10/25 03:22:46 jj Exp $ * serial.c: Serial port driver infrastructure for the Sparc. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -399,6 +399,14 @@ if (!ret) return memory_start; + +#ifdef __sparc_v9__ + ret = prom_finddevice("/ssp-serial"); + if (ret && ret != -1) { + /* Hello, Starfire. Pleased to meet you :) */ + return memory_start; + } +#endif prom_printf("No serial devices found, bailing out.\n"); prom_halt(); diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.126/linux/drivers/sbus/char/vfc_dev.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/vfc_dev.c Tue Oct 27 09:52:21 1998 @@ -218,7 +218,7 @@ return -ENOMEM; if(copy_from_user(buffer, inout.buffer, - inout.len*sizeof(char));) { + inout.len*sizeof(char))) { kfree_s(buffer,inout.len*sizeof(char)); return -EFAULT; } diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/char/zs.c linux/drivers/sbus/char/zs.c --- v2.1.126/linux/drivers/sbus/char/zs.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/char/zs.c Thu Nov 5 09:58:44 1998 @@ -1,4 +1,4 @@ -/* $Id: zs.c,v 1.29 1998/09/21 05:06:53 jj Exp $ +/* $Id: zs.c,v 1.31 1998/10/07 11:35:29 jj Exp $ * zs.c: Zilog serial port driver for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -1354,10 +1354,9 @@ if (!info->port) return; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; cli(); write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK)); - schedule(); + schedule_timeout(duration); write_zsreg(info->zs_channel, 5, info->curregs[5]); sti(); } @@ -1543,8 +1542,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } @@ -1808,7 +1806,7 @@ static void show_serial_version(void) { - char *revision = "$Revision: 1.29 $"; + char *revision = "$Revision: 1.31 $"; char *version, *p; version = strchr(revision, ' '); @@ -1830,6 +1828,7 @@ get_zs(int chip)) { unsigned int vaddr[2] = { 0, 0 }; + unsigned long mapped_addr = 0; int busnode, seen, zsnode, sun4u_ino; static int irq = 0; @@ -1854,7 +1853,30 @@ int len = prom_getproperty(zsnode, "address", (void *) vaddr, sizeof(vaddr)); - if(len % sizeof(unsigned int)) { + if(len == -1) { + struct linux_sbus *sbus; + struct linux_sbus_device *sdev = NULL; + + /* "address" property is not guarenteed, + * everything in I/O is implicitly mapped + * anyways by our clever TLB miss handling + * scheme, so don't fail here. -DaveM + */ + for_each_sbus(sbus) { + for_each_sbusdev(sdev, sbus) { + if (sdev->prom_node == zsnode) + goto found; + } + } + found: + if (sdev == NULL) + prom_halt(); + prom_apply_sbus_ranges(sbus, sdev->reg_addrs, 1, sdev); + mapped_addr = (unsigned long) + sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0, + PAGE_SIZE, "Zilog Registers", + sdev->reg_addrs[0].which_io, 0x0); + } else if(len % sizeof(unsigned int)) { prom_printf("WHOOPS: proplen for %s " "was %d, need multiple of " "%d\n", "address", len, @@ -1883,9 +1905,12 @@ } if(!zsnode) panic("get_zs: whee chip not found"); - if(!vaddr[0]) + if(!vaddr[0] && !mapped_addr) panic("get_zs: whee no serial chip mappable"); - return (struct sun_zslayout *)(unsigned long) vaddr[0]; + if (mapped_addr != 0) + return (struct sun_zslayout *) mapped_addr; + else + return (struct sun_zslayout *) (unsigned long) vaddr[0]; } #else /* !(__sparc_v9__) */ __initfunc(static struct sun_zslayout * @@ -2119,7 +2144,7 @@ kbd_ops.getledstate = sun_getledstate; kbd_ops.setkeycode = sun_setkeycode; kbd_ops.getkeycode = sun_getkeycode; -#ifdef CONFIG_PCI +#if defined(__sparc_v9__) && defined(CONFIG_PCI) sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count, sun_func_buf, sun_func_table, sun_funcbufsize, sun_funcbufleft, diff -u --recursive --new-file v2.1.126/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v2.1.126/linux/drivers/sbus/sbus.c Mon Oct 5 13:13:40 1998 +++ linux/drivers/sbus/sbus.c Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: sbus.c,v 1.72 1998/09/05 17:25:51 jj Exp $ +/* $Id: sbus.c,v 1.73 1998/10/07 11:35:50 jj Exp $ * sbus.c: SBus support routines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -278,8 +278,16 @@ if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || (nd = prom_getchild(iommund)) == 0 || (nd = prom_searchsiblings(nd, "sbus")) == 0) { +#ifdef CONFIG_PCI + if (!pcibios_present()) { + prom_printf("Neither SBUS nor PCI found.\n"); + prom_halt(); + } + return; +#else /* No reason to run further - the data access trap will occur. */ panic("sbus not found"); +#endif } } diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.126/linux/drivers/scsi/ChangeLog.ncr53c8xx Fri Oct 9 13:27:10 1998 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Oct 25 14:46:44 1998 @@ -1,3 +1,26 @@ +Wed Oct 21 21:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.1a + - Changes from Eddie Dost for Sparc and Alpha: + ioremap/iounmap support for Sparc. + pcivtophys changed to bus_dvma_to_phys. + - Add the 53c876 description to the chip table. This is only usefull + for printing the right name of the controller. + - DEL-441 Item 2 work-around for the 53c876 rev <= 5 (0x15). + - Add additionnal checking of INQUIRY data: + Check INQUIRY data received length is at least 7. Byte 7 of + inquiry data contains device features bits and the driver might + be confused by garbage. Also check peripheral qualifier. + - Cleanup of the SCSI tasks management: + Remove the special case for 32 tags. Now the driver only uses the + scheme that allows up to 64 tags per LUN. + Merge some code from the 896 driver. + Use a 1,3,5,...MAXTAGS*2+1 tag numbering. Previous driver could + use any tag number from 1 to 253 and some non conformant devices + might have problems with large tag numbers. + - 'no_sync' changed to 'no_disc' in the README file. This is an old + and trivial mistake that seems to demonstrate the README file is + not often read. :) + Sun Oct 4 14:00 1998 Gerard Roudier (groudier@club-internet.fr) * revision 3.0i - Cosmetic changes for sparc (but not for the driver) that needs diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.126/linux/drivers/scsi/Config.in Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/Config.in Wed Nov 4 11:27:23 1998 @@ -75,7 +75,7 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then - int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 + int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 4 int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE @@ -104,8 +104,11 @@ dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI -if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then - dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI + if [ "$CONFIG_SCSI_DC390T" != "n" ]; then + bool ' _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP + fi fi dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.126/linux/drivers/scsi/README.ncr53c8xx Wed Jul 1 19:38:54 1998 +++ linux/drivers/scsi/README.ncr53c8xx Sun Oct 25 14:46:44 1998 @@ -4,7 +4,7 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -27 June 1998 +18 October 1998 =============================================================================== 1. Introduction @@ -21,7 +21,7 @@ 8.4 Set order type for tagged command 8.5 Set debug mode 8.6 Clear profile counters - 8.7 Set flag (no_sync) + 8.7 Set flag (no_disc) 8.8 Set verbose level 9. Configuration parameters 10. Boot setup commands @@ -424,7 +424,7 @@ The "clearprof" command allows you to clear these counters at any time. -8.7 Set flag (no_sync) +8.7 Set flag (no_disc) setflag @@ -432,11 +432,11 @@ For the moment, only one flag is available: - no_sync: not allow target to disconnect. + no_disc: not allow target to disconnect. Do not specify any flag in order to reset the flag. For example: - setflag 4 - will reset no_sync flag for target 4, so will allow it disconnections. + will reset no_disc flag for target 4, so will allow it disconnections. - setflag all will allow disconnection for all devices on the SCSI bus. @@ -1067,7 +1067,7 @@ Will enable fast synchronous data transfer negotiation for all targets. - echo "setflag 3" >/proc/scsi/ncr53c8xx/0 - Will reset flags (no_sync) for target 3, and so will allow it to disconnect + Will reset flags (no_disc) for target 3, and so will allow it to disconnect the SCSI Bus. - echo "settags 3 8" >/proc/scsi/ncr53c8xx/0 diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/README.tmscsim linux/drivers/scsi/README.tmscsim --- v2.1.126/linux/drivers/scsi/README.tmscsim Wed Dec 31 16:00:00 1969 +++ linux/drivers/scsi/README.tmscsim Tue Oct 27 10:10:08 1998 @@ -0,0 +1,413 @@ +The tmscsim driver +================== + +1. Purpose and history +2. Installation +3. Features +4. Configuration via /proc/scsi/tmscsim/? +5. Configuration via boot/module params +6. Potential improvements +7. Bug reports, debugging and updates +8. Acknowledgements + + +1. Purpose and history +---------------------- +The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974 +chip. AM53C974 based SCSI adapters include: + Tekram DC390, DC390T + Dawicontrol 2974 + some on-board adapters +(This is most probably not a complete list) + +It has originally written by C.L. Huang from the Tekram corp. to support the +Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram +scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F +(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter, +tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more, +as the ncr53c8xx is perfectly supporting these adpaters since some time. + +The driver first appeared in April 1996, exclusively supported the DC390 +and has been enhanced since then in various steps. In May 1998 support for +general AM53C974 based adapters and some possibilities to configure it were +added. The non-DC390 support works by assuming some values for the data +normally taken from the DC390 EEPROM. See below (chapter 5) for details. + +When using the DC390, the configuration is still be done using the DC390 +BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or +module parameters (chapter 5) are ignored! However, you can change settings +dynamically, as described in chapter 4. + +For a more detailed description of the driver's history, see the first lines +of tmscsim.c. +The numbering scheme isn't consistent. The first versions went from 1.00 to +1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So +the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental), +2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send +fixes to people for testing, those will have a digit appended, e.g. 2.0a1. + + +2. Installation +--------------- +If you got any recent kernel with this driver and document included in +linux/drivers/scsi, you basically have to do nothing special to use this +driver. Of course you have to choose to compile SCSI support and DC390(T) +support into your kernel or as module when configuring your kernel for +compiling. + +If you got an older kernel with an old version of this driver included, you +should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and +README.tmscsim) from this directory to linux/drivers/scsi. You have to +recompile your kernel/module of course. + +You should apply the three patches included in dc390-20-kernel.diff +(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff) +The patches are against 2.1.103, so you might have to manually resolve +rejections when applying to another kernel version. + +The patches will update the kernel startup code to allow boot parameters to +be passed to the driver, update the Documentation and finally offer you the +possibility to omit the non-DC390 parts of the driver. +(By selecting "Omit support for non DC390" you basically disable the +emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes +of memory.) + +If you got a very old kernel without the tmscsim driver (pre 2.0.31) +I recommend upgrading your kernel. However, if you don't want to, please +contact me to get the appropriate patches. + +Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has +proven stable on many systems, but it's still a good idea to take some +precautions. In an ideal world you would have a full backup of your disks. +The world isn't ideal and most people don't have full backups (me neither). +So take at least the following two measures: +* make your kernel remount the FS read-only on detecting an error: + tune2fs -e remount-ro /dev/sd?? +* have copies of your SCSI disk's partition tables on some safe location: + dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1 +* make sure you are able to boot Linux (e.g. from floppy disk using InitRD) + if your SCSI disk gets corrupted. You can use + ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz + +One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram +DC390F (Sym53c875) accepted this as well as my Millenium. But the Am53C974 +produced errors and started to corrupt my disks. So don't do that! A 37.50 +MHz PCI bus works for me, though, but I don't recommend using higher clocks +than the 33.33 MHz being in the PCI spec. + +If you want to share the IRQ with another device and the driver refuses to +do, you might succeed with changing the DC390_IRQ type in tmscsim.c to +SA_SHIRQ | SA_INTERRUPT. + + +3.Features +---------- +- SCSI + * Tagged queueing + * Sync speed up to 10 MHz + * Disconnection + * Multiple LUNs + +- General / Linux interface + * Support for up to 4 adapters. + * DC390 EEPROM usage or boot/module params + * Information via cat /proc/scsi/tmscsim/? + * Dynamically configurable by writing to /proc/scsi/tmscsim/? + * Dynamic allocation of resources + * SMP support: Adapter specific locks (Linux 2.1.x) + * Uniform source code for Linux-2.x.y + * Support for dyn. addition/removal of devices via add/remove-single-device + (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi + H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care! + * Try to use the partition table for the determination of the mapping + + +4. Configuration via /proc/scsi/tmscsim/? +----------------------------------------- +First of all look at the output of /proc/scsi/tmscsim/? by typing + cat /proc/scsi/tmscsim/? +The "?" should be replaced by the SCSI host number. (The shell might do this +for you.) +You will see some info regarding the adapter and, at the end, a listing of +the attached devices and their settings. + +Here's an example: +garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0 +Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20 +SCSI Host Nr 0, AM53C974 Adapter Nr 0 +IOPortBase 0x6200, IRQLevel 0x09 +MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms +TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns +Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0 + Nr of lost arbitrations 17 +Nr of attached devices: 4, Nr of DCBs: 4 +Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs +00 00 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 +01 01 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 +02 03 00 Yes Yes Yes Yes No No 100 ns 10.0 M 15 +03 05 00 Yes No Yes Yes No No (200 ns) + +Note that the settings MaxID and MaxLUN are not zero- but one-based, which +means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This +is somehow inconvenient, but the way the mid-level SCSI code expects it to be. + +ACB and DCB are acronyms for Adapter Control Block and Device Control Block. +These are data structures of the driver containing information about the +adapter and the connected SCSI devices respectively. + +Idx is the device index (just a consecutive number for the driver), ID and +LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous +negotiation, DsCn Disconnection, SndS Send Start command on startup (not +used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and +SyncSpeed are somehow redundant, because they are reciprocal values +(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the +NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know +if certain devices will have problems with this discrepancy. Max. speed is +10 MHz corresp. to a min. NegoPeriod of 100 ns. +(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept +it, but that's out of adapter spec, on your own risk and unlikely to improve +performance. You're likely to crash your disks.) +SyncOffs is the offset used for synchronous negotiations; max. is 15. +The last values are only shown, if Sync is enabled. (NegoPeriod is still +displayed in brackets to show the values which will be used after enabling +Sync.) +The STOP parameter is for testing/debugging purposes only and should bet set +to No. Please don't fiddle with it, unless you want to get rid of the +contents of your disk. + +If you want to change a setting, you can do that by writing to +/proc/scsi/tmscsim/?. Basically you have to imitate the output of driver. +(Don't use the brackets for NegoPeriod on Sync disabled devices.) +You don't have to care about capitalisation. The driver will accept space, +tab, comma, = and : as separators. + +There are three kinds of changes: + +(1) Change driver settings: + You type the names of the parameters and the params following it. + Example: + echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0 + + Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut, + TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you + want to see what happens, if the driver hangs. + +(2) Change device settings: You write a config line to the driver. The Nr + must match the ID and LUN given. If you give "-" as parameter, it is + ignored and the corresponding setting won't be changed. + You can use "y" or "n" instead of "Yes" and "No" if you want to. + You don't need to specify a full line. The driver automatically performs + an INQUIRY on the device if necessary to check if it is capable to operate + with the given settings (Sync, TagQ). + Examples: + echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0 + echo "3 5 0 y n y" >/proc/scsi/tmscsim/0 + + To give a short explanation of the first example: + The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0), + select the device to which the following parameters apply. Note that it + would be sufficient to use the index or both SCSI ID and LUN, but I chose + to require all three to have a syntax similar to the output. + The following "y y y - y" enables Parity checking, enables Synchronous + transfers, Disconnection, leaves Send Start (not used) untouched and + enables Tagged Command Queueing for the selected device. The "-" skips + the Negotiation Period setting but the "10" sets the max sync. speed to + 10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as + discussed above. The values used in this example will result in maximum + performance. + +(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and + the removal of a device's DCB. + This is only used for debugging when you meet problems. The parameter of + the INQUIRY and remove command is the device index as shown by the + output of /proc/scsi/tmscsim/? in the device listing in the first column + (Idx). + Examples: + echo "reset" >/proc/scsi/tmscsim/0 + echo "inquiry 1" >/proc/scsi/tmscsim/0 + echo "remove 2" >/proc/scsi/tmscsim/1 + + Note that you will meet problems when you remove a device's DCB with the + remove command if it contains partitions which are mounted. Only use it + after unmounting its partitions, telling the SCSI mid-level code to + remove it (scsi remove-single-device) and you really need a few bytes of + memory. + + +I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing +settings to see if everything changed as requested. + + +5. Configuration via boot/module parameters +------------------------------------------- +With the DC390, the driver reads its EEPROM settings and IGNORES boot / +module parameters. If you want to override the EEPROM settings of a DC390, +you have to use the /proc/scsi/tmscsim/? interface described in the above +chapter. + +However, if you do have another AM53C974 based adapter you might want to +adjust some settings before you are able to write to the /proc/scsi/tmscsim/? +pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that +the log message "DC390: No EEPROM found!" is normal without a DC390.) +For this purpose, you can pass options to the driver before it is initialised +by using kernel or module parameters. See lilo(8) or modprobe(1) manual +pages on how to pass params to the kernel or a module. + +The syntax of the params is much shorter than the syntax of the /proc/... +interface. This makes it a little bit more difficult to use. However, long +parameter lines have the risk to be misinterpreted and the length of kernel +parameters is limited. + +As the support for non-DC390 adapters works by simulating the values of the +DC390 EEPROM, the settings are given in a DC390 BIOS' way. + +Here's the syntax: +tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds + +Each of the parameters is a number, containing the described information: + +* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7 + Default is 7. + +* SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values + 0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is + 1 (8.0 MHz). + +* DevMode is a bit mapped value describing the per-device features. It + applies to all devices. (Sync, Disc and TagQ will only apply, if the + device supports it.) The meaning of the bits (* = default): + + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Parity check + *1 0x02 2 Synchronous Negotiation + *2 0x04 4 Disconnection + *3 0x08 8 Send Start command on startup. (Not used) + *4 0x10 16 Tagged Queueing + + As usual, the desired value is obtained by adding the wanted values. If + you want to enable all values, e.g., you would use 31(0x1f). Default is 31. + +* AdaptMode is a bit mapped value describing the enabled adapter features. + + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Support more than two drives. (Not used) + *1 0x02 2 Use DOS compatible mapping for HDs greater than 1GB. + *2 0x04 4 Reset SCSI Bus on startup. + *3 0x08 8 Active Negation: Improves SCSI Bus noise immunity. + 4 0x10 16 Immediate return on BIOS seek command. (Not used) + (*)5 0x20 32 Check for LUNs >= 1. + + The default for LUN Check depends on CONFIG_SCSI_MULTI_LUN. + +* TaggedCmnds is a number indicating the maximum number of Tagged Commands. + It is the binary logarithm - 1 of the actual number. Max is 4 (32). + Value Number of Tagged Commands + 0 2 + 1 4 + 2 8 + *3 16 + 4 32 + +Example: + modprobe tmscsim tmscsim=6,2,31 +would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device +features and leave the adapter features and the number of Tagged Commands +to the defaults. + +As you can see, you don't need to specify all of the five params. + +The defaults (7,1,31,15,3) are aggressive to allow good performance. You can +use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is +perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut +for tmscsim=7,4,9,15,2. + + +6. Potential improvements +------------------------- +Most of the intended work on the driver has been done. Here are a few ideas +to further improve its usability: + +* More intelligent abort() routine +* Implement new_eh code (Linux-2.1+) +* Have the mid-level code (and not the driver) handle more of the various + conditions. +* Rework command queueing in the driver +* More user friendly boot/module param syntax + +Further investigation on these problems: + +* TagQ and Disconnection (Resel: SRB Tag Seleection) +* Problems with IRQ sharing (IO-APIC on SMP Systems) (??) +* Driver crashes with readcdda (xcdroast) + +Known problems: + +* There was a report that with a certain Scanner, the last SCSI command + won't be finished correctly. This might be a command queueing bug or a bug + in SCSI implementation of the scanner. Issueing another command to the + scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where + x is the index (not the SCSI ID!) of the scanner. See 4.(3).) +* If there is a valid partition table, the driver will use it for determing + the mapping. Other operating systems may not like this mapping, though + it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the + partition table and used a H/S = 64/32 or 255/63 translation. So if you + want to be compatible to those, use this old mapping when creating + partition tables. +* In some situations, the driver will get stuck in an abort loop. Please + disable DsCn, if you meet this problem. Please contact me for further + debugging. +* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c + There used to be a patch included here, which partially solved the + problem. I suggest you contact Chiaki Ishikawa , + Richard Waltham or Doug Ledford + , if you want to help further debugging it. +* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because + the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply + the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa. + I was told that this fix will be in 2.0.36, so you don't need it for + 2.0.36. +[The patch file is contained in the dc390-XXX.tar.gz files which can be found +on the ftp server. See below.] + + +7. Bug reports, debugging and updates +------------------------------------- +Whenever you have problems with the driver, you are invited to ask the +author for help. However, I'd suggest reading the docs and trying to solve +the problem yourself, first. +If you find something, which you believe to be a bug, please report it to me. +Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and +maybe the DC390 log messages to the report. + +Bug reports should be send to me (Kurt Garloff ) as well +as to the linux-scsi list (), as sometimes bugs +are caused by the SCSI mid-level code. + +I will ask you for some more details and probably I will also ask you to +enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX +defines). The driver will produce some data for the syslog facility then. +Beware: If your syslog gets written to a SCSI disk connected to your +AM53C974, the logging might produce log output again, and you might end +having your box spending most of its time doing the logging. + +The latest version of the driver can be found at: +ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ + + +8. Acknowledgements +------------------- +Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF +people, the XFree86 team and all the others for the wonderful OS and +software. +Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver +release and support. +Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding. +Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert +Tonneau) for intensively testing the driver (and even risking data loss +doing this during early revisions). + + +------------------------------------------------------------------------- +Written by Kurt Garloff 1998/06/11 +Last updated 1998/10/15, driver revision 2.0b +$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $ diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v2.1.126/linux/drivers/scsi/aic7xxx.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/aic7xxx.c Fri Nov 6 14:01:13 1998 @@ -349,7 +349,7 @@ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -#define AIC7XXX_C_VERSION "5.1.2" +#define AIC7XXX_C_VERSION "5.1.3" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -3429,10 +3429,7 @@ * here so that we can delay all re-sent commands for this device for the * 4 seconds and then have our timer routine pick them back up. */ - if(p->dev_timer[i].expires) - { - del_timer(&p->dev_timer[i]); - } + del_timer(&p->dev_timer[i]); p->dev_timer[i].expires = jiffies + (4 * HZ); add_timer(&p->dev_timer[i]); } @@ -3481,12 +3478,8 @@ "delayed_scbs queue!\n", p->host_no, channel, i, lun); scbq_init(&p->delayed_scbs[i]); } - if ( (p->delayed_scbs[i].head == NULL) && - (p->dev_timer[i].expires) ) - { + if ( p->delayed_scbs[i].head == NULL ) del_timer(&p->dev_timer[i]); - p->dev_timer[i].expires = 0; - } } } @@ -4007,7 +4000,7 @@ } if ( (p->dev_active_cmds[tindex] >= p->dev_temp_queue_depth[tindex]) || - (p->dev_last_reset[tindex] >= (jiffies - (4 * HZ))) ) + time_after_eq(p->dev_last_reset[tindex], jiffies - 4 * HZ) ) { #ifdef AIC7XXX_VERBOSE_DEBUGGING if (aic7xxx_verbose > 0xffff) @@ -4015,7 +4008,7 @@ p->host_no, CTL_OF_SCB(scb)); #endif scbq_insert_tail(&p->delayed_scbs[tindex], scb); - if ( !(p->dev_timer[tindex].expires) && + if ( !timer_pending(&p->dev_timer[tindex]) && !(p->dev_active_cmds[tindex]) ) { p->dev_timer[tindex].expires = p->dev_last_reset[tindex] + (4 * HZ); @@ -4154,15 +4147,8 @@ #endif for(i=0; idev_timer[i].expires) && - (p->dev_timer[i].expires <= jiffies) ) + if ( del_timer(&p->dev_timer[i]) ) { - p->dev_timer[i].expires = 0; - if ( (p->dev_timer[i].prev != NULL) || - (p->dev_timer[i].next != NULL) ) - { - del_timer(&p->dev_timer[i]); - } p->dev_temp_queue_depth[i] = p->dev_max_queue_depth[i]; j = 0; while ( ((scb = scbq_remove_head(&p->delayed_scbs[i])) != NULL) && @@ -4895,7 +4881,7 @@ p->activescbs--; scb->flags |= SCB_WAITINGQ | SCB_WAS_BUSY; - if (p->dev_timer[tindex].expires == 0) + if ( !timer_pending(&p->dev_timer[tindex]) ) { if ( p->dev_active_cmds[tindex] ) { @@ -7462,7 +7448,7 @@ } p->host = host; - p->last_reset = 0; + p->last_reset = jiffies; p->host_no = host->host_no; host->unique_id = p->instance; p->isr_count = 0; @@ -7489,7 +7475,7 @@ p->dev_commands_sent[i] = 0; p->dev_flags[i] = 0; p->dev_active_cmds[i] = 0; - p->dev_last_reset[i] = 0; + p->dev_last_reset[i] = jiffies; p->dev_last_queue_full[i] = 0; p->dev_last_queue_full_count[i] = 0; p->dev_max_queue_depth[i] = 1; @@ -7497,7 +7483,6 @@ p->dev_mid_level_queue_depth[i] = 3; scbq_init(&p->delayed_scbs[i]); init_timer(&p->dev_timer[i]); - p->dev_timer[i].expires = 0; p->dev_timer[i].data = (unsigned long)p; p->dev_timer[i].function = (void *)aic7xxx_timer; } @@ -9184,6 +9169,27 @@ aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | CACHETHEN | MPARCKEN) & ~DPARCKEN, DSCOMMAND0); + aic7xxx_load_seeprom(temp_p, &sxfrctl1); + break; + case AHC_AIC7880: + /* + * Only set the DSCOMMAND0 register if this is a Rev B. + * chipset. For those, we also enable Ultra mode by + * force due to brain-damage on the part of some BIOSes + * We overload the devconfig variable here since we can. + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) + pci_read_config_dword(pdev, DEVCONFIG, &devconfig); +#else + pcibios_read_config_dword(pci_bus, pci_devfn, DEVCONFIG, + &devconfig); +#endif + if ((devconfig & 0xff) >= 1) + { + aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | + CACHETHEN | MPARCKEN) & ~DPARCKEN, + DSCOMMAND0); + } aic7xxx_load_seeprom(temp_p, &sxfrctl1); break; } diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h --- v2.1.126/linux/drivers/scsi/dc390.h Fri Jul 31 17:07:58 1998 +++ linux/drivers/scsi/dc390.h Sat Nov 7 11:29:55 1998 @@ -4,16 +4,20 @@ * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ +/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */ #include /* - * AMD 53C974 driver, header file + * DC390/AMD 53C974 driver, header file */ #ifndef DC390_H #define DC390_H +#define DC390_BANNER "Tekram DC390/AM53C974" +#define DC390_VERSION "2.0b 1998/10/24" + #if defined(HOSTS_C) || defined(MODULE) #include @@ -30,24 +34,24 @@ # define DC390_release NULL #endif -extern struct proc_dir_entry proc_scsi_tmscsim; -extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +extern struct proc_dir_entry DC390_proc_scsi_tmscsim; +extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); -#define DC390_T { \ - proc_dir: &proc_scsi_tmscsim, \ - proc_info: tmscsim_proc_info, \ - name: "Tekram DC390(T) V1.12 Feb-25-1998",\ - detect: DC390_detect, \ - release: DC390_release, \ - queuecommand: DC390_queue_command, \ - abort: DC390_abort, \ - reset: DC390_reset, \ - bios_param: DC390_bios_param, \ - can_queue: 10, \ - this_id: 7, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 2, \ - use_clustering: DISABLE_CLUSTERING \ +#define DC390_T { \ + proc_dir: &DC390_proc_scsi_tmscsim, \ + proc_info: DC390_proc_info, \ + name: DC390_BANNER " V" DC390_VERSION, \ + detect: DC390_detect, \ + release: DC390_release, \ + queuecommand: DC390_queue_command, \ + abort: DC390_abort, \ + reset: DC390_reset, \ + bios_param: DC390_bios_param, \ + can_queue: 17, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 8, \ + use_clustering: DISABLE_CLUSTERING \ } #endif /* defined(HOSTS_C) || defined(MODULE) */ diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.126/linux/drivers/scsi/ncr53c8xx.c Fri Oct 9 13:27:11 1998 +++ linux/drivers/scsi/ncr53c8xx.c Sun Oct 25 14:46:44 1998 @@ -73,7 +73,7 @@ */ /* -** October 4 1998, version 3.0i +** October 21 1998, version 3.1a ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -169,9 +169,11 @@ #endif /* -** Define the BSD style u_int32 type +** Define the BSD style u_int32 and u_int64 type. +** Are in fact u_int32_t and u_int64_t :-) */ typedef u32 u_int32; +typedef u64 u_int64; #include "ncr53c8xx.h" @@ -366,25 +368,14 @@ #define NO_TAG (255) /* -** For more than 32 TAGS support, we do some address calculation -** from the SCRIPTS using 2 additionnal SCR_COPY's and a fiew -** bit handling on 64 bit integers. For these reasons, support for -** 32 up to 64 TAGS is compiled conditionnaly. +** Choose appropriate type for tag bitmap. */ - -#if SCSI_NCR_MAX_TAGS <= 32 -struct nlink { - ncrcmd l_cmd; - ncrcmd l_paddr; -}; +#if SCSI_NCR_MAX_TAGS > 32 +typedef u_int64 tagmap_t; #else -struct nlink { - ncrcmd l_paddr; -}; -typedef u64 u_int64; +typedef u_int32 tagmap_t; #endif - /* ** Number of targets supported by the driver. ** n permits target numbers 0..n-1. @@ -583,16 +574,12 @@ #define iounmap vfree #endif -#ifdef __sparc__ +#if defined (__sparc__) #include -#define remap_pci_mem(base, size) ((vm_offset_t) __va(base)) -#define unmap_pci_mem(vaddr, size) -#define pcivtophys(p) ((p) & pci_dvma_mask) -#else -#if defined(__alpha__) -#define pcivtophys(p) ((p) & 0xfffffffful) +#elif defined (__alpha__) +#define bus_dvma_to_mem(p) ((p) & 0xfffffffful) #else -#define pcivtophys(p) (p) +#define bus_dvma_to_mem(p) (p) #endif #ifndef NCR_IOMAPPED @@ -615,7 +602,6 @@ iounmap((void *) (vaddr & PAGE_MASK)); } #endif /* !NCR_IOMAPPED */ -#endif /* __sparc__ */ /* ** Insert a delay in micro-seconds and milli-seconds. @@ -1488,8 +1474,8 @@ ** 64 possible tags. **---------------------------------------------------------------- */ - struct nlink jump_ccb_0; /* Default table if no tags */ - struct nlink *jump_ccb; /* Virtual address */ + u_int32 jump_ccb_0; /* Default table if no tags */ + u_int32 *jump_ccb; /* Virtual address */ /*---------------------------------------------------------------- ** CCB queue management. @@ -1514,11 +1500,7 @@ */ u_char ia_tag; /* Allocation index */ u_char if_tag; /* Freeing index */ -#if SCSI_NCR_MAX_TAGS <= 32 - u_char cb_tags[32]; /* Circular tags buffer */ -#else - u_char cb_tags[64]; /* Circular tags buffer */ -#endif + u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer */ u_char usetags; /* Command queuing is active */ u_char maxtags; /* Max nr of tags asked by user */ u_char numtags; /* Current number of tags */ @@ -1528,14 +1510,13 @@ ** QUEUE FULL control and ORDERED tag control. **---------------------------------------------------------------- */ + /*---------------------------------------------------------------- + ** QUEUE FULL and ORDERED tag control. + **---------------------------------------------------------------- + */ u_short num_good; /* Nr of GOOD since QUEUE FULL */ -#if SCSI_NCR_MAX_TAGS <= 32 - u_int tags_umap; /* Used tags bitmap */ - u_int tags_smap; /* Tags in use at 'tag_stime' */ -#else - u_int64 tags_umap; /* Used tags bitmap */ - u_int64 tags_smap; /* Tags in use at 'tag_stime' */ -#endif + tagmap_t tags_umap; /* Used tags bitmap */ + tagmap_t tags_smap; /* Tags in use at 'tag_stime' */ u_long tags_stime; /* Last time we set smap=umap */ ccb_p held_ccb; /* CCB held for QUEUE FULL */ }; @@ -2065,18 +2046,10 @@ ncrcmd loadpos1 [ 4]; #endif ncrcmd resel_lun [ 6]; -#if SCSI_NCR_MAX_TAGS <= 32 - ncrcmd resel_tag [ 8]; -#else ncrcmd resel_tag [ 6]; ncrcmd jump_to_nexus [ 4]; ncrcmd nexus_indirect [ 4]; -#endif -#if SCSI_NCR_MAX_TAGS <= 32 - ncrcmd resel_notag [ 4]; -#else ncrcmd resel_notag [ 4]; -#endif ncrcmd data_in [MAX_SCATTERL * 4]; ncrcmd data_in2 [ 4]; ncrcmd data_out [MAX_SCATTERL * 4]; @@ -2987,18 +2960,12 @@ /* ** Read the TAG from the SIDL. ** Still an aggressive optimization. ;-) + ** Compute the CCB indirect jump address which + ** is (#TAG*2 & 0xfc) due to tag numbering using + ** 1,3,5..MAXTAGS*2+1 actual values. */ - SCR_FROM_REG (sidl), - 0, - /* - ** JUMP indirectly to the restart point of the CCB. - */ -#if SCSI_NCR_MAX_TAGS <= 32 - SCR_SFBR_REG (temp, SCR_AND, 0xf8), + SCR_REG_SFBR (sidl, SCR_SHL, 0), 0, - SCR_RETURN, - 0, -#else SCR_SFBR_REG (temp, SCR_AND, 0xfc), 0, }/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{ @@ -3011,7 +2978,6 @@ RADDR (temp), SCR_RETURN, 0, -#endif }/*-------------------------< RESEL_NOTAG >-------------------*/,{ /* ** No tag expected. @@ -3019,13 +2985,8 @@ */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin), -#if SCSI_NCR_MAX_TAGS <= 32 - SCR_RETURN, - 0, -#else SCR_JUMP, PADDR (jump_to_nexus), -#endif }/*-------------------------< DATA_IN >--------------------*/,{ /* ** Because the size depends on the @@ -3907,7 +3868,7 @@ switch (old & RELOC_MASK) { case RELOC_REGISTER: new = (old & ~RELOC_MASK) - + pcivtophys(np->paddr); + + bus_dvma_to_mem(np->paddr); break; case RELOC_LABEL: new = (old & ~RELOC_MASK) + np->p_script; @@ -4654,7 +4615,7 @@ np->scripth = np->scripth0; np->p_scripth = vtophys(np->scripth); - np->p_script = (np->paddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0); + np->p_script = (np->paddr2) ? bus_dvma_to_mem(np->paddr2) : vtophys(np->script0); ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); @@ -5063,12 +5024,12 @@ } } msgptr[msglen++] = order; -#if SCSI_NCR_MAX_TAGS <= 32 - msgptr[msglen++] = (cp->tag << 3) + 1; -#else - msgptr[msglen++] = (cp->tag << 2) + 1; -#endif - + /* + ** Actual tags are numbered 1,3,5,..2*MAXTAGS+1, + ** since we may have to deal with devices that have + ** problems with #TAG 0 or too great #TAG numbers. + */ + msgptr[msglen++] = (cp->tag << 1) + 1; } switch (nego) { @@ -5316,7 +5277,7 @@ ++lp->queuedccbs; cp = xpt_que_entry(qp, struct ccb, link_ccbq); xpt_insque_tail(qp, &lp->busy_ccbq); - lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag].l_paddr = + lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] = cpu_to_scr(CCB_PHYS (cp, restart)); ncr_put_start_queue(np, cp); } @@ -5705,7 +5666,7 @@ #ifdef DEBUG_NCR53C8XX printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); #endif - if (lp->maxnxs > 1) + if (lp->jump_ccb != &lp->jump_ccb_0) m_free(lp->jump_ccb, 256); m_free(lp, sizeof(*lp)); } @@ -5861,9 +5822,10 @@ /* ** On standard INQUIRY response (EVPD and CmDt ** not set), setup logical unit according to - ** announced capabilities. + ** announced capabilities (we need the 1rst 7 bytes). */ - if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3)) { + if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && + cmd->cmnd[4] >= 7) { ncr_setup_lcb (np, cmd->target, cmd->lun, (char *) cmd->request_buffer); } @@ -6219,6 +6181,14 @@ } /* + ** DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. + ** Disable overlapped arbitration. + */ + if (np->device_id == PCI_DEVICE_ID_NCR_53C875 && + np->revision_id >= 0x10 && np->revision_id <= 0x15) + OUTB (nc_ctest0, (1<<5)); + + /* ** Fill in target structure. ** Reinitialize usrsync. ** Reinitialize usrwide. @@ -7778,7 +7748,7 @@ ** We just assume lun=0, 1 CCB, no tag. */ if (tp->lp[0]) { - OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0].l_paddr)); + OUTL (nc_dsp, scr_to_cpu(tp->lp[0]->jump_ccb[0])); return; } case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */ @@ -8307,17 +8277,9 @@ if (lp) { if (tag != NO_TAG) { ++lp->ia_tag; -#if SCSI_NCR_MAX_TAGS <= 32 - if (lp->ia_tag == 32) -#else - if (lp->ia_tag == 64) -#endif + if (lp->ia_tag == SCSI_NCR_MAX_TAGS) lp->ia_tag = 0; -#if SCSI_NCR_MAX_TAGS <= 32 - lp->tags_umap |= (1u << tag); -#else - lp->tags_umap |= (((u_int64) 1) << tag); -#endif + lp->tags_umap |= (((tagmap_t) 1) << tag); } } @@ -8363,22 +8325,14 @@ if (lp) { if (cp->tag != NO_TAG) { lp->cb_tags[lp->if_tag++] = cp->tag; -#if SCSI_NCR_MAX_TAGS <= 32 - if (lp->if_tag == 32) -#else - if (lp->if_tag == 64) -#endif + if (lp->if_tag == SCSI_NCR_MAX_TAGS) lp->if_tag = 0; -#if SCSI_NCR_MAX_TAGS <= 32 - lp->tags_umap &= ~(1u << cp->tag); -#else - lp->tags_umap &= ~(((u_int64) 1) << cp->tag); -#endif + lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag); lp->tags_smap &= lp->tags_umap; - lp->jump_ccb[cp->tag].l_paddr = + lp->jump_ccb[cp->tag] = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q)); } else { - lp->jump_ccb[0].l_paddr = + lp->jump_ccb[0] = cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l)); } } @@ -8412,7 +8366,7 @@ #define ncr_reg_bus_addr(r) \ - (pcivtophys(np->paddr) + offsetof (struct ncr_reg, r)) + (bus_dvma_to_mem(np->paddr) + offsetof (struct ncr_reg, r)) /*------------------------------------------------------------------------ ** Initialize the fixed part of a CCB structure. @@ -8579,28 +8533,6 @@ /*------------------------------------------------------------------------ -** Reselection JUMP table initialisation. -**------------------------------------------------------------------------ -** The SCRIPTS processor jumps on reselection to the entry -** corresponding to the CCB using the tag as offset. -**------------------------------------------------------------------------ -*/ -static void ncr_setup_jump_ccb(ncb_p np, lcb_p lp) -{ - int i; - - lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb)); - for (i = 0 ; i < lp->maxnxs ; i++) { -#if SCSI_NCR_MAX_TAGS <= 32 - lp->jump_ccb[i].l_cmd = cpu_to_scr(SCR_JUMP); -#endif - lp->jump_ccb[i].l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q)); - lp->cb_tags[i] = i; - } -} - -/*------------------------------------------------------------------------ ** Lun control block allocation and initialization. **------------------------------------------------------------------------ ** This data structure is allocated and initialized after a SCSI @@ -8649,12 +8581,12 @@ xpt_que_init(&lp->skip_ccbq); /* - ** Set max CCBs to 1 and use the default jump table - ** by default. + ** Set max CCBs to 1 and use the default 1 entry + ** jump table by default. */ - lp->maxnxs = 1; - lp->jump_ccb = &lp->jump_ccb_0; - ncr_setup_jump_ccb(np, lp); + lp->maxnxs = 1; + lp->jump_ccb = &lp->jump_ccb_0; + lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb)); /* ** Initilialyze the reselect script: @@ -8733,6 +8665,13 @@ inq_byte7 = inq_data[7]; /* + ** Throw away announced LUN capabilities if we are told + ** that there is no real device supported by the logical unit. + */ + if ((inq_data[0] & 0xe0) > 0x20 || (inq_data[0] & 0x1f) == 0x1f) + inq_byte7 &= (INQ7_SYNC | INQ7_WIDE16); + + /* ** If user is wanting SYNC, force this feature. */ if (driver_setup.force_sync_nego) @@ -8751,19 +8690,21 @@ ** If unit supports tagged commands, allocate the ** CCB JUMP table if not yet. */ - if ((inq_byte7 & INQ7_QUEUE) && lp->maxnxs < 2) { - struct nlink *jumps; - jumps = m_alloc(256, 8); - if (!jumps) + if ((inq_byte7 & INQ7_QUEUE) && lp->jump_ccb == &lp->jump_ccb_0) { + int i; + lp->jump_ccb = m_alloc(256, 8); + if (!lp->jump_ccb) { + lp->jump_ccb = &lp->jump_ccb_0; goto fail; -#if SCSI_NCR_MAX_TAGS <= 32 - lp->maxnxs = 32; -#else - lp->maxnxs = 64; -#endif - lp->jump_ccb = jumps; - ncr_setup_jump_ccb(np, lp); - lp->tags_stime = jiffies; + } + lp->p_jump_ccb = cpu_to_scr(vtophys(lp->jump_ccb)); + for (i = 0 ; i < 64 ; i++) + lp->jump_ccb[i] = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q)); + for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++) + lp->cb_tags[i] = i; + lp->maxnxs = SCSI_NCR_MAX_TAGS; + lp->tags_stime = jiffies; } /* diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.1.126/linux/drivers/scsi/ncr53c8xx.h Fri Oct 9 13:27:11 1998 +++ linux/drivers/scsi/ncr53c8xx.h Sat Nov 7 11:29:54 1998 @@ -45,7 +45,7 @@ /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.0i" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.1a" /* ** Check supported Linux versions @@ -468,7 +468,10 @@ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ , \ - {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, \ + {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875", 6, 16, 5, \ + FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ + , \ + {PCI_DEVICE_ID_NCR_53C875, 0xff, "876", 6, 16, 5, \ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\ , \ {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \ diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.126/linux/drivers/scsi/scsi_obsolete.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/scsi_obsolete.c Mon Nov 2 09:14:08 1998 @@ -607,8 +607,10 @@ if ((++SCpnt->retries) < SCpnt->allowed) { if ((SCpnt->retries >= (SCpnt->allowed >> 1)) - && !(SCpnt->host->last_reset > 0 && - jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD) + /* FIXME: last_reset == 0 is allowed + * && !(SCpnt->host->last_reset > 0 */ && + time_before(jiffies, SCpnt->host->last_reset + + MIN_RESET_PERIOD) && !(SCpnt->flags & WAS_RESET)) { printk("scsi%d channel %d : resetting for second half of retries.\n", @@ -954,8 +956,8 @@ host->last_reset = jiffies; SCpnt->flags |= (WAS_RESET | IS_RESETTING); temp = host->hostt->reset(SCpnt, reset_flags); - if ((host->last_reset < jiffies) || - (host->last_reset > (jiffies + 20 * HZ))) + if (time_before(host->last_reset, jiffies) || + (time_after(host->last_reset, jiffies + 20 * HZ))) host->last_reset = jiffies; if (!host->block) host->host_busy--; } @@ -1070,7 +1072,7 @@ * timers for timeout. */ - if( SCset->eh_timeout.expires == 0 ) + if( !timer_pending(&SCset->eh_timeout) ) { rtn = 0; } diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c --- v2.1.126/linux/drivers/scsi/scsiiom.c Sun Jun 7 11:16:35 1998 +++ linux/drivers/scsi/scsiiom.c Tue Oct 27 10:10:08 1998 @@ -4,198 +4,264 @@ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ +/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */ - -static USHORT -DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +UCHAR +dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) { - USHORT ioport, rc; - UCHAR bval, bval1, i, cnt; - PUCHAR ptr; - ULONG wlval; + USHORT wlval; + UCHAR bval, bval1; pSRB->TagNumber = 31; - ioport = pACB->IOPortBase; - bval = pDCB->UnitSCSIID; - outb(bval,ioport+Scsi_Dest_ID); - bval = pDCB->SyncPeriod; - outb(bval,ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb(bval,ioport+Sync_Offset); - bval = pDCB->CtrlR1; - outb(bval,ioport+CtrlReg1); - bval = pDCB->CtrlR3; - outb(bval,ioport+CtrlReg3); - bval = pDCB->CtrlR4; - outb(bval,ioport+CtrlReg4); - bval = CLEAR_FIFO_CMD; /* Flush FIFO */ - outb(bval,ioport+ScsiCmd); - + DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ + DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ + pSRB->CmdBlock[0], pDCB->SyncMode);) pSRB->ScsiPhase = SCSI_NOP0; + //pSRB->MsgOutBuf[0] = MSG_NOP; + //pSRB->MsgCnt = 0; bval = pDCB->IdentifyMsg; - if( !(pDCB->SyncMode & EN_ATN_STOP) ) + if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */ { if( (pSRB->CmdBlock[0] == INQUIRY) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) { - bval &= 0xBF; /* NO disconnection */ - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval &= 0xBF; /* No DisConn */ + DC390_write8 (ScsiFifo, bval); + bval1 = SEL_W_ATN; pSRB->SRBState = SRB_START_; + DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || + { + if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ (pSRB->CmdBlock[0] != INQUIRY) ) { - bval1 = SEL_W_ATN_STOP; + bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ pSRB->SRBState = SRB_MSGOUT; } } } - else + else /* TagQ ? */ { - if(pDCB->SyncMode & EN_TAG_QUEUING) + DC390_write8 (ScsiFifo, bval); + if(pDCB->SyncMode & EN_TAG_QUEUEING) { - outb(bval,ioport+ScsiFifo); - bval = MSG_SIMPLE_QTAG; - outb(bval,ioport+ScsiFifo); - wlval = 1; - bval = 0; - while( wlval & pDCB->TagMask ) - { - wlval = wlval << 1; - bval++; - } - outb(bval,ioport+ScsiFifo); + DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG); + DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);) + bval = 0; wlval = 1; + while (wlval & pDCB->TagMask) + { bval++; wlval <<= 1; }; pDCB->TagMask |= wlval; + DC390_write8 (ScsiFifo, bval); pSRB->TagNumber = bval; - bval1 = SEL_W_ATN2; + DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) + bval1 = SEL_W_ATN3; pSRB->SRBState = SRB_START_; } - else + else /* No TagQ */ { - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval1 = SEL_W_ATN; + DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) pSRB->SRBState = SRB_START_; } } - if( pSRB->SRBFlag & AUTO_REQSENSE ) - { - bval = REQUEST_SENSE; - outb(bval,ioport+ScsiFifo); - bval = pDCB->IdentifyMsg << 5; - outb(bval,ioport+ScsiFifo); - bval = 0; - outb(bval,ioport+ScsiFifo); - outb(bval,ioport+ScsiFifo); - bval = sizeof(pSRB->pcmd->sense_buffer); - outb(bval,ioport+ScsiFifo); - bval = 0; - outb(bval,ioport+ScsiFifo); - } - else - { - cnt = pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; - for(i=0; iCmdBlock[0] == INQUIRY) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) { - bval &= 0xBF; - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval &= 0xBF; /* No DisConn */ + DC390_write8 (ScsiFifo, bval); + bval1 = SEL_W_ATN; + DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) pSRB->SRBState = SRB_START_; + /* ??? */ if( pDCB->SyncMode & SYNC_ENABLE ) { - if( !(pDCB->IdentifyMsg & 7) || + if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ (pSRB->CmdBlock[0] != INQUIRY) ) { - bval1 = SEL_W_ATN_STOP; + bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ pSRB->SRBState = SRB_MSGOUT; } } } - else + else /* TagQ ? */ { - if(pDCB->SyncMode & EN_TAG_QUEUING) + DC390_write8 (ScsiFifo, bval); + if(pDCB->SyncMode & EN_TAG_QUEUEING) { - outb(bval,ioport+ScsiFifo); pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - wlval = 1; - bval = 0; - while( wlval & pDCB->TagMask ) - { - wlval = wlval << 1; - bval++; - } + DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);) + bval = 0; wlval = 1; + while (wlval & pDCB->TagMask) + { bval++; wlval <<= 1; }; pDCB->TagMask |= wlval; pSRB->TagNumber = bval; + DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) pSRB->MsgOutBuf[1] = bval; pSRB->MsgCnt = 2; bval1 = SEL_W_ATN_STOP; - pSRB->SRBState = SRB_START_; + pSRB->SRBState = SRB_START_; /* ?? */ } - else + else /* No TagQ */ { - outb(bval,ioport+ScsiFifo); pSRB->MsgOutBuf[0] = MSG_NOP; pSRB->MsgCnt = 1; pSRB->SRBState = SRB_START_; bval1 = SEL_W_ATN_STOP; - } + DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) + }; } } - bval = inb( ioport+Scsi_Status ); - if( bval & INTERRUPT ) + if (bval1 != SEL_W_ATN_STOP) + { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + if( pSRB->SRBFlag & AUTO_REQSENSE ) + { + bval = 0; + DC390_write8 (ScsiFifo, REQUEST_SENSE); + DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, bval); + DEBUG1(printk ("DC390: AutoReqSense !\n");) + } + else /* write cmnd to bus */ + { + PUCHAR ptr; UCHAR i; + ptr = (PUCHAR) pSRB->CmdBlock; + for (i=0; iScsiCmdLen; i++) + DC390_write8 (ScsiFifo, *(ptr++)); + }; + } + + /* Check if we can't win arbitration */ + if (DC390_read8 (Scsi_Status) & INTERRUPT) { pSRB->SRBState = SRB_READY; pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); - rc = 1; + DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");) + return 1; } else { pSRB->ScsiPhase = SCSI_NOP1; + DEBUG0(if (pACB->pActiveDCB) \ + printk ("DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk ("DC390: ActiveSRB != 0\n");) pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; - rc = 0; - outb(bval1,ioport+ScsiCmd); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, bval1); + return 0; } - return( rc ); } +//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ +#define DMA_INT 0 + +#if DMA_INT +/* This is similar to AM53C974.c ... */ +static UCHAR +dc390_dma_intr (PACB pACB) +{ + PSRB pSRB; + UCHAR dstate; + DEBUG0(USHORT pstate;PDEVDECL1;) + + DEBUG0(PDEVSET1;) + DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);) + DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ + { printk("DC390: PCI state = %04x!\n", pstate); \ + PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};) + + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ + //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + + if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; + else pSRB = pACB->pActiveDCB->pActiveSRB; + + if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) + { + printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); + return dstate; + }; + if (dstate & DMA_XFER_DONE) + { + ULONG residual, xferCnt; int ctr = 5000000; + if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) + { + do + { + DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");) + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ + residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | + DC390_read8 (CtcReg_High) << 16; + residual += DC390_read8 (Current_Fifo) & 0x1f; + } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); + if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + /* residual = ... */ + } + else + residual = 0; + + /* ??? */ + + xferCnt = pSRB->SGToBeXferLen - residual; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = residual; +# ifdef DC390_DEBUG0 + printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", + (unsigned int)residual, (unsigned int)xferCnt); +# endif + + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + } + return dstate; +}; +#endif -static void +void __inline__ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { PACB pACB; PDCB pDCB; PSRB pSRB; - USHORT ioport = 0; - USHORT phase, i; + UCHAR sstatus=0; + UCHAR phase, i; void (*stateV)( PACB, PSRB, PUCHAR ); - UCHAR istate = 0; - UCHAR sstatus=0, istatus; + UCHAR istate, istatus; + UCHAR dstatus; + DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS + + pACB = dc390_pACB_start; - pACB = pACB_start; - if( pACB == NULL ) + if (pACB == 0) + { + printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n"); return; - for( i=0; i < adapterCnt; i++ ) + } + DC390_LOCK_DRV; + + for( i=0; i < dc390_adapterCnt; i++ ) { if( pACB->IRQLevel == (UCHAR) irq ) { - ioport = pACB->IOPortBase; - sstatus = inb( ioport+Scsi_Status ); + sstatus = DC390_read8 (Scsi_Status); if( sstatus & INTERRUPT ) break; else @@ -207,99 +273,128 @@ } } -#ifdef DC390_DEBUG1 - printk("sstatus=%2x,",sstatus); -#endif + DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) - if( pACB == (PACB )-1 ) - { - printk("DC390: Spurious interrupt detected!\n"); + if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; }; + +#if DMA_INT + DC390_LOCK_IO; + DC390_LOCK_ACB; + dstatus = dc390_dma_intr (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + + DEBUG1(printk ("dstatus=%02x,", dstatus);) + if (! (dstatus & SCSI_INTERRUPT)) + { + DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");) + DC390_UNLOCK_DRV; return; - } - - istate = inb( ioport+Intern_State ); - istatus = inb( ioport+INT_Status ); - -#ifdef DC390_DEBUG1 - printk("Istatus=%2x,",istatus); + }; +#else + dstatus = DC390_read8 (DMA_Status); #endif + DC390_LOCK_IO; + DC390_LOCK_ACB; + DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ + + istate = DC390_read8 (Intern_State); + istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ + + DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);) + dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus; + + if (sstatus & ILLEGAL_OP_ERR) + { + printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); + dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); + }; + if(istatus & DISCONNECTED) { - DC390_Disconnect( pACB ); - return; + dc390_Disconnect( pACB ); + goto unlock; } if(istatus & RESELECTED) { - DC390_Reselect( pACB ); - return; + dc390_Reselect( pACB ); + goto unlock; } if(istatus & INVALID_CMD) { - DC390_InvalidCmd( pACB ); - return; + dc390_InvalidCmd( pACB ); + goto unlock; } if(istatus & SCSI_RESET) { - DC390_ScsiRstDetect( pACB ); - return; + dc390_ScsiRstDetect( pACB ); + goto unlock; } - if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) ) + if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) { pDCB = pACB->pActiveDCB; - pSRB = pDCB->pActiveSRB; - if( pDCB ) + if (!pDCB) { - if( pDCB->DCBFlag & ABORT_DEV_ ) - EnableMsgOut( pACB, pSRB ); - } + printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); + goto unlock; + }; + pSRB = pDCB->pActiveSRB; + if( pDCB->DCBFlag & ABORT_DEV_ ) + dc390_EnableMsgOut( pACB, pSRB ); - phase = (USHORT) pSRB->ScsiPhase; - stateV = (void *) DC390_phase0[phase]; - stateV( pACB, pSRB, &sstatus ); + phase = pSRB->ScsiPhase; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);) + stateV = (void *) dc390_phase0[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); pSRB->ScsiPhase = sstatus & 7; - phase = (USHORT) sstatus & 7; - stateV = (void *) DC390_phase1[phase]; - stateV( pACB, pSRB, &sstatus ); - } + phase = (UCHAR) sstatus & 7; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);) + stateV = (void *) dc390_phase1[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); + } + unlock: + DC390_LOCK_DRV_NI; + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + DC390_UNLOCK_DRV; /* Restore initial flags */ } -static void +void do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); + DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);) + /* Locking is done in DC390_Interrupt */ DC390_Interrupt(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + DEBUG1(printk (".. IRQ returned\n");) } -static void -DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR sstatus, bval; - USHORT ioport; + UCHAR sstatus; PSGL psgl; ULONG ResidCnt, xferCnt; - ioport = pACB->IOPortBase; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { - if( sstatus & PARITY_ERR ) + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { - bval = inb(ioport+DMA_Status); - while( !(bval & DMA_XFER_DONE) ) - bval = inb(ioport+DMA_Status); + int ctr = 5000000; /* only try for about a tenth of a second */ + while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; if( pSRB->SGIndex < pSRB->SGcount ) @@ -307,7 +402,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -315,51 +410,50 @@ } else { - bval = inb( ioport+Current_Fifo ); - bval &= 0x1f; - ResidCnt = (ULONG) inb(ioport+CtcReg_High); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); - ResidCnt += (ULONG) bval; + ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; + ResidCnt += (ULONG) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGPhysAddr += xferCnt; + pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; } } - bval = WRITE_DIRECTION+DMA_IDLE_CMD; - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ } -static void -DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR sstatus, bval; - USHORT i, ioport, residual; + UCHAR sstatus, residual, bval; PSGL psgl; - ULONG ResidCnt, xferCnt; + ULONG ResidCnt, xferCnt, i; PUCHAR ptr; - - ioport = pACB->IOPortBase; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { - if( sstatus & PARITY_ERR ) + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { - bval = inb(ioport+DMA_Status); - while( !(bval & DMA_XFER_DONE) ) - bval = inb(ioport+DMA_Status); + int ctr = 5000000; /* only try for about a tenth of a second */ + int dstate = 0; + while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); + DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + + ((ULONG) DC390_read8 (CtcReg_Low));) + DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ - bval = READ_DIRECTION+DMA_IDLE_CMD; - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; @@ -368,7 +462,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -377,14 +471,15 @@ else /* phase changed */ { residual = 0; - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); while( bval & 0x1f ) { + DEBUG1(printk ("Check for residuals,");) if( (bval & 0x1f) == 1 ) { - for(i=0; i< 0x100; i++) + for(i=0; i < 0x100; i++) { - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); if( !(bval & 0x1f) ) goto din_1; else if( i == 0x0ff ) @@ -395,87 +490,85 @@ } } else - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); } din_1: - bval = READ_DIRECTION+DMA_BLAST_CMD; - outb(bval, ioport+DMA_Cmd); - for(i=0; i<0x8000; i++) + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); + for (i=0; i<0x8000; i++) { - bval = inb(ioport+DMA_Status); - if(bval & BLAST_COMPLETE) + bval = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (bval & BLAST_COMPLETE) break; } - bval = READ_DIRECTION+DMA_IDLE_CMD; - outb(bval, ioport+DMA_Cmd); + if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n"); + //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ - ResidCnt = (ULONG) inb(ioport+CtcReg_High); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); + DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);) + ResidCnt = (ULONG) DC390_read8 (CtcReg_High); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGPhysAddr += xferCnt; + pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; if( residual ) { - bval = inb(ioport+ScsiFifo); /* get residual byte */ - ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr ); + bval = DC390_read8 (ScsiFifo); /* get one residual byte */ + ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr ); *ptr = bval; - pSRB->SGPhysAddr++; + pSRB->SGBusAddr++; xferCnt++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } + DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ + pSRB->TotalXferredLen, pSRB->SGToBeXferLen);) + } } } static void -DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - ioport = pACB->IOPortBase; - bval = inb(ioport+ScsiFifo); - pSRB->TargetStatus = bval; - bval++; - bval = inb(ioport+ScsiFifo); /* get message */ - pSRB->EndMessage = bval; + pSRB->TargetStatus = DC390_read8 (ScsiFifo); + //udelay (1); + pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ *psstatus = SCSI_NOP0; pSRB->SRBState = SRB_COMPLETED; - bval = MSG_ACCEPTED_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); } static void -DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) *psstatus = SCSI_NOP0; + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { UCHAR bval; - USHORT ioport, wval, wval1; + USHORT wval, wval1; PDCB pDCB; PSRB psrb; - ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; - bval = inb( ioport+ScsiFifo ); + bval = DC390_read8 (ScsiFifo); if( !(pSRB->SRBState & SRB_MSGIN_MULTI) ) { if(bval == MSG_DISCONNECT) @@ -490,12 +583,12 @@ pSRB->SRBState |= SRB_MSGIN_MULTI; pSRB->MsgInBuf[0] = bval; pSRB->MsgCnt = 1; - pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; + pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]); } else if(bval == MSG_REJECT_) { - bval = RESET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + pDCB->NegoPeriod = 50; if( pSRB->SRBState & DO_SYNC_NEGO) goto set_async; } @@ -521,7 +614,7 @@ psrb = pDCB->pGoingLast; if( pSRB ) { - for( ;; ) + for( ;pSRB ; ) { if(pSRB->TagNumber != bval) { @@ -535,7 +628,7 @@ if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - EnableMsgOut( pACB, pSRB ); + dc390_EnableMsgOut( pACB, pSRB ); } if( !(pSRB->SRBState & SRB_DISCONNECT) ) goto mingx0; @@ -549,234 +642,199 @@ pSRB->SRBState = SRB_UNEXPECT_RESEL; pDCB->pActiveSRB = pSRB; pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; - EnableMsgOut2( pACB, pSRB ); + dc390_EnableMsgOut2( pACB, pSRB ); } } } else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) ) - { - pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO); - if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) ) + { /* Note: This will fail for target initiated SDTR ? */ + pSRB->SRBState &= ~(SRB_MSGIN_MULTI); + if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) ) { /* reject_msg: */ pSRB->MsgCnt = 1; pSRB->MsgInBuf[0] = MSG_REJECT_; - bval = SET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, SET_ATN_CMD); } else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) ) { set_async: pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; - pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */ + pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ pDCB->CtrlR4 &= 0x3f; - pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */ - goto re_prog; + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + goto re_prog; } else { /* set_sync: */ pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); + pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; pDCB->SyncOffset &= 0x0f0; pDCB->SyncOffset |= pSRB->MsgInBuf[4]; pDCB->NegoPeriod = pSRB->MsgInBuf[3]; wval = (USHORT) pSRB->MsgInBuf[3]; - wval = wval << 2; - wval--; - wval1 = wval / 25; + wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */ if( (wval1 * 25) != wval) wval1++; - bval = FAST_CLK+FAST_SCSI; - pDCB->CtrlR4 &= 0x3f; - if(wval1 >= 8) + bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ + pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ + if (pACB->glitch_cfg != NS_TO_GLITCH(0)) + pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); + else + pDCB->CtrlR4 |= NS_TO_GLITCH(0); + if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ + if (wval1 >= 8) { - wval1--; - bval = FAST_CLK; /* ;fast clock/normal scsi */ - pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */ + wval1--; /* Timing computation differs by 1 from FAST_SCSI */ + bval = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ } pDCB->CtrlR3 = bval; pDCB->SyncPeriod = (UCHAR)wval1; re_prog: - bval = pDCB->SyncPeriod; - outb(bval, ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb(bval, ioport+Sync_Offset); - bval = pDCB->CtrlR3; - outb(bval, ioport+CtrlReg3); - bval = pDCB->CtrlR4; - outb(bval, ioport+CtrlReg4); - SetXferRate( pACB, pDCB); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); + dc390_SetXferRate (pACB, pDCB); } } } min6: *psstatus = SCSI_NOP0; - bval = MSG_ACCEPTED_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) +void +dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) { PSGL psgl; - UCHAR bval; - USHORT ioport; ULONG lval; - - ioport = pACB->IOPortBase; if( pSRB->SGIndex < pSRB->SGcount ) { - bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; + DEBUG1(printk (" DC390: Next SG segment.");) } lval = pSRB->SGToBeXferLen; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_Low); - lval = lval >> 8; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_Mid); - lval = lval >> 8; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_High); + DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) + DC390_write8 (CtcReg_Low, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_Mid, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_High, (UCHAR) lval); - lval = pSRB->SGToBeXferLen; - outl(lval, ioport+DMA_XferCnt); - - lval = pSRB->SGPhysAddr; - outl( lval, ioport+DMA_XferAddr); - - bval = DMA_COMMAND+INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); + DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ pSRB->SRBState = SRB_DATA_XFER; - bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ - outb(bval, ioport+DMA_Cmd); + DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); - bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */ - outb(bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + //DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) } else /* xfer pad */ { + UCHAR bval = 0; if( pSRB->SGcount ) { pSRB->AdaptStatus = H_OVER_UNDER_RUN; pSRB->SRBStatus |= OVER_RUN; + DEBUG0(printk (" DC390: Overrun -");) } - bval = 0; - outb(bval,ioport+CtcReg_Low); - outb(bval,ioport+CtcReg_Mid); - outb(bval,ioport+CtcReg_High); + DEBUG0(printk (" Clear transfer pad \n");) + DC390_write8 (CtcReg_Low, bval); + DC390_write8 (CtcReg_Mid, bval); + DC390_write8 (CtcReg_High, bval); pSRB->SRBState |= SRB_XFERPAD; - bval = DMA_COMMAND+XFER_PAD_BYTE; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); /* - bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT - outb(bval, ioport+DMA_Cmd); - bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT - outb(bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); */ } } static void -DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR ioDir; - - ioDir = WRITE_DIRECTION; - DataIO_Comm( pACB, pSRB, ioDir); + dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION); } static void -DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR ioDir; - - ioDir = READ_DIRECTION; - DataIO_Comm( pACB, pSRB, ioDir); + dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION); } -static void -DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { PDCB pDCB; - UCHAR bval; + UCHAR i, cnt; PUCHAR ptr; - USHORT ioport, i, cnt; - - ioport = pACB->IOPortBase; - bval = RESET_ATN_CMD; - outb(bval, ioport+ScsiCmd); - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) { - cnt = (USHORT) pSRB->ScsiCmdLen; + cnt = (UCHAR) pSRB->ScsiCmdLen; ptr = (PUCHAR) pSRB->CmdBlock; for(i=0; i < cnt; i++) - { - outb(*ptr, ioport+ScsiFifo); - ptr++; - } + DC390_write8 (ScsiFifo, *(ptr++)); } else { - bval = REQUEST_SENSE; - outb(bval, ioport+ScsiFifo); + UCHAR bval = 0; + DC390_write8 (ScsiFifo, REQUEST_SENSE); pDCB = pACB->pActiveDCB; - bval = pDCB->IdentifyMsg << 5; - outb(bval, ioport+ScsiFifo); - bval = 0; - outb(bval, ioport+ScsiFifo); - outb(bval, ioport+ScsiFifo); - bval = sizeof(pSRB->pcmd->sense_buffer); - outb(bval, ioport+ScsiFifo); - bval = 0; - outb(bval, ioport+ScsiFifo); + DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, bval); } pSRB->SRBState = SRB_COMMAND; - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } static void -DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pSRB->SRBState = SRB_STATUS; - bval = INITIATOR_CMD_CMPLTE; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport, i, cnt; + UCHAR bval, i, cnt; PUCHAR ptr; PDCB pDCB; - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pDCB = pACB->pActiveDCB; if( !(pSRB->SRBState & SRB_MSGOUT) ) { @@ -785,10 +843,7 @@ { ptr = (PUCHAR) pSRB->MsgOutBuf; for(i=0; i < cnt; i++) - { - outb(*ptr, ioport+ScsiFifo); - ptr++; - } + DC390_write8 (ScsiFifo, *(ptr++)); pSRB->MsgCnt = 0; if( (pDCB->DCBFlag & ABORT_DEV_) && (pSRB->MsgOutBuf[0] == MSG_ABORT) ) @@ -804,76 +859,67 @@ if( pDCB->SyncMode & SYNC_ENABLE ) goto mop1; } - outb(bval, ioport+ScsiFifo); + DC390_write8 (ScsiFifo, bval); } - bval = INFO_XFER_CMD; - outb( bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } else { mop1: - bval = MSG_EXTENDED; - outb(bval, ioport+ScsiFifo); - bval = 3; /* ;length of extended msg */ - outb(bval, ioport+ScsiFifo); - bval = 1; /* ; sync nego */ - outb(bval, ioport+ScsiFifo); - bval = pDCB->NegoPeriod; - outb(bval, ioport+ScsiFifo); - bval = SYNC_NEGO_OFFSET; - outb(bval, ioport+ScsiFifo); + //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_write8 (ScsiFifo, MSG_EXTENDED); + DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ + DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ + DC390_write8 (ScsiFifo, pDCB->NegoPeriod); + if (pDCB->SyncOffset & 0x0f) + DC390_write8 (ScsiFifo, pDCB->SyncOffset); + else + DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET); pSRB->SRBState |= DO_SYNC_NEGO; - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } } static void -DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBState & SRB_MSGIN) ) { - pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState &= ~SRB_DISCONNECT; pSRB->SRBState |= SRB_MSGIN; } - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } static void -DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -SetXferRate( PACB pACB, PDCB pDCB ) +dc390_SetXferRate( PACB pACB, PDCB pDCB ) { - UCHAR bval; - USHORT cnt, i; + UCHAR bval, i, cnt; PDCB ptr; if( !(pDCB->IdentifyMsg & 0x07) ) { if( pACB->scan_devices ) { - CurrSyncOffset = pDCB->SyncOffset; + dc390_CurrSyncOffset = pDCB->SyncOffset; } else { ptr = pACB->pLinkDCB; - cnt = pACB->DeviceCnt; + cnt = pACB->DCBCnt; bval = pDCB->UnitSCSIID; for(i=0; iIOPortBase; pDCB = pACB->pActiveDCB; if (!pDCB) { -#ifdef DC390_DEBUG0 - printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB); -#endif - restore_flags(flags); return; + int j = 400; + DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\ + (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);) + while (--j) udelay (1000); + DC390_read8 (INT_Status); /* Reset Pending INT */ + DC390_write8 (ScsiCmd, EN_SEL_RESEL); + return; } pSRB = pDCB->pActiveSRB; pACB->pActiveDCB = 0; pSRB->ScsiPhase = SCSI_NOP0; - bval = EN_SEL_RESEL; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, EN_SEL_RESEL); if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { pSRB->SRBState = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else if( pSRB->SRBState & SRB_ABORT_SENT ) { @@ -942,7 +983,7 @@ pSRB = psrb; } pDCB->pGoingSRB = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else { @@ -952,7 +993,7 @@ if( !(pACB->scan_devices) ) { pSRB->SRBState = SRB_READY; - RewaitSRB( pDCB, pSRB); + dc390_RewaitSRB( pDCB, pSRB); } else { @@ -962,76 +1003,66 @@ } else if( pSRB->SRBState & SRB_DISCONNECT ) { - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else if( pSRB->SRBState & SRB_COMPLETED ) { disc1: if(pDCB->MaxCommand > 1) { - bval = pSRB->TagNumber; - pDCB->TagMask &= (~(1 << bval)); /* free tag mask */ + pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ } pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; - SRBdone( pACB, pDCB, pSRB); + dc390_SRBdone( pACB, pDCB, pSRB); } } - restore_flags(flags); return; } -static void -DC390_Reselect( PACB pACB ) +void +dc390_Reselect( PACB pACB ) { - PDCB pDCB, pdcb; + PDCB pDCB; PSRB pSRB; - USHORT ioport, wval; - UCHAR bval, bval1; - + USHORT wval; + UCHAR bval; -#ifdef DC390_DEBUG0 - printk("RSEL,"); -#endif - ioport = pACB->IOPortBase; + DEBUG0(printk(KERN_INFO "RSEL,");) pDCB = pACB->pActiveDCB; if( pDCB ) { /* Arbitration lost but Reselection win */ + DEBUG0(printk ("(ActiveDCB != 0)");) pSRB = pDCB->pActiveSRB; if( !( pACB->scan_devices ) ) { pSRB->SRBState = SRB_READY; - RewaitSRB( pDCB, pSRB); + dc390_RewaitSRB( pDCB, pSRB); } } - bval = inb(ioport+ScsiFifo); /* get ID */ - bval = bval ^ pACB->HostID_Bit; + bval = DC390_read8 (ScsiFifo); /* get ID */ + DEBUG0(printk ("Dev %02x,", bval);) + bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ wval = 0; - bval1 = 1; - for(;;) - { - if( !(bval & bval1) ) - { - bval1 = bval1 << 1; - wval++; - } - else - break; - } - wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */ + while (bval >>= 1) wval++; + wval |= ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8; /* get LUN */ + DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);) pDCB = pACB->pLinkDCB; - pdcb = pDCB; while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) { pDCB = pDCB->pNextDCB; - if( pDCB == pdcb ) + if( pDCB == pACB->pLinkDCB ) + { + printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); return; + } } pACB->pActiveDCB = pDCB; - if( pDCB->SyncMode & EN_TAG_QUEUING ) + if( pDCB->SyncMode & EN_TAG_QUEUEING ) { - pSRB = pACB->pTmpSRB; + pSRB = pACB->pTmpSRB; /* ?? */ pDCB->pActiveSRB = pSRB; } else @@ -1041,57 +1072,163 @@ { pSRB= pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; + printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); pDCB->pActiveSRB = pSRB; - EnableMsgOut( pACB, pSRB ); + dc390_EnableMsgOut( pACB, pSRB ); } else { if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - EnableMsgOut( pACB, pSRB ); + printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); + dc390_EnableMsgOut( pACB, pSRB ); } else pSRB->SRBState = SRB_DATA_XFER; } } + + DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) pSRB->ScsiPhase = SCSI_NOP0; - bval = pDCB->UnitSCSIID; - outb( bval, ioport+Scsi_Dest_ID); - bval = pDCB->SyncPeriod; - outb(bval, ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb( bval, ioport+Sync_Offset); - bval = pDCB->CtrlR1; - outb(bval, ioport+CtrlReg1); - bval = pDCB->CtrlR3; - outb(bval, ioport+CtrlReg3); - bval = pDCB->CtrlR4; /* ; Glitch eater */ - outb(bval, ioport+CtrlReg4); - bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */ - outb(bval, ioport+ScsiCmd); + DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ } -static void -SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +static void +dc390_remove_dev (PACB pACB, PDCB pDCB) +{ + PDCB pPrevDCB = pACB->pLinkDCB; + + pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); + if (pDCB->GoingSRBCnt > 1) + { + DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\ + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);) + return; + }; + + if (pDCB == pACB->pLinkDCB) + { + if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0; + pACB->pLinkDCB = pDCB->pNextDCB; + pACB->pLastDCB->pNextDCB = pDCB->pNextDCB; + } + else + { + while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB; + pPrevDCB->pNextDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB; + } + + DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\ + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) + kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; + pACB->DCBCnt--; + /* pACB->DeviceCnt--; */ +}; + + +static UCHAR __inline__ +dc390_tagq_blacklist (char* name) +{ + UCHAR i; + for(i=0; iVers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 ) + { + if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & TAG_QUEUEING_) && + /* ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD)) &&*/ + !dc390_tagq_blacklist (((char*)ptr)+8) ) + { + pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; + pDCB->TagMask = 0; + } + else + { + /* Do we really need to check for DevType here ? */ + if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/ + /* && ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD))*/ ) + pDCB->SyncMode |= EN_ATN_STOP; + else + //pDCB->SyncMode &= ~EN_ATN_STOP; + pDCB->SyncMode &= ~0; + } + } +}; + + +static void +dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) +{ + UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; + pDCB->DevType = bval1; + /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ + dc390_disc_tagq_set (pDCB, ptr); +}; + + +void +dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { PSRB psrb; - UCHAR bval, bval1, i, j, status; + UCHAR bval, status, i; PSCSICMD pcmd; PSCSI_INQDATA ptr; - USHORT disable_tag; - ULONG flags; PSGL ptr2; ULONG swlval; pcmd = pSRB->pcmd; status = pSRB->TargetStatus; + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ + pSRB, pcmd->pid);) if(pSRB->SRBFlag & AUTO_REQSENSE) - { + { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; pSRB->TargetStatus = SCSI_STAT_CHECKCOND; +#ifdef DC390_REMOVABLEDEBUG + switch (pcmd->sense_buffer[2] & 0x0f) + { + case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); break; + case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); break; + case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); break; + case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); break; + case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + status, pACB->scan_devices); break; + } +#endif + //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; if(status == SCSI_STAT_CHECKCOND) { pcmd->result = DID_BAD_TARGET << 16; @@ -1099,7 +1236,7 @@ } if(pSRB->RetryCnt == 0) { - *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0]; pSRB->TotalXferredLen = pSRB->Segment1[1]; if( (pSRB->TotalXferredLen) && (pSRB->TotalXferredLen >= pcmd->underflow) ) @@ -1107,28 +1244,29 @@ else pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | SCSI_STAT_CHECKCOND; -#ifdef DC390_DEBUG0 - printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0], - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); -#endif + REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } - else + else /* Retry */ { pSRB->RetryCnt--; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + /* Don't retry on TEST_UNIT_READY */ + if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */) { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; + pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) + | SCSI_STAT_CHECKCOND; + REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } pcmd->result |= (DRIVER_SENSE << 24); - pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; - pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; + pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); pSRB->SGIndex = 0; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; @@ -1140,8 +1278,8 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); return; } } @@ -1149,6 +1287,8 @@ { if( status == SCSI_STAT_CHECKCOND) { + REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) { bval = pSRB->SGcount; @@ -1159,12 +1299,10 @@ swlval += ptr2->length; ptr2++; } -#ifdef DC390_DEBUG0 - printk("XferredLen=%8x,NotXferLen=%8x,", - (UINT) pSRB->TotalXferredLen, (UINT) swlval); -#endif + REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\ + (UINT) pSRB->TotalXferredLen, (UINT) swlval);) } - RequestSense( pACB, pDCB, pSRB ); + dc390_RequestSense( pACB, pDCB, pSRB ); return; } else if( status == SCSI_STAT_QUEUEFULL ) @@ -1172,7 +1310,7 @@ bval = (UCHAR) pDCB->GoingSRBCnt; bval--; pDCB->MaxCommand = bval; - RewaitSRB( pDCB, pSRB ); + dc390_RewaitSRB( pDCB, pSRB ); pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; return; @@ -1182,12 +1320,22 @@ pSRB->AdaptStatus = H_SEL_TIMEOUT; pSRB->TargetStatus = 0; pcmd->result = DID_BAD_TARGET << 16; + /* Devices are removed below ... */ } - else + else if (status == SCSI_STAT_BUSY && + (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && + pACB->scan_devices) { pSRB->AdaptStatus = 0; + pSRB->TargetStatus = status; + pcmd->result = (ULONG) (pSRB->EndMessage << 8) + /* | (ULONG) status */; + } + else + { /* Another error */ + pSRB->AdaptStatus = 0; if( pSRB->RetryCnt ) - { + { /* Retry */ pSRB->RetryCnt--; pSRB->TargetStatus = 0; pSRB->SGIndex = 0; @@ -1201,19 +1349,19 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); return; } else - { + { /* Report error */ pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | (ULONG) status; } } } else - { + { /* Target status == 0 */ status = pSRB->AdaptStatus; if(status & H_OVER_UNDER_RUN) { @@ -1237,95 +1385,57 @@ { if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) { - if(pcmd->result != (DID_OK << 16)) - { - if( pcmd->result & SCSI_STAT_CHECKCOND ) - { - goto RTN_OK; - } - else - { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - pPrevDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && - ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) ) - { - pACB->scan_devices = 0; - } - } - } - else - { -RTN_OK: - pPrevDCB->pNextDCB = pDCB; - pDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) - pACB->scan_devices = END_SCAN; - } - } - else if( pSRB->CmdBlock[0] == INQUIRY ) - { - if( (pcmd->target == pACB->max_id) && - (pcmd->lun == pACB->max_lun) ) - { - pACB->scan_devices = 0; - } - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - bval1 = ptr->DevType & SCSI_DEVTYPE; - if(bval1 == SCSI_NODEV) - { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - pPrevDCB->pNextDCB = pACB->pLinkDCB; +#ifdef DC390_DEBUG0 + printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); + if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n", + pcmd->sense_buffer[0], pcmd->sense_buffer[1], + pcmd->sense_buffer[2], pcmd->sense_buffer[3]); + else printk ("\n"); +#endif + if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || + ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && + (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) + { + /* device not present: remove */ + dc390_remove_dev (pACB, pDCB); + + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) ) + pACB->scan_devices = 0; } else { - pACB->DeviceCnt++; - pPrevDCB = pDCB; - pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB )); - pDCB->DevType = bval1; - if(bval1 == TYPE_DISK || bval1 == TYPE_MOD) - { - if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) && - (ptr->Flags & SCSI_INQ_CMDQUEUE) && - (pDCB->DevMode & TAG_QUEUING_) && - (pDCB->DevMode & EN_DISCONNECT_) ) - { - disable_tag = 0; - for(i=0; iMaxCommand = pACB->TagMaxNum; - pDCB->SyncMode |= EN_TAG_QUEUING; - pDCB->TagMask = 0; - } - else - { - pDCB->SyncMode |= EN_ATN_STOP; - } - } - } + /* device present: add */ + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = END_SCAN ; + /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */ } } } - - save_flags( flags ); - cli(); -/* ReleaseSRB( pDCB, pSRB ); */ + + if( pSRB->CmdBlock[0] == INQUIRY && + (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) ) + { + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) + { + /* device not present: remove */ + dc390_remove_dev (pACB, pDCB); + } + else + { + /* device found: add */ + dc390_add_dev (pACB, pDCB, ptr); + if (pACB->scan_devices) pACB->DeviceCnt++; + } + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = 0; + }; +/* dc390_ReleaseSRB( pDCB, pSRB ); */ if(pSRB == pDCB->pGoingSRB ) { @@ -1344,33 +1454,34 @@ pACB->pFreeSRB = pSRB; pDCB->GoingSRBCnt--; - DoWaitingSRB( pACB ); - restore_flags(flags); + dc390_DoWaitingSRB( pACB ); -/* Notify cmd done */ + DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); + DC390_LOCK_ACB_NI; if( pDCB->QIORBCnt ) - DoNextCmd( pACB, pDCB ); + dc390_DoNextCmd( pACB, pDCB ); return; } -static void -DoingSRB_Done( PACB pACB ) +/* Remove all SRBs and tell midlevel code DID_RESET */ +void +dc390_DoingSRB_Done( PACB pACB ) { - PDCB pDCB, pdcb; - PSRB psrb, psrb2; - USHORT cnt, i; + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + UCHAR i; PSCSICMD pcmd; pDCB = pACB->pLinkDCB; pdcb = pDCB; + if (! pdcb) return; do { - cnt = pdcb->GoingSRBCnt; psrb = pdcb->pGoingSRB; - for( i=0; iGoingSRBCnt; i++) { psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; @@ -1381,63 +1492,46 @@ psrb->pNextSRB = pACB->pFreeSRB; pACB->pFreeSRB = psrb; + DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); + DC390_LOCK_ACB_NI; psrb = psrb2; } pdcb->GoingSRBCnt = 0;; pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; - } - while( pdcb != pDCB ); + } while( pdcb != pDCB ); } static void -DC390_ResetSCSIBus( PACB pACB ) +dc390_ResetSCSIBus( PACB pACB ) { - USHORT ioport; - UCHAR bval; - ULONG flags; - - save_flags(flags); - cli(); pACB->ACBFlag |= RESET_DEV; - ioport = pACB->IOPortBase; - - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = RST_SCSI_BUS_CMD; - outb(bval,ioport+ScsiCmd); + DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + udelay (250); + DC390_write8 (ScsiCmd, NOP_CMD); + + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); - restore_flags(flags); return; } - static void -DC390_ScsiRstDetect( PACB pACB ) +dc390_ScsiRstDetect( PACB pACB ) { - ULONG wlval, flags; - USHORT ioport; - UCHAR bval; - -#ifdef DC390_DEBUG0 - printk("RST_DETEC"); -#endif + printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); + //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + /* Unlock before ? */ /* delay a second */ - mdelay(1000); - - save_flags(flags); - cli(); - - ioport = pACB->IOPortBase; - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = CLEAR_FIFO_CMD; - outb(bval,ioport+ScsiCmd); + { unsigned int msec = 1*1000; while (--msec) udelay(1000); } + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( pACB->ACBFlag & RESET_DEV ) pACB->ACBFlag |= RESET_DONE; @@ -1445,30 +1539,32 @@ { pACB->ACBFlag |= RESET_DETECT; - ResetDevParam( pACB ); -/* DoingSRB_Done( pACB ); ???? */ - RecoverSRB( pACB ); + dc390_ResetDevParam( pACB ); +/* dc390_DoingSRB_Done( pACB ); ???? */ + dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } - restore_flags(flags); return; } -static void -RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +static void __inline__ +dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) { PSCSICMD pcmd; + REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ + pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0])); - pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4])); + pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; + pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); pSRB->Segment1[1] = pSRB->TotalXferredLen; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; + pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ pcmd = pSRB->pcmd; @@ -1478,52 +1574,40 @@ pSRB->SGcount = 1; pSRB->SGIndex = 0; - *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003; + pSRB->CmdBlock[0] = REQUEST_SENSE; pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer); + (USHORT) pSRB->CmdBlock[2] = 0; + (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); pSRB->ScsiCmdLen = 6; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; - if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); } -static void -EnableMsgOut2( PACB pACB, PSRB pSRB ) +static void __inline__ +dc390_EnableMsgOut2( PACB pACB, PSRB pSRB ) { - USHORT ioport; - UCHAR bval; - - ioport = pACB->IOPortBase; pSRB->MsgCnt = 1; - bval = SET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, SET_ATN_CMD); } -static void -EnableMsgOut( PACB pACB, PSRB pSRB ) +static void __inline__ +dc390_EnableMsgOut( PACB pACB, PSRB pSRB ) { pSRB->MsgOutBuf[0] = MSG_ABORT; - EnableMsgOut2( pACB, pSRB ); + dc390_EnableMsgOut2( pACB, pSRB ); + pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; } -static void -DC390_InvalidCmd( PACB pACB ) +static void __inline__ +dc390_InvalidCmd( PACB pACB ) { - UCHAR bval; - USHORT ioport; - PSRB pSRB; - - pSRB = pACB->pActiveDCB->pActiveSRB; - if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - { - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval,(ioport+ScsiCmd)); - } + if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); } diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.126/linux/drivers/scsi/sd.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/scsi/sd.c Mon Oct 26 14:04:21 1998 @@ -65,7 +65,8 @@ #define SD_MINOR_NUMBER(i) ((i) & 255) #define MKDEV_SD_PARTITION(i) MKDEV(SD_MAJOR_NUMBER(i), (i) & 255) #define MKDEV_SD(index) MKDEV_SD_PARTITION((index) << 4) -#define N_USED_SD_MAJORS ((sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) / SCSI_DISKS_PER_MAJOR) +#define N_USED_SCSI_DISKS (sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1) +#define N_USED_SD_MAJORS (N_USED_SCSI_DISKS / SCSI_DISKS_PER_MAJOR) #define MAX_RETRIES 5 @@ -1765,7 +1766,7 @@ scsi_unregister_module(MODULE_SCSI_DEV, &sd_template); for (i=0; i <= sd_template.dev_max / SCSI_DISKS_PER_MAJOR; i++) - unregister_blkdev(SD_MAJOR(i),"sd"); + unregister_blkdev(SD_MAJOR(i),"sd"); sd_registered--; if( rscsi_disks != NULL ) @@ -1783,13 +1784,13 @@ for (sdgd = gendisk_head; sdgd; sdgd = sdgd->next) { - if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK) + if (sdgd->next >= sd_gendisks && sdgd->next <= LAST_SD_GENDISK.max_nr) removed++, sdgd->next = sdgd->next->next; else sdgd = sdgd->next; } - if (removed != N_USED_SCSI_DISKS) + if (removed != N_USED_SD_MAJORS) printk("%s %d sd_gendisks in disk chain", - removed > N_USED_SCSI_DISKS ? "total" : "just", removed); + removed > N_USED_SD_MAJORS ? "total" : "just", removed); } diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.1.126/linux/drivers/scsi/tmscsim.c Sun Jun 7 11:16:35 1998 +++ linux/drivers/scsi/tmscsim.c Tue Oct 27 10:10:08 1998 @@ -5,35 +5,132 @@ * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ -/* Minor enhancements and bugfixes by * +/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $ */ +/* Enhancements and bugfixes by * * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * * REV# DATE NAME DESCRIPTION * - * 1.00 04/24/96 CLH First release * - * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable * + * 1.00 96/04/24 CLH First release * + * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable * * Device, scan all LUN. Support Pre2.0.10 * - * 1.02 06/18/96 CLH Fixed bug of Command timeout ... * - * 1.03 09/25/96 KG Added tmscsim_proc_info() * - * 1.04 10/11/96 CLH Updating for support KV 2.0.x * - * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)* - * 1.06 10/25/96 KG Fixed module support * - * 1.07 11/09/96 KG Fixed tmscsim_proc_info() * - * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() * - * 1.09 11/30/96 KG Added register the allocated IO space * - * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset * + * 1.02 96/06/18 CLH Fixed bug of Command timeout ... * + * 1.03 96/09/25 KG Added tmscsim_proc_info() * + * 1.04 96/10/11 CLH Updating for support KV 2.0.x * + * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)* + * 1.06 96/10/25 KG Fixed module support * + * 1.07 96/11/09 KG Fixed tmscsim_proc_info() * + * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() * + * 1.09 96/11/30 KG Added register the allocated IO space * + * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset * * pending interrupt in DC390_detect() * - * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater * - * than 1GB * - * 1.12 15/02/98 MJ Rewritten PCI probing * + * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater * + * than 1GB * + * 1.12 98/02/15 MJ Rewritten PCI probing * + * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,* + * changed max devs from 10 to 16 * + * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev * + * for LUNs if LUN_SCAN (BIOS) not set * + * runtime config using /proc interface * + * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks * + * 1.14c 98/05/07 KG 2.0.x compatibility * + * 1.20a 98/05/07 KG changed names of funcs to be consistent * + * DC390_ (entry points), dc390_ (internal)* + * reworked locking * + * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp * + * debug output * + * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults * + * 1.20d 98/05/14 KG bugs: list linkage, clear flag after * + * reset on startup, code cleanup * + * 1.20e 98/05/15 KG spinlock comments, name space cleanup * + * pLastDCB now part of ACB structure * + * added stats, timeout for 2.1, TagQ bug * + * RESET and INQUIRY interface commands * + * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs * + * for missing LUNs, pending int * + * 1.20g 98/05/19 KG Clean up: Avoid short * + * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... * + * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask * + * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB * + * == 0 in remove_dev and DoingSRB_Done * + * 1.20k 98/05/25 KG DMA_INT (experimental) * + * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; * + * 1.20m 98/06/10 KG glitch configurable; made some global * + * vars part of ACB; use DC390_readX * + * 1.20n 98/06/11 KG startup params * + * 1.20o 98/06/15 KG added TagMaxNum to boot/module params * + * Device Nr -> Idx, TagMaxNum power of 2 * + * 1.20p 98/06/17 KG Docu updates. Reset depends on settings * + * pci_set_master added; 2.0.xx: pcibios_* * + * used instead of MechNum things ... * + * 1.20q 98/06/23 KG Changed defaults. Added debug code for * + * removable media and fixed it. TagMaxNum * + * fixed for DC390. Locking: ACB, DRV for * + * better IRQ sharing. Spelling: Queueing * + * Parsing and glitch_cfg changes. Display * + * real SyncSpeed value. Made DisConn * + * functional (!) * + * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set * + * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module * + * param -1 fixed. * + * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,* + * phys_to_bus instead of phys_to_virt, * + * fixed sel. process, fixed locking, * + * added MODULE_XXX infos, changed IRQ * + * request flags, disable DMA_INT * + * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;* + * initfunc -> __init; better abort; * + * Timeout for XFER_DONE & BLAST_COMPLETE; * + * Allow up to 33 commands being processed * + * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing * + * all flags. Clear within while() loops * + * in DataIn_0/Out_0. Null ptr in dumpinfo * + * for pSRB==0. Better locking during init.* + * bios_param() now respects part. table. * + * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. * + * Disallow illegal idx in INQUIRY/REMOVE * ***********************************************************************/ +/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */ +#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */ -#define DC390_DEBUG +/* DEBUG options */ +//#define DC390_DEBUG0 +//#define DC390_DEBUG1 +//#define DC390_DCBDEBUG +//#define DC390_PARSEDEBUG +//#define DC390_REMOVABLEDEBUG -#define SCSI_MALLOC +/* Debug definitions */ +#ifdef DC390_DEBUG0 +# define DEBUG0(x) x; +#else +# define DEBUG0(x) +#endif +#ifdef DC390_DEBUG1 +# define DEBUG1(x) x; +#else +# define DEBUG1(x) +#endif +#ifdef DC390_DCBDEBUG +# define DCBDEBUG(x) x; +#else +# define DCBDEBUG(x) +#endif +#ifdef DC390_PARSEDEBUG +# define PARSEDEBUG(x) x; +#else +# define PARSEDEBUG(x) +#endif +#ifdef DC390_REMOVABLEDEBUG +# define REMOVABLEDEBUG(x) x; +#else +# define REMOVABLEDEBUG(x) +#endif +#define DCBDEBUG1(x) +/* Includes */ #ifdef MODULE # include #endif @@ -41,7 +138,6 @@ #include #include #include -#include #include #include #include @@ -51,14 +147,14 @@ #include #include #include +#include #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" -#include "tmscsim.h" #include "constants.h" #include "sd.h" #include @@ -67,107 +163,350 @@ #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI -struct proc_dir_entry proc_scsi_tmscsim ={ - PROC_SCSI_DC390T, 7 ,"tmscsim", - S_IFDIR | S_IRUGO | S_IXUGO, 2 - }; +/* Locking */ -static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); - -static void SetXferRate( PACB pACB, PDCB pDCB ); -static void DC390_Disconnect( PACB pACB ); -static void DC390_Reselect( PACB pACB ); -static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DoingSRB_Done( PACB pACB ); -static void DC390_ScsiRstDetect( PACB pACB ); -static void DC390_ResetSCSIBus( PACB pACB ); -static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void EnableMsgOut2( PACB pACB, PSRB pSRB ); -static void EnableMsgOut( PACB pACB, PSRB pSRB ); -static void DC390_InvalidCmd( PACB pACB ); +/* Note: Starting from 2.1.9x, the mid-level scsi code issues a + * spinlock_irqsave (&io_request_lock) before calling the driver's + * routines, so we don't need to lock. + * TODO: Verify, if we are locked in every case! + * The policy 3, let the midlevel scsi code do the io_request_locks + * and us locking on a driver specific lock, shouldn't hurt anybody; it + * just causes a minor performance degradation for setting the locks. + */ + +/* spinlock things + * level 3: lock on both adapter specific locks and (global) io_request_lock + * level 2: lock on adapter specific locks only + * level 1: rely on the locking of the mid level code (io_request_lock) + * undef : traditional save_flags; cli; restore_flags; + */ + +//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# include +# include +#endif -int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ); -void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +# define USE_SPINLOCKS 1 +# define NEW_PCI 1 +#else +# undef NEW_PCI +# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# define USE_SPINLOCKS 2 +# endif +#endif + +#ifdef USE_SPINLOCKS + +# if USE_SPINLOCKS == 3 /* both */ + +# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; +# else +# define DC390_LOCK_INIT +# endif + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; + +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; + +# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags) +# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags) + +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) + +# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags) +# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags) +# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock)) +# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock)) +//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock)) + +# else + +# if USE_SPINLOCKS == 2 /* adapter specific locks */ + +# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; +# else +# define DC390_LOCK_INIT +# endif + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS +# define DC390_DFLAGS unsigned long dflags; +# define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */ +# define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */ +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) +# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags) +# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags) +# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock)) +# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock)) +//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock)) + +# else /* USE_SPINLOCKS == 1: global lock io_request_lock */ + +# define DC390_AFLAGS +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; +# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags) +# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags) +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) +# define DC390_LOCK_ACB /* DC390_LOCK_IO */ +# define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */ +# define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */ +# define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */ +# define DC390_LOCK_INIT /* DC390_LOCK_INIT */ + +# endif /* 2 */ +# endif /* 3 */ + +#else /* USE_SPINLOCKS undefined */ + +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; +# define DC390_LOCK_IO save_flags (iflags); cli () +# define DC390_UNLOCK_IO restore_flags (iflags) +# define DC390_LOCK_DRV save_flags (dflags); cli () +# define DC390_UNLOCK_DRV restore_flags (dflags) +# define DC390_LOCK_DRV_NI +# define DC390_UNLOCK_DRV_NI +# define DC390_LOCK_ACB save_flags (aflags); cli () +# define DC390_UNLOCK_ACB restore_flags (aflags) +# define DC390_LOCK_ACB_NI +# define DC390_UNLOCK_ACB_NI +# define DC390_LOCK_INIT +#endif /* def */ + + +/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/ + +#ifdef NEW_PCI +# define PDEV pdev +# define PDEVDECL struct pci_dev *pdev +# define PDEVDECL0 struct pci_dev *pdev = NULL +# define PDEVDECL1 struct pci_dev *pdev +# define PDEVSET pACB->pdev=pdev +# define PDEVSET1 pdev=pACB->pdev +# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv) +# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv) +# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv) +# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv) +# define PCI_BUS_DEV pdev->bus->number, pdev->devfn +# define PCI_PRESENT pci_present () +# define PCI_SET_MASTER pci_set_master (pdev) +# define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev)) +# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq +#else +# include +# define PDEV pbus, pdevfn +# define PDEVDECL UCHAR pbus, UCHAR pdevfn +# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error +# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */ +# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */ +# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */ +# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv) +# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv) +# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv) +# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv) +# define PCI_BUS_DEV pbus, pdevfn +# define PCI_PRESENT pcibios_present () +# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn) +# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn)) +# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port); \ + error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq); \ + io_port &= 0xfffe; \ + if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; } +#endif + +#include "tmscsim.h" + +#ifndef __init +# define __init +#endif + +UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); + +static void dc390_SetXferRate( PACB pACB, PDCB pDCB ); +void dc390_Disconnect( PACB pACB ); +void dc390_Reselect( PACB pACB ); +void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); +void dc390_DoingSRB_Done( PACB pACB ); +static void dc390_ScsiRstDetect( PACB pACB ); +static void dc390_ResetSCSIBus( PACB pACB ); +static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB ); +static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB ); +static void __inline__ dc390_InvalidCmd( PACB pACB ); +static void dc390_remove_dev (PACB pACB, PDCB pDCB); +void do_DC390_Interrupt( int, void *, struct pt_regs *); + +int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index ); +void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ); +void dc390_updateDCB (PACB pACB, PDCB pDCB); #ifdef MODULE -static int DC390_release(struct Scsi_Host *host); -static int DC390_shutdown (struct Scsi_Host *host); + static int DC390_release(struct Scsi_Host *host); + static int dc390_shutdown (struct Scsi_Host *host); #endif -static PSHT pSHT_start = NULL; -static PSH pSH_start = NULL; -static PSH pSH_current = NULL; -static PACB pACB_start= NULL; -static PACB pACB_current = NULL; -static PDCB pPrevDCB = NULL; -static USHORT adapterCnt = 0; -static USHORT InitialTime = 0; -static USHORT CurrSyncOffset = 0; - -static PVOID DC390_phase0[]={ - DC390_DataOut_0, - DC390_DataIn_0, - DC390_Command_0, - DC390_Status_0, - DC390_Nop_0, - DC390_Nop_0, - DC390_MsgOut_0, - DC390_MsgIn_0, - DC390_Nop_1 - }; +//static PSHT dc390_pSHT_start = NULL; +//static PSH dc390_pSH_start = NULL; +//static PSH dc390_pSH_current = NULL; +static PACB dc390_pACB_start= NULL; +static PACB dc390_pACB_current = NULL; +static UCHAR dc390_adapterCnt = 0; +static UCHAR dc390_CurrSyncOffset = 0; +static ULONG dc390_lastabortedpid = 0; +static ULONG dc390_laststatus = 0; + +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +/* Startup values, to be overriden on the commandline */ +int tmscsim[] = {7, 1 /* 8MHz */, + PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ + | SYNC_NEGO_ | TAG_QUEUEING_, + MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION + /* | NO_SEEK */ +# ifdef CONFIG_SCSI_MULTI_LUN + | LUN_CHECK +# endif + , 3 /* 16 Tags per LUN */}; + +# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +MODULE_PARM(tmscsim, "1-5i"); +MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)"); +# endif + +#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + +#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +MODULE_AUTHOR("C.L. Huang / Kurt Garloff"); +MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters"); +MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); +#endif -static PVOID DC390_phase1[]={ - DC390_DataOutPhase, - DC390_DataInPhase, - DC390_CommandPhase, - DC390_StatusPhase, - DC390_Nop_0, - DC390_Nop_0, - DC390_MsgOutPhase, - DC390_MsgInPhase, - DC390_Nop_1, +static PVOID dc390_phase0[]={ + dc390_DataOut_0, + dc390_DataIn_0, + dc390_Command_0, + dc390_Status_0, + dc390_Nop_0, + dc390_Nop_0, + dc390_MsgOut_0, + dc390_MsgIn_0, + dc390_Nop_1 }; -UCHAR eepromBuf[MAX_ADAPTER_NUM][128]; - +static PVOID dc390_phase1[]={ + dc390_DataOutPhase, + dc390_DataInPhase, + dc390_CommandPhase, + dc390_StatusPhase, + dc390_Nop_0, + dc390_Nop_0, + dc390_MsgOutPhase, + dc390_MsgInPhase, + dc390_Nop_1 + }; -UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; +#ifdef DC390_DEBUG1 +static char* dc390_p0_str[] = { + "dc390_DataOut_0", + "dc390_DataIn_0", + "dc390_Command_0", + "dc390_Status_0", + "dc390_Nop_0", + "dc390_Nop_0", + "dc390_MsgOut_0", + "dc390_MsgIn_0", + "dc390_Nop_1" + }; + +static char* dc390_p1_str[] = { + "dc390_DataOutPhase", + "dc390_DataInPhase", + "dc390_CommandPhase", + "dc390_StatusPhase", + "dc390_Nop_0", + "dc390_Nop_0", + "dc390_MsgOutPhase", + "dc390_MsgInPhase", + "dc390_Nop_1" + }; +#endif -UCHAR baddevname1[2][28] ={ +/* Devices erroneously pretending to be able to do TagQ */ +UCHAR dc390_baddevname1[2][28] ={ "SEAGATE ST3390N 9546", "HP C3323-300 4269"}; - #define BADDEVCNT 2 +static char* dc390_adapname = "DC390"; +UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN]; +UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; + +struct proc_dir_entry DC390_proc_scsi_tmscsim ={ + PROC_SCSI_DC390T, 7 ,"tmscsim", + S_IFDIR | S_IRUGO | S_IXUGO, 2 + }; /*********************************************************************** * * * **********************************************************************/ -static void -QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd) { - ULONG flags; - PSCSICMD pcmd; + PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0; + while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun) + { + pDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLinkDCB) + { + printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n", + (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]); + return 0; + } + }; + DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \ + (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + return pDCB; +}; - save_flags(flags); - cli(); +static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +{ + PSCSICMD pcmd; if( !pDCB->QIORBCnt ) { @@ -185,83 +524,61 @@ cmd->next = NULL; } - restore_flags(flags); } -static PSCSICMD -Getcmd( PDCB pDCB ) +static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB ) { - ULONG flags; PSCSICMD pcmd; - save_flags(flags); - cli(); - pcmd = pDCB->pQIORBhead; pDCB->pQIORBhead = pcmd->next; pcmd->next = NULL; pDCB->QIORBCnt--; - restore_flags(flags); return( pcmd ); } -static PSRB -GetSRB( PACB pACB ) +static __inline__ PSRB dc390_GetSRB( PACB pACB ) { - ULONG flags; PSRB pSRB; - save_flags(flags); - cli(); - pSRB = pACB->pFreeSRB; if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } - restore_flags(flags); + return( pSRB ); } -static void -RewaitSRB0( PDCB pDCB, PSRB pSRB ) +static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB ) { PSRB psrb1; - ULONG flags; - - save_flags(flags); - cli(); if( (psrb1 = pDCB->pWaitingSRB) ) { pSRB->pNextSRB = psrb1; - pDCB->pWaitingSRB = pSRB; } else { pSRB->pNextSRB = NULL; - pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } - restore_flags(flags); + pDCB->pWaitingSRB = pSRB; } -static void -RewaitSRB( PDCB pDCB, PSRB pSRB ) +static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB ) { PSRB psrb1; - ULONG flags; UCHAR bval; - save_flags(flags); - cli(); - pDCB->GoingSRBCnt--; + pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++; + DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);) psrb1 = pDCB->pGoingSRB; if( pSRB == psrb1 ) { @@ -289,20 +606,14 @@ bval = pSRB->TagNumber; pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ - restore_flags(flags); } -static void -DoWaitingSRB( PACB pACB ) +static void dc390_DoWaitingSRB( PACB pACB ) { - ULONG flags; PDCB ptr, ptr1; PSRB pSRB; - save_flags(flags); - cli(); - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) { ptr = pACB->pDCBRunRobin; @@ -324,7 +635,7 @@ } else { - if( !DC390_StartSCSI(pACB, ptr1, pSRB) ) + if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) { ptr1->GoingSRBCnt++; if( ptr1->pWaitLast == pSRB ) @@ -348,55 +659,47 @@ } } } - restore_flags(flags); return; } -static void -SRBwaiting( PDCB pDCB, PSRB pSRB) +static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB) { if( pDCB->pWaitingSRB ) { pDCB->pWaitLast->pNextSRB = pSRB; - pDCB->pWaitLast = pSRB; pSRB->pNextSRB = NULL; } else { pDCB->pWaitingSRB = pSRB; - pDCB->pWaitLast = pSRB; } + pDCB->pWaitLast = pSRB; } -static void -SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +static void dc390_SendSRB( PACB pACB, PSRB pSRB ) { - ULONG flags; PDCB pDCB; - save_flags(flags); - cli(); - pDCB = pSRB->pSRBDCB; if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - SRBwaiting(pDCB, pSRB); + dc390_SRBwaiting(pDCB, pSRB); goto SND_EXIT; } if( pDCB->pWaitingSRB ) { - SRBwaiting(pDCB, pSRB); -/* pSRB = GetWaitingSRB(pDCB); */ + dc390_SRBwaiting(pDCB, pSRB); +/* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */ pSRB = pDCB->pWaitingSRB; pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } - if( !DC390_StartSCSI(pACB, pDCB, pSRB) ) + if( !dc390_StartSCSI(pACB, pDCB, pSRB) ) { pDCB->GoingSRBCnt++; if( pDCB->pGoingSRB ) @@ -411,13 +714,52 @@ } } else - RewaitSRB0( pDCB, pSRB ); + dc390_RewaitSRB0( pDCB, pSRB ); SND_EXIT: - restore_flags(flags); return; } +static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) +{ + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; + pSRB->ScsiCmdLen = pcmd->cmd_len; + memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + + if( pcmd->use_sg ) + { + pSRB->SGcount = (UCHAR) pcmd->use_sg; + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + } + else if( pcmd->request_buffer ) + { + pSRB->SGcount = 1; + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + else + pSRB->SGcount = 0; + + pSRB->SGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + if( pDCB->DevType != TYPE_TAPE ) + pSRB->RetryCnt = 1; + else + pSRB->RetryCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGBusAddr = 0; + pSRB->SGToBeXferLen = 0; + pSRB->ScsiPhase = 0; + pSRB->EndMessage = 0; +}; + /*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, @@ -425,272 +767,305 @@ * * Purpose : enqueues a SCSI command * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. + * Inputs : cmd - SCSI command, done - callback function called on + * completion, with a pointer to the command descriptor. * - * Returns : 0 + * Returns : (depending on kernel version) + * 2.0.x: always return 0 + * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x + * TO BE DONE: + * new model: return 0 if successful + * return 1 if command cannot be queued (queue full) + * command will be inserted in midlevel queue then ... * ***********************************************************************/ -int -DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - USHORT ioport, i; Scsi_Cmnd *pcmd; - struct Scsi_Host *psh; - PACB pACB; PDCB pDCB; PSRB pSRB; - ULONG flags; - PUCHAR ptr,ptr1; + DC390_AFLAGS + PACB pACB = (PACB) cmd->host->hostdata; - psh = cmd->host; - pACB = (PACB ) psh->hostdata; - ioport = pACB->IOPortBase; -#ifdef DC390_DEBUG0 -/* if(pACB->scan_devices) */ - printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun); -#endif + DEBUG0(/* if(pACB->scan_devices) */ \ + printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\ + cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);) + + DC390_LOCK_ACB; + + /* Assume BAD_TARGET; will be cleared later */ + cmd->result = DID_BAD_TARGET << 16; + + /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY + * commands and alloc a DCB for the device if not yet there. DCB will + * be removed in dc390_SRBdone if SEL_TIMEOUT */ if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) ) - { pACB->scan_devices = 0; - pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) ) - { + + else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) ) pACB->scan_devices = 0; - pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) ) + if ( ( cmd->target >= pACB->pScsiHost->max_id ) || + (cmd->lun >= pACB->pScsiHost->max_lun) ) { /* printk("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + DC390_UNLOCK_ACB; done(cmd); return( 0 ); } - if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { - if( pACB->DeviceCnt < MAX_DEVICES ) - { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); - pDCB = pACB->pDCB_free; -#ifdef DC390_DEBUG0 - printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target); -#endif - DC390_initDCB( pACB, pDCB, cmd ); - } - else /* ???? */ - { -/* printk("DC390: Ignore target %d lun %d\n", - cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + pACB->DCBmap[cmd->target] |= (1 << cmd->lun); + pACB->scan_devices = 1; + + dc390_initDCB( pACB, &pDCB, cmd ); + if (!pDCB) + { + printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target); + DC390_UNLOCK_ACB; done(cmd); return(0); - } + }; + } else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { -/* printk("DC390: Ignore target %d lun %d\n", - cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", + cmd->target, cmd->lun); + DC390_UNLOCK_ACB; done(cmd); return(0); } else { - pDCB = pACB->pLinkDCB; - while( (pDCB->UnitSCSIID != cmd->target) || - (pDCB->UnitSCSILUN != cmd->lun) ) - { - pDCB = pDCB->pNextDCB; - } -#ifdef DC390_DEBUG0 - printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target); -#endif + pDCB = dc390_findDCB (pACB, cmd); + if (!pDCB) + { /* should never happen */ + DC390_UNLOCK_ACB; + done(cmd); + return(0); + }; } + pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; - save_flags(flags); - cli(); - - if( pDCB->QIORBCnt ) + if( pDCB->QIORBCnt ) /* Unsent commands ? */ { - QLinkcmd( cmd, pDCB ); - pcmd = Getcmd( pDCB ); + dc390_QLinkcmd( cmd, pDCB ); + pcmd = dc390_Getcmd( pDCB ); /* Get first command */ + pACB->CmdInQ++; } else pcmd = cmd; - pSRB = GetSRB( pACB ); + pSRB = dc390_GetSRB( pACB ); if( !pSRB ) { - QLinkcmd( pcmd, pDCB ); - restore_flags(flags); + dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */ + pACB->CmdOutOfSRB++; + DC390_UNLOCK_ACB; return(0); } -/* BuildSRB(pSRB); */ + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_SendSRB( pACB, pSRB ); - pSRB->pSRBDCB = pDCB; - pSRB->pcmd = pcmd; - ptr = (PUCHAR) pSRB->CmdBlock; - ptr1 = (PUCHAR) pcmd->cmnd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - for(i=0; i< pcmd->cmd_len; i++) - { - *ptr = *ptr1; - ptr++; - ptr1++; - } - if( pcmd->use_sg ) - { - pSRB->SGcount = (UCHAR) pcmd->use_sg; - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - } - else if( pcmd->request_buffer ) - { - pSRB->SGcount = 1; - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } - else - pSRB->SGcount = 0; - - pSRB->SGIndex = 0; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pSRB->MsgCnt = 0; - if( pDCB->DevType != TYPE_TAPE ) - pSRB->RetryCnt = 1; - else - pSRB->RetryCnt = 0; - pSRB->SRBStatus = 0; - pSRB->SRBFlag = 0; - pSRB->SRBState = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGPhysAddr = 0; - pSRB->SGToBeXferLen = 0; - pSRB->ScsiPhase = 0; - pSRB->EndMessage = 0; - SendSRB( pcmd, pACB, pSRB ); - - restore_flags(flags); + DC390_UNLOCK_ACB; + DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);) return(0); } -static void -DoNextCmd( PACB pACB, PDCB pDCB ) +static void dc390_DoNextCmd( PACB pACB, PDCB pDCB ) { Scsi_Cmnd *pcmd; PSRB pSRB; - ULONG flags; - PUCHAR ptr,ptr1; - USHORT i; - if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) return; - save_flags(flags); - cli(); - pcmd = Getcmd( pDCB ); - pSRB = GetSRB( pACB ); + pcmd = dc390_Getcmd( pDCB ); + pSRB = dc390_GetSRB( pACB ); if( !pSRB ) - { - QLinkcmd( pcmd, pDCB ); - restore_flags(flags); - return; - } - - pSRB->pSRBDCB = pDCB; - pSRB->pcmd = pcmd; - ptr = (PUCHAR) pSRB->CmdBlock; - ptr1 = (PUCHAR) pcmd->cmnd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - for(i=0; i< pcmd->cmd_len; i++) - { - *ptr = *ptr1; - ptr++; - ptr1++; - } - if( pcmd->use_sg ) - { - pSRB->SGcount = (UCHAR) pcmd->use_sg; - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - } - else if( pcmd->request_buffer ) - { - pSRB->SGcount = 1; - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } + dc390_QLinkcmd( pcmd, pDCB ); else - pSRB->SGcount = 0; - - pSRB->SGIndex = 0; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pSRB->MsgCnt = 0; - if( pDCB->DevType != TYPE_TAPE ) - pSRB->RetryCnt = 1; - else - pSRB->RetryCnt = 0; - pSRB->SRBStatus = 0; - pSRB->SRBFlag = 0; - pSRB->SRBState = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGPhysAddr = 0; - pSRB->SGToBeXferLen = 0; - pSRB->ScsiPhase = 0; - pSRB->EndMessage = 0; - SendSRB( pcmd, pACB, pSRB ); - - restore_flags(flags); - return; + { + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_SendSRB( pACB, pSRB ); + }; +} + +/* We ignore mapping problems, as we expect everybody to respect + * valid partition tables. Waiting for complaints ;-) */ + +#ifdef CONFIG_SCSI_DC390T_TRADMAP +/* + * The next function, partsize(), is copied from scsicam.c. + * + * This is ugly code duplication, but I didn't find another way to solve it: + * We want to respect the partition table and if it fails, we apply the + * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do + * the job, because we don't know, whether the values returned are from + * the part. table or determined by setsize(). Unfortunately the setsize() + * values differ from the ones chosen by the DC390 BIOS. + * + * Looking forward to seeing suggestions for a better solution! KG, 98/10/14 + */ +#include + +/* + * Function : static int partsize(struct buffer_head *bh, unsigned long + * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); + * + * Purpose : to determine the BIOS mapping used to create the partition + * table, storing the results in *cyls, *hds, and *secs + * + * Returns : -1 on failure, 0 on success. + * + */ + +static int partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, unsigned int *secs) { + struct partition *p, *largest = NULL; + int i, largest_cyl; + int cyl, ext_cyl, end_head, end_cyl, end_sector; + unsigned int logical_end, physical_end, ext_physical_end; + + + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + for (largest_cyl = -1, p = (struct partition *) + (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { + if (!p->sys_ind) + continue; + cyl = p->cyl + ((p->sector & 0xc0) << 2); + if (cyl > largest_cyl) { + largest_cyl = cyl; + largest = p; + } + } + } + + if (largest) { + end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); + end_head = largest->end_head; + end_sector = largest->end_sector & 0x3f; + + physical_end = end_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; + + /* This is the actual _sector_ number at the end */ + logical_end = get_unaligned(&largest->start_sect) + + get_unaligned(&largest->nr_sects); + + /* This is for >1023 cylinders */ + ext_cyl= (logical_end-(end_head * end_sector + end_sector)) + /(end_head + 1) / end_sector; + ext_physical_end = ext_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; + + if ((logical_end == physical_end) || + (end_cyl==1023 && ext_physical_end==logical_end)) { + *secs = end_sector; + *hds = end_head + 1; + *cyls = capacity / ((end_head + 1) * end_sector); + return 0; + } + } + return -1; } - /*********************************************************************** * Function: * DC390_bios_param * * Description: * Return the disk geometry for the given SCSI device. + * Respect the partition table, otherwise try own heuristic + * + * Note: + * In contrary to other externally callable funcs (DC390_), we don't lock ***********************************************************************/ -int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]) +int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) { int heads, sectors, cylinders; - PACB pACB; + PACB pACB = (PACB) disk->device->host->hostdata; + struct buffer_head *bh; + int ret_code = -1; + int size = disk->capacity; - pACB = (PACB) disk->device->host->hostdata; - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) + if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024))) { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); + /* try to infer mapping from partition table */ + ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2, + (unsigned int *) geom + 0, (unsigned int *) geom + 1); + brelse (bh); } + if (ret_code == -1) + { + heads = 64; + sectors = 32; + cylinders = size / (heads * sectors); + + if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) + { + heads = 255; + sectors = 63; + cylinders = size / (heads * sectors); + } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + } return (0); } +#else +int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) +{ + return scsicam_bios_param (disk, devno, geom); +}; +#endif + + +void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) +{ + USHORT pstat; PDEVDECL1; + + if (pSRB) + { + printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n", + pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState, + pSRB->ScsiPhase); + printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus); + }; + printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus); + printk ("DC390: Register dump: SCSI block:\n"); + printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); + printk ("DC390: %06x %02x %02x %02x", + DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16), + DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State)); + printk (" %02x %02x %02x %02x %02x %02x\n", + DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), + DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); + printk ("DC390: Register dump: DMA engine:\n"); + printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n"); + printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n", + DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr), + DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr), + DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl)); + PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat); + printk ("DC390: Register dump: PCI Status: %04x\n", pstat); + printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n"); +}; /*********************************************************************** @@ -703,35 +1078,28 @@ * Returns : 0 on success, -1 on failure. ***********************************************************************/ -int -DC390_abort (Scsi_Cmnd *cmd) +int DC390_abort (Scsi_Cmnd *cmd) { - ULONG flags; - PACB pACB; - PDCB pDCB, pdcb; + PDCB pDCB; PSRB pSRB, psrb; - USHORT count, i; + ULONG count, i; PSCSICMD pcmd, pcmd1; int status; + ULONG sbac; + DC390_AFLAGS + PACB pACB = (PACB) cmd->host->hostdata; + + DC390_LOCK_ACB; + + pDCB = dc390_findDCB (pACB, cmd); + /* abort() is too buggy at the moment. If it's called we are in trouble anyway. + * so let's dump some info into the syslog at least. (KG, 98/08/20) */ + if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0; + printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n", + cmd->pid, pDCB, pSRB); + dc390_dumpinfo (pACB, pDCB, pSRB); - -#ifdef DC390_DEBUG0 - printk("DC390 : Abort Cmd."); -#endif - - save_flags(flags); - cli(); - - pACB = (PACB) cmd->host->hostdata; - pDCB = pACB->pLinkDCB; - pdcb = pDCB; - while( (pDCB->UnitSCSIID != cmd->target) || - (pDCB->UnitSCSILUN != cmd->lun) ) - { - pDCB = pDCB->pNextDCB; - if( pDCB == pdcb ) - goto NOT_RUN; - } + if( !pDCB ) goto NOT_RUN; if( pDCB->QIORBCnt ) { @@ -761,7 +1129,12 @@ } } } - + + /* Added 98/07/02 KG */ + pSRB = pDCB->pActiveSRB; + if (pSRB && pSRB->pcmd == cmd ) + goto ON_GOING; + pSRB = pDCB->pWaitingSRB; if( !pSRB ) goto ON_GOING; @@ -778,7 +1151,7 @@ while( psrb->pNextSRB->pcmd != cmd ) { psrb = psrb->pNextSRB; - if( !(psrb->pNextSRB) ) + if( !(psrb->pNextSRB) || psrb == pSRB) goto ON_GOING; } pSRB = psrb->pNextSRB; @@ -795,6 +1168,8 @@ ON_GOING: pSRB = pDCB->pGoingSRB; + pDCB->DCBFlag |= ABORT_DEV_; + /* Now for the hard part: The command is currently processed */ for( count = pDCB->GoingSRBCnt, i=0; ipcmd != cmd ) @@ -804,6 +1179,8 @@ if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) { status = SCSI_ABORT_BUSY; + printk ("DC390: Abort current command (pid %li, SRB %p)\n", + cmd->pid, pSRB); goto ABO_X; } else @@ -819,20 +1196,51 @@ ABO_X: cmd->result = DID_ABORT << 16; + printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); + if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ + { + /* Let's do something to help the bus getting clean again */ + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, DMA_COMMAND); + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + //DC390_write8 (ScsiCmd, RESET_ATN_CMD); + DC390_write8 (ScsiCmd, NOP_CMD); + //udelay (10000); + //DC390_read8 (INT_Status); + //DC390_write8 (ScsiCmd, EN_SEL_RESEL); + }; + sbac = DC390_read32 (DMA_ScsiBusCtrl); + if (sbac & SCSI_BUSY) + { /* clear BSY, SEL and ATN */ + printk (KERN_WARNING "DC390: Reset SCSI device: "); + //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES); + //udelay (250); + //sbac = DC390_read32 (DMA_ScsiBusCtrl); + //printk ("%08lx ", sbac); + //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM)); + //udelay (100); + //sbac = DC390_read32 (DMA_ScsiBusCtrl); + //printk ("%08lx ", sbac); + DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + udelay (250); + DC390_write8 (ScsiCmd, NOP_CMD); + sbac = DC390_read32 (DMA_ScsiBusCtrl); + printk ("%08lx\n", sbac); + }; + dc390_lastabortedpid = cmd->pid; + DC390_UNLOCK_ACB; + //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); cmd->scsi_done(cmd); - restore_flags(flags); return( status ); } -static void -ResetDevParam( PACB pACB ) +static void dc390_ResetDevParam( PACB pACB ) { PDCB pDCB, pdcb; pDCB = pACB->pLinkDCB; - if( pDCB == NULL ) - return; + if (! pDCB) return; pdcb = pDCB; do { @@ -840,24 +1248,22 @@ pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 &= NEGATE_REQACKDATA; - pDCB->CtrlR4 |= EATER_25NS; + pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; + pDCB->CtrlR4 |= pACB->glitch_cfg; pDCB = pDCB->pNextDCB; } while( pdcb != pDCB ); } -static void -RecoverSRB( PACB pACB ) +static void dc390_RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; - USHORT cnt, i; + ULONG cnt, i; pDCB = pACB->pLinkDCB; - if( pDCB == NULL ) - return; + if( !pDCB ) return; pdcb = pDCB; do { @@ -867,7 +1273,7 @@ { psrb2 = psrb; psrb = psrb->pNextSRB; -/* RewaitSRB( pDCB, psrb ); */ +/* dc390_RewaitSRB( pDCB, psrb ); */ if( pdcb->pWaitingSRB ) { psrb2->pNextSRB = pdcb->pWaitingSRB; @@ -884,8 +1290,7 @@ pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; - } - while( pdcb != pDCB ); + } while( pdcb != pDCB ); } @@ -901,77 +1306,80 @@ int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) { - USHORT ioport; - unsigned long flags; - PACB pACB; - UCHAR bval; - USHORT i; - + UCHAR bval; + ULONG i; + DC390_AFLAGS + PACB pACB = (PACB) cmd->host->hostdata; -#ifdef DC390_DEBUG1 - printk("DC390: RESET,"); -#endif + printk(KERN_INFO "DC390: RESET ... "); - pACB = (PACB ) cmd->host->hostdata; - ioport = pACB->IOPortBase; - save_flags(flags); - cli(); - bval = inb(ioport+CtrlReg1); + DC390_LOCK_ACB; + bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* disable interrupt */ - DC390_ResetSCSIBus( pACB ); - for( i=0; i<500; i++ ) - mdelay(1); - bval = inb(ioport+CtrlReg1); - bval &= ~DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* re-enable interrupt */ - - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = CLEAR_FIFO_CMD; - outb(bval,ioport+ScsiCmd); + DC390_write8 (CtrlReg1, bval); /* disable interrupt */ - ResetDevParam( pACB ); - DoingSRB_Done( pACB ); + dc390_ResetSCSIBus( pACB ); + /* Unlock ? */ + for( i=0; i<600; i++ ) + udelay(1000); + + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_read8 (INT_Status); /* Reset Pending INT */ + + dc390_ResetDevParam( pACB ); + dc390_DoingSRB_Done( pACB ); + /* dc390_RecoverSRB (pACB); */ pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - DoWaitingSRB( pACB ); + bval = DC390_read8 (CtrlReg1); + bval &= ~DIS_INT_ON_SCSI_RST; + DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ - restore_flags(flags); -#ifdef DC390_DEBUG1 - printk("DC390: RESET1,"); -#endif + dc390_DoWaitingSRB( pACB ); + + DC390_UNLOCK_ACB; + printk("done\n"); return( SCSI_RESET_SUCCESS ); } - #include "scsiiom.c" /*********************************************************************** - * Function : static void DC390_initDCB + * Function : static void dc390_initDCB * * Purpose : initialize the internal structures for a given DCB * * Inputs : cmd - pointer to this scsi cmd request block structure * ***********************************************************************/ -void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) { PEEprom prom; - UCHAR bval; - USHORT index; + UCHAR index; + PDCB pDCB; - if( pACB->DeviceCnt == 0 ) + pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC); + DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \ + cmd->target, cmd->lun, (int)pDCB);) + + *ppDCB = pDCB; + if (!pDCB) return; + if( pACB->DCBCnt == 0 ) { pACB->pLinkDCB = pDCB; pACB->pDCBRunRobin = pDCB; - pDCB->pNextDCB = pDCB; - pPrevDCB = pDCB; } else - pPrevDCB->pNextDCB = pDCB; + { + pACB->pLastDCB->pNextDCB = pDCB; + }; + + pACB->DCBCnt++; + + pACB->pLastDCB = pDCB; + pDCB->pNextDCB = pACB->pLinkDCB; pDCB->pDCBACB = pACB; pDCB->QIORBCnt = 0; @@ -983,122 +1391,143 @@ pDCB->pActiveSRB = NULL; pDCB->TagMask = 0; pDCB->MaxCommand = 1; - pDCB->AdaptIndex = pACB->AdapterIndex; index = pACB->AdapterIndex; pDCB->DCBFlag = 0; - prom = (PEEprom) &eepromBuf[index][cmd->target << 2]; + prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2]; pDCB->DevMode = prom->EE_MODE1; - pDCB->AdpMode = eepromBuf[index][EE_MODE2]; - - if( pDCB->DevMode & EN_DISCONNECT_ ) - bval = 0xC0; - else - bval = 0x80; - bval |= cmd->lun; - pDCB->IdentifyMsg = bval; pDCB->SyncMode = 0; - if( pDCB->DevMode & SYNC_NEGO_ ) - { - if( !(cmd->lun) || CurrSyncOffset ) - pDCB->SyncMode = SYNC_ENABLE; - } + dc390_updateDCB(pACB, pDCB); pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; - pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2; - - pDCB->CtrlR1 = pACB->AdaptSCSIID; - if( pDCB->DevMode & PARITY_CHK_ ) - pDCB->CtrlR1 |= PARITY_ERR_REPO; + pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 = EATER_25NS; - if( pDCB->AdpMode & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA; + pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; + if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } +/*********************************************************************** + * Function : static void dc390_updateDCB + * + * Purpose : Set the configuration dependent DCB parameters + * + ***********************************************************************/ +void dc390_updateDCB (PACB pACB, PDCB pDCB) +{ + pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN); + + if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP; + else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP; + + if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) ) + pDCB->SyncMode |= SYNC_ENABLE; + else + { + pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE); + pDCB->SyncOffset &= ~0x0f; + }; + + if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; + + pDCB->CtrlR1 = pACB->pScsiHost->this_id; + if( pDCB->DevMode & PARITY_CHK_ ) + pDCB->CtrlR1 |= PARITY_ERR_REPO; +}; + + +/*********************************************************************** + * Function : static void dc390_updateDCBs + * + * Purpose : Set the configuration dependent DCB params for all DCBs + * + ***********************************************************************/ +static void dc390_updateDCBs (PACB pACB) +{ + int i; + PDCB pDCB = pACB->pLinkDCB; + for (i = 0; i < pACB->DeviceCnt; i++) + { + dc390_updateDCB (pACB, pDCB); + pDCB = pDCB->pNextDCB; + }; +}; + /*********************************************************************** - * Function : static void DC390_initSRB + * Function : static void dc390_initSRB * * Purpose : initialize the internal structures for a given SRB * * Inputs : psrb - pointer to this scsi request block structure * ***********************************************************************/ -void DC390_initSRB( PSRB psrb ) +static void __inline__ dc390_initSRB( PSRB psrb ) { -#ifdef DC390_DEBUG0 - printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb)); -#endif - psrb->PhysSRB = virt_to_bus( psrb ); + /* psrb->PhysSRB = virt_to_phys( psrb ); */ } -void DC390_linkSRB( PACB pACB ) +void dc390_linkSRB( PACB pACB ) { - USHORT count, i; - PSRB psrb; + ULONG count, i; count = pACB->SRBCount; - for( i=0; i< count; i++) { if( i != count - 1) pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; - psrb = (PSRB) &pACB->SRB_array[i]; - DC390_initSRB( psrb ); + dc390_initSRB( &pACB->SRB_array[i] ); } } /*********************************************************************** - * Function : static void DC390_initACB + * Function : static void dc390_initACB * * Purpose : initialize the internal structures for a given SCSI host * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )) +void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { PACB pACB; - USHORT i; + UCHAR i; + DC390_AFLAGS psh->can_queue = MAX_CMD_QUEUE; psh->cmd_per_lun = MAX_CMD_PER_LUN; - psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID]; + psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; pACB = (PACB) psh->hostdata; + DC390_LOCK_INIT; + DC390_LOCK_ACB; + pACB->pScsiHost = psh; + pACB->IOPortBase = (USHORT) io_port; + pACB->IRQLevel = Irq; + + DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n", \ + index, psh->this_id, (int)io_port, Irq);) + psh->max_id = 8; -#ifdef CONFIG_SCSI_MULTI_LUN - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - psh->max_lun = 8; - else -#endif - psh->max_lun = 1; - pACB->max_id = 7; - if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) - pACB->max_id--; -#ifdef CONFIG_SCSI_MULTI_LUN - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - pACB->max_lun = 7; - else -#endif - pACB->max_lun = 0; + if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] ) + psh->max_id--; + psh->max_lun = 1; + if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK ) + psh->max_lun = 8; - pACB->pScsiHost = psh; - pACB->IOPortBase = (USHORT) io_port; pACB->pLinkDCB = NULL; pACB->pDCBRunRobin = NULL; pACB->pActiveDCB = NULL; @@ -1106,42 +1535,39 @@ pACB->SRBCount = MAX_SRB_CNT; pACB->AdapterIndex = index; pACB->status = 0; - pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID]; - pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); - pACB->AdaptSCSILUN = 0; + psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; pACB->DeviceCnt = 0; - pACB->IRQLevel = Irq; - pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2; + pACB->DCBCnt = 0; + pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM]; pACB->ACBFlag = 0; pACB->scan_devices = 1; - pACB->Gmode2 = eepromBuf[index][EE_MODE2]; - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - pACB->LUNchk = 1; - pACB->pDCB_free = &pACB->DCB_array[0]; - DC390_linkSRB( pACB ); + pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2]; + dc390_linkSRB( pACB ); pACB->pTmpSRB = &pACB->TmpSRB; - DC390_initSRB( pACB->pTmpSRB ); + dc390_initSRB( pACB->pTmpSRB ); for(i=0; iDCBmap[i] = 0; + pACB->sel_timeout = SEL_TIMEOUT; + pACB->glitch_cfg = EATER_25NS; + pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0; } /*********************************************************************** - * Function : static int DC390_initAdapter + * Function : static int dc390_initAdapter * * Purpose : initialize the SCSI chip ctrl registers * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index)) +int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { - USHORT ioport; - UCHAR bval; PACB pACB, pacb; - USHORT used_irq = 0; + UCHAR used_irq = 0, dstate; + int i; - pacb = pACB_start; + pacb = dc390_pACB_start; if( pacb != NULL ) { for ( ; (pacb != (PACB) -1) ; ) @@ -1158,49 +1584,54 @@ if( !used_irq ) { - if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL)) + if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) )) + { + printk(KERN_ERR "DC390: register IRQ error!\n"); + return( -1 ); + } + } + + if (check_region (io_port, psh->n_io_port)) { - printk("DC390: register IRQ error!\n"); + printk(KERN_ERR "DC390: register IO ports error!\n"); return( -1 ); } - } - - request_region(io_port,psh->n_io_port,"tmscsim"); - - ioport = (USHORT) io_port; - + else + request_region (io_port, psh->n_io_port, "tmscsim"); + pACB = (PACB) psh->hostdata; - bval = SEL_TIMEOUT; /* 250ms selection timeout */ - outb(bval,ioport+Scsi_TimeOut); - - bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */ - outb(bval,ioport+Clk_Factor); - - bval = NOP_CMD; /* NOP cmd - clear command register */ - outb(bval,ioport+ScsiCmd); - - bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */ - outb(bval,ioport+CtrlReg2); - - bval = FAST_CLK; /* fast clock */ - outb(bval,ioport+CtrlReg3); + /* pACB->IOPortBase = (USHORT) io_port; */ - bval = EATER_25NS; - if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION ) - bval |= NEGATE_REQACKDATA; - outb(bval,ioport+CtrlReg4); + DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port); /* Disable SCSI bus reset interrupt */ - bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */ - outb(bval,ioport+CtrlReg1); + if (pACB->Gmode2 & RST_SCSI_BUS) + { + dc390_ResetSCSIBus( pACB ); + /* Unlock before ? */ + for( i=0; i<600; i++ ) + udelay(1000); + }; + pACB->ACBFlag = 0; + + DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT); /* 250ms selection timeout */ + DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ); /* Conversion factor = 0 , 40MHz clock */ + DC390_write8 (ScsiCmd, NOP_CMD); /* NOP cmd - clear command register */ + DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD); /* Enable Feature and SCSI-2 */ + DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */ + DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */ + (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */ + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ return(0); } -void -DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval ) +static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval ) { - UCHAR bval; bval = 0; @@ -1208,15 +1639,68 @@ *regval = 0xc0; else *regval = 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); if(mode == DISABLE_CE) - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); } +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +static void __init dc390_EEpromDefaults (UCHAR index) +{ + PUCHAR ptr; + UCHAR id; + ptr = (PUCHAR) dc390_eepromBuf[index]; + + /* Adapter Settings */ + ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ + ptr[EE_MODE2] = (UCHAR)tmscsim[3]; + ptr[EE_DELAY] = 0; /* ?? */ + ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */ + + /* Device Settings */ + for (id = 0; id < MAX_SCSI_ID; id++) + { + ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ + ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ + }; + dc390_adapname = "AM53C974"; +} + +static void __init dc390_checkparams (void) +{ + PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\ + tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);) + if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */ + { + tmscsim[0] = 7; tmscsim[1] = 4; + tmscsim[2] = 9; tmscsim[3] = 15; + tmscsim[4] = 2; + printk (KERN_INFO "DC390: Using safe settings.\n"); + } + else + { + /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */ + if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4; + if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4; + }; +}; +/* Override defaults on cmdline: + * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) + */ +void __init dc390_setup (char *str, int *ints) +{ + int i; + for (i = 0; i < ints[0]; i++) + tmscsim[i] = ints[i+1]; + if (ints[0] > 5) + printk (KERN_NOTICE "DC390: ignore extra params!\n"); + /* dc390_checkparams (); */ +}; +#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + -void -DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry ) +static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) { UCHAR bval; @@ -1225,28 +1709,27 @@ { bval = 0x40; *regval = 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); } udelay(160); bval |= 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); bval = 0; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); } -UCHAR -DC390_EEpromInDO( struct pci_dev *pdev ) +static UCHAR __init dc390_EEpromInDO( PDEVDECL ) { UCHAR bval; - pci_write_config_byte(pdev, 0x80, 0x80); + PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80); udelay(160); - pci_write_config_byte(pdev, 0x80, 0x40); + PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40); udelay(160); - pci_read_config_byte(pdev, 0x00, &bval); + PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval); if(bval == 0x22) return(1); else @@ -1254,8 +1737,7 @@ } -USHORT -EEpromGetData1( struct pci_dev *pdev ) +static USHORT __init dc390_EEpromGetData1( PDEVDECL ) { UCHAR i; UCHAR carryFlag; @@ -1265,67 +1747,59 @@ for(i=0; i<16; i++) { wval <<= 1; - carryFlag = DC390_EEpromInDO(pdev); + carryFlag = dc390_EEpromInDO(PDEV); wval |= carryFlag; } return(wval); } -void -DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd ) +static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd ) { UCHAR i,j; - USHORT carryFlag; + UCHAR carryFlag; carryFlag = 1; j = 0x80; for(i=0; i<9; i++) { - DC390_EEpromOutDI(pdev,regval,carryFlag); + dc390_EEpromOutDI(PDEV,regval,carryFlag); carryFlag = (EEpromCmd & j) ? 1 : 0; j >>= 1; } } -void -DC390_ReadEEprom( struct pci_dev *pdev, int index ) +static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr) { UCHAR regval,cmd; - PUSHORT ptr; - USHORT i; + UCHAR i; - ptr = (PUSHORT) &eepromBuf[index][0]; cmd = EEPROM_READ; for(i=0; i<0x40; i++) { - DC390_EnDisableCE(ENABLE_CE, pdev, ®val); - DC390_Prepare(pdev, ®val, cmd); - *ptr = EEpromGetData1(pdev); - ptr++; - cmd++; - DC390_EnDisableCE(DISABLE_CE, pdev, ®val); + dc390_EnDisableCE(ENABLE_CE, PDEV, ®val); + dc390_Prepare(PDEV, ®val, cmd++); + *ptr++ = dc390_EEpromGetData1(PDEV); + dc390_EnDisableCE(DISABLE_CE, PDEV, ®val); } } -USHORT -DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index ) +static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) { - USHORT wval, rc, *ptr; UCHAR i; + char EEbuf[128]; + USHORT wval, *ptr = (PUSHORT)EEbuf; - DC390_ReadEEprom( pdev, index ); + dc390_ReadEEprom( PDEV, ptr ); + memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID); + memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], + &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID); wval = 0; - ptr = (PUSHORT) &eepromBuf[index][0]; - for(i=0; i<128 ;i+=2, ptr++) + for(i=0; i<0x40; i++, ptr++) wval += *ptr; - if( wval == 0x1234 ) - rc = 0; - else - rc = -1; - return( rc ); + return (wval == 0x1234 ? 0 : 1); } @@ -1338,71 +1812,95 @@ * * Preconditions : when this function is called, the chip_type * field of the pACB structure MUST have been set. + * + * Note: written in capitals, because the locking is only done here, + * not in DC390_detect, called from outside ***********************************************************************/ -__initfunc(static int -DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index)) +static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index) { PSH psh; PACB pACB; - - if( !DC390_CheckEEpromCheckSum( pdev, index ) ) + DC390_AFLAGS + + if (dc390_CheckEEpromCheckSum (PDEV, index)) { - psh = scsi_register( psht, sizeof(DC390_ACB) ); - if( !psh ) - return( -1 ); - if( !pSH_start ) - { - pSH_start = psh; - pSH_current = psh; - } - else - { - pSH_current->next = psh; - pSH_current = psh; - } +#ifdef CONFIG_SCSI_DC390T_NOGENSUPP + printk (KERN_ERR "DC390_init: No EEPROM found!\n"); + return( -1 ); +#else + int period; + printk (KERN_INFO "DC390_init: No EEPROM found!\n"); + printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n"); + dc390_checkparams (); + period = dc390_clock_period1[tmscsim[1]]; + printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz)," + " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1], + 40 / period, ((40%period)*10 + period/2) / period, + (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4])); + dc390_EEpromDefaults (index); +#endif + }; + + psh = scsi_register( psht, sizeof(DC390_ACB) ); + if( !psh ) return( -1 ); + + pACB = (PACB) psh->hostdata; + DC390_LOCK_INIT; + DC390_LOCK_ACB; -#ifdef DC390_DEBUG0 - printk("DC390: pSH = %8x,", (UINT) psh); - printk("DC390: Index %02i,", index); +#if 0 + if( !dc390_pSH_start ) + { + dc390_pSH_start = psh; + dc390_pSH_current = psh; + } + else + { + dc390_pSH_current->next = psh; + dc390_pSH_current = psh; + } #endif - DC390_initACB( psh, io_port, Irq, index ); - if( !DC390_initAdapter( psh, io_port, Irq, index ) ) - { - pACB = (PACB) psh->hostdata; - if( !pACB_start ) - { - pACB_start = pACB; - pACB_current = pACB; - pACB->pNextACB = (PACB) -1; - } - else - { - pACB_current->pNextACB = pACB; - pACB_current = pACB; - pACB->pNextACB = (PACB) -1; - } + DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);) + DEBUG0(printk("DC390: Index %02i,", index);) -#ifdef DC390_DEBUG0 - printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n", - (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array); - printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n", - sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ); -#endif + dc390_initACB( psh, io_port, Irq, index ); + PDEVSET; + + DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ + if( !dc390_initAdapter( psh, io_port, Irq, index ) ) + { + pACB = (PACB) psh->hostdata; + if( !dc390_pACB_start ) + { + dc390_pACB_start = pACB; + dc390_pACB_current = pACB; + pACB->pNextACB = (PACB) -1; } else { - pSH_start = NULL; - scsi_unregister( psh ); - return( -1 ); + dc390_pACB_current->pNextACB = pACB; + dc390_pACB_current = pACB; + pACB->pNextACB = (PACB) -1; } - return( 0 ); + + DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\ + (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);) + DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\ + sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );) + + DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ + + DC390_UNLOCK_ACB; + return (0); } else { - printk("DC390_init: EEPROM reading error!\n"); + //dc390_pSH_start = NULL; + scsi_unregister( psh ); + DC390_UNLOCK_ACB; return( -1 ); } } @@ -1421,54 +1919,437 @@ * ***********************************************************************/ -__initfunc(int -DC390_detect(Scsi_Host_Template *psht)) +#ifndef NEW_PCI +/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering: + * We use pci_set_master () for 2.1.x and this func for 2.0.x: */ +static void __init dc390_set_master (PDEVDECL) +{ + USHORT cmd; + UCHAR lat; + + PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd); + + if (! (cmd & PCI_COMMAND_MASTER)) { + printk("PCI: Enabling bus mastering for device %02x:%02x\n", + PCI_BUS_DEV); + cmd |= PCI_COMMAND_MASTER; + PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd); + } + PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat); + if (lat < 16 /* || lat == 255 */) { + printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n", + PCI_BUS_DEV, lat); + PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64); + } + +}; +#endif /* ! NEW_PCI */ + +static void __init dc390_set_pci_cfg (PDEVDECL) +{ + USHORT cmd; + PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd); + PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)); +}; + + +int __init DC390_detect (Scsi_Host_Template *psht) { - struct pci_dev *pdev = NULL; - UINT irq; + PDEVDECL0; + UCHAR irq; UINT io_port; - USHORT adaptCnt = 0; /* Number of boards detected */ + UCHAR adaptCnt = 0; /* Number of boards detected */ + DC390_IFLAGS DC390_DFLAGS - psht->proc_dir = &proc_scsi_tmscsim; + DC390_LOCK_DRV; + //dc390_pSHT_start = psht; + dc390_pACB_start = NULL; - InitialTime = 1; - pSHT_start = psht; - pACB_start = NULL; - - if ( pci_present() ) - while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev))) + if ( PCI_PRESENT ) + while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { - io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - irq = pdev->irq; -#ifdef DC390_DEBUG0 - printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq); -#endif - if( !DC390_init(psht, io_port, irq, pdev, adaptCnt)) + DC390_LOCK_IO; /* Remove this when going to new eh */ + PCI_GET_IO_AND_IRQ; + DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);) + + if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt)) + { + PCI_SET_MASTER; + dc390_set_pci_cfg (PDEV); adaptCnt++; + }; + DC390_UNLOCK_IO; /* Remove when going to new eh */ } - - InitialTime = 0; - adapterCnt = adaptCnt; + else + printk (KERN_ERR "DC390: No PCI BIOS found!\n"); + + if (adaptCnt) + psht->proc_dir = &DC390_proc_scsi_tmscsim; + + printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt); + dc390_adapterCnt = adaptCnt; + DC390_UNLOCK_DRV; return( adaptCnt ); } +static void dc390_inquiry_done (Scsi_Cmnd* cmd) +{ + printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n", + cmd->target, cmd->lun, cmd->result); + if (cmd->result) + { + PACB pACB = (PACB)cmd->host->hostdata; + PDCB pDCB = dc390_findDCB (pACB, cmd); + printk ("DC390: Unsetting DsCn, Sync and TagQ!\n"); + if (pDCB) + { + pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ ); + dc390_updateDCB (pACB, pDCB); + }; + }; + kfree (cmd->buffer); + kfree (cmd); +}; + +void dc390_inquiry (PACB pACB, PDCB pDCB) +{ + char* buffer; + Scsi_Cmnd* cmd; + buffer = kmalloc (256, GFP_ATOMIC); + cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC); + + memset (buffer, 0, 256); + memset (cmd, 0, sizeof(Scsi_Cmnd)); + cmd->cmnd[0] = INQUIRY; + cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0; + cmd->cmnd[4] = 0xff; + + cmd->cmd_len = 6; cmd->old_cmd_len = 6; + cmd->host = pACB->pScsiHost; + cmd->target = pDCB->UnitSCSIID; + cmd->lun = pDCB->UnitSCSILUN; + cmd->serial_number = 1; + cmd->bufflen = 128; + cmd->buffer = buffer; + cmd->request_bufflen = 128; + cmd->request_buffer = &buffer[128]; + cmd->done = dc390_inquiry_done; + cmd->scsi_done = dc390_inquiry_done; + cmd->timeout_per_command = HZ; + + cmd->request.rq_status = RQ_SCSI_BUSY; + + printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n", + pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_queue_command (cmd, dc390_inquiry_done); +}; + /******************************************************************** - * Function: tmscsim_set_info() - * - * Purpose: Set adapter info (!) + * Function: dc390_set_info() * - * Not yet implemented + * Purpose: Change adapter config * + * Strings are parsed similar to the output of tmscsim_proc_info () + * '-' means no change *******************************************************************/ -int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +static int dc390_scanf (char** p1, char** p2, int* var) { - return(-ENOSYS); /* Currently this is a no-op */ -} + *p2 = *p1; + *var = simple_strtoul (*p2, p1, 10); + if (*p2 == *p1) return -1; + *p1 = strtok (0, " \t\n:=,;."); + return 0; +}; + +#define SCANF(p1, p2, var, min, max) \ +if (dc390_scanf (&p1, &p2, &var)) goto einv; \ +else if (varmax) goto einv2 + +static int dc390_yesno (char** p, char* var, char bmask) +{ + switch (**p) + { + case 'Y': *var |= bmask; break; + case 'N': *var &= ~bmask; break; + case '-': break; + default: return -1; + } + *p = strtok (0, " \t\n:=,;"); + return 0; +}; + +#define YESNO(p, var, bmask) \ +if (dc390_yesno (&p, &var, bmask)) goto einv; \ +else dc390_updateDCB (pACB, pDCB); \ +if (!p) goto ok + +static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign) +{ + int dum; + if (! memcmp (*p1, txt, strlen(txt))) + { + *p2 = strtok (0, " \t\n:=,;"); + if (!*p2) return -1; + dum = simple_strtoul (*p2, p1, 10); + if (*p2 == *p1) return -1; + if (dum >= 0 && dum <= max) + { *var = (dum * 100) / scale; } + else return -2; + *p1 = strtok (0, " \t\n:=,;"); + if (*ign && *p1 && strlen(*p1) >= strlen(ign) && + !(memcmp (*p1, ign, strlen(ign)))) + *p1 = strtok (0, " \t\n:=,;"); + + } + return 0; +}; + +#define SEARCH(p1, p2, var, txt, max) \ +if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \ +else if (!p1) goto ok2 + +#define SEARCH2(p1, p2, var, txt, max, scale) \ +if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \ +else if (!p1) goto ok2 + +#define SEARCH3(p1, p2, var, txt, max, scale, ign) \ +if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \ +else if (!p1) goto ok2 + + +#ifdef DC390_PARSEDEBUG +static char _prstr[256]; +char* prstr (char* p, char* e) +{ + char* c = _prstr; + while (p < e) + if (*p == 0) { *c++ = ':'; p++; } + else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; } + else *c++ = *p++; + *c = 0; + return _prstr; +}; +#endif + +int dc390_set_info (char *buffer, int length, PACB pACB) +{ + char *pos = buffer, *p0 = buffer; + char needs_inquiry = 0; + int dum = 0; + char dev; + PDCB pDCB = pACB->pLinkDCB; + DC390_IFLAGS + DC390_AFLAGS + pos[length] = 0; + + DC390_LOCK_IO; + DC390_LOCK_ACB; + /* UPPERCASE */ + /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */ + while (*pos) + { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; }; + + /* We should protect __strtok ! */ + /* spin_lock (strtok_lock); */ + + /* Remove WS */ + pos = strtok (buffer, " \t:\n=,;"); + if (!pos) goto ok; + + next: + if (!memcmp (pos, "RESET", 5)) goto reset; + else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry; + else if (!memcmp (pos, "REMOVE", 6)) goto remove; + + if (isdigit (*pos)) + { + /* Device config line */ + int dev, id, lun; char* pdec; + char olddevmode; + + SCANF (pos, p0, dev, 0, pACB->DCBCnt-1); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + if (!pos) goto einv; + + PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));) + pDCB = pACB->pLinkDCB; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + /* Sanity Check */ + if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) + { + printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n", + dev, id, lun); + goto einv2; + }; + + olddevmode = pDCB->DevMode; + YESNO (pos, pDCB->DevMode, PARITY_CHK_); + needs_inquiry++; + YESNO (pos, pDCB->DevMode, SYNC_NEGO_); + if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--; + needs_inquiry++; + YESNO (pos, pDCB->DevMode, EN_DISCONNECT_); + if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--; + YESNO (pos, pDCB->DevMode, SEND_START_); + needs_inquiry++; + YESNO (pos, pDCB->DevMode, TAG_QUEUEING_); + if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--; + YESNO (pos, pDCB->SyncMode, EN_ATN_STOP); + + dc390_updateDCB (pACB, pDCB); + if (!pos) goto ok; + + olddevmode = pDCB->NegoPeriod; + /* Look for decimal point (Speed) */ + pdec = pos; + while (pdec++ < &buffer[length]) if (*pdec == '.') break; + /* NegoPeriod */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 76, 800); + pDCB->NegoPeriod = dum >> 2; + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; + if (!pos) goto ok; + if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;."); + } + else pos = strtok (0, " \t\n:=,;."); + if (!pos) goto ok; + + /* Speed: NegoPeriod */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 1, 13); + pDCB->NegoPeriod = (1000/dum) >> 2; + if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++; + if (!pos) goto ok; + /* decimal */ + if (pos-1 == pdec) + { + int dumold = dum; + dum = simple_strtoul (pos, &p0, 10) * 10; + for (; p0-pos > 1; p0--) dum /= 10; + pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2; + if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19; + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; + pos = strtok (0, " \t\n:=,;"); + if (!pos) goto ok; + }; + if (*pos == 'M') pos = strtok (0, " \t\n:=,;"); + } + else pos = strtok (0, " \t\n:=,;"); + /* dc390_updateDCB (pACB, pDCB); */ + if (!pos) goto ok; + + olddevmode = pDCB->SyncOffset; + /* SyncOffs */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 0, 0x0f); + pDCB->SyncOffset = dum; + if (pDCB->SyncOffset > olddevmode) needs_inquiry++; + } + else pos = strtok (0, " \t\n:=,;"); + dc390_updateDCB (pACB, pDCB); + } + else + { + char* p1 = pos; UCHAR dum; + PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));) + dum = GLITCH_TO_NS (pACB->glitch_cfg); + /* Adapter setting */ + SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); + SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); + SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); + SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); + SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255); + SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); + SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); + ok2: + pACB->glitch_cfg = NS_TO_GLITCH (dum); + if (pACB->sel_timeout < 60) pACB->sel_timeout = 60; + dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; + pACB->TagMaxNum &= (1 << --dum); + if (pos == p1) goto einv; + dc390_updateDCBs (pACB); + } + if (pos) goto next; + + ok: + /* spin_unlock (strtok_lock); */ + DC390_UNLOCK_ACB; + if (needs_inquiry) + { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); }; + DC390_UNLOCK_IO; + return (length); + + einv2: + pos = p0; + einv: + /* spin_unlock (strtok_lock); */ + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL")); + return (-EINVAL); + + reset: + { + Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost; + printk (KERN_WARNING "DC390: Driver reset requested!\n"); + DC390_UNLOCK_ACB; + DC390_reset (&cmd, 0); + DC390_UNLOCK_IO; + }; + return (length); + + inquiry: + { + pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + dev = simple_strtoul (pos, &p0, 10); + if (dev >= pACB->DCBCnt) goto einv_dev; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n", + dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_UNLOCK_ACB; + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + + remove: + { + pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + dev = simple_strtoul (pos, &p0, 10); + if (dev >= pACB->DCBCnt) goto einv_dev; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n", + dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dc390_remove_dev (pACB, pDCB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + }; + return (length); + + einv_dev: + printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", + dev, pACB->DCBCnt - 1); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + return (-EINVAL); + + +} + +#undef SEARCH +#undef YESNO +#undef SCANF /******************************************************************** - * Function: tmscsim_proc_info(char* buffer, char **start, + * Function: DC390_proc_info(char* buffer, char **start, * off_t offset, int length, int hostno, int inout) * * Purpose: return SCSI Adapter/Device Info @@ -1491,79 +2372,86 @@ #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, ## args) -#define YESNO(YN)\ -if (YN) SPRINTF(" Yes ");\ -else SPRINTF(" No ") +#define YESNO(YN) \ + if (YN) SPRINTF(" Yes "); \ + else SPRINTF(" No ") + -int tmscsim_proc_info(char *buffer, char **start, - off_t offset, int length, int hostno, int inout) +int DC390_proc_info (char *buffer, char **start, + off_t offset, int length, int hostno, int inout) { int dev, spd, spd1; char *pos = buffer; PSH shpnt; - PACB acbpnt; - PDCB dcbpnt; - unsigned long flags; -/* Scsi_Cmnd *ptr; */ + PACB pACB; + PDCB pDCB; + DC390_AFLAGS - acbpnt = pACB_start; + pACB = dc390_pACB_start; - while(acbpnt != (PACB)-1) + while(pACB != (PACB)-1) { - shpnt = acbpnt->pScsiHost; + shpnt = pACB->pScsiHost; if (shpnt->host_no == hostno) break; - acbpnt = acbpnt->pNextACB; + pACB = pACB->pNextACB; } - if (acbpnt == (PACB)-1) return(-ESRCH); + if (pACB == (PACB)-1) return(-ESRCH); if(!shpnt) return(-ESRCH); if(inout) /* Has data been written to the file ? */ - return(tmscsim_set_info(buffer, length, shpnt)); + return dc390_set_info(buffer, length, pACB); + + SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, "); + SPRINTF("Driver Version %s\n", DC390_VERSION); - SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, "); - SPRINTF("Driver Version 1.12, 1998/02/25\n"); - - save_flags(flags); - cli(); + DC390_LOCK_ACB; SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); - SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex); - SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel); - - SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun); - SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN); - - SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status); + SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); + SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); + SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel); + + SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); + SPRINTF("AdapterID %i, SelTimeout %i ms\n", + shpnt->this_id, (pACB->sel_timeout*164)/100); + + SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n", + pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); + + SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n", + pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); + SPRINTF(" Lost arbitrations %li\n", pACB->SelLost); + + SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt); - SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt); + SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n"); - SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n"); - - dcbpnt = acbpnt->pLinkDCB; - for (dev = 0; dev < acbpnt->DeviceCnt; dev++) + pDCB = pACB->pLinkDCB; + for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN); - YESNO(dcbpnt->DevMode & PARITY_CHK_); - YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE); - YESNO(dcbpnt->DevMode & EN_DISCONNECT_); - YESNO(dcbpnt->DevMode & SEND_START_); - YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING); - SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2); - if (dcbpnt->SyncOffset & 0x0f) + SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + YESNO(pDCB->DevMode & PARITY_CHK_); + YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); + YESNO(pDCB->DevMode & EN_DISCONNECT_); + //YESNO(pDCB->SyncMode & EN_ATN_STOP); + YESNO(pDCB->DevMode & SEND_START_); + YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); + YESNO(pDCB->SyncMode & EN_ATN_STOP); + if (pDCB->SyncOffset & 0x0f) { - spd = 1000/(dcbpnt->NegoPeriod <<2); - spd1 = 1000%(dcbpnt->NegoPeriod <<2); - spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f)); + int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; + SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); + spd = 40/(sp); spd1 = 40%(sp); + spd1 = (spd1 * 10 + sp/2) / (sp); + SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f)); } - else SPRINTF("\n"); + else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2); /* Add more info ...*/ - dcbpnt = dcbpnt->pNextDCB; + pDCB = pDCB->pNextDCB; } - restore_flags(flags); + DC390_UNLOCK_ACB; *start = buffer + offset; if (pos - buffer < offset) @@ -1574,75 +2462,92 @@ return length; } +#undef YESNO +#undef SPRINTF #ifdef MODULE /*********************************************************************** - * Function : static int DC390_shutdown (struct Scsi_Host *host) + * Function : static int dc390_shutdown (struct Scsi_Host *host) * * Purpose : does a clean (we hope) shutdown of the SCSI chip. * Use prior to dumping core, unloading the driver, etc. * * Returns : 0 on success ***********************************************************************/ -static int -DC390_shutdown (struct Scsi_Host *host) +static int dc390_shutdown (struct Scsi_Host *host) { UCHAR bval; - USHORT ioport; - unsigned long flags; PACB pACB = (PACB)(host->hostdata); - - ioport = (unsigned int) pACB->IOPortBase; - - save_flags (flags); - cli(); - + /* pACB->soft_reset(host); */ -#ifdef DC390_DEBUG0 - printk("DC390: shutdown,"); -#endif + printk(KERN_INFO "DC390: shutdown\n"); - bval = inb(ioport+CtrlReg1); + pACB->ACBFlag = RESET_DONE; + bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* disable interrupt */ - DC390_ResetSCSIBus( pACB ); + DC390_write8 (CtrlReg1, bval); /* disable interrupt */ + if (pACB->Gmode2 & RST_SCSI_BUS) + dc390_ResetSCSIBus (pACB); - restore_flags (flags); return( 0 ); } +void dc390_freeDCBs (struct Scsi_Host *host) +{ + PDCB pDCB, nDCB; + PACB pACB = (PACB)(host->hostdata); + + pDCB = pACB->pLinkDCB; + if (!pDCB) return; + do + { + nDCB = pDCB->pNextDCB; + DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\ + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) + kfree (pDCB); + pDCB = nDCB; + } while (pDCB && pDCB != pACB->pLinkDCB); + +}; int DC390_release(struct Scsi_Host *host) { - int irq_count; - struct Scsi_Host *tmp; + int irq_count; + PACB pACB; + DC390_AFLAGS DC390_IFLAGS +#if USE_SPINLOCKS > 1 + PACB pACB = (PACB)(host->hostdata); +#endif + + DC390_LOCK_IO; + DC390_LOCK_ACB; - DC390_shutdown (host); + dc390_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next) + for (irq_count = 0, pACB = dc390_pACB_start; + pACB && pACB != (PACB)-1; pACB = pACB->pNextACB) { - if ( tmp->irq == host->irq ) + if ( pACB->IRQLevel == host->irq ) ++irq_count; } if (irq_count == 1) { -#ifdef DC390_DEBUG0 - printk("DC390: Free IRQ %i.",host->irq); -#endif + DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);) free_irq(host->irq,NULL); } } release_region(host->io_port,host->n_io_port); - + dc390_freeDCBs (host); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; return( 1 ); } Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" #endif /* def MODULE */ - diff -u --recursive --new-file v2.1.126/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h --- v2.1.126/linux/drivers/scsi/tmscsim.h Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/tmscsim.h Tue Oct 27 10:10:08 1998 @@ -3,12 +3,23 @@ ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * ;* Device Driver * ;***********************************************************************/ +/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */ #ifndef _TMSCSIM_H #define _TMSCSIM_H #define IRQ_NONE 255 +#define MAX_ADAPTER_NUM 4 +#define MAX_SG_LIST_BUF 16 +#define MAX_CMD_PER_LUN 8 +#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1 +#define MAX_SCSI_ID 8 +#define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */ +#define END_SCAN 2 + +#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ + typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned long ULONG; @@ -54,17 +65,6 @@ } SGentry1, *PSGE; -#define MAX_ADAPTER_NUM 4 -#define MAX_DEVICES 10 -#define MAX_SG_LIST_BUF 16 -#define MAX_CMD_QUEUE 20 -#define MAX_CMD_PER_LUN 8 -#define MAX_SCSI_ID 8 -#define MAX_SRB_CNT MAX_CMD_QUEUE+4 -#define END_SCAN 2 - -#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ - /* ;----------------------------------------------------------------------- ; SCSI Request Block @@ -79,40 +79,46 @@ PSCSICMD pcmd; PSGL pSegmentList; -ULONG PhysSRB; +ULONG Segment0[2]; +ULONG Segment1[2]; + +/* 0x2c:*/ ULONG TotalXferredLen; -ULONG SGPhysAddr; /*;a segment starting address */ +ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/ ULONG SGToBeXferLen; /*; to be xfer length */ +ULONG SRBState; + +/* 0x3c: */ +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; +/* 0x48: */ SGL Segmentx; /* make a one entry of S/G list table */ PUCHAR pMsgPtr; -USHORT SRBState; -USHORT Revxx2; /* ??? */ -UCHAR MsgInBuf[6]; -UCHAR MsgOutBuf[6]; +UCHAR ScsiCmdLen; +UCHAR ScsiPhase; UCHAR AdaptStatus; UCHAR TargetStatus; + +/* 0x5c: */ UCHAR MsgCnt; UCHAR EndMessage; +UCHAR RetryCnt; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ UCHAR TagNumber; UCHAR SGcount; UCHAR SGIndex; -UCHAR IORBFlag; /*;81h-Reset, 2-retry */ - UCHAR SRBStatus; -UCHAR RetryCnt; -UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -UCHAR ScsiCmdLen; -UCHAR ScsiPhase; -UCHAR Reserved3[3]; /*;for dword alignment */ -ULONG Segment0[2]; -ULONG Segment1[2]; + //UCHAR IORBFlag; /*;81h-Reset, 2-retry */ + +/* 0x64: */ }; + typedef struct _SRB DC390_SRB, *PSRB; /* @@ -129,42 +135,44 @@ PSCSICMD pQIORBtail; PSCSICMD AboIORBhead; PSCSICMD AboIORBtail; -USHORT QIORBCnt; -USHORT AboIORBcnt; +ULONG QIORBCnt; +ULONG AboIORBcnt; +/* 0x20: */ PSRB pWaitingSRB; PSRB pWaitLast; PSRB pGoingSRB; PSRB pGoingLast; PSRB pActiveSRB; -USHORT GoingSRBCnt; -USHORT WaitSRBCnt; /* ??? */ +UCHAR GoingSRBCnt; +UCHAR WaitSRBCnt; /* ??? */ +UCHAR DevType; +UCHAR MaxCommand; +/* 0x38: */ ULONG TagMask; -USHORT MaxCommand; -USHORT AdaptIndex; /*; UnitInfo struc start */ -USHORT UnitIndex; /*; nth Unit on this card */ UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ - +UCHAR DevMode; UCHAR IdentifyMsg; + UCHAR CtrlR1; UCHAR CtrlR3; UCHAR CtrlR4; -UCHAR InqDataBuf[8]; -UCHAR CapacityBuf[8]; -UCHAR DevMode; -UCHAR AdpMode; +UCHAR DCBFlag; + +/* 0x44: */ UCHAR SyncMode; /*; 0:async mode */ UCHAR NegoPeriod; /*;for nego. */ UCHAR SyncPeriod; /*;for reg. */ UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ -UCHAR UnitCtrlFlag; -UCHAR DCBFlag; -UCHAR DevType; -UCHAR Reserved2[3]; /*;for dword alignment */ + +/* 0x48:*/ +//UCHAR InqDataBuf[8]; +//UCHAR CapacityBuf[8]; +/* 0x58: */ }; typedef struct _DCB DC390_DCB, *PDCB; @@ -175,40 +183,55 @@ */ struct _ACB { -ULONG PhysACB; PSH pScsiHost; struct _ACB *pNextACB; USHORT IOPortBase; -USHORT Revxx1; /* ??? */ +UCHAR IRQLevel; +UCHAR status; + +UCHAR SRBCount; +UCHAR AdapterIndex; /*; nth Adapter this driver */ +UCHAR DeviceCnt; +UCHAR DCBCnt; + +/* 0x10: */ +UCHAR TagMaxNum; +UCHAR ACBFlag; +UCHAR Gmode2; +UCHAR scan_devices; PDCB pLinkDCB; +PDCB pLastDCB; PDCB pDCBRunRobin; PDCB pActiveDCB; -PDCB pDCB_free; PSRB pFreeSRB; PSRB pTmpSRB; -USHORT SRBCount; -USHORT AdapterIndex; /*; nth Adapter this driver */ -USHORT max_id; -USHORT max_lun; + +/* 0x2c: */ UCHAR msgin123[4]; -UCHAR status; -UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */ -UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */ -UCHAR DeviceCnt; -UCHAR IRQLevel; -UCHAR TagMaxNum; -UCHAR ACBFlag; -UCHAR Gmode2; -UCHAR LUNchk; -UCHAR scan_devices; -UCHAR HostID_Bit; -UCHAR Reserved1[1]; /*;for dword alignment */ UCHAR DCBmap[MAX_SCSI_ID]; -DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */ -DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */ + +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +spinlock_t lock; +#endif +UCHAR sel_timeout; +UCHAR glitch_cfg; + +UCHAR reserved[2]; /* alignment */ + +PDEVDECL1; /* Pointer to PCI cfg. space */ +/* 0x44/0x40: */ +ULONG Cmds; +ULONG CmdInQ; +ULONG CmdOutOfSRB; +ULONG SelLost; + +/* 0x50/0x4c: */ DC390_SRB TmpSRB; +/* 0xb4/0xb0: */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */ +/* 0x7bc/0x7b8: */ }; typedef struct _ACB DC390_ACB, *PACB; @@ -278,14 +301,6 @@ #define DO_SYNC_NEGO BIT13 #define SRB_UNEXPECT_RESEL BIT14 -/*;---ACBFlag */ -#define RESET_DEV BIT0 -#define RESET_DETECT BIT1 -#define RESET_DONE BIT2 - -/*;---DCBFlag */ -#define ABORT_DEV_ BIT0 - /*;---SRBstatus */ #define SRB_OK BIT0 #define ABORTION BIT1 @@ -294,6 +309,14 @@ #define PARITY_ERROR BIT4 #define SRB_ERROR BIT5 +/*;---ACBFlag */ +#define RESET_DEV BIT0 +#define RESET_DETECT BIT1 +#define RESET_DONE BIT2 + +/*;---DCBFlag */ +#define ABORT_DEV_ BIT0 + /*;---SRBFlag */ #define DATAOUT BIT7 #define DATAIN BIT6 @@ -316,7 +339,7 @@ #define H_BAD_CCB_OR_SG 0x1A #define H_ABORT 0x0FF -/*; SCSI Status byte codes*/ +/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */ #define SCSI_STAT_GOOD 0x0 /*; Good status */ #define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ #define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ @@ -335,9 +358,9 @@ #define SYNC_DISABLE 0 #define SYNC_ENABLE BIT0 #define SYNC_NEGO_DONE BIT1 -#define WIDE_ENABLE BIT2 -#define WIDE_NEGO_DONE BIT3 -#define EN_TAG_QUEUING BIT4 +#define WIDE_ENABLE BIT2 /* Not used ;-) */ +#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */ +#define EN_TAG_QUEUEING BIT4 #define EN_ATN_STOP BIT5 #define SYNC_NEGO_OFFSET 15 @@ -352,7 +375,7 @@ #define SCSI_MSG_OUT 6 #define SCSI_MSG_IN 7 -/*;----SCSI MSG BYTE*/ +/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ #define MSG_COMPLETE 0x00 #define MSG_EXTENDED 0x01 #define MSG_SAVE_PTR 0x02 @@ -373,13 +396,6 @@ #define MSG_IDENTIFY 0x80 #define MSG_HOST_ID 0x0C0 -/*;----SCSI STATUS BYTE*/ -#define STATUS_GOOD 0x00 -#define CHECK_CONDITION_ 0x02 -#define STATUS_BUSY 0x08 -#define STATUS_INTERMEDIATE 0x10 -#define RESERVE_CONFLICT 0x18 - /* cmd->result */ #define STATUS_MASK_ 0xFF #define MSG_MASK 0xFF00 @@ -389,7 +405,7 @@ ** Inquiry Data format */ -typedef struct _SCSIInqData { /* INQ */ +typedef struct _SCSIInqData { /* INQUIRY */ UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/ UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */ @@ -412,6 +428,7 @@ #define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ #define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ +#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */ /* Inquiry byte 1 mask */ @@ -420,18 +437,10 @@ /* Peripheral Device Type definitions */ +/* see include/scsi/scsi.h for the rest */ -#define SCSI_DASD 0x00 /* Direct-access Device */ -#define SCSI_SEQACESS 0x01 /* Sequential-access device */ -#define SCSI_PRINTER 0x02 /* Printer device */ -#define SCSI_PROCESSOR 0x03 /* Processor device */ -#define SCSI_WRITEONCE 0x04 /* Write-once device */ -#define SCSI_CDROM 0x05 /* CD-ROM device */ -#define SCSI_SCANNER 0x06 /* Scanner device */ -#define SCSI_OPTICAL 0x07 /* Optical memory device */ -#define SCSI_MEDCHGR 0x08 /* Medium changer device */ -#define SCSI_COMM 0x09 /* Communications device */ -#define SCSI_NODEV 0x1F /* Unknown or no device type */ +#define TYPE_PRINTER 0x02 /* Printer device */ +#define TYPE_COMM 0x09 /* Communications device */ /* ** Inquiry flag definitions (Inq data byte 7) @@ -459,17 +468,24 @@ UCHAR xx2; } EEprom, *PEEprom; -#define EE_ADAPT_SCSI_ID 64 -#define EE_MODE2 65 -#define EE_DELAY 66 -#define EE_TAG_CMD_NUM 67 +#define REAL_EE_ADAPT_SCSI_ID 64 +#define REAL_EE_MODE2 65 +#define REAL_EE_DELAY 66 +#define REAL_EE_TAG_CMD_NUM 67 + +#define EE_ADAPT_SCSI_ID 32 +#define EE_MODE2 33 +#define EE_DELAY 34 +#define EE_TAG_CMD_NUM 35 + +#define EE_LEN 40 /*; EE_MODE1 bits definition*/ #define PARITY_CHK_ BIT0 #define SYNC_NEGO_ BIT1 #define EN_DISCONNECT_ BIT2 #define SEND_START_ BIT3 -#define TAG_QUEUING_ BIT4 +#define TAG_QUEUEING_ BIT4 /*; EE_MODE2 bits definition*/ #define MORE2_DRV BIT0 @@ -494,34 +510,42 @@ ;==================== */ -/*; Command Reg.(+0CH) */ +/*; Command Reg.(+0CH) (rw) */ #define DMA_COMMAND BIT7 #define NOP_CMD 0 #define CLEAR_FIFO_CMD 1 #define RST_DEVICE_CMD 2 #define RST_SCSI_BUS_CMD 3 + #define INFO_XFER_CMD 0x10 #define INITIATOR_CMD_CMPLTE 0x11 #define MSG_ACCEPTED_CMD 0x12 #define XFER_PAD_BYTE 0x18 #define SET_ATN_CMD 0x1A #define RESET_ATN_CMD 0x1B -#define SELECT_W_ATN 0x42 + +#define SEL_WO_ATN 0x41 /* currently not used */ +#define SEL_W_ATN 0x42 #define SEL_W_ATN_STOP 0x43 +#define SEL_W_ATN3 0x46 #define EN_SEL_RESEL 0x44 -#define SEL_W_ATN2 0x46 +#define DIS_SEL_RESEL 0x45 /* currently not used */ +#define RESEL 0x40 /* " */ +#define RESEL_ATN3 0x47 /* " */ + #define DATA_XFER_CMD INFO_XFER_CMD -/*; SCSI Status Reg.(+10H) */ +/*; SCSI Status Reg.(+10H) (r) */ #define INTERRUPT BIT7 #define ILLEGAL_OP_ERR BIT6 #define PARITY_ERR BIT5 #define COUNT_2_ZERO BIT4 #define GROUP_CODE_VALID BIT3 -#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) +#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) +/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */ -/*; Interrupt Status Reg.(+14H) */ +/*; Interrupt Status Reg.(+14H) (r) */ #define SCSI_RESET BIT7 #define INVALID_CMD BIT6 #define DISCONNECTED BIT5 @@ -531,11 +555,12 @@ #define SEL_ATTENTION BIT1 #define SELECTED BIT0 -/*; Internal State Reg.(+18H) */ +/*; Internal State Reg.(+18H) (r) */ #define SYNC_OFFSET_FLAG BIT3 #define INTRN_STATE_MASK (BIT2+BIT1+BIT0) +/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */ -/*; Clock Factor Reg.(+24H) */ +/*; Clock Factor Reg.(+24H) (w) */ #define CLK_FREQ_40MHZ 0 #define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0) #define CLK_FREQ_30MHZ (BIT2+BIT1) @@ -544,47 +569,54 @@ #define CLK_FREQ_15MHZ (BIT1+BIT0) #define CLK_FREQ_10MHZ BIT1 -/*; Control Reg. 1(+20H) */ +/*; Control Reg. 1(+20H) (rw) */ #define EXTENDED_TIMING BIT7 #define DIS_INT_ON_SCSI_RST BIT6 #define PARITY_ERR_REPO BIT4 -#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) +#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */ -/*; Control Reg. 2(+2CH) */ +/*; Control Reg. 2(+2CH) (rw) */ #define EN_FEATURE BIT6 #define EN_SCSI2_CMD BIT3 -/*; Control Reg. 3(+30H) */ +/*; Control Reg. 3(+30H) (rw) */ #define ID_MSG_CHECK BIT7 #define EN_QTAG_MSG BIT6 #define EN_GRP2_CMD BIT5 #define FAST_SCSI BIT4 /* ;10MB/SEC */ #define FAST_CLK BIT3 /* ;25 - 40 MHZ */ -/*; Control Reg. 4(+34H) */ +/*; Control Reg. 4(+34H) (rw) */ #define EATER_12NS 0 #define EATER_25NS BIT7 #define EATER_35NS BIT6 #define EATER_0NS (BIT7+BIT6) +#define REDUCED_POWER BIT5 +#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */ #define NEGATE_REQACKDATA BIT2 #define NEGATE_REQACK BIT3 + +#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2))) +#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0) + /* ;==================== ; DMA Register ;==================== */ -/*; DMA Command Reg.(+40H) */ +/*; DMA Command Reg.(+40H) (rw) */ #define READ_DIRECTION BIT7 #define WRITE_DIRECTION 0 #define EN_DMA_INT BIT6 -#define MAP_TO_MDL BIT5 -#define DIAGNOSTIC BIT4 +#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */ +#define MAP_TO_MDL BIT4 +#define DIAGNOSTIC BIT2 #define DMA_IDLE_CMD 0 #define DMA_BLAST_CMD BIT0 #define DMA_ABORT_CMD BIT1 #define DMA_START_CMD (BIT1+BIT0) -/*; DMA Status Reg.(+54H) */ +/*; DMA Status Reg.(+54H) (r) */ #define PCI_MS_ABORT BIT6 #define BLAST_COMPLETE BIT5 #define SCSI_INTERRUPT BIT4 @@ -593,71 +625,77 @@ #define DMA_XFER_ERROR BIT1 #define POWER_DOWN BIT0 -/* -; DMA SCSI Bus and Ctrl.(+70H) -;EN_INT_ON_PCI_ABORT -*/ +/*; DMA SCSI Bus and Ctrl.(+70H) */ +#define EN_INT_ON_PCI_ABORT BIT25 +#define WRT_ERASE_DMA_STAT BIT24 +#define PW_DOWN_CTRL BIT21 +#define SCSI_BUSY BIT20 +#define SCLK BIT19 +#define SCAM BIT18 +#define SCSI_LINES 0x0003ffff /* ;========================================================== ; SCSI Chip register address offset ;========================================================== +;Registers are rw unless declared otherwise */ -#define CtcReg_Low 0x00 -#define CtcReg_Mid 0x04 +#define CtcReg_Low 0x00 /* r curr. transfer count */ +#define CtcReg_Mid 0x04 /* r */ +#define CtcReg_High 0x38 /* r */ #define ScsiFifo 0x08 #define ScsiCmd 0x0C -#define Scsi_Status 0x10 -#define INT_Status 0x14 -#define Sync_Period 0x18 -#define Sync_Offset 0x1C -#define CtrlReg1 0x20 -#define Clk_Factor 0x24 +#define Scsi_Status 0x10 /* r */ +#define INT_Status 0x14 /* r */ +#define Sync_Period 0x18 /* w */ +#define Sync_Offset 0x1C /* w */ +#define Clk_Factor 0x24 /* w */ +#define CtrlReg1 0x20 #define CtrlReg2 0x2C #define CtrlReg3 0x30 #define CtrlReg4 0x34 -#define CtcReg_High 0x38 #define DMA_Cmd 0x40 -#define DMA_XferCnt 0x44 -#define DMA_XferAddr 0x48 -#define DMA_Wk_ByteCntr 0x4C -#define DMA_Wk_AddrCntr 0x50 -#define DMA_Status 0x54 -#define DMA_MDL_Addr 0x58 -#define DMA_Wk_MDL_Cntr 0x5C -#define DMA_ScsiBusCtrl 0x70 - -#define StcReg_Low CtcReg_Low -#define StcReg_Mid CtcReg_Mid -#define Scsi_Dest_ID Scsi_Status -#define Scsi_TimeOut INT_Status -#define Intern_State Sync_Period -#define Current_Fifo Sync_Offset -#define StcReg_High CtcReg_High - -#define am_target Scsi_Status -#define am_timeout INT_Status -#define am_seq_step Sync_Period -#define am_fifo_count Sync_Offset - - -#define DC390_read8(address) \ - inb(DC390_ioport + (address))) - -#define DC390_read16(address) \ - inw(DC390_ioport + (address))) - -#define DC390_read32(address) \ - inl(DC390_ioport + (address))) +#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */ +#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */ +#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */ +#define DMA_Wk_AddrCntr 0x50 /* r working address counter */ +#define DMA_Status 0x54 /* r */ +#define DMA_MDL_Addr 0x58 /* rw starting MDL address */ +#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */ +#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */ + +#define StcReg_Low CtcReg_Low /* w start transfer count */ +#define StcReg_Mid CtcReg_Mid /* w */ +#define StcReg_High CtcReg_High /* w */ +#define Scsi_Dest_ID Scsi_Status /* w */ +#define Scsi_TimeOut INT_Status /* w */ +#define Intern_State Sync_Period /* r */ +#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */ + + +#define DC390_read8(address) \ + (inb (pACB->IOPortBase + (address))) + +#define DC390_read8_(address, base) \ + (inb ((USHORT)(base) + (address))) + +#define DC390_read16(address) \ + (inw (pACB->IOPortBase + (address))) + +#define DC390_read32(address) \ + (inl (pACB->IOPortBase + (address))) + +#define DC390_write8(address,value) \ + outb ((value), pACB->IOPortBase + (address)) -#define DC390_write8(address,value) \ - outb((value), DC390_ioport + (address))) +#define DC390_write8_(address,value,base) \ + outb ((value), (USHORT)(base) + (address)) -#define DC390_write16(address,value) \ - outw((value), DC390_ioport + (address))) +#define DC390_write16(address,value) \ + outw ((value), pACB->IOPortBase + (address)) -#define DC390_write32(address,value) \ - outl((value), DC390_ioport + (address))) +#define DC390_write32(address,value) \ + outl ((value), pACB->IOPortBase + (address)) #endif /* _TMSCSIM_H */ diff -u --recursive --new-file v2.1.126/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c --- v2.1.126/linux/drivers/sgi/char/sgiserial.c Fri May 8 23:14:50 1998 +++ linux/drivers/sgi/char/sgiserial.c Thu Nov 5 09:58:44 1998 @@ -1279,10 +1279,9 @@ if (!info->port) return; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; cli(); write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK)); - schedule(); + schedule_timeout(duration); write_zsreg(info->zs_channel, 5, info->curregs[5]); sti(); } @@ -1483,8 +1482,7 @@ if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + info->close_delay; - schedule(); + schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c --- v2.1.126/linux/drivers/sound/cs4232.c Sun Jul 26 11:57:16 1998 +++ linux/drivers/sound/cs4232.c Wed Nov 4 09:47:14 1998 @@ -96,9 +96,7 @@ static void sleep(unsigned howlong) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + howlong; - schedule(); - current->timeout = 0; + schedule_timeout(howlong); } int probe_cs4232(struct address_info *hw_config) diff -u --recursive --new-file v2.1.126/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v2.1.126/linux/drivers/sound/dmabuf.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/sound/dmabuf.c Wed Nov 4 09:50:43 1998 @@ -16,8 +16,8 @@ * 12k or so * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to * determine if it was woken up by the expiring timeout or by - * an explicit wake_up. current->timeout can be used instead; - * if 0, the wakeup was due to the timeout. + * an explicit wake_up. The return value from schedule_timeout + * can be used instead; if 0, the wakeup was due to the timeout. */ #include @@ -38,9 +38,9 @@ static int debugmem = 0; /* switched off by default */ static int dma_buffsize = DSP_BUFFSIZE; -static void dmabuf_set_timeout(struct dma_buffparms *dmap) +static long dmabuf_timeout(struct dma_buffparms *dmap) { - unsigned long tmout; + long tmout; tmout = (dmap->fragment_size * HZ) / dmap->data_rate; tmout += HZ / 5; /* Some safety distance */ @@ -48,7 +48,7 @@ tmout = HZ / 2; if (tmout > 20 * HZ) tmout = 20 * HZ; - current->timeout = jiffies + tmout; + return tmout; } static int sound_alloc_dmap(struct dma_buffparms *dmap) @@ -332,11 +332,9 @@ adev->dmap_out->underrun_count = 0; if (!signal_pending(current) && adev->dmap_out->qlen && - adev->dmap_out->underrun_count == 0) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - current->timeout = 0; - } + adev->dmap_out->underrun_count == 0) + interruptible_sleep_on_timeout(&adev->out_sleeper, + dmabuf_timeout(dmap)); adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* @@ -427,14 +425,14 @@ adev->dmap_out->underrun_count = 0; while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - if (!current->timeout) { + long t = dmabuf_timeout(dmap); + t = interruptible_sleep_on_timeout(&adev->out_sleeper, + t); + if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; restore_flags(flags); return adev->dmap_out->qlen; } - current->timeout = 0; } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); restore_flags(flags); @@ -447,11 +445,10 @@ save_flags(flags); cli(); if (adev->d->local_qlen) { /* Device has hidden buffers */ - while (!signal_pending(current) && adev->d->local_qlen(dev)) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - current->timeout = 0; - } + while (!signal_pending(current) && + adev->d->local_qlen(dev)) + interruptible_sleep_on_timeout(&adev->out_sleeper, + dmabuf_timeout(dmap)); } restore_flags(flags); } @@ -546,6 +543,7 @@ restore_flags(flags); return -EINVAL; } else while (dmap->qlen <= 0 && n++ < 10) { + long timeout = MAX_SCHEDULE_TIMEOUT; if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { restore_flags(flags); return -EAGAIN; @@ -560,19 +558,17 @@ restore_flags(flags); return -EAGAIN; } - if (!(go = adev->go)) - current->timeout = 0; - else - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->in_sleeper); - if (go && !current->timeout) { + if ((go = adev->go)) + timeout = dmabuf_timeout(dmap); + timeout = interruptible_sleep_on_timeout(&adev->in_sleeper, + timeout); + if (!timeout) { /* FIXME: include device name */ err = -EIO; printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); dma_reset_input(dev); } else err = -EINTR; - current->timeout = 0; } restore_flags(flags); @@ -725,6 +721,7 @@ int err = 0; struct dma_buffparms *dmap = adev->dmap_out; int timeout; + long timeout_value; if (dontblock) return -EAGAIN; @@ -738,15 +735,15 @@ return -EIO; timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); if (timeout) - dmabuf_set_timeout(dmap); + timeout_value = dmabuf_timeout(dmap); else - current->timeout = 0; - interruptible_sleep_on(&adev->out_sleeper); - if (timeout && !current->timeout) { + timeout_value = MAX_SCHEDULE_TIMEOUT; + timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper, + timeout_value); + if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); dma_reset_output(dev); } else { - current->timeout = 0; if (signal_pending(current)) err = -EINTR; } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c --- v2.1.126/linux/drivers/sound/dmasound.c Wed Aug 26 11:37:39 1998 +++ linux/drivers/sound/dmasound.c Wed Nov 4 09:47:40 1998 @@ -816,8 +816,7 @@ #define ONE_SECOND HZ /* in jiffies (100ths of a second) */ #define NO_TIME_LIMIT 0xffffffff #define SLEEP(queue, time_limit) \ - current->timeout = jiffies+(time_limit); \ - interruptible_sleep_on(&queue); + interruptible_sleep_on(&queue, (time_limit)); #define WAKE_UP(queue) (wake_up_interruptible(&queue)) /* diff -u --recursive --new-file v2.1.126/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c --- v2.1.126/linux/drivers/sound/es1370.c Fri Oct 23 22:01:21 1998 +++ linux/drivers/sound/es1370.c Thu Nov 5 09:58:46 1998 @@ -101,6 +101,7 @@ /*****************************************************************************/ +#include #include #include #include @@ -1016,11 +1017,8 @@ } tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1054,11 +1052,8 @@ } tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV); tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -2200,11 +2195,8 @@ return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; diff -u --recursive --new-file v2.1.126/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c --- v2.1.126/linux/drivers/sound/es1371.c Sat Sep 5 16:46:41 1998 +++ linux/drivers/sound/es1371.c Thu Nov 5 09:58:46 1998 @@ -1462,11 +1462,8 @@ } tmo = (count * HZ) / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1500,11 +1497,8 @@ } tmo = (count * HZ) / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -2635,11 +2629,8 @@ return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; diff -u --recursive --new-file v2.1.126/linux/drivers/sound/gus_wave.c linux/drivers/sound/gus_wave.c --- v2.1.126/linux/drivers/sound/gus_wave.c Fri Oct 23 22:01:22 1998 +++ linux/drivers/sound/gus_wave.c Wed Nov 4 09:41:13 1998 @@ -1927,11 +1927,8 @@ */ active_device = GUS_DEV_WAVE; - current->timeout = jiffies + HZ; - interruptible_sleep_on(&dram_sleeper); - if (!current->timeout) + if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ)) printk("GUS: DMA Transfer timed out\n"); - current->timeout = 0; restore_flags(flags); } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/maui.c linux/drivers/sound/maui.c --- v2.1.126/linux/drivers/sound/maui.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/maui.c Thu Nov 5 09:58:46 1998 @@ -81,10 +81,8 @@ { if (inb(HOST_STAT_PORT) & mask) return 1; - current->timeout = jiffies + HZ / 10; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(HZ / 10); if (signal_pending(current)) return 0; } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/midibuf.c linux/drivers/sound/midibuf.c --- v2.1.126/linux/drivers/sound/midibuf.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/midibuf.c Sat Oct 31 10:17:22 1998 @@ -90,11 +90,8 @@ if (midi_devs[dev]->buffer_status != NULL) while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) - { - current->timeout = jiffies + HZ / 10; - interruptible_sleep_on(&midi_sleeper[dev]); - current->timeout = 0; - } + interruptible_sleep_on_timeout(&midi_sleeper[dev], + HZ/10); } static void midi_input_intr(int dev, unsigned char data) @@ -181,7 +178,7 @@ midi_input_intr, midi_output_intr)) < 0) return err; - parms[dev].prech_timeout = 0; + parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); if (midi_in_buf[dev] == NULL) @@ -325,9 +322,9 @@ if (!DATA_AVAIL(midi_in_buf[dev])) { /* * No data yet, wait */ - current->timeout = parms[dev].prech_timeout ? jiffies + parms[dev].prech_timeout : 0; - interruptible_sleep_on(&input_sleeper[dev]); - current->timeout = 0; + interruptible_sleep_on_timeout(&input_sleeper[dev], + parms[dev].prech_timeout); + if (signal_pending(current)) c = -EINTR; /* The user is getting restless */ } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.1.126/linux/drivers/sound/msnd_pinnacle.c Fri Oct 23 22:01:22 1998 +++ linux/drivers/sound/msnd_pinnacle.c Wed Nov 4 09:46:36 1998 @@ -639,16 +639,12 @@ if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) return; set_bit(F_WRITEFLUSH, &dev.flags); - current->timeout = jiffies + get_play_delay_jiffies(dev.DAPF.len) + HZ / 8; - interruptible_sleep_on(&dev.writeflush); + interruptible_sleep_on_timeout(&dev.writeflush, get_play_delay_jiffies(dev.DAPF.len) + HZ / 8); clear_bit(F_WRITEFLUSH, &dev.flags); if (!signal_pending(current)) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE); - schedule(); - current->timeout = 0; - } else - current->timeout = 0; + schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); + } clear_bit(F_WRITING, &dev.flags); } @@ -923,12 +919,8 @@ if (count > 0) { set_bit(F_READBLOCK, &dev.flags); - current->timeout = jiffies + get_rec_delay_jiffies(DAR_BUFF_SIZE); - interruptible_sleep_on(&dev.readblock); - if (current->timeout == 0) + if (!interruptible_sleep_on_timeout(&dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE))) clear_bit(F_READING, &dev.flags); - else - current->timeout = 0; clear_bit(F_READBLOCK, &dev.flags); if (signal_pending(current)) return -EINTR; @@ -968,9 +960,7 @@ if (count > 0) { set_bit(F_WRITEBLOCK, &dev.flags); - current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE); - interruptible_sleep_on(&dev.writeblock); - current->timeout = 0; + interruptible_sleep_on_timeout(&dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE)); clear_bit(F_WRITEBLOCK, &dev.flags); if (signal_pending(current)) return -EINTR; @@ -1300,9 +1290,7 @@ if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ / 3; - schedule(); - current->timeout = 0; + schedule_timeout(HZ / 3); printk("successful\n"); return 0; } diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sequencer.c linux/drivers/sound/sequencer.c --- v2.1.126/linux/drivers/sound/sequencer.c Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/sequencer.c Sat Oct 31 10:17:22 1998 @@ -113,9 +113,9 @@ restore_flags(flags); return -EAGAIN; } - current->timeout = pre_event_timeout ? jiffies + pre_event_timeout : 0; - interruptible_sleep_on(&midi_sleeper); - current->timeout = 0; + + interruptible_sleep_on_timeout(&midi_sleeper, + pre_event_timeout); if (!iqlen) { restore_flags(flags); @@ -355,7 +355,6 @@ /* * Sleep until there is enough space on the queue */ - current->timeout = 0; interruptible_sleep_on(&seq_sleeper); } if (qlen >= SEQ_MAX_QUEUE) @@ -1026,7 +1025,7 @@ max_mididev = num_midis; max_synthdev = num_synths; - pre_event_timeout = 0; + pre_event_timeout = MAX_SCHEDULE_TIMEOUT; seq_mode = SEQ_1; if (pending_timer != -1) @@ -1153,11 +1152,9 @@ * Let's have a delay */ - if (n) { - current->timeout = jiffies + HZ / 10; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; - } + if (n) + interruptible_sleep_on_timeout(&seq_sleeper, + HZ/10); } } @@ -1179,9 +1176,8 @@ while (!signal_pending(current) && qlen > 0) { seq_sync(); - current->timeout = jiffies + 3 * HZ; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; + interruptible_sleep_on_timeout(&seq_sleeper, + 3*HZ); /* Extra delay */ } } @@ -1233,11 +1229,8 @@ save_flags(flags); cli(); - if (qlen > 0) { - current->timeout = jiffies + HZ; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; - } + if (qlen > 0) + interruptible_sleep_on_timeout(&seq_sleeper, HZ); restore_flags(flags); return qlen; } @@ -1262,9 +1255,7 @@ save_flags(flags); cli(); while (n && !midi_devs[dev]->outputc(dev, data)) { - current->timeout = jiffies + 4; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; + interruptible_sleep_on_timeout(&seq_sleeper, HZ/25); n--; } restore_flags(flags); diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sgalaxy.c linux/drivers/sound/sgalaxy.c --- v2.1.126/linux/drivers/sound/sgalaxy.c Fri Oct 23 22:01:22 1998 +++ linux/drivers/sound/sgalaxy.c Thu Nov 5 09:58:46 1998 @@ -29,9 +29,7 @@ static void sleep( unsigned howlong ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + howlong; - schedule(); - current->timeout = 0; + schedule(howlong); } #define DPORT 0x80 diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c --- v2.1.126/linux/drivers/sound/sonicvibes.c Sat Sep 5 16:46:41 1998 +++ linux/drivers/sound/sonicvibes.c Thu Nov 5 09:58:46 1998 @@ -1245,11 +1245,8 @@ } tmo = (count * HZ) / s->ratedac; tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "sv: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; @@ -2025,11 +2022,8 @@ return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "sv: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; diff -u --recursive --new-file v2.1.126/linux/drivers/sound/sscape.c linux/drivers/sound/sscape.c --- v2.1.126/linux/drivers/sound/sscape.c Thu May 14 19:47:42 1998 +++ linux/drivers/sound/sscape.c Tue Nov 3 22:46:00 1998 @@ -124,10 +124,8 @@ static void sleep(unsigned howlong) { - current->timeout = jiffies + 1; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(1); } static unsigned char sscape_read(struct sscape_info *devc, int reg) diff -u --recursive --new-file v2.1.126/linux/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c --- v2.1.126/linux/drivers/sound/wavfront.c Thu Sep 17 17:53:37 1998 +++ linux/drivers/sound/wavfront.c Wed Nov 4 09:50:01 1998 @@ -343,11 +343,8 @@ wavefront_sleep (wf_config *hw, int limit) { - current->timeout = jiffies + limit; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; - + schedule_timeout(limit); return signal_pending(current); } @@ -2266,8 +2263,7 @@ cli(); hw->irq_ok = 0; outb (val,port); - current->timeout = jiffies + timeout; - interruptible_sleep_on (&hw->interrupt_sleeper); + interruptible_sleep_on_timeout(&hw->interrupt_sleeper, timeout); restore_flags (flags); } diff -u --recursive --new-file v2.1.126/linux/drivers/video/mdacon.c linux/drivers/video/mdacon.c --- v2.1.126/linux/drivers/video/mdacon.c Fri Oct 9 13:27:12 1998 +++ linux/drivers/video/mdacon.c Wed Oct 28 22:04:59 1998 @@ -3,6 +3,8 @@ * * (c) 1998 Andrew Apted * + * including portions (c) 1995-1998 Patrick Caulfield. + * * This file is based on the VGA console driver (vgacon.c): * * Created 28 Sep 1997 by Geert Uytterhoeven @@ -34,6 +36,7 @@ #include #include #include +#include #include #include @@ -50,6 +53,8 @@ static unsigned int mda_index_port; /* Register select port */ static unsigned int mda_value_port; /* Register value port */ static unsigned int mda_mode_port; /* Mode control port */ +static unsigned int mda_status_port; /* Status and Config port */ +static unsigned int mda_gfx_port; /* Graphics control port */ /* current hardware state */ @@ -58,24 +63,48 @@ static int mda_cursor_size_from=-1; static int mda_cursor_size_to=-1; +static enum { TYPE_MDA, TYPE_HERC, TYPE_HERCPLUS, TYPE_HERCCOLOR } mda_type; +static char *mda_type_name; + /* console information */ -static int mda_first_vc = 12; -static int mda_last_vc = 15; +static int mda_first_vc = 13; +static int mda_last_vc = 16; static struct vc_data *mda_display_fg = NULL; #ifdef MODULE_PARM -MODULE_PARM(mda_first_vc, "0-255i"); -MODULE_PARM(mda_last_vc, "0-255i"); +MODULE_PARM(mda_first_vc, "1-255i"); +MODULE_PARM(mda_last_vc, "1-255i"); #endif +/* MDA register values + */ + +#define MDA_CURSOR_BLINKING 0x00 +#define MDA_CURSOR_OFF 0x20 +#define MDA_CURSOR_SLOWBLINK 0x60 + +#define MDA_MODE_GRAPHICS 0x02 +#define MDA_MODE_VIDEO_EN 0x08 +#define MDA_MODE_BLINK_EN 0x20 +#define MDA_MODE_GFX_PAGE1 0x80 + +#define MDA_STATUS_HSYNC 0x01 +#define MDA_STATUS_VSYNC 0x80 +#define MDA_STATUS_VIDEO 0x08 + +#define MDA_CONFIG_COL132 0x08 +#define MDA_GFX_MODE_EN 0x01 +#define MDA_GFX_PAGE_EN 0x02 + + /* * MDA could easily be classified as "pre-dinosaur hardware". */ -static void write_mda_b(unsigned char reg, unsigned int val) +static void write_mda_b(unsigned int val, unsigned char reg) { unsigned long flags; @@ -87,24 +116,40 @@ restore_flags(flags); } -static void write_mda_w(unsigned char reg, unsigned int val) +static void write_mda_w(unsigned int val, unsigned char reg) { unsigned long flags; save_flags(flags); cli(); - outb_p(reg, mda_index_port); outb_p(val>>8, mda_value_port); - outb_p(reg+1, mda_index_port); outb_p(val&0xff, mda_value_port); + outb_p(reg, mda_index_port); outb_p(val >> 8, mda_value_port); + outb_p(reg+1, mda_index_port); outb_p(val & 0xff, mda_value_port); restore_flags(flags); } +static int test_mda_b(unsigned char val, unsigned char reg) +{ + unsigned long flags; + + save_flags(flags); cli(); + + outb_p(reg, mda_index_port); + outb (val, mda_value_port); + + udelay(20); val = (inb_p(mda_value_port) == val); + + restore_flags(flags); + + return val; +} + static inline void mda_set_origin(unsigned int location) { if (mda_origin_loc == location) return; - write_mda_w(0x0c, location >> 1); + write_mda_w(location >> 1, 0x0c); mda_origin_loc = location; } @@ -114,7 +159,7 @@ if (mda_cursor_loc == location) return; - write_mda_w(0x0e, location >> 1); + write_mda_w(location >> 1, 0x0e); mda_cursor_loc = location; } @@ -125,10 +170,10 @@ return; if (from > to) { - write_mda_b(0x0a, 0x20); /* disable cursor */ + write_mda_b(MDA_CURSOR_OFF, 0x0a); /* disable cursor */ } else { - write_mda_b(0x0a, from); /* cursor start */ - write_mda_b(0x0b, to); /* cursor end */ + write_mda_b(from, 0x0a); /* cursor start */ + write_mda_b(to, 0x0b); /* cursor end */ } mda_cursor_size_from = from; @@ -144,53 +189,158 @@ if (ints[0] < 2) return; - if (ints[1] < 0 || ints[1] >= MAX_NR_CONSOLES || - ints[2] < 0 || ints[2] >= MAX_NR_CONSOLES) + if (ints[1] < 1 || ints[1] > MAX_NR_CONSOLES || + ints[2] < 1 || ints[2] > MAX_NR_CONSOLES) return; - mda_first_vc = ints[1]; - mda_last_vc = ints[2]; + mda_first_vc = ints[1]-1; + mda_last_vc = ints[2]-1; } #endif #ifdef MODULE -static const char *mdacon_startup(void) +static int mda_detect(void) #else -__initfunc(static const char *mdacon_startup(void)) +__initfunc(static int mda_detect(void)) #endif { int count=0; - u16 saved; - u16 *p; + u16 *p, p_save; + u16 *q, q_save; + + /* do a memory check */ + + p = (u16 *) mda_vram_base; + q = (u16 *) (mda_vram_base + 0x01000); + + p_save = scr_readw(p); q_save = scr_readw(q); + + scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++; + scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++; + scr_writew(p_save, p); + + if (count != 2) { + return 0; + } + + /* check if we have 4K or 8K */ + + scr_writew(0xA55A, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0xA55A) count++; + + scr_writew(0x5AA5, q); scr_writew(0x0000, p); + if (scr_readw(q) == 0x5AA5) count++; + scr_writew(p_save, p); scr_writew(q_save, q); + + if (count == 4) { + mda_vram_len = 0x02000; + } + + /* Ok, there is definitely a card registering at the correct + * memory location, so now we do an I/O port test. + */ + + if (! test_mda_b(0x66, 0x0f)) { /* cursor low register */ + return 0; + } + if (! test_mda_b(0x99, 0x0f)) { /* cursor low register */ + return 0; + } + + /* See if the card is a Hercules, by checking whether the vsync + * bit of the status register is changing. This test lasts for + * approximately 1/10th of a second. + */ + + p_save = q_save = inb_p(mda_status_port) & MDA_STATUS_VSYNC; + + for (count=0; count < 50000 && p_save == q_save; count++) { + q_save = inb(mda_status_port) & MDA_STATUS_VSYNC; + udelay(2); + } + + if (p_save != q_save) { + switch (inb_p(mda_status_port) & 0x70) { + case 0x10: + mda_type = TYPE_HERCPLUS; + mda_type_name = "HerculesPlus"; + break; + case 0x50: + mda_type = TYPE_HERCCOLOR; + mda_type_name = "HerculesColor"; + break; + default: + mda_type = TYPE_HERC; + mda_type_name = "Hercules"; + break; + } + } + + return 1; +} + +#ifdef MODULE +static void mda_initialize(void) +#else +__initfunc(static void mda_initialize(void)) +#endif +{ + write_mda_b(97, 0x00); /* horizontal total */ + write_mda_b(80, 0x01); /* horizontal displayed */ + write_mda_b(82, 0x02); /* horizontal sync pos */ + write_mda_b(15, 0x03); /* horizontal sync width */ + + write_mda_b(25, 0x04); /* vertical total */ + write_mda_b(6, 0x05); /* vertical total adjust */ + write_mda_b(25, 0x06); /* vertical displayed */ + write_mda_b(25, 0x07); /* vertical sync pos */ + + write_mda_b(2, 0x08); /* interlace mode */ + write_mda_b(13, 0x09); /* maximum scanline */ + write_mda_b(12, 0x0a); /* cursor start */ + write_mda_b(13, 0x0b); /* cursor end */ + + write_mda_w(0x0000, 0x0c); /* start address */ + write_mda_w(0x0000, 0x0e); /* cursor location */ + + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); + outb_p(0x00, mda_status_port); + outb_p(0x00, mda_gfx_port); +} + +#ifdef MODULE +static const char *mdacon_startup(void) +#else +__initfunc(static const char *mdacon_startup(void)) +#endif +{ mda_num_columns = 80; mda_num_lines = 25; mda_vram_base = VGA_MAP_MEM(0xb0000); mda_vram_len = 0x01000; - mda_index_port = 0x3b4; - mda_value_port = 0x3b5; - mda_mode_port = 0x3b8; - - /* Make sure there is an MDA card present. - * Are there smarter methods around? - */ - - p = (u16 *) mda_vram_base; - saved = scr_readw(p); + mda_index_port = 0x3b4; + mda_value_port = 0x3b5; + mda_mode_port = 0x3b8; + mda_status_port = 0x3ba; + mda_gfx_port = 0x3bf; - scr_writew(0xAA55, p); if (scr_readw(p) == 0xAA55) count++; - scr_writew(0x55AA, p); if (scr_readw(p) == 0x55AA) count++; - scr_writew(saved, p); + mda_type = TYPE_MDA; + mda_type_name = "MDA"; - if (count != 2) { + if (! mda_detect()) { printk("mdacon: MDA card not detected."); return NULL; } - printk("mdacon: MDA with %ldK of memory detected.\n", - mda_vram_len/1024); + if (mda_type != TYPE_MDA) { + mda_initialize(); + } + + printk("mdacon: %s with %ldK of memory detected.\n", + mda_type_name, mda_vram_len/1024); return "MDA-2"; } @@ -347,7 +497,7 @@ if (blank) { outb_p(0x00, mda_mode_port); /* disable video */ } else { - outb_p(0x28, mda_mode_port); /* enable video & blinking */ + outb_p(MDA_MODE_VIDEO_EN | MDA_MODE_BLINK_EN, mda_mode_port); } return 0; @@ -380,7 +530,7 @@ case CUR_BLOCK: mda_set_cursor_size(1, 13); break; case CUR_NONE: mda_set_cursor_size(14, 13); break; default: mda_set_cursor_size(12, 13); break; - } + } } static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) diff -u --recursive --new-file v2.1.126/linux/fs/autofs/autofs_i.h linux/fs/autofs/autofs_i.h --- v2.1.126/linux/fs/autofs/autofs_i.h Tue Aug 18 22:02:05 1998 +++ linux/fs/autofs/autofs_i.h Sat Nov 7 11:29:58 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/autofs_i.h * - * Copyright 1997 Transmeta Corporation - All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation - All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -47,11 +47,13 @@ struct autofs_dir_ent { int hash; - struct autofs_dir_ent *next; - struct autofs_dir_ent **back; char *name; int len; ino_t ino; + struct dentry *dentry; + /* Linked list of entries */ + struct autofs_dir_ent *next; + struct autofs_dir_ent **back; /* The following entries are for the expiry system */ unsigned long last_usage; struct autofs_dir_ent *exp_next; @@ -123,7 +125,7 @@ struct autofs_dir_ent *autofs_hash_lookup(const struct autofs_dirhash *,struct qstr *); void autofs_hash_insert(struct autofs_dirhash *,struct autofs_dir_ent *); void autofs_hash_delete(struct autofs_dir_ent *); -struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *); +struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *,off_t *,struct autofs_dir_ent *); void autofs_hash_nuke(struct autofs_dirhash *); /* Expiration-handling functions */ diff -u --recursive --new-file v2.1.126/linux/fs/autofs/dir.c linux/fs/autofs/dir.c --- v2.1.126/linux/fs/autofs/dir.c Wed Aug 26 11:37:40 1998 +++ linux/fs/autofs/dir.c Tue Oct 27 14:13:53 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/dir.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your diff -u --recursive --new-file v2.1.126/linux/fs/autofs/dirhash.c linux/fs/autofs/dirhash.c --- v2.1.126/linux/fs/autofs/dirhash.c Tue Aug 18 22:02:05 1998 +++ linux/fs/autofs/dirhash.c Tue Oct 27 14:13:53 1998 @@ -59,13 +59,11 @@ return ent; /* Symlinks are always expirable */ /* Get the dentry for the autofs subdirectory */ - dentry = lookup_dentry(ent->name, dget(sb->s_root), 0); + dentry = ent->dentry; - if ( IS_ERR(dentry) ) { - printk("autofs: no such dentry on expiry queue: %s\n", - ent->name); + if ( !dentry ) { + printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name); autofs_delete_usage(ent); - continue; } if ( !dentry->d_inode ) { @@ -79,24 +77,12 @@ /* Make sure entry is mounted and unused; note that dentry will point to the mounted-on-top root. */ if ( !S_ISDIR(dentry->d_inode->i_mode) - || dentry->d_covers == dentry ) { - dput(dentry); + || dentry->d_mounts == dentry ) { DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); continue; } - /* - * Now, this is known to be a mount point; therefore the dentry - * will be held by the superblock. is_root_busy() will break if - * we hold a use count here, so we have to dput() it before calling - * is_root_busy(). However, since it is a mount point (already - * verified), dput() will be a nonblocking operation and the use - * count will not go to zero; therefore the call to is_root_busy() - * here is legal. - */ - dput(dentry); - - if ( !is_root_busy(dentry) ) { + if ( !is_root_busy(dentry->d_mounts) ) { DPRINTK(("autofs: signaling expire on %s\n", ent->name)); return ent; /* Expirable! */ } @@ -136,6 +122,8 @@ autofs_say(ent->name,ent->len); autofs_init_usage(dh,ent); + if ( ent->dentry ) + ent->dentry->d_count++; dhnp = &dh->h[(unsigned) ent->hash % AUTOFS_HASH_SIZE]; ent->next = *dhnp; @@ -153,6 +141,8 @@ autofs_delete_usage(ent); + if ( ent->dentry ) + dput(ent->dentry); kfree(ent->name); kfree(ent); } @@ -161,8 +151,12 @@ * Used by readdir(). We must validate "ptr", so we can't simply make it * a pointer. Values below 0xffff are reserved; calling with any value * <= 0x10000 will return the first entry found. + * + * "last" can be NULL or the value returned by the last search *if* we + * want the next sequential entry. */ -struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, off_t *ptr) +struct autofs_dir_ent *autofs_hash_enum(const struct autofs_dirhash *dh, + off_t *ptr, struct autofs_dir_ent *last) { int bucket, ecount, i; struct autofs_dir_ent *ent; @@ -176,19 +170,23 @@ DPRINTK(("autofs_hash_enum: bucket %d, entry %d\n", bucket, ecount)); - ent = NULL; + ent = last ? last->next : NULL; - while ( bucket < AUTOFS_HASH_SIZE ) { - ent = dh->h[bucket]; - for ( i = ecount ; ent && i ; i-- ) - ent = ent->next; - - if (ent) { - ecount++; /* Point to *next* entry */ - break; + if ( ent ) { + ecount++; + } else { + while ( bucket < AUTOFS_HASH_SIZE ) { + ent = dh->h[bucket]; + for ( i = ecount ; ent && i ; i-- ) + ent = ent->next; + + if (ent) { + ecount++; /* Point to *next* entry */ + break; + } + + bucket++; ecount = 0; } - - bucket++; ecount = 0; } #ifdef DEBUG @@ -214,6 +212,8 @@ for ( i = 0 ; i < AUTOFS_HASH_SIZE ; i++ ) { for ( ent = dh->h[i] ; ent ; ent = nent ) { nent = ent->next; + if ( ent->dentry ) + dput(ent->dentry); kfree(ent->name); kfree(ent); } diff -u --recursive --new-file v2.1.126/linux/fs/autofs/init.c linux/fs/autofs/init.c --- v2.1.126/linux/fs/autofs/init.c Fri Sep 5 20:15:37 1997 +++ linux/fs/autofs/init.c Tue Oct 27 14:13:53 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/init.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your diff -u --recursive --new-file v2.1.126/linux/fs/autofs/inode.c linux/fs/autofs/inode.c --- v2.1.126/linux/fs/autofs/inode.c Mon Apr 6 17:41:00 1998 +++ linux/fs/autofs/inode.c Tue Oct 27 14:13:53 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/inode.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your diff -u --recursive --new-file v2.1.126/linux/fs/autofs/root.c linux/fs/autofs/root.c --- v2.1.126/linux/fs/autofs/root.c Wed Aug 26 11:37:40 1998 +++ linux/fs/autofs/root.c Tue Oct 27 15:13:47 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/root.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -66,7 +66,7 @@ static int autofs_root_readdir(struct file *filp, void *dirent, filldir_t filldir) { - struct autofs_dir_ent *ent; + struct autofs_dir_ent *ent = NULL; struct autofs_dirhash *dirhash; struct inode * inode = filp->f_dentry->d_inode; off_t onr, nr; @@ -90,10 +90,12 @@ filp->f_pos = ++nr; /* fall through */ default: - while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr) ) { - if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0) - return 0; - filp->f_pos = nr; + while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) { + if ( !ent->dentry || ent->dentry->d_mounts != ent->dentry ) { + if (filldir(dirent,ent->name,ent->len,onr,ent->ino) < 0) + return 0; + filp->f_pos = nr; + } } break; } @@ -110,8 +112,8 @@ if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) { do { if ( status && dentry->d_inode ) { - printk("autofs warning: lookup failure on existing dentry, status = %d, name = %s\n", status, dentry->d_name.name); - break; + printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name); + return 0; /* Try to get the kernel to invalidate this dentry */ } /* Turn this into a real negative dentry? */ @@ -148,8 +150,9 @@ /* We don't update the usages for the autofs daemon itself, this is necessary for recursive autofs mounts */ - if ( !autofs_oz_mode(sbi) ) + if ( !autofs_oz_mode(sbi) ) { autofs_update_usage(&sbi->dirhash,ent); + } dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; return 1; @@ -193,7 +196,8 @@ /* Update the usage list */ if ( !autofs_oz_mode(sbi) ) { ent = (struct autofs_dir_ent *) dentry->d_time; - autofs_update_usage(&sbi->dirhash,ent); + if ( ent ) + autofs_update_usage(&sbi->dirhash,ent); } return 1; } @@ -207,7 +211,6 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry) { struct autofs_sb_info *sbi; - struct inode *res; int oz_mode; DPRINTK(("autofs_root_lookup: name = ")); @@ -216,7 +219,6 @@ if (!S_ISDIR(dir->i_mode)) return -ENOTDIR; - res = NULL; sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; oz_mode = autofs_oz_mode(sbi); @@ -249,6 +251,15 @@ return -ERESTARTNOINTR; } + /* + * If this dentry is unhashed, then we shouldn't honour this + * lookup even if the dentry is positive. Returning ENOENT here + * doesn't do the right thing for all system calls, but it should + * be OK for the operations we permit from an autofs. + */ + if ( dentry->d_inode && list_empty(&dentry->d_hash) ) + return -ENOENT; + return 0; } @@ -304,6 +315,7 @@ ent->ino = AUTOFS_FIRST_SYMLINK + n; ent->hash = dentry->d_name.hash; memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len)); + ent->dentry = NULL; /* We don't keep the dentry for symlinks */ autofs_hash_insert(dh,ent); d_instantiate(dentry, iget(dir->i_sb,ent->ino)); @@ -339,7 +351,8 @@ n = ent->ino - AUTOFS_FIRST_SYMLINK; if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap) ) return -EINVAL; /* Not a symlink inode, can't unlink */ - + + dentry->d_time = (unsigned long)(struct autofs_dirhash *)NULL; autofs_hash_delete(ent); clear_bit(n,sbi->symlink_bitmap); kfree(sbi->symlink[n].data); @@ -364,6 +377,11 @@ if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) return -ENOTDIR; /* Not a directory */ + if ( ent->dentry != dentry ) { + printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name); + } + + dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL; autofs_hash_delete(ent); dir->i_nlink--; d_drop(dentry); @@ -399,12 +417,14 @@ return -ENOSPC; } + dir->i_nlink++; + d_instantiate(dentry, iget(dir->i_sb,ent->ino)); + ent->hash = dentry->d_name.hash; memcpy(ent->name, dentry->d_name.name, 1+(ent->len = dentry->d_name.len)); ent->ino = sbi->next_dir_ino++; + ent->dentry = dentry; autofs_hash_insert(dh,ent); - dir->i_nlink++; - d_instantiate(dentry, iget(dir->i_sb,ent->ino)); return 0; } diff -u --recursive --new-file v2.1.126/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c --- v2.1.126/linux/fs/autofs/symlink.c Mon Sep 28 10:51:34 1998 +++ linux/fs/autofs/symlink.c Tue Oct 27 14:13:53 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/symlink.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your diff -u --recursive --new-file v2.1.126/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c --- v2.1.126/linux/fs/autofs/waitq.c Mon Dec 1 10:34:11 1997 +++ linux/fs/autofs/waitq.c Tue Oct 27 14:13:53 1998 @@ -2,7 +2,7 @@ * * linux/fs/autofs/waitq.c * - * Copyright 1997 Transmeta Corporation -- All Rights Reserved + * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -20,6 +20,9 @@ is better if we don't reassign numbers easily even across filesystems */ static int autofs_next_wait_queue = 1; +/* These are the signals we allow interrupting a pending mount */ +#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT)) + void autofs_catatonic_mode(struct autofs_sb_info *sbi) { struct autofs_wait_queue *wq, *nwq; @@ -133,9 +136,25 @@ } else wq->wait_ctr++; + /* wq->name is NULL if and only if the lock is already released */ + if ( wq->name ) { - /* wq->name is NULL if and only if the lock is released */ + /* Block all but "shutdown" signals while waiting */ + sigset_t oldset; + unsigned long irqflags; + + spin_lock_irqsave(¤t->sigmask_lock, irqflags); + oldset = current->blocked; + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); + interruptible_sleep_on(&wq->queue); + + spin_lock_irqsave(¤t->sigmask_lock, irqflags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); } else { DPRINTK(("autofs_wait: skipped sleeping\n")); } diff -u --recursive --new-file v2.1.126/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.126/linux/fs/binfmt_elf.c Fri Oct 23 22:01:22 1998 +++ linux/fs/binfmt_elf.c Tue Oct 27 10:23:40 1998 @@ -608,7 +608,7 @@ base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ - load_bias = (elf_ex.e_type == ET_DYN ? ELF_ET_DYN_BASE : 0); + load_bias = ELF_PAGESTART(elf_ex.e_type==ET_DYN ? ELF_ET_DYN_BASE : 0); /* Now we do a little grungy work by mmaping the ELF image into the correct location in memory. At this point, we assume that @@ -618,51 +618,50 @@ old_fs = get_fs(); set_fs(get_ds()); for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { - if (elf_ppnt->p_type == PT_LOAD) { - int elf_prot = 0, elf_flags; - unsigned long vaddr; - - if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; - if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - - elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; - - vaddr = elf_ppnt->p_vaddr; - if (elf_ex.e_type == ET_EXEC || load_addr_set) { - elf_flags |= MAP_FIXED; - } + int elf_prot = 0, elf_flags; + unsigned long vaddr; + + if (elf_ppnt->p_type != PT_LOAD) + continue; + + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; + if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + + elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; + + vaddr = elf_ppnt->p_vaddr; + if (elf_ex.e_type == ET_EXEC || load_addr_set) { + elf_flags |= MAP_FIXED; + } - error = do_mmap(file, - ELF_PAGESTART(load_bias + vaddr), - (elf_ppnt->p_filesz + - ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), - elf_prot, elf_flags, - (elf_ppnt->p_offset - - ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); - - if (!load_addr_set) { - load_addr_set = 1; - load_addr = (elf_ppnt->p_vaddr - - elf_ppnt->p_offset); - if (elf_ex.e_type == ET_DYN) { - load_bias = error - ELF_PAGESTART(load_bias + vaddr); - load_addr += error; - } + error = do_mmap(file, ELF_PAGESTART(load_bias + vaddr), + (elf_ppnt->p_filesz + + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), + elf_prot, elf_flags, (elf_ppnt->p_offset - + ELF_PAGEOFFSET(elf_ppnt->p_vaddr))); + + if (!load_addr_set) { + load_addr_set = 1; + load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); + if (elf_ex.e_type == ET_DYN) { + load_bias += error - + ELF_PAGESTART(load_bias + vaddr); + load_addr += error; } - k = elf_ppnt->p_vaddr; - if (k < start_code) start_code = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if (k > elf_bss) - elf_bss = k; - if ((elf_ppnt->p_flags & PF_X) && end_code < k) - end_code = k; - if (end_data < k) - end_data = k; - k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) - elf_brk = k; } + k = elf_ppnt->p_vaddr; + if (k < start_code) start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + if ((elf_ppnt->p_flags & PF_X) && end_code < k) + end_code = k; + if (end_data < k) + end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if (k > elf_brk) + elf_brk = k; } set_fs(old_fs); fput(file); /* all done with the file */ diff -u --recursive --new-file v2.1.126/linux/fs/exec.c linux/fs/exec.c --- v2.1.126/linux/fs/exec.c Fri Oct 23 22:01:22 1998 +++ linux/fs/exec.c Mon Nov 2 15:00:30 1998 @@ -54,9 +54,6 @@ #include #endif -asmlinkage int sys_exit(int exit_code); -asmlinkage int sys_brk(unsigned long); - /* * Here are the actual binaries that will be accepted: * add more with "register_binfmt()" if using modules... @@ -752,24 +749,28 @@ /* handle /sbin/loader.. */ { struct exec * eh = (struct exec *) bprm->buf; + struct linux_binprm bprm_loader; if (!bprm->loader && eh->fh.f_magic == 0x183 && (eh->fh.f_flags & 0x3000) == 0x3000) { + int i; char * dynloader[] = { "/sbin/loader" }; struct dentry * dentry; dput(bprm->dentry); bprm->dentry = NULL; - remove_arg_zero(bprm); - bprm->p = copy_strings(1, dynloader, bprm->page, bprm->p, 2); - bprm->argc++; - bprm->loader = bprm->p; + + bprm_loader.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + for (i=0 ; identry = dentry; + bprm->loader = bprm_loader.p; retval = prepare_binprm(bprm); if (retval<0) return retval; diff -u --recursive --new-file v2.1.126/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c --- v2.1.126/linux/fs/ext2/balloc.c Fri Oct 23 22:01:22 1998 +++ linux/fs/ext2/balloc.c Wed Oct 28 21:54:56 1998 @@ -721,7 +721,7 @@ bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; - if (!(le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) & + if (!(sb->u.ext2_sb.s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) || ext2_group_sparse(i)) { if (!ext2_test_bit (0, bh->b_data)) diff -u --recursive --new-file v2.1.126/linux/fs/ext2/super.c linux/fs/ext2/super.c --- v2.1.126/linux/fs/ext2/super.c Mon Sep 28 10:51:34 1998 +++ linux/fs/ext2/super.c Wed Oct 28 21:54:56 1998 @@ -786,7 +786,7 @@ * superblocks is turned on, then not all groups have * this. */ - if (le32_to_cpu(sb->u.ext2_sb.s_feature_ro_compat) & + if (sb->u.ext2_sb.s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) { ngroups = 0; for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++) diff -u --recursive --new-file v2.1.126/linux/fs/fat/mmap.c linux/fs/fat/mmap.c --- v2.1.126/linux/fs/fat/mmap.c Tue Mar 10 10:03:33 1998 +++ linux/fs/fat/mmap.c Mon Nov 2 13:26:51 1998 @@ -58,6 +58,7 @@ } filp.f_reada = 0; filp.f_pos = pos; + filp.f_dentry=area->vm_file->f_dentry; need_read = PAGE_SIZE - clear; { mm_segment_t cur_fs = get_fs(); diff -u --recursive --new-file v2.1.126/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog --- v2.1.126/linux/fs/hfs/ChangeLog Fri Oct 9 13:27:14 1998 +++ linux/fs/hfs/ChangeLog Mon Nov 2 09:35:16 1998 @@ -1,3 +1,57 @@ +1998-11-02 a sun + + * mdb.c (hfs_mdb_get): plugged up an mdb failed initialization + leak. + +1998-10-31 a sun + + * version.c (hfs_version): bumped to version 0.96. + + * mdb.c (hfs_mdb_commit): you only write out the alternate MDB + when the catalog or extents overflow files grow. that just leaves + the btree corruption problems. bleah (whilst deleting a bunch of + files, more of the btree can get pruned away than desired). + +1998-10-30 a sun + + * dir.c: fixed a bunch of silliness with deletions. make sure to + zero out stuff and set mark_inode_dirty(). + +1998-10-29 a sun + + * string.c (hfs_strcmp, hfs_streq, hfs_strhash): converted them to + take name/len arguments instead of hfs_name to reduce copying. + + * dir.c, dir_nat.c, dir_cap.c, dir_dbl.c, sysdep.c: modified + relevant areas to reflect string.c changes. + +1998-10-28 a sun + + * hfs.h (hfs_lookup_dentry): oh my. more silliness. make sure to + have the d_lookup use the same hash value as the one generated by + hfs_hash_dentry. i also changed the argument order. + (hfs_drop_special): change the argument order to be more in line + with what the dcache stuff looks like. + + * sysdep.c (hfs_compare_dentry): the compare was returning the + wrong value for correct matches and causing all sorts of + mischief. this fixes both directory counts and mounting on top of + hfs volumes. + + * file.c, file_cap.c, file_hdr.c: added mark_inode_dirty()'s in + the relevant places. + +1998-10-11 root + + * mdb.c (hfs_mdb_get): moved initialization of mdb->entry_dirty + list to here to deal with trying to read a bad hfs volume. + +1998-10-10 a sun + + * inode.c, catalog.c, dir_*.c, sysdep.c: parts of the dcache + conversion didn't get done properly. specifically, i forgot to + move the hfs_cat_puts into the right place. that's fixed now. + 1998-09-11 a sun * mdb.c: altered mdb struct to reflect hfs plus usage. diff -u --recursive --new-file v2.1.126/linux/fs/hfs/TODO linux/fs/hfs/TODO --- v2.1.126/linux/fs/hfs/TODO Sun Jan 4 10:40:17 1998 +++ linux/fs/hfs/TODO Mon Nov 2 09:35:16 1998 @@ -10,10 +10,8 @@ 1. Header files have compiled-in limit (currently 10) on descriptors. Missing features: -1. The partition code should be migrated into the kernel to allow - simultaneous access to multiple partitions on a single disk. -2. 1k block support is needed for some devices. -3. An ioctl()-based interface is needed to provide a consistent way +1. 1k block support is needed for some devices. +2. An ioctl()-based interface is needed to provide a consistent way to do things under all of the representations of forked files. Possible additional "fork" mount options: diff -u --recursive --new-file v2.1.126/linux/fs/hfs/bnode.c linux/fs/hfs/bnode.c --- v2.1.126/linux/fs/hfs/bnode.c Sun Jan 4 10:40:17 1998 +++ linux/fs/hfs/bnode.c Mon Nov 2 09:35:16 1998 @@ -510,6 +510,8 @@ } else { hfs_warn("hfs_bnode_find: use %d(%d) lvl %d [%d]\n", bn->count, bn->buf->b_count, bn->ndNHeight, bnode_count); + hfs_warn("hfs_bnode_find: blnk %u flnk %u recs %u\n", + bn->ndBLink, bn->ndFLink, bn->ndNRecs); } #endif diff -u --recursive --new-file v2.1.126/linux/fs/hfs/catalog.c linux/fs/hfs/catalog.c --- v2.1.126/linux/fs/hfs/catalog.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/catalog.c Mon Nov 2 09:35:16 1998 @@ -127,17 +127,15 @@ * * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer. */ -static inline unsigned long hashfn(const struct hfs_mdb *mdb, +static inline unsigned int hashfn(const struct hfs_mdb *mdb, const struct hfs_cat_key *key) { -#define LSB(X) (((unsigned char *)(&X))[3]) - unsigned long hash; + unsigned int hash; - hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | - hfs_strhash(&key->CName); + hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | + hfs_strhash(key->CName.Name, key->CName.Len); hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2); return hash & C_HASHMASK; -#undef LSB } /* @@ -533,7 +531,6 @@ HFS_BKEY(key), HFS_BFIND_READ_EQ)) { /* uh oh. we failed to read the record. * the entry doesn't actually exist. */ - entry->state |= HFS_DELETED; goto read_fail; } @@ -564,12 +561,14 @@ return NULL; read_fail: - /* spinlock unlocked already. we don't need to mark the entry - * dirty here because we know that it doesn't exist. */ - remove_hash(entry); - entry->state &= ~HFS_LOCK; - hfs_wake_up(&entry->wait); - hfs_cat_put(entry); + /* short-cut hfs_cat_put by doing everything here. */ + spin_lock(&entry_lock); + list_del(&entry->hash); + list_del(&entry->list); + init_entry(entry); + list_add(&entry->list, &entry_unused); + entries_stat.nr_free_entries++; + spin_unlock(&entry_lock); return NULL; } @@ -586,6 +585,11 @@ { struct hfs_cat_entry * entry; +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_get_entry: mdb=%p key=%s read=%d\n", + mdb, key->CName.Name, read); +#endif + spin_lock(&entry_lock); entry = find_entry(mdb, key); if (!entry) { @@ -759,6 +763,7 @@ /* complete the cache entry and return success */ __read_entry(entry, record); unlock_entry(entry); + if (result) { *result = entry; } else { @@ -786,17 +791,7 @@ * * Release an entry we aren't using anymore. * - * NOTE: We must be careful any time we sleep on a non-deleted - * entry that the entry is in a consistent state, since another - * process may get the entry while we sleep. That is why we - * 'goto repeat' after each operation that might sleep. - * - * ADDITIONAL NOTE: the sys_entries will remove themselves from - * the sys_entry list on the final iput, so we don't need - * to worry about them here. - * - * nothing in hfs_cat_put goes to sleep now except - * on the initial entry. + * nothing in hfs_cat_put goes to sleep now except on the initial entry. */ void hfs_cat_put(struct hfs_cat_entry * entry) { @@ -810,9 +805,13 @@ return; } +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_cat_put: %p(%u) type=%d state=%lu\n", + entry, entry->count, entry->type, entry->state); +#endif spin_lock(&entry_lock); if (!--entry->count) { - if ((entry->state & HFS_DELETED)) + if ((entry->state & HFS_DELETED)) goto entry_deleted; if ((entry->type == HFS_CDR_FIL)) { @@ -840,10 +839,7 @@ HFS_DELETE(entry); entries_stat.nr_entries--; } else { - spin_unlock(&entry_lock); - wait_on_entry(entry); init_entry(entry); - spin_lock(&entry_lock); list_add(&entry->list, &entry_unused); entries_stat.nr_free_entries++; } @@ -919,7 +915,7 @@ * hfs_cat_invalidate() * * Called by hfs_mdb_put() to remove all the entries - * in the cache which are associated with a given MDB. + * in the cache that are associated with a given MDB. */ void hfs_cat_invalidate(struct hfs_mdb *mdb) { @@ -931,6 +927,11 @@ spin_unlock(&entry_lock); delete_list(&throw_away); +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_cat_invalidate: free=%d total=%d\n", + entries_stat.nr_free_entries, + entries_stat.nr_entries); +#endif } /* @@ -941,7 +942,7 @@ void hfs_cat_commit(struct hfs_mdb *mdb) { struct list_head *tmp, *head = &mdb->entry_dirty; - struct hfs_cat_entry * entry; + struct hfs_cat_entry *entry; spin_lock(&entry_lock); while ((tmp = head->prev) != head) { @@ -1018,7 +1019,8 @@ if (parents != 0) { retval = (int)parents; } else { - retval = hfs_strcmp(&key1->CName, &key2->CName); + retval = hfs_strcmp(key1->CName.Name, key1->CName.Len, + key2->CName.Name, key2->CName.Len); } return retval; } @@ -1170,9 +1172,6 @@ * Create a new file with the indicated name in the indicated directory. * The file will have the indicated flags, type and creator. * If successful an (struct hfs_cat_entry) is returned in '*result'. - * - * XXX: the presence of "record" probably means that the following two - * aren't currently SMP safe and need spinlocks. */ int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key, hfs_u8 flags, hfs_u32 type, hfs_u32 creator, @@ -1182,6 +1181,10 @@ hfs_u32 id = new_cnid(parent->mdb); hfs_u32 mtime = hfs_time(); +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_cat_create: %p/%s flags=%d res=%p\n", + parent, key->CName.Name, flags, result); +#endif /* init some fields for the file record */ memset(&record, 0, sizeof(record)); record.cdrType = HFS_CDR_FIL; @@ -1209,6 +1212,11 @@ hfs_u32 id = new_cnid(parent->mdb); hfs_u32 mtime = hfs_time(); +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_cat_mkdir: %p/%s res=%p\n", parent, key->CName.Name, + result); +#endif + /* init some fields for the directory record */ memset(&record, 0, sizeof(record)); record.cdrType = HFS_CDR_DIR; @@ -1234,6 +1242,10 @@ struct hfs_mdb *mdb = parent->mdb; int is_dir, error = 0; +#if defined(DEBUG_CATALOG) || defined(DEBUG_ALL) + hfs_warn("hfs_cat_delete: %p/%p type=%d state=%lu, thread=%d\n", + parent, entry, entry->type, entry->state, with_thread); +#endif if (parent->mdb != entry->mdb) { return -EINVAL; } @@ -1252,39 +1264,39 @@ if (entry->type == HFS_CDR_DIR) { start_read(entry); - if (entry->u.dir.files || entry->u.dir.dirs) { - error = -ENOTEMPTY; - } + error = -ENOTEMPTY; + if (entry->u.dir.files || entry->u.dir.dirs) + goto hfs_delete_end; } /* try to delete the file or directory */ - if (!error) { - lock_entry(entry); - if ((entry->state & HFS_DELETED)) { - /* somebody beat us to it */ - error = -ENOENT; - } else { - error = hfs_bdelete(mdb->cat_tree, - HFS_BKEY(&entry->key)); - } - unlock_entry(entry); + lock_entry(entry); + error = -ENOENT; + if ((entry->state & HFS_DELETED)) { + /* somebody beat us to it. */ + goto hfs_delete_unlock; + } + + /* delete the catalog record */ + if ((error = hfs_bdelete(mdb->cat_tree, HFS_BKEY(&entry->key)))) { + goto hfs_delete_unlock; } - if (!error) { - /* Mark the entry deleted and remove it from the cache */ - lock_entry(entry); - delete_entry(entry); - - /* try to delete the thread entry if it exists */ - if (with_thread) { - hfs_cat_build_key(entry->cnid, NULL, &key); - (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key)); - } - - unlock_entry(entry); - update_dir(mdb, parent, is_dir, -1); + /* Mark the entry deleted and remove it from the cache */ + delete_entry(entry); + + /* try to delete the thread entry if it exists */ + if (with_thread) { + hfs_cat_build_key(entry->cnid, NULL, &key); + (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key)); } + + update_dir(mdb, parent, is_dir, -1); + +hfs_delete_unlock: + unlock_entry(entry); +hfs_delete_end: if (entry->type == HFS_CDR_DIR) { end_read(entry); } @@ -1332,10 +1344,10 @@ return -EINVAL; } - spin_lock(&entry_lock); while (mdb->rename_lock) { hfs_sleep_on(&mdb->rename_wait); } + spin_lock(&entry_lock); mdb->rename_lock = 1; spin_unlock(&entry_lock); @@ -1575,5 +1587,3 @@ i--; } while (i); } - - diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir.c linux/fs/hfs/dir.c --- v2.1.126/linux/fs/hfs/dir.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/dir.c Mon Nov 2 09:35:16 1998 @@ -41,7 +41,8 @@ /* check against reserved names */ reserved = HFS_SB(dir->i_sb)->s_reserved1; while (reserved->Len) { - if (hfs_streq(reserved, &cname)) { + if (hfs_streq(reserved->Name, reserved->Len, + cname.Name, cname.Len)) { return 1; } ++reserved; @@ -51,7 +52,8 @@ if (HFS_I(dir)->entry->cnid == htonl(HFS_ROOT_CNID)) { reserved = HFS_SB(dir->i_sb)->s_reserved2; while (reserved->Len) { - if (hfs_streq(reserved, &cname)) { + if (hfs_streq(reserved->Name, reserved->Len, + cname.Name, cname.Len)) { return 1; } ++reserved; @@ -129,16 +131,23 @@ * * Update inodes associated with a deleted entry to reflect its deletion. * Well, we really just drop the dentry. + * + * XXX: we should be using delete_inode for some of this stuff. */ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, struct dentry *dentry) { struct dentry *de; + struct inode *tmp; int i; for (i = 0; i < 4; ++i) { if ((de = entry->sys_entry[i]) && (dentry != de)) { dget(de); + tmp = de->d_inode; + tmp->i_nlink = 0; + tmp->i_ctime = CURRENT_TIME; + mark_inode_dirty(tmp); d_delete(de); dput(de); } @@ -177,32 +186,32 @@ int error; /* build the key, checking against reserved names */ - if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) { - error = -EEXIST; - } else { - /* try to create the file */ - error = hfs_cat_create(entry, &key, - (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK, - HFS_SB(dir->i_sb)->s_type, - HFS_SB(dir->i_sb)->s_creator, &new); - } - - if (!error) { - update_dirs_plus(entry, 0); - - /* create an inode for the new file */ - inode = hfs_iget(new, HFS_I(dir)->file_type, dentry); - if (!inode) { - /* XXX correct error? */ - error = -EIO; - } else { - if (HFS_I(dir)->d_drop_op) - HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type); - d_instantiate(dentry, inode); - } - } + if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) + return -EEXIST; - return error; + if ((error = hfs_cat_create(entry, &key, + (mode & S_IWUSR) ? 0 : HFS_FIL_LOCK, + HFS_SB(dir->i_sb)->s_type, + HFS_SB(dir->i_sb)->s_creator, &new))) + return error; + + /* create an inode for the new file. back out if we run + * into trouble. */ + new->count++; /* hfs_iget() eats one */ + if (!(inode = hfs_iget(new, HFS_I(dir)->file_type, dentry))) { + hfs_cat_delete(entry, new, 1); + hfs_cat_put(new); + return -EIO; + } + + hfs_cat_put(new); + update_dirs_plus(entry, 0); + /* toss any relevant negative dentries */ + if (HFS_I(dir)->d_drop_op) + HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type); + mark_inode_dirty(inode); + d_instantiate(dentry, inode); + return 0; } /* @@ -223,23 +232,26 @@ /* build the key, checking against reserved names */ if (build_key(&key, parent, dentry->d_name.name, - dentry->d_name.len)) { - error = -EEXIST; - } else { - /* try to create the directory */ - error = hfs_cat_mkdir(entry, &key, &new); - } - - if (!error) { - update_dirs_plus(entry, 1); - inode = hfs_iget(new, HFS_I(parent)->file_type, dentry); - if (!inode) { - error = -EIO; - } else - d_instantiate(dentry, inode); - } + dentry->d_name.len)) + return -EEXIST; - return error; + /* try to create the directory */ + if ((error = hfs_cat_mkdir(entry, &key, &new))) + return error; + + /* back out if we run into trouble */ + new->count++; /* hfs_iget eats one */ + if (!(inode = hfs_iget(new, HFS_I(parent)->file_type, dentry))) { + hfs_cat_delete(entry, new, 1); + hfs_cat_put(new); + return -EIO; + } + + hfs_cat_put(new); + update_dirs_plus(entry, 1); + mark_inode_dirty(inode); + d_instantiate(dentry, inode); + return 0; } /* @@ -257,16 +269,14 @@ */ int hfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) { - int error; + if (!dir) + return -ENOENT; - if (!dir) { - error = -ENOENT; - } else if (S_ISREG(mode)) { - error = hfs_create(dir, dentry, mode); - } else { - error = -EPERM; - } - return error; + /* the only thing we currently do. */ + if (S_ISREG(mode)) + return hfs_create(dir, dentry, mode); + + return -EPERM; } /* @@ -285,18 +295,28 @@ int error; if (build_key(&key, dir, dentry->d_name.name, - dentry->d_name.len)) { - error = -EPERM; - } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { - error = -ENOENT; - } else if (victim->type != HFS_CDR_FIL) { - error = -EPERM; - } else if (!(error = hfs_cat_delete(entry, victim, 1))) { + dentry->d_name.len)) + return -EPERM; + + if (!(victim = hfs_cat_get(entry->mdb, &key))) + return -ENOENT; + + error = -EPERM; + if (victim->type != HFS_CDR_FIL) + goto hfs_unlink_put; + + if (!(error = hfs_cat_delete(entry, victim, 1))) { + struct inode *inode = dentry->d_inode; + mark_inodes_deleted(victim, dentry); + inode->i_nlink--; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); d_delete(dentry); update_dirs_minus(entry, 0); } +hfs_unlink_put: hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ return error; } @@ -313,31 +333,50 @@ { struct hfs_cat_entry *entry = HFS_I(parent)->entry; struct hfs_cat_entry *victim = NULL; + struct inode *inode = dentry->d_inode; struct hfs_cat_key key; int error; + if (parent == inode) /* can't delete . */ + return -EPERM; + if (build_key(&key, parent, dentry->d_name.name, - dentry->d_name.len)) { - error = -EPERM; - } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { - error = -ENOENT; - } else if (victim->type != HFS_CDR_DIR) { - error = -ENOTDIR; - } else if (/* we only have to worry about 2 and 3 for mount points */ - (victim->sys_entry[2] && - (victim->sys_entry[2] != - victim->sys_entry[2]->d_mounts)) || - (victim->sys_entry[3] && - (victim->sys_entry[3] != - victim->sys_entry[3]->d_mounts)) - ) { - error = -EBUSY; - } else if (!(error = hfs_cat_delete(entry, victim, 1))) { - mark_inodes_deleted(victim, dentry); - d_delete(dentry); - update_dirs_minus(entry, 1); - } + dentry->d_name.len)) + return -EPERM; + + if (!(victim = hfs_cat_get(entry->mdb, &key))) + return -ENOENT; + + error = -ENOTDIR; + if (victim->type != HFS_CDR_DIR) + goto hfs_rmdir_put; + + error = -EBUSY; + if (dentry->d_count > 1) + goto hfs_rmdir_put; + + if (/* we only have to worry about 2 and 3 for mount points */ + (victim->sys_entry[2] && + (victim->sys_entry[2]->d_mounts != + victim->sys_entry[2]->d_covers)) || + (victim->sys_entry[3] && + (victim->sys_entry[3]->d_mounts != + victim->sys_entry[3]->d_covers)) + ) + goto hfs_rmdir_put; + + + if ((error = hfs_cat_delete(entry, victim, 1))) + goto hfs_rmdir_put; + + mark_inodes_deleted(victim, dentry); + inode->i_nlink = 0; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + d_delete(dentry); + update_dirs_minus(entry, 1); +hfs_rmdir_put: hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ return error; } @@ -365,35 +404,40 @@ if (build_key(&key, old_dir, old_dentry->d_name.name, old_dentry->d_name.len) || - (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) { - error = -EPERM; - } else if (!(victim = hfs_cat_get(old_parent->mdb, &key))) { - error = -ENOENT; - } else if (build_key(&key, new_dir, new_dentry->d_name.name, - new_dentry->d_name.len)) { - error = -EPERM; - } else if (!(error = hfs_cat_move(old_parent, new_parent, - victim, &key, &deleted))) { - int is_dir = (victim->type == HFS_CDR_DIR); + (HFS_ITYPE(old_dir->i_ino) != HFS_ITYPE(new_dir->i_ino))) + return -EPERM; + if (!(victim = hfs_cat_get(old_parent->mdb, &key))) + return -ENOENT; + + error = -EPERM; + if (build_key(&key, new_dir, new_dentry->d_name.name, + new_dentry->d_name.len)) + goto hfs_rename_put; + + if (!(error = hfs_cat_move(old_parent, new_parent, + victim, &key, &deleted))) { + int is_dir = (victim->type == HFS_CDR_DIR); + /* drop the old dentries */ mark_inodes_deleted(victim, old_dentry); update_dirs_minus(old_parent, is_dir); if (deleted) { - mark_inodes_deleted(deleted, new_dentry); - hfs_cat_put(deleted); + mark_inodes_deleted(deleted, new_dentry); + hfs_cat_put(deleted); } else { - /* no existing inodes. just drop negative dentries */ - if (HFS_I(new_dir)->d_drop_op) - HFS_I(new_dir)->d_drop_op(new_dentry, - HFS_I(new_dir)->file_type); - update_dirs_plus(new_parent, is_dir); + /* no existing inodes. just drop negative dentries */ + if (HFS_I(new_dir)->d_drop_op) + HFS_I(new_dir)->d_drop_op(new_dentry, + HFS_I(new_dir)->file_type); + update_dirs_plus(new_parent, is_dir); } - + /* update dcache */ d_move(old_dentry, new_dentry); } +hfs_rename_put: hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ return error; } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_cap.c linux/fs/hfs/dir_cap.c --- v2.1.126/linux/fs/hfs/dir_cap.c Wed Aug 26 11:37:41 1998 +++ linux/fs/hfs/dir_cap.c Mon Nov 2 09:35:16 1998 @@ -167,43 +167,26 @@ hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); - /* Check for "." */ - if (hfs_streq(&cname, DOT)) { - /* this little trick skips the iget and iput */ - d_add(dentry, dir); - return 0; - } - - /* Check for "..". */ - if (hfs_streq(&cname, DOT_DOT)) { - struct hfs_cat_entry *parent; - - if (dtype != HFS_CAP_NDIR) { - /* Case for ".." in ".finderinfo" or ".resource" */ - parent = entry; - ++entry->count; /* __hfs_iget() eats one */ - } else { - /* Case for ".." in a normal directory */ - parent = hfs_cat_parent(entry); - } - inode = hfs_iget(parent, HFS_CAP_NDIR, dentry); - goto done; - } + /* no need to check for "." or ".." */ /* Check for special directories if in a normal directory. Note that cap_dupdir() does an iput(dir). */ if (dtype==HFS_CAP_NDIR) { /* Check for ".resource", ".finderinfo" and ".rootinfo" */ - if (hfs_streq(&cname, DOT_RESOURCE)) { + if (hfs_streq(cname.Name, cname.Len, + DOT_RESOURCE->Name, DOT_RESOURCE_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_RDIR, dentry); goto done; - } else if (hfs_streq(&cname, DOT_FINDERINFO)) { + } else if (hfs_streq(cname.Name, cname.Len, + DOT_FINDERINFO->Name, + DOT_FINDERINFO_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_FDIR, dentry); goto done; } else if ((entry->cnid == htonl(HFS_ROOT_CNID)) && - hfs_streq(&cname, DOT_ROOTINFO)) { + hfs_streq(cname.Name, cname.Len, + DOT_ROOTINFO->Name, DOT_ROOTINFO_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_CAP_FNDR, dentry); goto done; @@ -372,15 +355,14 @@ void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type) { if (type == HFS_CAP_DATA) { /* given name */ - hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry); - hfs_drop_special(DOT_RESOURCE, dentry->d_parent, dentry); + hfs_drop_special(dentry->d_parent, DOT_FINDERINFO, dentry); + hfs_drop_special(dentry->d_parent, DOT_RESOURCE, dentry); } else { struct dentry *de; - /* look for name */ - if ((de = hfs_lookup_dentry(dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_parent))) { + /* given {.resource,.finderinfo}/name, look for name */ + if ((de = hfs_lookup_dentry(dentry->d_parent->d_parent, + dentry->d_name.name, dentry->d_name.len))) { if (!de->d_inode) d_drop(de); dput(de); @@ -389,13 +371,13 @@ switch (type) { case HFS_CAP_RSRC: /* given .resource/name */ /* look for .finderinfo/name */ - hfs_drop_special(DOT_FINDERINFO, dentry->d_parent->d_parent, + hfs_drop_special(dentry->d_parent->d_parent, DOT_FINDERINFO, dentry); break; case HFS_CAP_FNDR: /* given .finderinfo/name. i don't this * happens. */ /* look for .resource/name */ - hfs_drop_special(DOT_RESOURCE, dentry->d_parent->d_parent, + hfs_drop_special(dentry->d_parent->d_parent, DOT_RESOURCE, dentry); break; } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_dbl.c linux/fs/hfs/dir_dbl.c --- v2.1.126/linux/fs/hfs/dir_dbl.c Wed Aug 26 11:37:41 1998 +++ linux/fs/hfs/dir_dbl.c Mon Nov 2 09:35:16 1998 @@ -147,22 +147,12 @@ /* Perform name-mangling */ hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); - /* Check for "." */ - if (hfs_streq(&cname, DOT)) { - /* this little trick skips the iget and iput */ - d_add(dentry, dir); - return 0; - } - - /* Check for "..". */ - if (hfs_streq(&cname, DOT_DOT)) { - inode = hfs_iget(hfs_cat_parent(entry), HFS_DBL_DIR, dentry); - goto done; - } + /* no need to check for "." or ".." */ /* Check for "%RootInfo" if in the root directory. */ if ((entry->cnid == htonl(HFS_ROOT_CNID)) && - hfs_streq(&cname, PCNT_ROOTINFO)) { + hfs_streq(cname.Name, cname.Len, + PCNT_ROOTINFO->Name, PCNT_ROOTINFO_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_DBL_HDR, dentry); goto done; @@ -445,15 +435,15 @@ switch (type) { case HFS_DBL_HDR: /* given %name, look for name. i don't think this happens. */ - de = hfs_lookup_dentry(dentry->d_name.name + 1, dentry->d_name.len - 1, - dentry->d_parent); + de = hfs_lookup_dentry(dentry->d_parent, + dentry->d_name.name + 1, dentry->d_name.len - 1); break; case HFS_DBL_DATA: /* given name, look for %name */ tmp_name[0] = '%'; strncpy(tmp_name + 1, dentry->d_name.name, HFS_NAMELEN - 1); - de = hfs_lookup_dentry(tmp_name, dentry->d_name.len + 1, - dentry->d_parent); + de = hfs_lookup_dentry(dentry->d_parent, + tmp_name, dentry->d_name.len + 1); } if (de) { diff -u --recursive --new-file v2.1.126/linux/fs/hfs/dir_nat.c linux/fs/hfs/dir_nat.c --- v2.1.126/linux/fs/hfs/dir_nat.c Wed Aug 26 11:37:41 1998 +++ linux/fs/hfs/dir_nat.c Mon Nov 2 09:35:16 1998 @@ -42,6 +42,7 @@ #define DOT_DOT_LEN 2 #define DOT_APPLEDOUBLE_LEN 12 #define DOT_PARENT_LEN 7 +#define ROOTINFO_LEN 8 const struct hfs_name hfs_nat_reserved1[] = { {DOT_LEN, "."}, @@ -52,13 +53,14 @@ }; const struct hfs_name hfs_nat_reserved2[] = { - {0, ""}, + {ROOTINFO_LEN, "RootInfo"}, }; #define DOT (&hfs_nat_reserved1[0]) #define DOT_DOT (&hfs_nat_reserved1[1]) #define DOT_APPLEDOUBLE (&hfs_nat_reserved1[2]) #define DOT_PARENT (&hfs_nat_reserved1[3]) +#define ROOTINFO (&hfs_nat_reserved2[0]) static struct file_operations hfs_nat_dir_operations = { NULL, /* lseek - default */ @@ -153,44 +155,33 @@ /* Perform name-mangling */ hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); - /* Check for "." */ - if (hfs_streq(&cname, DOT)) { - /* this little trick skips the iget and iput */ - d_add(dentry, dir); - return 0; - } - - /* Check for "..". */ - if (hfs_streq(&cname, DOT_DOT)) { - struct hfs_cat_entry *parent; - - if (dtype != HFS_NAT_NDIR) { - /* Case for ".." in ".AppleDouble" */ - parent = entry; - ++entry->count; /* __hfs_iget() eats one */ - } else { - /* Case for ".." in a normal directory */ - parent = hfs_cat_parent(entry); - } - inode = hfs_iget(parent, HFS_NAT_NDIR, dentry); - goto done; - } + /* no need to check for "." or ".." */ /* Check for ".AppleDouble" if in a normal directory, and for ".Parent" in ".AppleDouble". */ if (dtype==HFS_NAT_NDIR) { /* Check for ".AppleDouble" */ - if (hfs_streq(&cname, DOT_APPLEDOUBLE)) { + if (hfs_streq(cname.Name, cname.Len, + DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_NAT_HDIR, dentry); goto done; } } else if (dtype==HFS_NAT_HDIR) { - if (hfs_streq(&cname, DOT_PARENT)) { + if (hfs_streq(cname.Name, cname.Len, + DOT_PARENT->Name, DOT_PARENT_LEN)) { ++entry->count; /* __hfs_iget() eats one */ inode = hfs_iget(entry, HFS_NAT_HDR, dentry); goto done; } + + if ((entry->cnid == htonl(HFS_ROOT_CNID)) && + hfs_streq(cname.Name, cname.Len, + ROOTINFO->Name, ROOTINFO_LEN)) { + ++entry->count; /* __hfs_iget() eats one */ + inode = hfs_iget(entry, HFS_NAT_HDR, dentry); + goto done; + } } /* Do an hfs_iget() on the mangled name. */ @@ -271,7 +262,7 @@ filp->f_pos = 2; } - if (filp->f_pos < (dir->i_size - 1)) { + if (filp->f_pos < (dir->i_size - 2)) { hfs_u32 cnid; hfs_u8 type; @@ -279,7 +270,7 @@ hfs_cat_next(entry, &brec, filp->f_pos - 2, &cnid, &type)) { return 0; } - while (filp->f_pos < (dir->i_size - 1)) { + while (filp->f_pos < (dir->i_size - 2)) { if (hfs_cat_next(entry, &brec, 1, &cnid, &type)) { return 0; } @@ -302,7 +293,7 @@ hfs_cat_close(entry, &brec); } - if (filp->f_pos == (dir->i_size - 1)) { + if (filp->f_pos == (dir->i_size - 2)) { if (type == HFS_NAT_NDIR) { /* In normal dirs entry 2 is for ".AppleDouble" */ if (filldir(dirent, DOT_APPLEDOUBLE->Name, @@ -321,6 +312,19 @@ ++filp->f_pos; } + if (filp->f_pos == (dir->i_size - 1)) { + /* handle ROOT/.AppleDouble/RootInfo as the last entry. */ + if ((entry->cnid == htonl(HFS_ROOT_CNID)) && + (type == HFS_NAT_HDIR)) { + if (filldir(dirent, ROOTINFO->Name, + ROOTINFO_LEN, filp->f_pos, + ntohl(entry->cnid) | HFS_NAT_HDR)) { + return 0; + } + } + ++filp->f_pos; + } + return 0; } @@ -337,9 +341,9 @@ switch (type) { case HFS_NAT_HDR: /* given .AppleDouble/name */ /* look for name */ - de = hfs_lookup_dentry(dentry->d_name.name, - dentry->d_name.len, - dentry->d_parent->d_parent); + de = hfs_lookup_dentry(dentry->d_parent->d_parent, + dentry->d_name.name, dentry->d_name.len); + if (de) { if (!de->d_inode) d_drop(de); @@ -348,9 +352,10 @@ break; case HFS_NAT_DATA: /* given name */ /* look for .AppleDouble/name */ - hfs_drop_special(DOT_APPLEDOUBLE, dentry->d_parent, dentry); + hfs_drop_special(dentry->d_parent, DOT_APPLEDOUBLE, dentry); break; } + } /* @@ -370,7 +375,8 @@ int error; hfs_nameout(parent, &cname, dentry->d_name.name, dentry->d_name.len); - if (hfs_streq(&cname, DOT_APPLEDOUBLE)) { + if (hfs_streq(cname.Name, cname.Len, + DOT_APPLEDOUBLE->Name, DOT_APPLEDOUBLE_LEN)) { if (!HFS_SB(parent->i_sb)->s_afpd) { /* Not in AFPD compatibility mode */ error = -EPERM; @@ -415,7 +421,8 @@ hfs_nameout(dir, &cname, dentry->d_name.name, dentry->d_name.len); - if (!hfs_streq(&cname, DOT_PARENT)) { + if (!hfs_streq(cname.Name, cname.Len, + DOT_PARENT->Name, DOT_PARENT_LEN)) { struct hfs_cat_entry *victim; struct hfs_cat_key key; @@ -465,7 +472,8 @@ hfs_nameout(old_dir, &cname, old_dentry->d_name.name, old_dentry->d_name.len); - if (!hfs_streq(&cname, DOT_PARENT)) { + if (!hfs_streq(cname.Name, cname.Len, + DOT_PARENT->Name, DOT_PARENT_LEN)) { struct hfs_cat_entry *victim; struct hfs_cat_key key; diff -u --recursive --new-file v2.1.126/linux/fs/hfs/extent.c linux/fs/hfs/extent.c --- v2.1.126/linux/fs/hfs/extent.c Mon Jan 12 14:46:24 1998 +++ linux/fs/hfs/extent.c Mon Nov 2 09:35:16 1998 @@ -339,6 +339,7 @@ if (error) { hfs_warn("hfs_truncate: error %d deleting an extent.\n", error); } + HFS_DELETE(ext); } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file.c linux/fs/hfs/file.c --- v2.1.126/linux/fs/hfs/file.c Thu Sep 17 17:53:37 1998 +++ linux/fs/hfs/file.c Mon Nov 2 09:35:16 1998 @@ -98,11 +98,11 @@ /* If writing the block, then we have exclusive access to the file until we return, so it can't have moved. */ - if (tmp) { - hfs_cat_mark_dirty(fork->entry); - return getblk(dev, tmp, HFS_SECTOR_SIZE); - } - return NULL; + if (tmp) { + hfs_cat_mark_dirty(fork->entry); + return getblk(dev, tmp, HFS_SECTOR_SIZE); + } + return NULL; } else { /* If reading the block, then retry since the location on disk could have changed while @@ -220,8 +220,10 @@ pos += written; *ppos = pos; - if (*ppos > inode->i_size) + if (*ppos > inode->i_size) { inode->i_size = *ppos; + mark_inode_dirty(inode); + } return written; } @@ -236,7 +238,6 @@ */ static void hfs_file_truncate(struct inode * inode) { - /*struct inode *inode = dentry->d_inode;*/ struct hfs_fork *fork = HFS_I(inode)->fork; fork->lsize = inode->i_size; @@ -245,6 +246,7 @@ inode->i_size = fork->lsize; inode->i_blocks = fork->psize; + mark_inode_dirty(inode); } /* diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file_cap.c linux/fs/hfs/file_cap.c --- v2.1.126/linux/fs/hfs/file_cap.c Thu Sep 17 17:53:37 1998 +++ linux/fs/hfs/file_cap.c Mon Nov 2 09:35:16 1998 @@ -180,6 +180,7 @@ if (read) { inode->i_atime = CURRENT_TIME; *ppos = pos; + mark_inode_dirty(inode); } return read; @@ -280,6 +281,7 @@ } inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); return count; } @@ -291,9 +293,8 @@ */ static void cap_info_truncate(struct inode *inode) { - /*struct inode *inode = dentry->d_inode;*/ - if (inode->i_size > HFS_FORK_MAX) { inode->i_size = HFS_FORK_MAX; + mark_inode_dirty(inode); } } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/file_hdr.c linux/fs/hfs/file_hdr.c --- v2.1.126/linux/fs/hfs/file_hdr.c Thu Sep 17 17:53:37 1998 +++ linux/fs/hfs/file_hdr.c Mon Nov 2 09:35:16 1998 @@ -559,6 +559,7 @@ if (read) { inode->i_atime = CURRENT_TIME; *ppos = pos; + mark_inode_dirty(inode); } return read; } @@ -874,6 +875,7 @@ if (pos > inode->i_size) inode->i_size = pos; inode->i_mtime = inode->i_atime = CURRENT_TIME; + mark_inode_dirty(inode); } return written; } @@ -887,7 +889,6 @@ */ static void hdr_truncate(struct inode *inode) { - /*struct inode *inode = dentry->d_inode;*/ struct hfs_cat_entry *entry = HFS_I(inode)->entry; struct hfs_hdr_layout *layout; size_t size = inode->i_size; diff -u --recursive --new-file v2.1.126/linux/fs/hfs/hfs.h linux/fs/hfs/hfs.h --- v2.1.126/linux/fs/hfs/hfs.h Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/hfs.h Mon Nov 2 09:35:16 1998 @@ -64,12 +64,16 @@ #define HFS_EXT_CNID 3 /* EXTents B-tree */ #define HFS_CAT_CNID 4 /* CATalog B-tree */ #define HFS_BAD_CNID 5 /* BAD blocks file */ +#define HFS_ALLOC_CNID 6 /* ALLOCation file (HFS+) */ +#define HFS_START_CNID 7 /* STARTup file (HFS+) */ +#define HFS_ATTR_CNID 8 /* ATTRibutes file (HFS+) */ +#define HFS_EXCH_CNID 15 /* ExchangeFiles temp id */ /* values for hfs_cat_rec.cdrType */ -#define HFS_CDR_DIR 0x01 -#define HFS_CDR_FIL 0x02 -#define HFS_CDR_THD 0x03 -#define HFS_CDR_FTH 0x04 +#define HFS_CDR_DIR 0x01 /* folder (directory) */ +#define HFS_CDR_FIL 0x02 /* file */ +#define HFS_CDR_THD 0x03 /* folder (directory) thread */ +#define HFS_CDR_FTH 0x04 /* file thread */ /* legal values for hfs_ext_key.FkType and hfs_file.fork */ #define HFS_FK_DATA 0x00 @@ -484,42 +488,43 @@ extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *); /* string.c */ -extern unsigned long hfs_strhash(const struct hfs_name *); -extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *); -extern int hfs_streq(const struct hfs_name *, const struct hfs_name *); +extern unsigned int hfs_strhash(const unsigned char *, unsigned int); +extern int hfs_strcmp(const unsigned char *, unsigned int, + const unsigned char *, unsigned int); +extern int hfs_streq(const unsigned char *, unsigned int, + const unsigned char *, unsigned int); extern void hfs_tolower(unsigned char *, int); -extern __inline__ struct dentry -*hfs_lookup_dentry(const char *name, const int len, - struct dentry *base) +static __inline__ struct dentry +*hfs_lookup_dentry(struct dentry *base, const char *name, const int len) { struct qstr this; this.name = name; this.len = len; - this.hash = full_name_hash(name, len); + this.hash = hfs_strhash(name, len); return d_lookup(base, &this); } -/* drop a dentry for one of the special subdirectories */ -extern __inline__ void hfs_drop_special(const struct hfs_name *name, - struct dentry *base, +/* drop a dentry for one of the special directories. + * it's in the form of base/name/dentry. */ +static __inline__ void hfs_drop_special(struct dentry *base, + const struct hfs_name *name, struct dentry *dentry) { struct dentry *dparent, *de; - dparent = hfs_lookup_dentry(name->Name, name->Len, base); + dparent = hfs_lookup_dentry(base, name->Name, name->Len); if (dparent) { - de = hfs_lookup_dentry(dentry->d_name.name, dentry->d_name.len, - dparent); - dput(dparent); - - if (de) { - if (!de->d_inode) - d_drop(de); - dput(de); - } + de = hfs_lookup_dentry(dparent, dentry->d_name.name, + dentry->d_name.len); + if (de) { + if (!de->d_inode) + d_drop(de); + dput(de); + } + dput(dparent); } } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/inode.c linux/fs/hfs/inode.c --- v2.1.126/linux/fs/hfs/inode.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/inode.c Mon Nov 2 09:35:16 1998 @@ -73,6 +73,9 @@ */ void hfs_put_inode(struct inode * inode) { + struct hfs_cat_entry *entry = HFS_I(inode)->entry; + + hfs_cat_put(entry); if (inode->i_count == 1) { struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; @@ -243,7 +246,7 @@ if (inode->i_dev != sb->s_dev) { iput(inode); /* automatically does an hfs_cat_put */ inode = NULL; - } else if (!inode->i_mode) { + } else if (!inode->i_mode || (*sys_entry == NULL)) { /* Initialize the inode */ struct hfs_sb_info *hsb = HFS_SB(sb); @@ -266,8 +269,7 @@ inode->i_mode &= ~hsb->s_umask; if (!inode->i_mode) { - clear_inode(inode); - hfs_cat_put(entry); + iput(inode); /* does an hfs_cat_put */ inode = NULL; } else *sys_entry = dentry; /* cache dentry */ @@ -398,7 +400,7 @@ struct hfs_dir *hdir = &entry->u.dir; inode->i_blocks = 0; - inode->i_size = hdir->files + hdir->dirs + 3; + inode->i_size = hdir->files + hdir->dirs + 4; inode->i_mode = S_IRWXUGO | S_IFDIR; HFS_I(inode)->dir_size = 1; if (type == HFS_NAT_NDIR) { diff -u --recursive --new-file v2.1.126/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c --- v2.1.126/linux/fs/hfs/mdb.c Thu Sep 17 17:53:37 1998 +++ linux/fs/hfs/mdb.c Mon Nov 2 09:35:16 1998 @@ -99,24 +99,30 @@ memset(mdb, 0, sizeof(*mdb)); mdb->magic = HFS_MDB_MAGIC; mdb->sys_mdb = sys_mdb; + INIT_LIST_HEAD(&mdb->entry_dirty); /* See if this is an HFS filesystem */ buf = hfs_buffer_get(sys_mdb, part_start + HFS_MDB_BLK, 1); if (!hfs_buffer_ok(buf)) { hfs_warn("hfs_fs: Unable to read superblock\n"); + HFS_DELETE(mdb); goto bail2; } + raw = (struct raw_mdb *)hfs_buffer_data(buf); if (hfs_get_ns(raw->drSigWord) != htons(HFS_SUPER_MAGIC)) { hfs_buffer_put(buf); + HFS_DELETE(mdb); goto bail2; } mdb->buf = buf; - + bs = hfs_get_hl(raw->drAlBlkSiz); if (!bs || bs > HFS_USHRT_MAX || (bs & (HFS_SECTOR_SIZE-1))) { hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs); - goto bail1; + hfs_buffer_put(buf); + HFS_DELETE(mdb); + goto bail2; } mdb->alloc_blksz = bs >> HFS_SECTOR_SIZE_BITS; @@ -127,7 +133,7 @@ mdb->backup_date = hfs_get_hl(raw->drVolBkUp); mdb->clumpablks = (hfs_get_hl(raw->drClpSiz) / mdb->alloc_blksz) >> HFS_SECTOR_SIZE_BITS; - memcpy(mdb->vname, raw->drVN, 28); + memcpy(mdb->vname, raw->drVN, sizeof(raw->drVN)); /* These parameters are read from and written to the MDB */ mdb->modify_date = hfs_get_nl(raw->drLsMod); @@ -139,8 +145,8 @@ mdb->root_dirs = hfs_get_hs(raw->drNmRtDirs); mdb->file_count = hfs_get_hl(raw->drFilCnt); mdb->dir_count = hfs_get_hl(raw->drDirCnt); - - /* TRY to get the alternate (backup) MDB */ + + /* TRY to get the alternate (backup) MDB. */ lcv = mdb->fs_start + mdb->fs_ablocks * mdb->alloc_blksz; limit = lcv + mdb->alloc_blksz; for (; lcv < limit; ++lcv) { @@ -148,20 +154,21 @@ if (hfs_buffer_ok(buf)) { struct raw_mdb *tmp = (struct raw_mdb *)hfs_buffer_data(buf); - + if (hfs_get_ns(tmp->drSigWord) == - htons(HFS_SUPER_MAGIC)) { + htons(HFS_SUPER_MAGIC)) { mdb->alt_buf = buf; break; } - hfs_buffer_put(buf); } + hfs_buffer_put(buf); } + if (mdb->alt_buf == NULL) { hfs_warn("hfs_fs: unable to locate alternate MDB\n"); hfs_warn("hfs_fs: continuing without an alternate MDB\n"); } - + /* read in the bitmap */ block = hfs_get_hs(raw->drVBMSt) + part_start; bmbuf = mdb->bitmap; @@ -253,23 +260,29 @@ hfs_put_hl(mdb->file_count, raw->drFilCnt); hfs_put_hl(mdb->dir_count, raw->drDirCnt); - /* write MDB to disk */ - hfs_buffer_dirty(mdb->buf); - - /* write the backup MDB, not returning until it is written */ + /* write the backup MDB, not returning until it is written. + * we only do this when either the catalog or extents overflow + * files grow. */ if (backup && hfs_buffer_ok(mdb->alt_buf)) { - memcpy(hfs_buffer_data(mdb->alt_buf), - hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE); - hfs_buffer_dirty(mdb->alt_buf); - hfs_buffer_sync(mdb->alt_buf); + struct raw_mdb *tmp = (struct raw_mdb *) + hfs_buffer_data(mdb->alt_buf); + + if ((hfs_get_hl(tmp->drCTFlSize) < + hfs_get_hl(raw->drCTFlSize)) || + (hfs_get_hl(tmp->drXTFlSize) < + hfs_get_hl(raw->drXTFlSize))) { + memcpy(hfs_buffer_data(mdb->alt_buf), + hfs_buffer_data(mdb->buf), HFS_SECTOR_SIZE); + hfs_buffer_dirty(mdb->alt_buf); + hfs_buffer_sync(mdb->alt_buf); + } } } /* * hfs_mdb_put() * - * Release the resources associated with the in-core MDB. - */ + * Release the resources associated with the in-core MDB. */ void hfs_mdb_put(struct hfs_mdb *mdb, int readonly) { int lcv; @@ -287,7 +300,7 @@ /* update volume attributes */ if (!readonly) { - struct raw_mdb *raw = + struct raw_mdb *raw = (struct raw_mdb *)hfs_buffer_data(mdb->buf); hfs_put_ns(mdb->attrib, raw->drAtrb); hfs_buffer_dirty(mdb->buf); diff -u --recursive --new-file v2.1.126/linux/fs/hfs/string.c linux/fs/hfs/string.c --- v2.1.126/linux/fs/hfs/string.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/string.c Mon Nov 2 09:35:16 1998 @@ -81,13 +81,13 @@ /* * Hash a string to an integer in a case-independent way */ -unsigned long hfs_strhash(const struct hfs_name *cname) +unsigned int hfs_strhash(const unsigned char *name, unsigned int len) { unsigned long hash = init_name_hash(); - unsigned int i; - for (i = 0; i < cname->Len; i++) { - hash = partial_name_hash(caseorder[cname->Name[i]], hash); - } + + while (len--) + hash = partial_name_hash(caseorder[*name++], + hash); return end_name_hash(hash); } @@ -98,45 +98,34 @@ * Equivalent to ARDI's call: * ROMlib_RelString(s1+1, s2+1, true, false, (s1[0]<<16) | s2[0]) */ -int hfs_strcmp(const struct hfs_name *s1, const struct hfs_name *s2) +int hfs_strcmp(const unsigned char *s1, unsigned int len1, + const unsigned char *s2, unsigned int len2) { int len, tmp; - const unsigned char *p1, *p2; - - if (!s1 || !s2) { - return 0; - } - len = (s1->Len > s2->Len) ? s2->Len : s1->Len; - p1 = s1->Name; - p2 = s2->Name; + len = (len1 > len2) ? len2 : len1; while (len--) { - if ((tmp = (int)caseorder[*(p1++)]-(int)caseorder[*(p2++)])) { + if ((tmp = (int)caseorder[*(s1++)] - + (int)caseorder[*(s2++)])) { return tmp; } } - return s1->Len - s2->Len; + return len1 - len2; } /* * Test for equality of two strings in the HFS filename character ordering. */ -int hfs_streq(const struct hfs_name *s1, const struct hfs_name *s2) +int hfs_streq(const unsigned char *s1, unsigned int len1, + const unsigned char *s2, unsigned int len2) { - int len; - const unsigned char *p1, *p2; - - if (!s1 || !s2 || (s1->Len != s2->Len)) { + if (len1 != len2) { return 0; } - len = s1->Len; - p1 = s1->Name; - p2 = s2->Name; - - while (len--) { - if (caseorder[*(p1++)] != caseorder[*(p2++)]) { + while (len1--) { + if (caseorder[*(s1++)] != caseorder[*(s2++)]) { return 0; } } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/super.c linux/fs/hfs/super.c --- v2.1.126/linux/fs/hfs/super.c Thu Aug 27 19:56:29 1998 +++ linux/fs/hfs/super.c Mon Nov 2 09:35:17 1998 @@ -34,7 +34,7 @@ /*================ Forward declarations ================*/ -static void hfs_read_inode(struct inode *inode); +static void hfs_read_inode(struct inode *); static void hfs_put_super(struct super_block *); static int hfs_statfs(struct super_block *, struct statfs *, int); static void hfs_write_super(struct super_block *); @@ -45,7 +45,7 @@ hfs_read_inode, /* read_inode */ NULL, /* write_inode */ hfs_put_inode, /* put_inode - in inode.c */ - NULL, /* delete inode */ + NULL, /* delete_inode */ hfs_notify_change, /* notify_change - in inode.c */ hfs_put_super, /* put_super */ hfs_write_super, /* write_super */ @@ -75,7 +75,6 @@ inode->i_op = NULL; } - /* * hfs_write_super() * @@ -134,8 +133,6 @@ set_blocksize(sb->s_dev, BLOCK_SIZE); MOD_DEC_USE_COUNT; - - return; } /* @@ -145,7 +142,7 @@ * HFS filesystems. The purpose is to return various data about the * filesystem. * - * XXX: changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. + * changed f_files/f_ffree to reflect the fs_ablock/free_ablocks. */ static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len) { @@ -434,14 +431,13 @@ if (!mdb) { if (!silent) { - printk("VFS: Can't find a HFS filesystem on dev %s.\n", + hfs_warn("VFS: Can't find a HFS filesystem on dev %s.\n", kdevname(dev)); } goto bail2; } - HFS_SB(s)->s_mdb = mdb; - INIT_LIST_HEAD(&mdb->entry_dirty); + HFS_SB(s)->s_mdb = mdb; if (HFS_ITYPE(mdb->next_id) != 0) { hfs_warn("hfs_fs: too many files.\n"); goto bail1; @@ -480,8 +476,8 @@ hfs_mdb_put(mdb, s->s_flags & MS_RDONLY); bail2: set_blocksize(dev, BLOCK_SIZE); - MOD_DEC_USE_COUNT; unlock_super(s); + MOD_DEC_USE_COUNT; bail3: s->s_dev = 0; return NULL; diff -u --recursive --new-file v2.1.126/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c --- v2.1.126/linux/fs/hfs/sysdep.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/sysdep.c Mon Nov 2 09:35:17 1998 @@ -61,29 +61,23 @@ /* hfs_strhash now uses the same hashing function as the dcache. */ static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this) { - struct hfs_name cname; - - if ((cname.Len = this->len) > HFS_NAMELEN) + if (this->len > HFS_NAMELEN) return 0; - strncpy(cname.Name, this->name, this->len); - this->hash = hfs_strhash(&cname); + this->hash = hfs_strhash(this->name, this->len); return 0; } +/* return 1 on failure and 0 on success */ static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) { - struct hfs_name s1, s2; - if (a->len != b->len) return 1; - if ((s1.Len = s2.Len = a->len) > HFS_NAMELEN) + if (a->len > HFS_NAMELEN) return 1; - strncpy(s1.Name, a->name, s1.Len); - strncpy(s2.Name, b->name, s2.Len); - return hfs_streq(&s1, &s2); + return !hfs_streq(a->name, a->len, b->name, b->len); } static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode) @@ -91,6 +85,5 @@ struct hfs_cat_entry *entry = HFS_I(inode)->entry; entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; - hfs_cat_put(entry); iput(inode); } diff -u --recursive --new-file v2.1.126/linux/fs/hfs/version.c linux/fs/hfs/version.c --- v2.1.126/linux/fs/hfs/version.c Tue Mar 17 22:18:15 1998 +++ linux/fs/hfs/version.c Mon Nov 2 09:35:17 1998 @@ -7,4 +7,4 @@ * This file contains the version string for this release. */ -const char hfs_version[]="0.95+asun3"; +const char hfs_version[]="0.96"; diff -u --recursive --new-file v2.1.126/linux/fs/lockd/clntlock.c linux/fs/lockd/clntlock.c --- v2.1.126/linux/fs/lockd/clntlock.c Fri Oct 23 22:01:22 1998 +++ linux/fs/lockd/clntlock.c Sat Oct 31 10:17:23 1998 @@ -71,7 +71,11 @@ * a 1 minute timeout would do. See the comment before * nlmclnt_lock for an explanation. */ - current->timeout = jiffies + 30 * HZ; + /* + * FIXME, can we be not interruptible and so be allowed to use + * a timeout here? -arca + */ +/* current->timeout = jiffies + 30 * HZ; */ sleep_on(&block.b_wait); for (head = &nlm_blocked; *head; head = &(*head)->b_next) { diff -u --recursive --new-file v2.1.126/linux/fs/lockd/clntproc.c linux/fs/lockd/clntproc.c --- v2.1.126/linux/fs/lockd/clntproc.c Wed Aug 26 11:37:41 1998 +++ linux/fs/lockd/clntproc.c Sat Oct 31 10:17:22 1998 @@ -174,9 +174,9 @@ nlmclnt_grace_wait(struct nlm_host *host) { if (!host->h_reclaiming) - current->timeout = jiffies + 10 * HZ; - interruptible_sleep_on(&host->h_gracewait); - current->timeout = 0; + interruptible_sleep_on_timeout(&host->h_gracewait, 10*HZ); + else + interruptible_sleep_on(&host->h_gracewait); return signalled()? -ERESTARTSYS : 0; } @@ -194,10 +194,8 @@ if (call) return call; printk("nlmclnt_alloc_call: failed, waiting for memory\n"); - current->timeout = jiffies + 5 * HZ; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(5*HZ); } return NULL; } @@ -247,9 +245,7 @@ } /* Back off a little and try again */ - current->timeout = jiffies + 15 * HZ; - interruptible_sleep_on(&host->h_gracewait); - current->timeout = 0; + interruptible_sleep_on_timeout(&host->h_gracewait, 15*HZ); } while (!signalled()); return -ERESTARTSYS; diff -u --recursive --new-file v2.1.126/linux/fs/lockd/svc.c linux/fs/lockd/svc.c --- v2.1.126/linux/fs/lockd/svc.c Sat Sep 5 16:46:41 1998 +++ linux/fs/lockd/svc.c Mon Nov 2 09:37:52 1998 @@ -46,7 +46,7 @@ unsigned long nlmsvc_grace_period = 0; unsigned long nlmsvc_timeout = 0; -static struct wait_queue * lockd_start = NULL; +static struct semaphore lockd_start = MUTEX_LOCKED; static struct wait_queue * lockd_exit = NULL; /* @@ -73,7 +73,7 @@ * Let our maker know we're running. */ nlmsvc_pid = current->pid; - wake_up(&lockd_start); + up(&lockd_start); exit_mm(current); current->session = 1; @@ -121,6 +121,7 @@ */ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { + long timeout = MAX_SCHEDULE_TIMEOUT; if (signalled()) { spin_lock_irq(¤t->sigmask_lock); flush_signals(current); @@ -134,7 +135,7 @@ * during grace period). */ if (!nlmsvc_grace_period) { - current->timeout = nlmsvc_retry_blocked(); + timeout = nlmsvc_retry_blocked() - jiffies; } else if (nlmsvc_grace_period < jiffies) nlmsvc_grace_period = 0; @@ -142,7 +143,7 @@ * Find a socket with data available and call its * recvfrom routine. */ - if ((err = svc_recv(serv, rqstp)) == -EAGAIN) + if ((err = svc_recv(serv, rqstp, timeout)) == -EAGAIN) continue; if (err < 0) { if (err != -EINTR) @@ -250,7 +251,7 @@ "lockd_up: create thread failed, error=%d\n", error); goto destroy_and_out; } - sleep_on(&lockd_start); + down(&lockd_start); /* * Note: svc_serv structures have an initial use count of 1, @@ -291,9 +292,7 @@ * the lockd semaphore, we can't wait around forever ... */ current->sigpending = 0; - current->timeout = jiffies + HZ; - interruptible_sleep_on(&lockd_exit); - current->timeout = 0; + interruptible_sleep_on_timeout(&lockd_exit, HZ); if (nlmsvc_pid) { printk(KERN_WARNING "lockd_down: lockd failed to exit, clearing pid\n"); diff -u --recursive --new-file v2.1.126/linux/fs/namei.c linux/fs/namei.c --- v2.1.126/linux/fs/namei.c Fri Oct 23 22:01:22 1998 +++ linux/fs/namei.c Thu Nov 5 09:54:04 1998 @@ -28,10 +28,23 @@ #include #include #include -#include #include #include +/* + * The bitmask for a lookup event: + * - follow links at the end + * - require a directory + * - ending slashes ok even for nonexistent files + * - internal "there are more path compnents" flag + */ +#define LOOKUP_FOLLOW (1) +#define LOOKUP_DIRECTORY (2) +#define LOOKUP_SLASHOK (4) +#define LOOKUP_CONTINUE (8) + +#include + /* This can be removed after the beta phase. */ #define CACHE_SUPERVISE /* debug the correctness of dcache entries */ #undef DEBUG /* some other debugging */ @@ -282,18 +295,6 @@ return result; } -/* - * The bitmask for a lookup event: - * - follow links at the end - * - require a directory - * - ending slashes ok even for nonexistent files - * - internal "there are more path compnents" flag - */ -#define LOOKUP_FOLLOW (1) -#define LOOKUP_DIRECTORY (2) -#define LOOKUP_SLASHOK (4) -#define LOOKUP_CONTINUE (8) - static struct dentry * do_follow_link(struct dentry *base, struct dentry *dentry, unsigned int follow) { struct inode * inode = dentry->d_inode; @@ -342,10 +343,10 @@ if (*name == '/') { if (base) dput(base); - base = dget(current->fs->root); do { name++; } while (*name == '/'); + base = dget(current->fs->root); } else if (!base) { base = dget(current->fs->pwd); } @@ -626,7 +627,7 @@ if (!inode) goto exit; - error = -EACCES; + error = -ELOOP; if (S_ISLNK(inode->i_mode)) goto exit; @@ -1195,7 +1196,7 @@ error = -ENOENT; if (!old_dentry->d_inode) - goto exit; + goto exit_old; { unsigned int flags = 0; diff -u --recursive --new-file v2.1.126/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c --- v2.1.126/linux/fs/ncpfs/sock.c Tue Mar 10 10:03:34 1998 +++ linux/fs/ncpfs/sock.c Thu Nov 5 09:58:46 1998 @@ -94,7 +94,7 @@ poll_table wait_table; struct poll_table_entry entry; int init_timeout, max_timeout; - int timeout; + int timeout; long tmp_timeout; int retrans; int major_timeout_seen; int acknowledge_seen; @@ -173,6 +173,7 @@ wait_table.entry = &entry; current->state = TASK_INTERRUPTIBLE; if (!(file->f_op->poll(file, &wait_table) & POLLIN)) { + int timed_out; if (timeout > max_timeout) { /* JEJB/JSP 2/7/94 * This is useful to see if the system is @@ -182,17 +183,15 @@ } timeout = max_timeout; } - current->timeout = jiffies + timeout; - schedule(); + timed_out = !schedule_timeout(timeout); remove_wait_queue(entry.wait_address, &entry.wait); fput(file); current->state = TASK_RUNNING; if (signal_pending(current)) { - current->timeout = 0; result = -ERESTARTSYS; break; } - if (!current->timeout) { + if (timed_out) { if (n < retrans) continue; if (server->m.flags & NCP_MOUNT_SOFT) { @@ -208,8 +207,7 @@ } major_timeout_seen = 1; continue; - } else - current->timeout = 0; + } } else if (wait_table.nr) { remove_wait_queue(entry.wait_address, &entry.wait); fput(file); diff -u --recursive --new-file v2.1.126/linux/fs/nfs/inode.c linux/fs/nfs/inode.c --- v2.1.126/linux/fs/nfs/inode.c Fri Oct 23 22:01:22 1998 +++ linux/fs/nfs/inode.c Sat Oct 31 10:17:23 1998 @@ -106,10 +106,10 @@ printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino); #endif nfs_invalidate_pages(inode); - while (NFS_WRITEBACK(inode) != NULL && jiffies < timeout) { + while (NFS_WRITEBACK(inode) != NULL && + time_before(jiffies, timeout)) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/10; - schedule(); + schedule_timeout(HZ/10); } current->state = TASK_RUNNING; if (NFS_WRITEBACK(inode) != NULL) diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/auth.c linux/fs/nfsd/auth.c --- v2.1.126/linux/fs/nfsd/auth.c Mon Apr 7 11:35:31 1997 +++ linux/fs/nfsd/auth.c Sat Oct 31 10:49:35 1998 @@ -41,7 +41,21 @@ current->fsgid = cred->cr_gid; else current->fsgid = exp->ex_anon_gid; - for (i = 0; i < NGROUPS; i++) - current->groups[i] = cred->cr_groups[i]; + for (i = 0; i < NGROUPS; i++) { + gid_t group = cred->cr_groups[i]; + if (group == (gid_t) NOGROUP) + break; + current->groups[i] = group; + } + current->ngroups = i; + + if ((cred->cr_uid)) { + cap_lower(current->cap_effective, CAP_DAC_OVERRIDE); + cap_lower(current->cap_effective, CAP_DAC_READ_SEARCH); + } else { + cap_raise(current->cap_effective, CAP_DAC_OVERRIDE); + cap_raise(current->cap_effective, CAP_DAC_READ_SEARCH); + } + rqstp->rq_userset = 1; } diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/export.c linux/fs/nfsd/export.c --- v2.1.126/linux/fs/nfsd/export.c Fri Oct 23 22:01:22 1998 +++ linux/fs/nfsd/export.c Tue Oct 27 15:15:35 1998 @@ -457,14 +457,17 @@ char *path, struct knfs_fh *f) { struct svc_export *exp; - struct dentry *dentry; + struct dentry *dentry = NULL; struct inode *inode; struct svc_fh fh; int err; + err = -EPERM; if (path) { - dentry = lookup_dentry(path, NULL, 0); - + if (!(dentry = lookup_dentry(path, NULL, 0))) { + printk("nfsd: exp_rootfh path not found %s", path); + return -EPERM; + } dev = dentry->d_inode->i_dev; ino = dentry->d_inode->i_ino; @@ -474,17 +477,21 @@ } else { dprintk("nfsd: exp_rootfh(%s:%x/%ld)\n", clp->cl_ident, dev, ino); - exp = exp_get(clp, dev, ino); - dentry = dget(exp->ex_dentry); + if ((exp = exp_get(clp, dev, ino))) + if (!(dentry = dget(exp->ex_dentry))) { + printk("exp_rootfh: Aieee, NULL dentry\n"); + return -EPERM; + } } - err = -EPERM; - if (!exp) + if (!exp) { + dprintk("nfsd: exp_rootfh export not found.\n"); goto out; + } inode = dentry->d_inode; if (!inode) { printk("exp_rootfh: Aieee, NULL d_inode\n"); - return -EPERM; + goto out; } if (inode->i_dev != dev || inode->i_ino != ino) { printk("exp_rootfh: Aieee, ino/dev mismatch\n"); diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c --- v2.1.126/linux/fs/nfsd/nfsfh.c Fri Oct 23 22:01:22 1998 +++ linux/fs/nfsd/nfsfh.c Tue Oct 27 15:15:35 1998 @@ -1061,31 +1061,6 @@ goto out; /* - * Security: Check that the export is valid for dentry - */ - if (fh->fh_dev != fh->fh_xdev) { - printk("fh_verify: Security: export on other device" - " (%d, %d).\n", fh->fh_dev, fh->fh_xdev); - goto out; - } else { - struct dentry *tdentry = dentry; - - do { - if (exp->ex_dentry == tdentry) { - error = 0; - break; - } - if (tdentry->d_parent == tdentry) - break; - } while ((tdentry = tdentry->d_parent)); - if (error) { - printk("fh_verify: Security: %s/%s bad export.\n", - dentry->d_parent->d_name.name, - dentry->d_name.name); - goto out; - } - } - /* * Note: it's possible the returned dentry won't be the one in the * file handle. We can correct the file handle for our use, but * unfortunately the client will keep sending the broken one. Let's @@ -1105,6 +1080,7 @@ check_type: dentry = fhp->fh_dentry; inode = dentry->d_inode; + exp = fhp->fh_export; if (type > 0 && (inode->i_mode & S_IFMT) != type) { error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir; goto out; @@ -1114,9 +1090,45 @@ goto out; } + /* + * Security: Check that the export is valid for dentry + */ + if (fh->fh_dev != fh->fh_xdev) { + printk("fh_verify: Security: export on other device" + " (%d, %d).\n", fh->fh_dev, fh->fh_xdev); + goto out; + } else if (exp->ex_dentry != dentry) { + struct dentry *tdentry = dentry; + int err2 = 0; + + error = nfserr_stale; + do { + tdentry = tdentry->d_parent; + if (exp->ex_dentry == tdentry) { + error = 0; + break; + } + if ((err2 = nfsd_permission(exp, tdentry, MAY_READ))) { + error = err2; +#ifdef NFSD_PARANOIA + goto out1; +#else + goto out; +#endif + } + } while ((tdentry != tdentry->d_parent)); + if (error) { + printk("fh_verify: Security: %s/%s bad export.\n", + dentry->d_parent->d_name.name, + dentry->d_name.name); + goto out; + } + } + /* Finally, check access permissions. */ - error = nfsd_permission(fhp->fh_export, dentry, access); + error = nfsd_permission(exp, dentry, access); #ifdef NFSD_PARANOIA +out1: if (error) printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, access, error); diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/nfssvc.c linux/fs/nfsd/nfssvc.c --- v2.1.126/linux/fs/nfsd/nfssvc.c Wed Sep 9 14:51:09 1998 +++ linux/fs/nfsd/nfssvc.c Sat Oct 31 10:37:14 1998 @@ -115,7 +115,7 @@ * Find a socket with data available and call its * recvfrom routine. */ - while ((err = svc_recv(serv, rqstp)) == -EAGAIN) + while ((err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) ; if (err < 0) break; diff -u --recursive --new-file v2.1.126/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c --- v2.1.126/linux/fs/nfsd/vfs.c Fri Oct 23 22:01:22 1998 +++ linux/fs/nfsd/vfs.c Wed Nov 4 10:11:14 1998 @@ -14,6 +14,7 @@ * Copyright (C) 1995, 1996, 1997 Olaf Kirch */ +#include #include #include #include @@ -554,13 +555,10 @@ if (EX_WGATHER(exp) && (inode->i_writecount > 1 || (last_ino == inode->i_ino && last_dev == inode->i_dev))) { #if 0 - current->timeout = jiffies + 10 * HZ / 1000; - interruptible_sleep_on(&inode->i_wait); + interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000); #else dprintk("nfsd: write defer %d\n", current->pid); - current->need_resched = 1; - current->timeout = jiffies + HZ / 100; - schedule(); + schedule_timeout((HZ+99)/100); dprintk("nfsd: write resume %d\n", current->pid); #endif } diff -u --recursive --new-file v2.1.126/linux/fs/nls/nls_base.c linux/fs/nls/nls_base.c --- v2.1.126/linux/fs/nls/nls_base.c Tue Mar 17 22:18:15 1998 +++ linux/fs/nls/nls_base.c Sun Oct 25 14:16:35 1998 @@ -49,7 +49,6 @@ int c0, c, nc; struct utf8_table *t; - printk("utf8_mbtowc\n"); nc = 0; c0 = *s; l = c0; @@ -80,11 +79,9 @@ const __u8 *ip; int size; - printk("\nutf8_mbstowcs: n=%d\n", n); op = pwcs; ip = s; while (*ip && n > 0) { - printk(" %02x", *ip); if (*ip & 0x80) { size = utf8_mbtowc(op, ip, n); if (size == -1) { diff -u --recursive --new-file v2.1.126/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.126/linux/fs/proc/array.c Fri Oct 23 22:01:22 1998 +++ linux/fs/proc/array.c Sat Oct 31 10:17:22 1998 @@ -887,7 +887,7 @@ tsk->times.tms_cstime, priority, nice, - tsk->timeout, + 0UL /* removed */, tsk->it_real_value, tsk->start_time, vsize, diff -u --recursive --new-file v2.1.126/linux/fs/select.c linux/fs/select.c --- v2.1.126/linux/fs/select.c Wed Jul 1 19:38:56 1998 +++ linux/fs/select.c Sat Oct 31 10:17:22 1998 @@ -124,28 +124,25 @@ #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) #define POLLEX_SET (POLLPRI) -int do_select(int n, fd_set_buffer *fds, unsigned long timeout) +int do_select(int n, fd_set_buffer *fds, long *timeout) { poll_table wait_table, *wait; - int retval; - int i; - - lock_kernel(); + int retval, i; + long __timeout = *timeout; wait = NULL; - current->timeout = timeout; - if (timeout) { - struct poll_table_entry *entry = (struct poll_table_entry *) - __get_free_page(GFP_KERNEL); - if (!entry) { - retval = -ENOMEM; - goto out_nowait; - } + if (__timeout) { + struct poll_table_entry *entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL); + if (!entry) + return -ENOMEM; + wait_table.nr = 0; wait_table.entry = entry; wait = &wait_table; } + lock_kernel(); + retval = max_select_fd(n, fds); if (retval < 0) goto out; @@ -190,18 +187,22 @@ } } wait = NULL; - if (retval || !current->timeout || signal_pending(current)) + if (retval || !__timeout || signal_pending(current)) break; - schedule(); + __timeout = schedule_timeout(__timeout); } current->state = TASK_RUNNING; out: - if (timeout) { + if (*timeout) { free_wait(&wait_table); free_page((unsigned long) wait_table.entry); } -out_nowait: + + /* + * Up-to-date the caller timeout. + */ + *timeout = __timeout; unlock_kernel(); return retval; } @@ -218,10 +219,10 @@ sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { fd_set_buffer *fds; - unsigned long timeout; + long timeout; int ret; - timeout = ~0UL; + timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { time_t sec, usec; @@ -232,8 +233,6 @@ timeout = ROUND_UP(usec, 1000000/HZ); timeout += sec * (unsigned long) HZ; - if (timeout) - timeout += jiffies + 1; } ret = -ENOMEM; @@ -253,12 +252,11 @@ zero_fd_set(n, fds->res_out); zero_fd_set(n, fds->res_ex); - ret = do_select(n, fds, timeout); + ret = do_select(n, fds, &timeout); if (tvp && !(current->personality & STICKY_TIMEOUTS)) { - unsigned long timeout = current->timeout - jiffies - 1; time_t sec = 0, usec = 0; - if ((long) timeout > 0) { + if (timeout) { sec = timeout / HZ; usec = timeout % HZ; usec *= (1000000/HZ); @@ -266,7 +264,6 @@ put_user(sec, &tvp->tv_sec); put_user(usec, &tvp->tv_usec); } - current->timeout = 0; if (ret < 0) goto out; @@ -287,7 +284,8 @@ return ret; } -static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait) +static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait, + long timeout) { int count = 0; @@ -321,15 +319,15 @@ } wait = NULL; - if (count || !current->timeout || signal_pending(current)) + if (count || !timeout || signal_pending(current)) break; - schedule(); + timeout = schedule_timeout(timeout); } current->state = TASK_RUNNING; return count; } -asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout) +asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) { int i, fdcount, err, size; struct pollfd * fds, *fds1; @@ -342,9 +340,9 @@ goto out; if (timeout < 0) - timeout = 0x7fffffff; + timeout = MAX_SCHEDULE_TIMEOUT; else if (timeout) - timeout = ((unsigned long)timeout*HZ+999)/1000+jiffies+1; + timeout = (timeout*HZ+999)/1000+1; err = -ENOMEM; if (timeout) { @@ -366,9 +364,7 @@ if (copy_from_user(fds, ufds, size)) goto out_fds; - current->timeout = timeout; - fdcount = do_poll(nfds, fds, wait); - current->timeout = 0; + fdcount = do_poll(nfds, fds, wait, timeout); /* OK, now copy the revents fields back to user space. */ fds1 = fds; diff -u --recursive --new-file v2.1.126/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v2.1.126/linux/fs/smbfs/proc.c Thu Aug 27 19:56:30 1998 +++ linux/fs/smbfs/proc.c Tue Nov 3 21:56:58 1998 @@ -520,9 +520,7 @@ /* * Wait for the new connection. */ - current->timeout = jiffies + 5*HZ; - interruptible_sleep_on(&server->wait); - current->timeout = 0; + interruptible_sleep_on_timeout(&server->wait, 5*HZ); if (signal_pending(current)) printk("smb_retry: caught signal\n"); @@ -1602,10 +1600,8 @@ /* Windows 95 is not able to deliver answers * to FIND_NEXT fast enough, so sleep 0.2 sec */ - current->timeout = jiffies + HZ / 5; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(HZ/5); } } diff -u --recursive --new-file v2.1.126/linux/fs/ufs/util.h linux/fs/ufs/util.h --- v2.1.126/linux/fs/ufs/util.h Fri Oct 23 22:01:22 1998 +++ linux/fs/ufs/util.h Mon Nov 2 09:09:46 1998 @@ -305,7 +305,7 @@ count = min (size + offset, uspi->s_bpf); size -= count - offset; pos = ext2_find_next_zero_bit (ubh->bh[base]->b_data, count, offset); - if (pos < count + offset || !size) + if (pos < count || !size) break; base++; offset = 0; diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/README-WIP.txt linux/fs/umsdos/README-WIP.txt --- v2.1.126/linux/fs/umsdos/README-WIP.txt Thu Sep 17 17:53:38 1998 +++ linux/fs/umsdos/README-WIP.txt Thu Nov 5 15:29:43 1998 @@ -1,6 +1,6 @@ Changes by Matija Nalis (mnalis@jagor.srce.hr) on umsdos dentry fixing (started by Peter T. Waltenberg ) -Final conversion to dentries Bill Hawes +(Final conversion to dentries Bill Hawes ) ---------- WARNING --------- WARNING --------- WARNING ----------- There is no warning any more. @@ -16,7 +16,7 @@ Legend: those lines marked with '+' on the beggining of line indicates it passed all of my tests, and performed perfect in all of them. -Current status (980915) - UMSDOS dentry-Beta 0.83: +Current status (981018) - UMSDOS dentry-Beta 0.83: (1) pure MSDOS (no --linux-.--- EMD file): @@ -47,18 +47,18 @@ + read file - works + switching MSDOS/UMSDOS - works + switching UMSDOS/MSDOS - works -- pseudo root things - DOES NOT WORK. COMMENTED OUT. See Notes below. +- pseudo root things - works mostly. See notes below. + resolve symlink - works + dereference symlink - works + dangling symlink - works -- hard links - DOES NOT WORK CORRECTLY ALWAYS. +- hard links - seems to work mostly + special files (block/char devices, FIFOs, sockets...) - works - various umsdos ioctls - works WRITE: -- create symlink - sometimes works, but see WARNING below -- create hardlink - works +- create symlink - works mostly, but see WARNING below +- create hardlink - works, but see portability WARNING below + create file - works + create special file - works + write to file - works @@ -88,7 +88,8 @@ Note: creating and using pseudo-hardlinks is always non-perfect, especially in filesystems that might be externally modified like umsdos. There is -example is specs file about it. +example is specs file about it. Specifically, moving directory which +contains hardlinks will break them. Warning: moving symlinks around may break them until umount/remount. @@ -97,17 +98,22 @@ file instead of symlink until next umount/mount pair. Tracking this one down... -Wanted: I am currently looking for volunteers that already have UMSDOS -filesystems in pseudo-root, or are able to get them, to test PSEUDO-ROOT -stuff (and get new patches from me), which I currently can't do. Anyone know -of URL of nice UMSDOS pseudo-root ready image ? As always, any patches or -pointer to things done in wrong way (or ideas of better ways) are greatly -appreciated ! - -Note: If you are currently trying to use UMSDOS as root partition (with -linux installed in c:\linux) it will not work. Pseudo-root is currently -commented out. See 'wanted' above and contact me if you are interested in -testing it. +Note: (about pseudoroot) If you are currently trying to use UMSDOS as root +partition (with linux installed in c:\linux) it will boot, but there are +some problems. Volunteers ready to test pseudoroot are needed (preferably +ones with working backups or unimportant data). There are problems with +different interpretation of hard links in normal in pseudo-root modes, +resulting is 'silent delete' of them sometimes. Also, '/DOS' pseudo +directory is only partially re-implemented and buggy. It works most of the +time, though. + +Warning: (about creating hardlinks in pseudoroot mode) - hardlinks created in +pseudoroot mode are not compatibile with 'normal' hardlinks, and vice versa. +That is because harlink which is /foo in pseudoroot mode, becomes +/linux/foo in normal mode. I'm thinking about this one. However, since most +people either always use pseudoroot, or always use normal umsdos filesystem, +this is no showstopper. + ------------------------------------------------------------------------------ diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/check.c linux/fs/umsdos/check.c --- v2.1.126/linux/fs/umsdos/check.c Wed Sep 9 14:51:09 1998 +++ linux/fs/umsdos/check.c Thu Nov 5 15:29:43 1998 @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -75,6 +76,7 @@ /* * check an inode */ +extern struct inode_operations umsdos_rdir_inode_operations; void check_inode (struct inode *inode) { diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v2.1.126/linux/fs/umsdos/dir.c Mon Sep 28 10:51:35 1998 +++ linux/fs/umsdos/dir.c Thu Nov 5 15:29:43 1998 @@ -44,7 +44,7 @@ } } -static struct dentry_operations umsdos_dentry_operations = +struct dentry_operations umsdos_dentry_operations = { umsdos_dentry_validate, /* d_validate(struct dentry *) */ NULL, /* d_hash */ @@ -123,7 +123,6 @@ if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root && !internal_read) { -Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n")); /* * We don't need to simulate this pseudo directory * when umsdos_readdir_x is called for internal operation @@ -134,6 +133,8 @@ * linux root), it simulate a directory /DOS which points to * the real root of the file system. */ + + Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n")); if (filldir (dirbuf, "DOS", 3, UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO) == 0) { filp->f_pos++; @@ -477,6 +478,7 @@ * A lookup of DOS in the pseudo root will always succeed * and return the inode of the real root. */ + Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n")); inode = saved_root->d_inode; goto out_add; } @@ -542,7 +544,7 @@ * which are recorded independently of the pseudo-root * mode. */ -printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n"); +printk("umsdos_lookup_x: skipping DOS/linux\n"); ret = -ENOENT; goto out_dput; } @@ -557,7 +559,7 @@ ret = 0; out_dput: - if (dret != dentry) + if (dret && dret != dentry) d_drop(dret); dput(dret); out: diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v2.1.126/linux/fs/umsdos/inode.c Mon Sep 28 10:51:35 1998 +++ linux/fs/umsdos/inode.c Thu Nov 5 15:29:43 1998 @@ -148,13 +148,13 @@ { struct inode *inode = dentry->d_inode; -Printk (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino)); +PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino)); /* * Classify the inode based on EMD/non-EMD status. */ -Printk (("umsdos_patch_inode: call x_set_dirinfo(%p,%p,%lu)\n", -inode, dir, f_pos)); +PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n", +dentry, f_pos)); umsdos_set_dirinfo_new(dentry, f_pos); inode->u.umsdos_i.i_emd_dir = 0; @@ -275,8 +275,8 @@ fill_new_filp (&filp, demd); filp.f_pos = inode->u.umsdos_i.pos; -Printk(("UMSDOS_notify_change: %s/%s reading at %u\n", -dentry->d_parent->d_name.name, dentry->d_name.name, filp.f_pos)); +Printk(("UMSDOS_notify_change: %s/%s reading at %d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, (int) filp.f_pos)); /* Read only the start of the entry since we don't touch the name */ ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE); @@ -398,11 +398,14 @@ /* Check whether to change to the /linux root */ new_root = check_pseudo_root(sb); + if (new_root) { - pseudo_root = new_root->d_inode; /* sanity check */ if (new_root->d_op != &umsdos_dentry_operations) printk("umsdos_read_super: pseudo-root wrong ops!\n"); + + pseudo_root = new_root->d_inode; + saved_root = sb->s_root; sb->s_root = new_root; printk(KERN_INFO "UMSDOS: changed to alternate root\n"); @@ -411,6 +414,9 @@ /* if d_count is not 1, mount will fail with -EBUSY! */ if (sb->s_root->d_count > 1) { shrink_dcache_sb(sb); + if (sb->s_root->d_count > 1) { + printk(KERN_ERR "UMSDOS: root count %d > 1 !", sb->s_root->d_count); + } } return sb; diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c --- v2.1.126/linux/fs/umsdos/namei.c Mon Sep 28 10:51:35 1998 +++ linux/fs/umsdos/namei.c Thu Nov 5 15:29:43 1998 @@ -1033,12 +1033,12 @@ if (empty == 1) { struct dentry *demd; -Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); demd = umsdos_get_emd_dentry(dentry); if (!IS_ERR(demd)) { err = -ENOENT; if (demd->d_inode) err = msdos_unlink (dentry->d_inode, demd); +Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err)); #ifdef UMSDOS_PARANOIA if (err) printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n", diff -u --recursive --new-file v2.1.126/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v2.1.126/linux/fs/umsdos/rdir.c Mon Sep 28 10:51:35 1998 +++ linux/fs/umsdos/rdir.c Thu Nov 5 15:29:43 1998 @@ -107,8 +107,8 @@ * depending on whether this is an MS-DOS or * a UMSDOS directory */ -Printk ((KERN_DEBUG "umsdos_rlookup_x: setting up setup_dir_inode %lu...\n", -inode->i_ino)); +Printk ((KERN_DEBUG "umsdos_rlookup_x: patch_dentry_inode %s/%s\n", +dentry->d_parent->d_name.name, dentry->d_name.name)); umsdos_patch_dentry_inode(dentry, 0); /* N.B. Won't work -- /linux dentry will already have diff -u --recursive --new-file v2.1.126/linux/include/asm-i386/spinlock.h linux/include/asm-i386/spinlock.h --- v2.1.126/linux/include/asm-i386/spinlock.h Thu Aug 6 14:06:33 1998 +++ linux/include/asm-i386/spinlock.h Tue Nov 3 22:11:55 1998 @@ -14,10 +14,10 @@ */ #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED { } + #define SPIN_LOCK_UNLOCKED (spinlock_t) { } #else typedef struct { int gcc_is_buggy; } spinlock_t; - #define SPIN_LOCK_UNLOCKED { 0 } + #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #endif #define spin_lock_init(lock) do { } while(0) @@ -38,7 +38,7 @@ typedef struct { volatile unsigned int lock; } spinlock_t; -#define SPIN_LOCK_UNLOCKED { 0 } +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(x) do { (x)->lock = 0; } while (0) #define spin_trylock(lock) (!test_and_set_bit(0,(lock))) @@ -61,7 +61,7 @@ volatile unsigned int babble; const char *module; } spinlock_t; -#define SPIN_LOCK_UNLOCKED { 0, 25, __BASE_FILE__ } +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 25, __BASE_FILE__ } #include @@ -88,9 +88,16 @@ * can "mix" irq-safe locks - any writer needs to get a * irq-safe write-lock, but readers can get non-irqsafe * read-locks. + * + * Gcc-2.7.x has a nasty bug with empty initializers. */ -typedef struct { } rwlock_t; -#define RW_LOCK_UNLOCKED { } +#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) + typedef struct { } rwlock_t; + #define RW_LOCK_UNLOCKED (rwlock_t) { } +#else + typedef struct { int gcc_is_buggy; } rwlock_t; + #define RW_LOCK_UNLOCKED (rwlock_t) { 0 } +#endif #define read_lock(lock) do { } while(0) #define read_unlock(lock) do { } while(0) @@ -120,7 +127,7 @@ volatile unsigned int lock; } spinlock_t; -#define SPIN_LOCK_UNLOCKED { 0 } +#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(x) do { (x)->lock = 0; } while(0) /* @@ -188,7 +195,7 @@ unsigned long previous; } rwlock_t; -#define RW_LOCK_UNLOCKED { 0, 0 } +#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 } /* * On x86, we implement read-write locks as a 32-bit counter diff -u --recursive --new-file v2.1.126/linux/include/asm-i386/system.h linux/include/asm-i386/system.h --- v2.1.126/linux/include/asm-i386/system.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-i386/system.h Tue Oct 27 10:20:56 1998 @@ -88,7 +88,7 @@ "1:\t" \ "movl %0,%%" #seg "\n" \ "2:\n" \ - ".section fixup,\"ax\"\n" \ + ".section .fixup,\"ax\"\n" \ "3:\t" \ "pushl $0\n\t" \ "popl %%" #seg "\n\t" \ diff -u --recursive --new-file v2.1.126/linux/include/asm-mips/floppy.h linux/include/asm-mips/floppy.h --- v2.1.126/linux/include/asm-mips/floppy.h Fri Oct 23 22:01:22 1998 +++ linux/include/asm-mips/floppy.h Mon Oct 26 09:57:56 1998 @@ -11,7 +11,6 @@ #ifndef __ASM_MIPS_FLOPPY_H #define __ASM_MIPS_FLOPPY_H -#include #include #include #include diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/asm_offsets.h linux/include/asm-sparc/asm_offsets.h --- v2.1.126/linux/include/asm-sparc/asm_offsets.h Thu Aug 6 14:06:33 1998 +++ linux/include/asm-sparc/asm_offsets.h Tue Oct 27 09:52:21 1998 @@ -146,19 +146,21 @@ #define ASIZ_task_cap_inheritable 0x00000004 #define AOFF_task_cap_permitted 0x0000016c #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_rlim 0x00000170 +#define AOFF_task_user 0x00000170 +#define ASIZ_task_user 0x00000004 +#define AOFF_task_rlim 0x00000174 #define ASIZ_task_rlim 0x00000050 -#define AOFF_task_used_math 0x000001c0 +#define AOFF_task_used_math 0x000001c4 #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x000001c2 +#define AOFF_task_comm 0x000001c6 #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x000001d4 +#define AOFF_task_link_count 0x000001d8 #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x000001d8 +#define AOFF_task_tty 0x000001dc #define ASIZ_task_tty 0x00000004 -#define AOFF_task_semundo 0x000001dc +#define AOFF_task_semundo 0x000001e0 #define ASIZ_task_semundo 0x00000004 -#define AOFF_task_semsleeping 0x000001e0 +#define AOFF_task_semsleeping 0x000001e4 #define ASIZ_task_semsleeping 0x00000004 #define AOFF_task_tss 0x000001e8 #define ASIZ_task_tss 0x00000388 @@ -169,20 +171,20 @@ #define AOFF_task_mm 0x00000578 #define ASIZ_task_mm 0x00000004 #define AOFF_task_sigmask_lock 0x0000057c -#define ASIZ_task_sigmask_lock 0x00000000 -#define AOFF_task_sig 0x0000057c +#define ASIZ_task_sigmask_lock 0x00000001 +#define AOFF_task_sig 0x00000580 #define ASIZ_task_sig 0x00000004 -#define AOFF_task_signal 0x00000580 +#define AOFF_task_signal 0x00000584 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x00000588 +#define AOFF_task_blocked 0x0000058c #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x00000590 +#define AOFF_task_sigqueue 0x00000594 #define ASIZ_task_sigqueue 0x00000004 -#define AOFF_task_sigqueue_tail 0x00000594 +#define AOFF_task_sigqueue_tail 0x00000598 #define ASIZ_task_sigqueue_tail 0x00000004 -#define AOFF_task_sas_ss_sp 0x00000598 +#define AOFF_task_sas_ss_sp 0x0000059c #define ASIZ_task_sas_ss_sp 0x00000004 -#define AOFF_task_sas_ss_size 0x0000059c +#define AOFF_task_sas_ss_size 0x000005a0 #define ASIZ_task_sas_ss_size 0x00000004 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000004 @@ -419,19 +421,21 @@ #define ASIZ_task_cap_inheritable 0x00000004 #define AOFF_task_cap_permitted 0x00000264 #define ASIZ_task_cap_permitted 0x00000004 -#define AOFF_task_rlim 0x00000268 +#define AOFF_task_user 0x00000268 +#define ASIZ_task_user 0x00000004 +#define AOFF_task_rlim 0x0000026c #define ASIZ_task_rlim 0x00000050 -#define AOFF_task_used_math 0x000002b8 +#define AOFF_task_used_math 0x000002bc #define ASIZ_task_used_math 0x00000002 -#define AOFF_task_comm 0x000002ba +#define AOFF_task_comm 0x000002be #define ASIZ_task_comm 0x00000010 -#define AOFF_task_link_count 0x000002cc +#define AOFF_task_link_count 0x000002d0 #define ASIZ_task_link_count 0x00000004 -#define AOFF_task_tty 0x000002d0 +#define AOFF_task_tty 0x000002d4 #define ASIZ_task_tty 0x00000004 -#define AOFF_task_semundo 0x000002d4 +#define AOFF_task_semundo 0x000002d8 #define ASIZ_task_semundo 0x00000004 -#define AOFF_task_semsleeping 0x000002d8 +#define AOFF_task_semsleeping 0x000002dc #define ASIZ_task_semsleeping 0x00000004 #define AOFF_task_tss 0x000002e0 #define ASIZ_task_tss 0x00000388 @@ -442,20 +446,20 @@ #define AOFF_task_mm 0x00000670 #define ASIZ_task_mm 0x00000004 #define AOFF_task_sigmask_lock 0x00000674 -#define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x00000678 +#define ASIZ_task_sigmask_lock 0x00000008 +#define AOFF_task_sig 0x0000067c #define ASIZ_task_sig 0x00000004 -#define AOFF_task_signal 0x0000067c +#define AOFF_task_signal 0x00000680 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x00000684 +#define AOFF_task_blocked 0x00000688 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x0000068c +#define AOFF_task_sigqueue 0x00000690 #define ASIZ_task_sigqueue 0x00000004 -#define AOFF_task_sigqueue_tail 0x00000690 +#define AOFF_task_sigqueue_tail 0x00000694 #define ASIZ_task_sigqueue_tail 0x00000004 -#define AOFF_task_sas_ss_sp 0x00000694 +#define AOFF_task_sas_ss_sp 0x00000698 #define ASIZ_task_sas_ss_sp 0x00000004 -#define AOFF_task_sas_ss_size 0x00000698 +#define AOFF_task_sas_ss_size 0x0000069c #define ASIZ_task_sas_ss_size 0x00000004 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000004 diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h --- v2.1.126/linux/include/asm-sparc/dma.h Fri May 8 23:14:56 1998 +++ linux/include/asm-sparc/dma.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.26 1998/04/13 07:27:05 davem Exp $ +/* $Id: dma.h,v 1.28 1998/10/26 20:03:09 davem Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -15,6 +15,22 @@ #include #include #include +#include +#include + +extern spinlock_t dma_spin_lock; + +static __inline__ unsigned long claim_dma_lock(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_spin_lock, flags); + return flags; +} + +static __inline__ void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} /* These are irrelevant for Sparc DMA, but we leave it in so that * things can compile. diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/fcntl.h linux/include/asm-sparc/fcntl.h --- v2.1.126/linux/include/asm-sparc/fcntl.h Fri Oct 23 22:01:26 1998 +++ linux/include/asm-sparc/fcntl.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.10 1998/08/26 10:33:29 davem Exp $ */ +/* $Id: fcntl.h,v 1.11 1998/10/26 20:03:10 davem Exp $ */ #ifndef _SPARC_FCNTL_H #define _SPARC_FCNTL_H diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/hardirq.h linux/include/asm-sparc/hardirq.h --- v2.1.126/linux/include/asm-sparc/hardirq.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-sparc/hardirq.h Tue Oct 27 09:52:21 1998 @@ -1,6 +1,7 @@ /* hardirq.h: 32-bit Sparc hard IRQ support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) */ #ifndef __SPARC_HARDIRQ_H @@ -9,19 +10,25 @@ #include extern unsigned int local_irq_count[NR_CPUS]; -#define in_interrupt() (local_irq_count[smp_processor_id()] != 0) + +/* + * Are we in an interrupt context? Either doing bottom half + * or hardware interrupt processing? + */ +#define in_interrupt() ({ int __cpu = smp_processor_id(); \ + (local_irq_count[__cpu] + local_bh_count[__cpu] != 0); }) #ifndef __SMP__ #define hardirq_trylock(cpu) (local_irq_count[cpu] == 0) -#define hardirq_endlock(cpu) do { } while(0) +#define hardirq_endlock(cpu) do { } while (0) #define hardirq_enter(cpu) (local_irq_count[cpu]++) #define hardirq_exit(cpu) (local_irq_count[cpu]--) #define synchronize_irq() barrier() -#else /* __SMP__ */ +#else #include #include @@ -32,37 +39,33 @@ extern spinlock_t global_irq_lock; extern atomic_t global_irq_count; -#define release_irqlock(cpu) \ -do { if(global_irq_holder == (unsigned char) cpu) { \ - global_irq_holder = NO_PROC_ID; \ - spin_unlock(&global_irq_lock); \ - } \ -} while(0) - -/* Ordering of the counter bumps is _deadly_ important. */ -#define hardirq_enter(cpu) \ - do { ++local_irq_count[cpu]; atomic_inc(&global_irq_count); } while(0) - -#define hardirq_exit(cpu) \ - do { atomic_dec(&global_irq_count); --local_irq_count[cpu]; } while(0) - -#define hardirq_trylock(cpu) \ -({ unsigned long flags; int ret = 1; \ - __save_flags(flags); \ - __cli(); \ - if(atomic_add_return(1, &global_irq_count) != 1 || \ - *(((unsigned char *)(&global_irq_lock)))) { \ - atomic_dec(&global_irq_count); \ - __restore_flags(flags); \ - ret = 0; \ - } else { \ - ++local_irq_count[cpu]; \ - __sti(); \ - } \ - ret; \ -}) +static inline void release_irqlock(int cpu) +{ + /* if we didn't own the irq lock, just ignore.. */ + if (global_irq_holder == (unsigned char) cpu) { + global_irq_holder = NO_PROC_ID; + spin_unlock(&global_irq_lock); + } +} + +static inline void hardirq_enter(int cpu) +{ + ++local_irq_count[cpu]; + atomic_inc(&global_irq_count); +} + +static inline void hardirq_exit(int cpu) +{ + atomic_dec(&global_irq_count); + --local_irq_count[cpu]; +} + +static inline int hardirq_trylock(int cpu) +{ + return !atomic_read(&global_irq_count) && !*(((volatile unsigned char *)(&global_irq_lock))); +} -#define hardirq_endlock(cpu) do { __cli(); hardirq_exit(cpu); __sti(); } while(0) +#define hardirq_endlock(cpu) do { } while (0) extern void synchronize_irq(void); diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/perfctr.h linux/include/asm-sparc/perfctr.h --- v2.1.126/linux/include/asm-sparc/perfctr.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc/perfctr.h Tue Oct 27 09:52:21 1998 @@ -0,0 +1,101 @@ +/*---------------------------------------- + PERFORMANCE INSTRUMENTATION + Guillaume Thouvenin 08/10/98 + David S. Miller 10/06/98 + ---------------------------------------*/ +#ifndef PERF_COUNTER_API +#define PERF_COUNTER_API + +/* sys_perfctr() interface. First arg is operation code + * from enumeration below. The meaning of further arguments + * are determined by the operation code. + * + * int sys_perfctr(int opcode, unsigned long arg0, + * unsigned long arg1, unsigned long arg2) + * + * Pointers which are passed by the user are pointers to 64-bit + * integers. + * + * Once enabled, performance counter state is retained until the + * process either exits or performs an exec. That is, performance + * counters remain enabled for fork/clone children. + */ +enum perfctr_opcode { + /* Enable UltraSparc performance counters, ARG0 is pointer + * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer + * to 64-bit accumulator for D1 counter. ARG2 is a pointer to + * the initial PCR register value to use. + */ + PERFCTR_ON, + + /* Disable UltraSparc performance counters. The PCR is written + * with zero and the user counter accumulator pointers and + * working PCR register value are forgotten. + */ + PERFCTR_OFF, + + /* Add current D0 and D1 PIC values into user pointers given + * in PERFCTR_ON operation. The PIC is cleared before returning. + */ + PERFCTR_READ, + + /* Clear the PIC register. */ + PERFCTR_CLRPIC, + + /* Begin using a new PCR value, the pointer to which is passed + * in ARG0. The PIC is also cleared after the new PCR value is + * written. + */ + PERFCTR_SETPCR, + + /* Store in pointer given in ARG0 the current PCR register value + * being used. + */ + PERFCTR_GETPCR +}; + +/* I don't want the kernel's namespace to be polluted with this + * stuff when this file is included. --DaveM + */ +#ifndef __KERNEL__ + +#define PRIV 0x00000001 +#define USR 0x00000002 +#define SYS 0x00000004 + +/* Pic.S0 Selection Bit Field Encoding */ +#define CYCLE_CNT 0x00000000 +#define INSTR_CNT 0x00000010 +#define DISPATCH0_IC_MISS 0x00000020 +#define DISPATCH0_STOREBUF 0x00000030 +#define IC_REF 0x00000080 +#define DC_RD 0x00000090 +#define DC_WR 0x000000A0 +#define LOAD_USE 0x000000B0 +#define EC_REF 0x000000C0 +#define EC_WRITE_HIT_RDO 0x000000D0 +#define EC_SNOOP_INV 0x000000E0 +#define EC_RD_HIT 0x000000F0 + +/* Pic.S1 Selection Bit Field Encoding */ +#define CYCLE_CNT_D1 0x00000000 +#define INSTR_CNT_D1 0x00000800 +#define DISPATCH0_IC_MISPRED 0x00001000 +#define DISPATCH0_FP_USE 0x00001800 +#define IC_HIT 0x00004000 +#define DC_RD_HIT 0x00004800 +#define DC_WR_HIT 0x00005000 +#define LOAD_USE_RAW 0x00005800 +#define EC_HIT 0x00006000 +#define EC_WB 0x00006800 +#define EC_SNOOP_CB 0x00007000 +#define EC_IT_HIT 0x00007800 + +struct vcounter_struct { + unsigned long long vcnt0; + unsigned long long vcnt1; +}; + +#endif /* !(__KERNEL__) */ + +#endif /* !(PERF_COUNTER_API) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h --- v2.1.126/linux/include/asm-sparc/sigcontext.h Mon Mar 17 14:54:31 1997 +++ linux/include/asm-sparc/sigcontext.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: sigcontext.h,v 1.12 1997/03/03 16:51:52 jj Exp $ */ +/* $Id: sigcontext.h,v 1.13 1998/10/06 09:28:35 jj Exp $ */ #ifndef __SPARC_SIGCONTEXT_H #define __SPARC_SIGCONTEXT_H @@ -51,6 +51,16 @@ unsigned long insn; } si_fpqueue [16]; } __siginfo_fpu_t; + +/* This magic should be in g_upper[0] for all upper parts + to be valid. + This is generated by sparc64 only, but for 32bit processes, + so we define it here as well. */ +#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 +typedef struct { + unsigned int g_upper[8]; + unsigned int o_upper[8]; +} siginfo_extra_v8plus_t; #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/softirq.h linux/include/asm-sparc/softirq.h --- v2.1.126/linux/include/asm-sparc/softirq.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-sparc/softirq.h Tue Oct 27 09:52:21 1998 @@ -1,133 +1,173 @@ /* softirq.h: 32-bit Sparc soft IRQ support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au) */ #ifndef __SPARC_SOFTIRQ_H #define __SPARC_SOFTIRQ_H #include +#include #include -/* The locking mechanism for base handlers, to prevent re-entrancy, - * is entirely private to an implementation, it should not be - * referenced at all outside of this file. - */ +extern unsigned int local_bh_count[NR_CPUS]; + #define get_active_bhs() (bh_mask & bh_active) #ifdef __SMP__ -extern atomic_t __sparc_bh_counter; - -#define start_bh_atomic() \ - do { atomic_inc(&__sparc_bh_counter); synchronize_irq(); } while(0) - -#define end_bh_atomic() atomic_dec(&__sparc_bh_counter) - -#include - -extern spinlock_t global_bh_lock; - -#define init_bh(nr, routine) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_base[ent] = routine; \ - bh_mask_count[ent] = 0; \ - bh_mask |= 1 << ent; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define remove_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_base[ent] = NULL; \ - bh_mask &= ~(1 << ent); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define mark_bh(nr) \ -do { unsigned long flags; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_active |= (1 << nr); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define disable_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_mask &= ~(1 << ent); \ - bh_mask_count[ent]++; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define enable_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - if (!--bh_mask_count[ent]) \ - bh_mask |= 1 << ent; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define softirq_trylock(cpu) \ -({ \ - int ret = 1; \ - if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \ - atomic_dec(&__sparc_bh_counter); \ - ret = 0; \ - } \ - ret; \ -}) -#define softirq_endlock(cpu) atomic_dec(&__sparc_bh_counter) -#define clear_active_bhs(mask) \ -do { unsigned long flags; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_active &= ~(mask); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#else /* !(__SMP__) */ - -extern int __sparc_bh_counter; +/* + * The locking mechanism for base handlers, to prevent re-entrancy, + * is entirely private to an implementation, it should not be + * referenced at all outside of this file. + */ +extern atomic_t global_bh_lock; +extern atomic_t global_bh_count; +extern spinlock_t sparc_bh_lock; + +extern void synchronize_bh(void); + +static inline void clear_active_bhs(unsigned int mask) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + bh_active &= ~(mask); + spin_unlock_irqrestore(&sparc_bh_lock, flags); +} + +extern inline void init_bh(int nr, void (*routine)(void)) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + bh_base[nr] = routine; + bh_mask_count[nr] = 0; + bh_mask |= 1 << nr; + spin_unlock_irqrestore(&sparc_bh_lock, flags); +} + +extern inline void remove_bh(int nr) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + bh_base[nr] = NULL; + bh_mask &= ~(1 << nr); + spin_unlock_irqrestore(&sparc_bh_lock, flags); +} + +extern inline void mark_bh(int nr) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + bh_active |= (1 << nr); + spin_unlock_irqrestore(&sparc_bh_lock, flags); +} + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; + spin_unlock_irqrestore(&sparc_bh_lock, flags); + synchronize_bh(); +} + +extern inline void enable_bh(int nr) +{ + unsigned long flags; + spin_lock_irqsave(&sparc_bh_lock, flags); + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; + spin_unlock_irqrestore(&sparc_bh_lock, flags); +} + +static inline void start_bh_atomic(void) +{ + atomic_inc(&global_bh_lock); + synchronize_bh(); +} + +static inline void end_bh_atomic(void) +{ + atomic_dec(&global_bh_lock); +} + +/* These are for the IRQs testing the lock */ +static inline int softirq_trylock(int cpu) +{ + if (atomic_add_return(1, &global_bh_count) == 1) { + if (atomic_read(&global_bh_lock) == 0) { + ++local_bh_count[cpu]; + return 1; + } + } + atomic_dec(&global_bh_count); + return 0; +} + +static inline void softirq_endlock(int cpu) +{ + local_bh_count[cpu]--; + atomic_dec(&global_bh_count); +} -#define start_bh_atomic() do { __sparc_bh_counter++; barrier(); } while(0) -#define end_bh_atomic() do { barrier(); __sparc_bh_counter--; } while(0) +#else -#define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1)) -#define softirq_endlock(cpu) (__sparc_bh_counter = 0) #define clear_active_bhs(x) (bh_active &= ~(x)) -#define synchronize_bh() barrier() /* XXX implement SMP version -DaveM */ - -#define init_bh(nr, routine) \ -do { int ent = nr; \ - bh_base[ent] = routine; \ - bh_mask_count[ent] = 0; \ - bh_mask |= 1 << ent; \ -} while(0) - -#define remove_bh(nr) \ -do { int ent = nr; \ - bh_base[ent] = NULL; \ - bh_mask &= ~(1 << ent); \ -} while(0) - #define mark_bh(nr) (bh_active |= (1 << (nr))) -#define disable_bh(nr) \ -do { int ent = nr; \ - bh_mask &= ~(1 << ent); \ - bh_mask_count[ent]++; \ -} while(0) - -#define enable_bh(nr) \ -do { int ent = nr; \ - if (!--bh_mask_count[ent]) \ - bh_mask |= 1 << ent; \ -} while(0) +/* These are for the irq's testing the lock */ +#define softirq_trylock(cpu) (local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1)) +#define softirq_endlock(cpu) (local_bh_count[cpu] = 0) +#define synchronize_bh() barrier() + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; + synchronize_bh(); +} + +extern inline void enable_bh(int nr) +{ + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; +} + +extern inline void init_bh(int nr, void (*routine)(void)) +{ + bh_base[nr] = routine; + bh_mask_count[nr] = 0; + bh_mask |= 1 << nr; +} + +extern inline void remove_bh(int nr) +{ + bh_base[nr] = NULL; + bh_mask &= ~(1 << nr); +} + +extern inline void start_bh_atomic(void) +{ + local_bh_count[0]++; + barrier(); +} + +extern inline void end_bh_atomic(void) +{ + barrier(); + local_bh_count[0]--; +} -#endif /* __SMP__ */ +#endif /* SMP */ -#endif /* __SPARC_SOFTIRQ_H */ +#endif /* __SPARC_SOFTIRQ_H */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h --- v2.1.126/linux/include/asm-sparc/spinlock.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-sparc/spinlock.h Tue Oct 27 09:52:21 1998 @@ -10,13 +10,8 @@ #ifndef __SMP__ -#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED { } -#else - typedef unsigned char spinlock_t; - #define SPIN_LOCK_UNLOCKED 0 -#endif +typedef unsigned char spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 #define spin_lock_init(lock) do { } while(0) #define spin_lock(lock) do { } while(0) @@ -270,18 +265,16 @@ /* Sort of like atomic_t's on Sparc, but even more clever. * * ------------------------------------ - * | 16-bit counter | clock | wlock | rwlock_t + * | 24-bit counter | wlock | rwlock_t * ------------------------------------ - * 31 16 15 8 7 0 + * 31 8 7 0 * - * wlock signifies the one writer is in, the clock protects - * counter bumping, however a reader must acquire wlock - * before he can bump the counter on a read_lock(). - * Similarly a writer, once he has the wlock, must await - * for the top 24 bits to all clear before he can finish - * going in (this includes the clock of course). + * wlock signifies the one writer is in or somebody is updating + * counter. For a writer, if he successfully acquires the wlock, + * but counter is non-zero, he has to release the lock and wait, + * till both counter and wlock are zero. * - * Unfortunately this scheme limits us to ~65,000 cpus. + * Unfortunately this scheme limits us to ~16,000,000 cpus. */ extern __inline__ void _read_lock(rwlock_t *rw) { @@ -310,7 +303,7 @@ __asm__ __volatile__(" mov %%o7, %%g4 call ___rw_read_exit - ldstub [%%g1 + 2], %%g2 + ldstub [%%g1 + 3], %%g2 " : /* no outputs */ : "r" (lp) : "g2", "g4", "g7", "memory", "cc"); diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v2.1.126/linux/include/asm-sparc/system.h Mon Oct 5 13:13:43 1998 +++ linux/include/asm-sparc/system.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.70 1998/09/29 09:46:32 davem Exp $ */ +/* $Id: system.h,v 1.71 1998/10/13 03:51:06 jj Exp $ */ #include #ifndef __SPARC_SYSTEM_H @@ -235,18 +235,16 @@ extern unsigned char global_irq_holder; -#define save_flags(x) \ -do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \ - ((getipl() & PSR_PIL) ? 2 : 0))); } while(0) - #define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) #ifdef DEBUG_IRQLOCK extern void __global_cli(void); extern void __global_sti(void); +extern unsigned long __global_save_flags(void); extern void __global_restore_flags(unsigned long flags); #define cli() __global_cli() #define sti() __global_sti() +#define save_flags(flags) ((flags)=__global_save_flags()) #define restore_flags(flags) __global_restore_flags(flags) #else diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v2.1.126/linux/include/asm-sparc/unistd.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc/unistd.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.47 1998/09/21 05:07:22 jj Exp $ */ +/* $Id: unistd.h,v 1.48 1998/10/07 01:27:50 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -33,7 +33,7 @@ #define __NR_chmod 15 /* Common */ #define __NR_lchown 16 /* Common */ #define __NR_brk 17 /* Common */ -/* #define __NR_ni_syscall 18 ENOSYS under SunOS */ +/* #define __NR_ni_syscall 18 RESERVED for sparc64 perf-counter syscall */ #define __NR_lseek 19 /* Common */ #define __NR_getpid 20 /* Common */ #define __NR_capget 21 /* Linux Specific */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/asm_offsets.h linux/include/asm-sparc64/asm_offsets.h --- v2.1.126/linux/include/asm-sparc64/asm_offsets.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/asm_offsets.h Tue Oct 27 09:52:21 1998 @@ -163,30 +163,30 @@ #define AOFF_task_semsleeping 0x00000370 #define ASIZ_task_semsleeping 0x00000008 #define AOFF_task_tss 0x00000380 -#define ASIZ_task_tss 0x00000440 -#define AOFF_task_fs 0x000007c0 +#define ASIZ_task_tss 0x00000470 +#define AOFF_task_fs 0x000007f0 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x000007c8 +#define AOFF_task_files 0x000007f8 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x000007d0 +#define AOFF_task_mm 0x00000800 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sigmask_lock 0x000007d8 -#define ASIZ_task_sigmask_lock 0x00000000 -#define AOFF_task_sig 0x000007d8 +#define AOFF_task_sigmask_lock 0x00000808 +#define ASIZ_task_sigmask_lock 0x00000001 +#define AOFF_task_sig 0x00000810 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000007e0 +#define AOFF_task_signal 0x00000818 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x000007e8 +#define AOFF_task_blocked 0x00000820 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x000007f0 +#define AOFF_task_sigqueue 0x00000828 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x000007f8 +#define AOFF_task_sigqueue_tail 0x00000830 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x00000800 +#define AOFF_task_sas_ss_sp 0x00000838 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000808 +#define AOFF_task_sas_ss_size 0x00000840 #define ASIZ_task_sas_ss_size 0x00000008 -#define ASIZ_task 0x00000810 +#define ASIZ_task 0x00000850 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_cache 0x00000008 @@ -266,18 +266,30 @@ #define ASIZ_thread_sig_address 0x00000008 #define AOFF_thread_sig_desc 0x000003f0 #define ASIZ_thread_sig_desc 0x00000008 -#define AOFF_thread_fpdepth 0x000003f8 +#define AOFF_thread_user_cntd0 0x000003f8 +#define ASIZ_thread_user_cntd0 0x00000008 +#define AOFF_thread_user_cntd1 0x00000400 +#define ASIZ_thread_user_cntd1 0x00000008 +#define AOFF_thread_kernel_cntd0 0x00000408 +#define ASIZ_thread_kernel_cntd0 0x00000008 +#define AOFF_thread_kernel_cntd1 0x00000410 +#define ASIZ_thread_kernel_cntd1 0x00000008 +#define AOFF_thread_pcr_reg 0x00000418 +#define ASIZ_thread_pcr_reg 0x00000008 +#define AOFF_thread_fpdepth 0x00000420 #define ASIZ_thread_fpdepth 0x00000001 -#define AOFF_thread_fpsaved 0x000003f9 +#define AOFF_thread_fpsaved 0x00000421 #define ASIZ_thread_fpsaved 0x00000007 -#define AOFF_thread_gsr 0x00000400 +#define AOFF_thread_gsr 0x00000428 #define ASIZ_thread_gsr 0x00000007 -#define AOFF_thread_xfsr 0x00000408 +#define AOFF_thread_xfsr 0x00000430 #define ASIZ_thread_xfsr 0x00000038 -#define ASIZ_thread 0x00000440 +#define ASIZ_thread 0x00000470 #else /* __SMP__ */ +#ifndef SPIN_LOCK_DEBUG + #define AOFF_task_state 0x00000000 #define ASIZ_task_state 0x00000008 #define AOFF_task_flags 0x00000008 @@ -437,30 +449,314 @@ #define AOFF_task_semsleeping 0x00000560 #define ASIZ_task_semsleeping 0x00000008 #define AOFF_task_tss 0x00000570 -#define ASIZ_task_tss 0x00000440 -#define AOFF_task_fs 0x000009b0 +#define ASIZ_task_tss 0x00000470 +#define AOFF_task_fs 0x000009e0 #define ASIZ_task_fs 0x00000008 -#define AOFF_task_files 0x000009b8 +#define AOFF_task_files 0x000009e8 #define ASIZ_task_files 0x00000008 -#define AOFF_task_mm 0x000009c0 +#define AOFF_task_mm 0x000009f0 #define ASIZ_task_mm 0x00000008 -#define AOFF_task_sigmask_lock 0x000009c8 +#define AOFF_task_sigmask_lock 0x000009f8 #define ASIZ_task_sigmask_lock 0x00000001 -#define AOFF_task_sig 0x000009d0 +#define AOFF_task_sig 0x00000a00 +#define ASIZ_task_sig 0x00000008 +#define AOFF_task_signal 0x00000a08 +#define ASIZ_task_signal 0x00000008 +#define AOFF_task_blocked 0x00000a10 +#define ASIZ_task_blocked 0x00000008 +#define AOFF_task_sigqueue 0x00000a18 +#define ASIZ_task_sigqueue 0x00000008 +#define AOFF_task_sigqueue_tail 0x00000a20 +#define ASIZ_task_sigqueue_tail 0x00000008 +#define AOFF_task_sas_ss_sp 0x00000a28 +#define ASIZ_task_sas_ss_sp 0x00000008 +#define AOFF_task_sas_ss_size 0x00000a30 +#define ASIZ_task_sas_ss_size 0x00000008 +#define ASIZ_task 0x00000a40 +#define AOFF_mm_mmap 0x00000000 +#define ASIZ_mm_mmap 0x00000008 +#define AOFF_mm_mmap_cache 0x00000008 +#define ASIZ_mm_mmap_cache 0x00000008 +#define AOFF_mm_pgd 0x00000010 +#define ASIZ_mm_pgd 0x00000008 +#define AOFF_mm_count 0x00000018 +#define ASIZ_mm_count 0x00000004 +#define AOFF_mm_map_count 0x0000001c +#define ASIZ_mm_map_count 0x00000004 +#define AOFF_mm_mmap_sem 0x00000020 +#define ASIZ_mm_mmap_sem 0x00000010 +#define AOFF_mm_context 0x00000030 +#define ASIZ_mm_context 0x00000008 +#define AOFF_mm_start_code 0x00000038 +#define ASIZ_mm_start_code 0x00000008 +#define AOFF_mm_end_code 0x00000040 +#define ASIZ_mm_end_code 0x00000008 +#define AOFF_mm_start_data 0x00000048 +#define ASIZ_mm_start_data 0x00000008 +#define AOFF_mm_end_data 0x00000050 +#define ASIZ_mm_end_data 0x00000008 +#define AOFF_mm_start_brk 0x00000058 +#define ASIZ_mm_start_brk 0x00000008 +#define AOFF_mm_brk 0x00000060 +#define ASIZ_mm_brk 0x00000008 +#define AOFF_mm_start_stack 0x00000068 +#define ASIZ_mm_start_stack 0x00000008 +#define AOFF_mm_arg_start 0x00000070 +#define ASIZ_mm_arg_start 0x00000008 +#define AOFF_mm_arg_end 0x00000078 +#define ASIZ_mm_arg_end 0x00000008 +#define AOFF_mm_env_start 0x00000080 +#define ASIZ_mm_env_start 0x00000008 +#define AOFF_mm_env_end 0x00000088 +#define ASIZ_mm_env_end 0x00000008 +#define AOFF_mm_rss 0x00000090 +#define ASIZ_mm_rss 0x00000008 +#define AOFF_mm_total_vm 0x00000098 +#define ASIZ_mm_total_vm 0x00000008 +#define AOFF_mm_locked_vm 0x000000a0 +#define ASIZ_mm_locked_vm 0x00000008 +#define AOFF_mm_def_flags 0x000000a8 +#define ASIZ_mm_def_flags 0x00000008 +#define AOFF_mm_cpu_vm_mask 0x000000b0 +#define ASIZ_mm_cpu_vm_mask 0x00000008 +#define AOFF_mm_segments 0x000000b8 +#define ASIZ_mm_segments 0x00000008 +#define ASIZ_mm 0x000000c0 +#define AOFF_thread_ksp 0x00000000 +#define ASIZ_thread_ksp 0x00000008 +#define AOFF_thread_wstate 0x00000008 +#define ASIZ_thread_wstate 0x00000002 +#define AOFF_thread_cwp 0x0000000a +#define ASIZ_thread_cwp 0x00000002 +#define AOFF_thread_flags 0x0000000c +#define ASIZ_thread_flags 0x00000002 +#define AOFF_thread_ctx 0x0000000e +#define ASIZ_thread_ctx 0x00000002 +#define AOFF_thread_w_saved 0x00000010 +#define ASIZ_thread_w_saved 0x00000002 +#define AOFF_thread_new_signal 0x00000012 +#define ASIZ_thread_new_signal 0x00000002 +#define AOFF_thread____pad 0x00000014 +#define ASIZ_thread____pad 0x00000004 +#define AOFF_thread_current_ds 0x00000018 +#define ASIZ_thread_current_ds 0x00000008 +#define AOFF_thread_kregs 0x00000020 +#define ASIZ_thread_kregs 0x00000008 +#define AOFF_thread_utraps 0x00000028 +#define ASIZ_thread_utraps 0x00000008 +#define AOFF_thread_reg_window 0x00000030 +#define ASIZ_thread_reg_window 0x00000380 +#define AOFF_thread_rwbuf_stkptrs 0x000003b0 +#define ASIZ_thread_rwbuf_stkptrs 0x00000038 +#define AOFF_thread_sig_address 0x000003e8 +#define ASIZ_thread_sig_address 0x00000008 +#define AOFF_thread_sig_desc 0x000003f0 +#define ASIZ_thread_sig_desc 0x00000008 +#define AOFF_thread_user_cntd0 0x000003f8 +#define ASIZ_thread_user_cntd0 0x00000008 +#define AOFF_thread_user_cntd1 0x00000400 +#define ASIZ_thread_user_cntd1 0x00000008 +#define AOFF_thread_kernel_cntd0 0x00000408 +#define ASIZ_thread_kernel_cntd0 0x00000008 +#define AOFF_thread_kernel_cntd1 0x00000410 +#define ASIZ_thread_kernel_cntd1 0x00000008 +#define AOFF_thread_pcr_reg 0x00000418 +#define ASIZ_thread_pcr_reg 0x00000008 +#define AOFF_thread_fpdepth 0x00000420 +#define ASIZ_thread_fpdepth 0x00000001 +#define AOFF_thread_fpsaved 0x00000421 +#define ASIZ_thread_fpsaved 0x00000007 +#define AOFF_thread_gsr 0x00000428 +#define ASIZ_thread_gsr 0x00000007 +#define AOFF_thread_xfsr 0x00000430 +#define ASIZ_thread_xfsr 0x00000038 +#define ASIZ_thread 0x00000470 + +#else /* SPIN_LOCK_DEBUG */ + +#define AOFF_task_state 0x00000000 +#define ASIZ_task_state 0x00000008 +#define AOFF_task_flags 0x00000008 +#define ASIZ_task_flags 0x00000008 +#define AOFF_task_sigpending 0x00000010 +#define ASIZ_task_sigpending 0x00000004 +#define AOFF_task_addr_limit 0x00000018 +#define ASIZ_task_addr_limit 0x00000008 +#define AOFF_task_exec_domain 0x00000020 +#define ASIZ_task_exec_domain 0x00000008 +#define AOFF_task_need_resched 0x00000028 +#define ASIZ_task_need_resched 0x00000008 +#define AOFF_task_counter 0x00000030 +#define ASIZ_task_counter 0x00000008 +#define AOFF_task_priority 0x00000038 +#define ASIZ_task_priority 0x00000008 +#define AOFF_task_has_cpu 0x00000040 +#define ASIZ_task_has_cpu 0x00000004 +#define AOFF_task_processor 0x00000044 +#define ASIZ_task_processor 0x00000004 +#define AOFF_task_last_processor 0x00000048 +#define ASIZ_task_last_processor 0x00000004 +#define AOFF_task_lock_depth 0x0000004c +#define ASIZ_task_lock_depth 0x00000004 +#define AOFF_task_next_task 0x00000050 +#define ASIZ_task_next_task 0x00000008 +#define AOFF_task_prev_task 0x00000058 +#define ASIZ_task_prev_task 0x00000008 +#define AOFF_task_next_run 0x00000060 +#define ASIZ_task_next_run 0x00000008 +#define AOFF_task_prev_run 0x00000068 +#define ASIZ_task_prev_run 0x00000008 +#define AOFF_task_binfmt 0x00000070 +#define ASIZ_task_binfmt 0x00000008 +#define AOFF_task_exit_code 0x00000078 +#define ASIZ_task_exit_code 0x00000004 +#define AOFF_task_exit_signal 0x0000007c +#define ASIZ_task_exit_signal 0x00000004 +#define AOFF_task_pdeath_signal 0x00000080 +#define ASIZ_task_pdeath_signal 0x00000004 +#define AOFF_task_personality 0x00000088 +#define ASIZ_task_personality 0x00000008 +#define AOFF_task_pid 0x00000094 +#define ASIZ_task_pid 0x00000004 +#define AOFF_task_pgrp 0x00000098 +#define ASIZ_task_pgrp 0x00000004 +#define AOFF_task_tty_old_pgrp 0x0000009c +#define ASIZ_task_tty_old_pgrp 0x00000004 +#define AOFF_task_session 0x000000a0 +#define ASIZ_task_session 0x00000004 +#define AOFF_task_leader 0x000000a4 +#define ASIZ_task_leader 0x00000004 +#define AOFF_task_p_opptr 0x000000a8 +#define ASIZ_task_p_opptr 0x00000008 +#define AOFF_task_p_pptr 0x000000b0 +#define ASIZ_task_p_pptr 0x00000008 +#define AOFF_task_p_cptr 0x000000b8 +#define ASIZ_task_p_cptr 0x00000008 +#define AOFF_task_p_ysptr 0x000000c0 +#define ASIZ_task_p_ysptr 0x00000008 +#define AOFF_task_p_osptr 0x000000c8 +#define ASIZ_task_p_osptr 0x00000008 +#define AOFF_task_pidhash_next 0x000000d0 +#define ASIZ_task_pidhash_next 0x00000008 +#define AOFF_task_pidhash_pprev 0x000000d8 +#define ASIZ_task_pidhash_pprev 0x00000008 +#define AOFF_task_tarray_ptr 0x000000e0 +#define ASIZ_task_tarray_ptr 0x00000008 +#define AOFF_task_wait_chldexit 0x000000e8 +#define ASIZ_task_wait_chldexit 0x00000008 +#define AOFF_task_timeout 0x000000f0 +#define ASIZ_task_timeout 0x00000008 +#define AOFF_task_policy 0x000000f8 +#define ASIZ_task_policy 0x00000008 +#define AOFF_task_rt_priority 0x00000100 +#define ASIZ_task_rt_priority 0x00000008 +#define AOFF_task_it_real_value 0x00000108 +#define ASIZ_task_it_real_value 0x00000008 +#define AOFF_task_it_prof_value 0x00000110 +#define ASIZ_task_it_prof_value 0x00000008 +#define AOFF_task_it_virt_value 0x00000118 +#define ASIZ_task_it_virt_value 0x00000008 +#define AOFF_task_it_real_incr 0x00000120 +#define ASIZ_task_it_real_incr 0x00000008 +#define AOFF_task_it_prof_incr 0x00000128 +#define ASIZ_task_it_prof_incr 0x00000008 +#define AOFF_task_it_virt_incr 0x00000130 +#define ASIZ_task_it_virt_incr 0x00000008 +#define AOFF_task_real_timer 0x00000138 +#define ASIZ_task_real_timer 0x00000028 +#define AOFF_task_times 0x00000160 +#define ASIZ_task_times 0x00000020 +#define AOFF_task_start_time 0x00000180 +#define ASIZ_task_start_time 0x00000008 +#define AOFF_task_per_cpu_utime 0x00000188 +#define ASIZ_task_per_cpu_utime 0x00000100 +#define AOFF_task_min_flt 0x00000388 +#define ASIZ_task_min_flt 0x00000008 +#define AOFF_task_maj_flt 0x00000390 +#define ASIZ_task_maj_flt 0x00000008 +#define AOFF_task_nswap 0x00000398 +#define ASIZ_task_nswap 0x00000008 +#define AOFF_task_cmin_flt 0x000003a0 +#define ASIZ_task_cmin_flt 0x00000008 +#define AOFF_task_cmaj_flt 0x000003a8 +#define ASIZ_task_cmaj_flt 0x00000008 +#define AOFF_task_cnswap 0x000003b0 +#define ASIZ_task_cnswap 0x00000008 +#define AOFF_task_swap_address 0x000003c0 +#define ASIZ_task_swap_address 0x00000008 +#define AOFF_task_old_maj_flt 0x000003c8 +#define ASIZ_task_old_maj_flt 0x00000008 +#define AOFF_task_dec_flt 0x000003d0 +#define ASIZ_task_dec_flt 0x00000008 +#define AOFF_task_swap_cnt 0x000003d8 +#define ASIZ_task_swap_cnt 0x00000008 +#define AOFF_task_uid 0x000003e0 +#define ASIZ_task_uid 0x00000004 +#define AOFF_task_euid 0x000003e4 +#define ASIZ_task_euid 0x00000004 +#define AOFF_task_suid 0x000003e8 +#define ASIZ_task_suid 0x00000004 +#define AOFF_task_fsuid 0x000003ec +#define ASIZ_task_fsuid 0x00000004 +#define AOFF_task_gid 0x000003f0 +#define ASIZ_task_gid 0x00000004 +#define AOFF_task_egid 0x000003f4 +#define ASIZ_task_egid 0x00000004 +#define AOFF_task_sgid 0x000003f8 +#define ASIZ_task_sgid 0x00000004 +#define AOFF_task_fsgid 0x000003fc +#define ASIZ_task_fsgid 0x00000004 +#define AOFF_task_ngroups 0x00000400 +#define ASIZ_task_ngroups 0x00000004 +#define AOFF_task_groups 0x00000404 +#define ASIZ_task_groups 0x00000080 +#define AOFF_task_cap_effective 0x00000484 +#define ASIZ_task_cap_effective 0x00000004 +#define AOFF_task_cap_inheritable 0x00000488 +#define ASIZ_task_cap_inheritable 0x00000004 +#define AOFF_task_cap_permitted 0x0000048c +#define ASIZ_task_cap_permitted 0x00000004 +#define AOFF_task_user 0x00000490 +#define ASIZ_task_user 0x00000008 +#define AOFF_task_rlim 0x00000498 +#define ASIZ_task_rlim 0x000000a0 +#define AOFF_task_used_math 0x00000538 +#define ASIZ_task_used_math 0x00000002 +#define AOFF_task_comm 0x0000053a +#define ASIZ_task_comm 0x00000010 +#define AOFF_task_link_count 0x0000054c +#define ASIZ_task_link_count 0x00000004 +#define AOFF_task_tty 0x00000550 +#define ASIZ_task_tty 0x00000008 +#define AOFF_task_semundo 0x00000558 +#define ASIZ_task_semundo 0x00000008 +#define AOFF_task_semsleeping 0x00000560 +#define ASIZ_task_semsleeping 0x00000008 +#define AOFF_task_tss 0x00000570 +#define ASIZ_task_tss 0x00000470 +#define AOFF_task_fs 0x000009e0 +#define ASIZ_task_fs 0x00000008 +#define AOFF_task_files 0x000009e8 +#define ASIZ_task_files 0x00000008 +#define AOFF_task_mm 0x000009f0 +#define ASIZ_task_mm 0x00000008 +#define AOFF_task_sigmask_lock 0x000009f8 +#define ASIZ_task_sigmask_lock 0x0000000c +#define AOFF_task_sig 0x00000a08 #define ASIZ_task_sig 0x00000008 -#define AOFF_task_signal 0x000009d8 +#define AOFF_task_signal 0x00000a10 #define ASIZ_task_signal 0x00000008 -#define AOFF_task_blocked 0x000009e0 +#define AOFF_task_blocked 0x00000a18 #define ASIZ_task_blocked 0x00000008 -#define AOFF_task_sigqueue 0x000009e8 +#define AOFF_task_sigqueue 0x00000a20 #define ASIZ_task_sigqueue 0x00000008 -#define AOFF_task_sigqueue_tail 0x000009f0 +#define AOFF_task_sigqueue_tail 0x00000a28 #define ASIZ_task_sigqueue_tail 0x00000008 -#define AOFF_task_sas_ss_sp 0x000009f8 +#define AOFF_task_sas_ss_sp 0x00000a30 #define ASIZ_task_sas_ss_sp 0x00000008 -#define AOFF_task_sas_ss_size 0x00000a00 +#define AOFF_task_sas_ss_size 0x00000a38 #define ASIZ_task_sas_ss_size 0x00000008 -#define ASIZ_task 0x00000a10 +#define ASIZ_task 0x00000a40 #define AOFF_mm_mmap 0x00000000 #define ASIZ_mm_mmap 0x00000008 #define AOFF_mm_mmap_cache 0x00000008 @@ -540,15 +836,26 @@ #define ASIZ_thread_sig_address 0x00000008 #define AOFF_thread_sig_desc 0x000003f0 #define ASIZ_thread_sig_desc 0x00000008 -#define AOFF_thread_fpdepth 0x000003f8 +#define AOFF_thread_user_cntd0 0x000003f8 +#define ASIZ_thread_user_cntd0 0x00000008 +#define AOFF_thread_user_cntd1 0x00000400 +#define ASIZ_thread_user_cntd1 0x00000008 +#define AOFF_thread_kernel_cntd0 0x00000408 +#define ASIZ_thread_kernel_cntd0 0x00000008 +#define AOFF_thread_kernel_cntd1 0x00000410 +#define ASIZ_thread_kernel_cntd1 0x00000008 +#define AOFF_thread_pcr_reg 0x00000418 +#define ASIZ_thread_pcr_reg 0x00000008 +#define AOFF_thread_fpdepth 0x00000420 #define ASIZ_thread_fpdepth 0x00000001 -#define AOFF_thread_fpsaved 0x000003f9 +#define AOFF_thread_fpsaved 0x00000421 #define ASIZ_thread_fpsaved 0x00000007 -#define AOFF_thread_gsr 0x00000400 +#define AOFF_thread_gsr 0x00000428 #define ASIZ_thread_gsr 0x00000007 -#define AOFF_thread_xfsr 0x00000408 +#define AOFF_thread_xfsr 0x00000430 #define ASIZ_thread_xfsr 0x00000038 -#define ASIZ_thread 0x00000440 +#define ASIZ_thread 0x00000470 +#endif /* SPIN_LOCK_DEBUG */ #endif /* __SMP__ */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h --- v2.1.126/linux/include/asm-sparc64/dma.h Fri May 8 23:14:56 1998 +++ linux/include/asm-sparc64/dma.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.8 1998/04/13 07:27:06 davem Exp $ +/* $Id: dma.h,v 1.9 1998/10/26 20:03:15 davem Exp $ * include/asm-sparc64/dma.h * * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu) @@ -13,6 +13,21 @@ #include #include #include +#include + +extern spinlock_t dma_spin_lock; + +static __inline__ unsigned long claim_dma_lock(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_spin_lock, flags); + return flags; +} + +static __inline__ void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} /* These are irrelevant for Sparc DMA, but we leave it in so that * things can compile. diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h --- v2.1.126/linux/include/asm-sparc64/fcntl.h Fri Oct 23 22:01:26 1998 +++ linux/include/asm-sparc64/fcntl.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: fcntl.h,v 1.4 1998/08/26 10:33:36 davem Exp $ */ +/* $Id: fcntl.h,v 1.5 1998/10/26 20:03:15 davem Exp $ */ #ifndef _SPARC64_FCNTL_H #define _SPARC64_FCNTL_H diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h --- v2.1.126/linux/include/asm-sparc64/floppy.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/floppy.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: floppy.h,v 1.15 1998/09/14 18:28:37 ecd Exp $ +/* $Id: floppy.h,v 1.16 1998/10/06 20:32:15 ecd Exp $ * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -661,8 +661,9 @@ tmp |= FCR_LDE; ns87303_writeb(config, FCR, tmp); + tmp = sun_floppy_types[0]; sun_floppy_types[0] = sun_floppy_types[1]; - sun_floppy_types[1] = 0; + sun_floppy_types[1] = tmp; if (sun_pci_broken_drive != -1) { sun_pci_broken_drive = 1 - sun_pci_broken_drive; diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h --- v2.1.126/linux/include/asm-sparc64/hardirq.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/hardirq.h Tue Oct 27 09:52:21 1998 @@ -1,6 +1,6 @@ /* hardirq.h: 64-bit Sparc hard IRQ support. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu) */ #ifndef __SPARC64_HARDIRQ_H @@ -13,7 +13,12 @@ #else #define local_irq_count (cpu_data[smp_processor_id()].irq_count) #endif -#define in_interrupt() (local_irq_count != 0) + +/* + * Are we in an interrupt context? Either doing bottom half + * or hardware interrupt processing? + */ +#define in_interrupt() ((local_irq_count + local_bh_count) != 0) #ifndef __SMP__ @@ -47,7 +52,7 @@ static inline void hardirq_enter(int cpu) { - ++cpu_data[cpu].irq_count; + ++(cpu_data[cpu].irq_count); atomic_inc(&global_irq_count); membar("#StoreLoad | #StoreStore"); } @@ -56,31 +61,16 @@ { membar("#StoreStore | #LoadStore"); atomic_dec(&global_irq_count); - --cpu_data[cpu].irq_count; + --(cpu_data[cpu].irq_count); } static inline int hardirq_trylock(int cpu) { - unsigned long flags; - - __save_and_cli(flags); - atomic_inc(&global_irq_count); - if(atomic_read(&global_irq_count) != 1 || - (*(((unsigned char *)(&global_irq_lock)))) != 0) { - atomic_dec(&global_irq_count); - __restore_flags(flags); - return 0; - } - ++cpu_data[cpu].irq_count; - return 1; + return (! atomic_read(&global_irq_count) && + ! spin_is_locked (&global_irq_lock)); } -static inline void hardirq_endlock(int cpu) -{ - __cli(); - hardirq_exit(cpu); - __sti(); -} +#define hardirq_endlock(cpu) do { } while (0) extern void synchronize_irq(void); diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/ioctl.h linux/include/asm-sparc64/ioctl.h --- v2.1.126/linux/include/asm-sparc64/ioctl.h Fri Dec 13 01:37:47 1996 +++ linux/include/asm-sparc64/ioctl.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: ioctl.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */ +/* $Id: ioctl.h,v 1.2 1998/10/15 05:40:38 jj Exp $ */ #ifndef _SPARC64_IOCTL_H #define _SPARC64_IOCTL_H @@ -39,5 +39,13 @@ #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the PCMCIA... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) #endif /* !(_SPARC64_IOCTL_H) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h --- v2.1.126/linux/include/asm-sparc64/mmu_context.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/mmu_context.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: mmu_context.h,v 1.31 1998/09/24 03:22:01 davem Exp $ */ +/* $Id: mmu_context.h,v 1.32 1998/10/13 14:03:52 davem Exp $ */ #ifndef __SPARC64_MMU_CONTEXT_H #define __SPARC64_MMU_CONTEXT_H @@ -118,11 +118,10 @@ * the context for the new mm so we see the new mappings. */ #define activate_context(__tsk) \ -do { unsigned long __flags; \ - __save_and_cli(__flags); \ - flushw_user(); \ +do { flushw_user(); \ + spin_lock(&scheduler_lock); \ __get_mmu_context(__tsk); \ - __restore_flags(__flags); \ + spin_unlock(&scheduler_lock); \ } while(0) #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h --- v2.1.126/linux/include/asm-sparc64/namei.h Thu Apr 23 20:21:38 1998 +++ linux/include/asm-sparc64/namei.h Tue Oct 27 14:48:45 1998 @@ -12,7 +12,7 @@ #define SPARC_SOL_EMUL "usr/gnemul/solaris/" static inline struct dentry * -__sparc64_lookup_dentry(const char *name, int follow_link) +__sparc64_lookup_dentry(const char *name, int lookup_flags) { struct dentry *base; char *emul; @@ -29,18 +29,18 @@ return NULL; } - base = lookup_dentry (emul, dget (current->fs->root), 1); + base = lookup_dentry (emul, dget (current->fs->root), (LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_SLASHOK)); if (IS_ERR (base)) return NULL; - base = lookup_dentry (name, base, follow_link); + base = lookup_dentry (name, base, lookup_flags); if (IS_ERR (base)) return NULL; if (!base->d_inode) { struct dentry *fromroot; - fromroot = lookup_dentry (name, dget (current->fs->root), follow_link); + fromroot = lookup_dentry (name, dget (current->fs->root), lookup_flags); if (IS_ERR (fromroot)) return base; @@ -55,9 +55,9 @@ return base; } -#define __prefix_lookup_dentry(name, follow_link) \ +#define __prefix_lookup_dentry(name, lookup_flags) \ if (current->personality) { \ - dentry = __sparc64_lookup_dentry (name, follow_link); \ + dentry = __sparc64_lookup_dentry (name, lookup_flags); \ if (dentry) return dentry; \ } diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/oplib.h linux/include/asm-sparc64/oplib.h --- v2.1.126/linux/include/asm-sparc64/oplib.h Thu Jul 31 13:09:18 1997 +++ linux/include/asm-sparc64/oplib.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $ +/* $Id: oplib.h,v 1.9 1998/10/06 20:56:05 ecd Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -117,8 +117,8 @@ * kernel is still active, the prom will call this routine. * */ -typedef void (*sync_func_t)(long *cmd); -extern void prom_setsync(sync_func_t func_ptr); +typedef int (*callback_func_t)(long *cmd); +extern void prom_setcallback(callback_func_t func_ptr); /* Acquire the IDPROM of the root node in the prom device tree. This * gets passed a buffer where you would like it stuffed. The return value diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h --- v2.1.126/linux/include/asm-sparc64/page.h Thu Aug 6 14:06:34 1998 +++ linux/include/asm-sparc64/page.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.23 1998/06/12 14:54:33 jj Exp $ */ +/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */ #ifndef _SPARC64_PAGE_H #define _SPARC64_PAGE_H @@ -18,7 +18,7 @@ #ifndef __ASSEMBLY__ -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +extern void clear_page(unsigned long page); extern void copy_page(unsigned long to, unsigned long from); /* GROSS, defining this makes gcc pass these types as aggregates, diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/perfctr.h linux/include/asm-sparc64/perfctr.h --- v2.1.126/linux/include/asm-sparc64/perfctr.h Wed Dec 31 16:00:00 1969 +++ linux/include/asm-sparc64/perfctr.h Tue Oct 27 09:52:21 1998 @@ -0,0 +1,101 @@ +/*---------------------------------------- + PERFORMANCE INSTRUMENTATION + Guillaume Thouvenin 08/10/98 + David S. Miller 10/06/98 + ---------------------------------------*/ +#ifndef PERF_COUNTER_API +#define PERF_COUNTER_API + +/* sys_perfctr() interface. First arg is operation code + * from enumeration below. The meaning of further arguments + * are determined by the operation code. + * + * int sys_perfctr(int opcode, unsigned long arg0, + * unsigned long arg1, unsigned long arg2) + * + * Pointers which are passed by the user are pointers to 64-bit + * integers. + * + * Once enabled, performance counter state is retained until the + * process either exits or performs an exec. That is, performance + * counters remain enabled for fork/clone children. + */ +enum perfctr_opcode { + /* Enable UltraSparc performance counters, ARG0 is pointer + * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer + * to 64-bit accumulator for D1 counter. ARG2 is a pointer to + * the initial PCR register value to use. + */ + PERFCTR_ON, + + /* Disable UltraSparc performance counters. The PCR is written + * with zero and the user counter accumulator pointers and + * working PCR register value are forgotten. + */ + PERFCTR_OFF, + + /* Add current D0 and D1 PIC values into user pointers given + * in PERFCTR_ON operation. The PIC is cleared before returning. + */ + PERFCTR_READ, + + /* Clear the PIC register. */ + PERFCTR_CLRPIC, + + /* Begin using a new PCR value, the pointer to which is passed + * in ARG0. The PIC is also cleared after the new PCR value is + * written. + */ + PERFCTR_SETPCR, + + /* Store in pointer given in ARG0 the current PCR register value + * being used. + */ + PERFCTR_GETPCR +}; + +/* I don't want the kernel's namespace to be polluted with this + * stuff when this file is included. --DaveM + */ +#ifndef __KERNEL__ + +#define PRIV 0x00000001 +#define USR 0x00000002 +#define SYS 0x00000004 + +/* Pic.S0 Selection Bit Field Encoding */ +#define CYCLE_CNT 0x00000000 +#define INSTR_CNT 0x00000010 +#define DISPATCH0_IC_MISS 0x00000020 +#define DISPATCH0_STOREBUF 0x00000030 +#define IC_REF 0x00000080 +#define DC_RD 0x00000090 +#define DC_WR 0x000000A0 +#define LOAD_USE 0x000000B0 +#define EC_REF 0x000000C0 +#define EC_WRITE_HIT_RDO 0x000000D0 +#define EC_SNOOP_INV 0x000000E0 +#define EC_RD_HIT 0x000000F0 + +/* Pic.S1 Selection Bit Field Encoding */ +#define CYCLE_CNT_D1 0x00000000 +#define INSTR_CNT_D1 0x00000800 +#define DISPATCH0_IC_MISPRED 0x00001000 +#define DISPATCH0_FP_USE 0x00001800 +#define IC_HIT 0x00004000 +#define DC_RD_HIT 0x00004800 +#define DC_WR_HIT 0x00005000 +#define LOAD_USE_RAW 0x00005800 +#define EC_HIT 0x00006000 +#define EC_WB 0x00006800 +#define EC_SNOOP_CB 0x00007000 +#define EC_IT_HIT 0x00007800 + +struct vcounter_struct { + unsigned long long vcnt0; + unsigned long long vcnt1; +}; + +#endif /* !(__KERNEL__) */ + +#endif /* !(PERF_COUNTER_API) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h --- v2.1.126/linux/include/asm-sparc64/pgtable.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/pgtable.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.90 1998/09/24 03:21:56 davem Exp $ +/* $Id: pgtable.h,v 1.95 1998/10/22 03:05:57 davem Exp $ * pgtable.h: SpitFire page table operations. * * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -169,10 +169,9 @@ #define flush_cache_range(mm, start, end) flushw_user() #define flush_cache_page(vma, page) flushw_user() -extern void flush_page_to_ram(unsigned long page); - -/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */ +/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */ #define flush_icache_range(start, end) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) extern void __flush_dcache_range(unsigned long start, unsigned long end); @@ -379,7 +378,7 @@ if(ret) { struct page *page = mem_map + MAP_NR(ret); - clear_page(ret); + memset(ret, 0, PAGE_SIZE); (unsigned long)page->pprev_hash = 2; (unsigned long *)page->next_hash = pgd_quicklist; pgd_quicklist = (unsigned long *)page; @@ -409,7 +408,7 @@ } else { ret = (unsigned long *) __get_free_page(GFP_KERNEL); if(ret) - clear_page(ret); + memset(ret, 0, PAGE_SIZE); } return (pgd_t *)ret; } @@ -562,26 +561,41 @@ #define mmu_lockarea(vaddr, len) (vaddr) #define mmu_unlockarea(vaddr, len) do { } while(0) +/* There used to be some funny code here which tried to guess which + * TLB wanted the mapping, that wasn't accurate enough to justify it's + * existance. The real way to do that is to have each TLB miss handler + * pass in a distinct code to do_sparc64_fault() and do it more accurately + * there. + * + * What we do need to handle here is prevent I-cache corruption. The + * deal is that the I-cache snoops stores from other CPUs and all DMA + * activity, however stores from the local processor are not snooped. + * The dynamic linker and our signal handler mechanism take care of + * the cases where they write into instruction space, but when a page + * is copied in the kernel and then executed in user-space is not handled + * right. This leads to corruptions if things are "just right", consider + * the following scenerio: + * 1) Process 1 frees up a page that was used for the PLT of libc in + * it's address space. + * 2) Process 2 writes into a page in the PLT of libc for the first + * time. do_wp_page() copies the page locally, the local I-cache of + * the processor does not notice the writes during the page copy. + * The new page used just so happens to be the one just freed in #1. + * 3) After the PLT write, later the cpu calls into an unresolved PLT + * entry, the CPU executes old instructions from process 1's PLT + * table. + * 4) Splat. + */ +extern void flush_icache_page(unsigned long phys_page); #define update_mmu_cache(__vma, __address, _pte) \ -__asm__ __volatile__( \ - "rdpr %%pstate, %%g1\n\t" \ - "wrpr %%g1, %0, %%pstate\n\t" \ - "brz,pt %1, 1f\n\t" \ - " mov %2, %%g2\n\t" \ - "stxa %3, [%%g2] %5\n\t" \ - "ba,pt %%xcc, 2f\n\t" \ - " stxa %4, [%%g0] %6\n\t" \ -"1: stxa %3, [%%g2] %7\n\t" \ -" stxa %4, [%%g0] %8\n\t" \ -"2: wrpr %%g1, 0x0, %%pstate\n" \ - : /* no outputs */ \ - : "i" (PSTATE_IE), \ - "r" (((__vma)->vm_flags&(VM_READ|VM_WRITE|VM_EXEC))==(VM_READ|VM_EXEC)), \ - "i" (TLB_TAG_ACCESS), \ - "r" ((__address) | ((__vma)->vm_mm->context & 0x3ff)), \ - "r" (pte_val(_pte)), "i" (ASI_IMMU), "i" (ASI_ITLB_DATA_IN), \ - "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_IN) \ - : "g1", "g2") +do { \ + unsigned short __flags = ((__vma)->vm_flags); \ + if ((__flags & VM_EXEC) != 0 && \ + ((pte_val(_pte) & (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED)) == \ + (_PAGE_PRESENT | _PAGE_WRITE | _PAGE_MODIFIED))) { \ + flush_icache_page(pte_page(_pte) - page_offset); \ + } \ +} while(0) /* Make a non-present pseudo-TTE. */ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/processor.h linux/include/asm-sparc64/processor.h --- v2.1.126/linux/include/asm-sparc64/processor.h Thu Aug 6 14:06:34 1998 +++ linux/include/asm-sparc64/processor.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.49 1998/07/31 10:42:40 jj Exp $ +/* $Id: processor.h,v 1.51 1998/10/21 03:21:19 davem Exp $ * include/asm-sparc64/processor.h * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -61,6 +61,11 @@ unsigned long sig_address __attribute__ ((aligned (8))); unsigned long sig_desc; + /* Performance counter state */ + u64 *user_cntd0, *user_cntd1; + u64 kernel_cntd0, kernel_cntd1; + u64 pcr_reg; + unsigned char fpdepth; unsigned char fpsaved[7]; unsigned char gsr[7]; @@ -74,6 +79,7 @@ #define SPARC_FLAG_NEWSIGNALS 0x040 /* task wants new-style signals */ #define SPARC_FLAG_32BIT 0x080 /* task is older 32-bit binary */ #define SPARC_FLAG_NEWCHILD 0x100 /* task is just-spawned child process */ +#define SPARC_FLAG_PERFCTR 0x200 /* task has performance counters active */ #define INIT_MMAP { &init_mm, 0xfffff80000000000, 0xfffff80001000000, \ PAGE_SHARED , VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap } @@ -91,6 +97,8 @@ { 0, 0, 0, 0, 0, 0, 0, }, \ /* sig_address, sig_desc */ \ 0, 0, \ +/* user_cntd0, user_cndd1, kernel_cntd0, kernel_cntd0, pcr_reg */ \ + 0, 0, 0, 0, 0, \ /* fpdepth, fpsaved, gsr, xfsr */ \ 0, { 0 }, { 0 }, { 0 }, \ } diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h --- v2.1.126/linux/include/asm-sparc64/psrcompat.h Mon Jul 7 08:18:56 1997 +++ linux/include/asm-sparc64/psrcompat.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: psrcompat.h,v 1.4 1997/06/20 11:54:39 davem Exp $ */ +/* $Id: psrcompat.h,v 1.5 1998/10/06 09:28:39 jj Exp $ */ #ifndef _SPARC64_PSRCOMPAT_H #define _SPARC64_PSRCOMPAT_H @@ -21,21 +21,24 @@ #define PSR_VERS 0x0f000000 /* cpu-version field */ #define PSR_IMPL 0xf0000000 /* cpu-implementation field */ +#define PSR_V8PLUS 0xff000000 /* fake impl/ver, meaning a 64bit CPU is present */ +#define PSR_XCC 0x000f0000 /* if PSR_V8PLUS, this is %xcc */ + extern inline unsigned int tstate_to_psr(unsigned long tstate) { - unsigned long vers; - - __asm__ __volatile__("rdpr %%ver, %0" : "=r" (vers)); return ((tstate & TSTATE_CWP) | PSR_S | ((tstate & TSTATE_ICC) >> 12) | - (((vers << 8) >> 32) & PSR_IMPL) | - (((vers << 24) >> 36) & PSR_VERS)); + ((tstate & TSTATE_XCC) >> 20) | + PSR_V8PLUS); } extern inline unsigned long psr_to_tstate_icc(unsigned int psr) { - return ((unsigned long)(psr & PSR_ICC)) << 12; + unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12; + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) + tstate |= ((unsigned long)(psr & PSR_XCC)) << 20; + return tstate; } #endif /* !(_SPARC64_PSRCOMPAT_H) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/sab82532.h linux/include/asm-sparc64/sab82532.h --- v2.1.126/linux/include/asm-sparc64/sab82532.h Thu Sep 4 12:54:49 1997 +++ linux/include/asm-sparc64/sab82532.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: sab82532.h,v 1.3 1997/09/03 11:55:04 ecd Exp $ +/* $Id: sab82532.h,v 1.4 1998/10/25 23:04:29 ecd Exp $ * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -143,7 +143,7 @@ int xmit_fifo_size; int recv_fifo_size; int custom_divisor; - int quot; + int baud; int x_char; int close_delay; unsigned short closing_wait; diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h --- v2.1.126/linux/include/asm-sparc64/semaphore.h Sat Aug 16 09:51:10 1997 +++ linux/include/asm-sparc64/semaphore.h Tue Oct 27 09:52:21 1998 @@ -24,17 +24,24 @@ #define wake_one_more(sem) atomic_inc(&sem->waking); -#define waking_non_zero(sem) \ -({ unsigned long flags; \ - int ret = 0; \ - save_and_cli(flags); \ - if (atomic_read(&sem->waking) > 0) { \ - atomic_dec(&sem->waking); \ - ret = 1; \ - } \ - restore_flags(flags); \ - ret; \ -}) +static __inline__ int waking_non_zero(struct semaphore *sem) +{ + int ret; + + __asm__ __volatile__(" +1: ldsw [%1], %%g5 + brlez,pt %%g5, 2f + mov 0, %0 + sub %%g5, 1, %%g7 + cas [%1], %%g5, %%g7 + cmp %%g5, %%g7 + bne,pn %%icc, 1b + mov 1, %0 +2:" : "=r" (ret) + : "r" (&((sem)->waking)) + : "g5", "g7", "cc", "memory"); + return ret; +} extern __inline__ void down(struct semaphore * sem) { diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/sigcontext.h linux/include/asm-sparc64/sigcontext.h --- v2.1.126/linux/include/asm-sparc64/sigcontext.h Mon Jan 12 15:15:58 1998 +++ linux/include/asm-sparc64/sigcontext.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: sigcontext.h,v 1.10 1997/12/11 15:16:11 jj Exp $ */ +/* $Id: sigcontext.h,v 1.11 1998/10/06 09:28:37 jj Exp $ */ #ifndef __SPARC64_SIGCONTEXT_H #define __SPARC64_SIGCONTEXT_H @@ -76,6 +76,14 @@ unsigned long si_gsr; unsigned long si_fprs; } __siginfo_fpu_t; + +/* This magic should be in g_upper[0] for all upper parts + to be valid. */ +#define SIGINFO_EXTRA_V8PLUS_MAGIC 0x130e269 +typedef struct { + unsigned int g_upper[8]; + unsigned int o_upper[8]; +} siginfo_extra_v8plus_t; #endif /* !(__ASSEMBLY__) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h --- v2.1.126/linux/include/asm-sparc64/smp.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/smp.h Tue Oct 27 09:52:21 1998 @@ -34,16 +34,16 @@ struct cpuinfo_sparc { /* Dcache line 1 */ unsigned long irq_count; + unsigned long bh_count; unsigned int multiplier; unsigned int counter; - unsigned long pgcache_size; - unsigned long pgdcache_size; + unsigned long udelay_val; /* Dcache line 2 */ - unsigned long *pgd_cache; + unsigned long pgcache_size; unsigned long *pte_cache; - unsigned long udelay_val; - unsigned long dummy; + unsigned long pgdcache_size; + unsigned long *pgd_cache; }; extern struct cpuinfo_sparc cpu_data[NR_CPUS]; diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/smplock.h linux/include/asm-sparc64/smplock.h --- v2.1.126/linux/include/asm-sparc64/smplock.h Mon Aug 3 17:48:28 1998 +++ linux/include/asm-sparc64/smplock.h Tue Oct 27 09:52:21 1998 @@ -3,6 +3,7 @@ * * Default SMP lock implementation */ +#include #include #include @@ -36,14 +37,14 @@ * so we only need to worry about other * CPU's. */ -extern __inline__ void lock_kernel(void) -{ - if (!++current->lock_depth) - spin_lock(&kernel_flag); -} - -extern __inline__ void unlock_kernel(void) -{ - if (--current->lock_depth < 0) - spin_unlock(&kernel_flag); -} +#define lock_kernel() \ +do { \ + if (!++current->lock_depth) \ + spin_lock(&kernel_flag); \ +} while(0) + +#define unlock_kernel() \ +do { \ + if (--current->lock_depth < 0) \ + spin_unlock(&kernel_flag); \ +} while(0) diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/softirq.h linux/include/asm-sparc64/softirq.h --- v2.1.126/linux/include/asm-sparc64/softirq.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/softirq.h Tue Oct 27 09:52:21 1998 @@ -1,6 +1,6 @@ /* softirq.h: 64-bit Sparc soft IRQ support. * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1997, 1998 David S. Miller (davem@caip.rutgers.edu) */ #ifndef __SPARC64_SOFTIRQ_H @@ -9,129 +9,121 @@ #include #include +#ifndef __SMP__ +extern unsigned int local_bh_count; +#else +#define local_bh_count (cpu_data[smp_processor_id()].bh_count) +#endif + /* The locking mechanism for base handlers, to prevent re-entrancy, * is entirely private to an implementation, it should not be * referenced at all outside of this file. */ #define get_active_bhs() (bh_mask & bh_active) +#define clear_active_bhs(mask) \ + __asm__ __volatile__( \ +"1: ldx [%1], %%g7\n" \ +" andn %%g7, %0, %%g5\n" \ +" casx [%1], %%g7, %%g5\n" \ +" cmp %%g7, %%g5\n" \ +" bne,pn %%xcc, 1b\n" \ +" nop" \ + : /* no outputs */ \ + : "HIr" (mask), "r" (&bh_active) \ + : "g5", "g7", "cc", "memory") + +extern inline void init_bh(int nr, void (*routine)(void)) +{ + bh_base[nr] = routine; + bh_mask_count[nr] = 0; + bh_mask |= 1 << nr; +} + +extern inline void remove_bh(int nr) +{ + bh_base[nr] = NULL; + bh_mask &= ~(1 << nr); +} + +extern inline void mark_bh(int nr) +{ + set_bit(nr, &bh_active); +} #ifndef __SMP__ -extern int __sparc64_bh_counter; - -#define softirq_trylock(cpu) (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1)) -#define softirq_endlock(cpu) (__sparc64_bh_counter = 0) -#define clear_active_bhs(x) (bh_active &= ~(x)) -#define synchronize_bh() barrier() /* XXX implement SMP version -DaveM */ - -#define init_bh(nr, routine) \ -do { int ent = nr; \ - bh_base[ent] = routine; \ - bh_mask_count[ent] = 0; \ - bh_mask |= 1 << ent; \ -} while(0) - -#define remove_bh(nr) \ -do { int ent = nr; \ - bh_base[ent] = NULL; \ - bh_mask &= ~(1 << ent); \ -} while(0) - -#define mark_bh(nr) (bh_active |= (1 << (nr))) - -#define disable_bh(nr) \ -do { int ent = nr; \ - bh_mask &= ~(1 << ent); \ - bh_mask_count[ent]++; \ - barrier(); \ -} while(0) - -#define enable_bh(nr) \ -do { int ent = nr; \ - barrier(); \ - if (!--bh_mask_count[ent]) \ - bh_mask |= 1 << ent; \ -} while(0) - -#define start_bh_atomic() do { __sparc64_bh_counter++; barrier(); } while(0) - -#define end_bh_atomic() do { barrier(); __sparc64_bh_counter--; } while(0) +extern inline void start_bh_atomic(void) +{ + local_bh_count++; + barrier(); +} + +extern inline void end_bh_atomic(void) +{ + barrier(); + local_bh_count--; +} + +/* These are for the irq's testing the lock */ +#define softirq_trylock(cpu) (local_bh_count ? 0 : (local_bh_count=1)) +#define softirq_endlock(cpu) (local_bh_count = 0) +#define synchronize_bh() barrier() #else /* (__SMP__) */ -extern atomic_t __sparc64_bh_counter; +extern atomic_t global_bh_lock; +extern spinlock_t global_bh_count; -#define start_bh_atomic() \ - do { atomic_inc(&__sparc64_bh_counter); synchronize_irq(); } while(0) +extern void synchronize_bh(void); -#define end_bh_atomic() atomic_dec(&__sparc64_bh_counter) - -#include - -extern spinlock_t global_bh_lock; - -#define init_bh(nr, routine) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_base[ent] = routine; \ - bh_mask_count[ent] = 0; \ - bh_mask |= 1 << ent; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define remove_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_base[ent] = NULL; \ - bh_mask &= ~(1 << ent); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define mark_bh(nr) \ -do { unsigned long flags; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_active |= (1 << nr); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define disable_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_mask &= ~(1 << ent); \ - bh_mask_count[ent]++; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define enable_bh(nr) \ -do { unsigned long flags; \ - int ent = nr; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - if (!--bh_mask_count[ent]) \ - bh_mask |= 1 << ent; \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) - -#define softirq_trylock(cpu) \ -({ \ - int ret = 1; \ - if(atomic_add_return(1, &__sparc64_bh_counter) != 1) { \ - atomic_dec(&__sparc64_bh_counter); \ - ret = 0; \ - } \ - ret; \ -}) -#define softirq_endlock(cpu) atomic_dec(&__sparc64_bh_counter) -#define clear_active_bhs(mask) \ -do { unsigned long flags; \ - spin_lock_irqsave(&global_bh_lock, flags); \ - bh_active &= ~(mask); \ - spin_unlock_irqrestore(&global_bh_lock, flags); \ -} while(0) +static inline void start_bh_atomic(void) +{ + atomic_inc(&global_bh_lock); + synchronize_bh(); +} + +static inline void end_bh_atomic(void) +{ + atomic_dec(&global_bh_lock); +} + +/* These are for the IRQs testing the lock */ +static inline int softirq_trylock(int cpu) +{ + if (spin_trylock(&global_bh_count)) { + if (atomic_read(&global_bh_lock) == 0) { + ++(cpu_data[cpu].bh_count); + return 1; + } + spin_unlock(&global_bh_count); + } + return 0; +} + +static inline void softirq_endlock(int cpu) +{ + (cpu_data[cpu].bh_count)--; + spin_unlock(&global_bh_count); +} #endif /* (__SMP__) */ + +/* + * These use a mask count to correctly handle + * nested disable/enable calls + */ +extern inline void disable_bh(int nr) +{ + bh_mask &= ~(1 << nr); + bh_mask_count[nr]++; + synchronize_bh(); +} + +extern inline void enable_bh(int nr) +{ + if (!--bh_mask_count[nr]) + bh_mask |= 1 << nr; +} #endif /* !(__SPARC64_SOFTIRQ_H) */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h --- v2.1.126/linux/include/asm-sparc64/spinlock.h Thu Aug 6 14:06:34 1998 +++ linux/include/asm-sparc64/spinlock.h Tue Oct 27 09:52:21 1998 @@ -10,13 +10,8 @@ #ifndef __SMP__ -#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8) - typedef struct { } spinlock_t; - #define SPIN_LOCK_UNLOCKED { } -#else - typedef unsigned char spinlock_t; - #define SPIN_LOCK_UNLOCKED 0 -#endif +typedef unsigned char spinlock_t; +#define SPIN_LOCK_UNLOCKED 0 #define spin_lock_init(lock) do { } while(0) #define spin_lock(lock) do { } while(0) @@ -58,6 +53,11 @@ #else /* !(__SMP__) */ +/* To get debugging spinlocks which detect and catch + * deadlock situations, set DEBUG_SPINLOCKS in the sparc64 + * specific makefile and rebuild your kernel. + */ + /* All of these locking primitives are expected to work properly * even in an RMO memory model, which currently is what the kernel * runs in. @@ -71,10 +71,13 @@ * must be pre-V9 branches. */ +#ifndef SPIN_LOCK_DEBUG + typedef unsigned char spinlock_t; #define SPIN_LOCK_UNLOCKED 0 #define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) +#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) #define spin_unlock_wait(lock) \ do { membar("#LoadLoad"); \ @@ -177,8 +180,42 @@ : "memory"); } +#else /* !(SPIN_LOCK_DEBUG) */ + +typedef struct { + unsigned char lock; + unsigned int owner_pc, owner_cpu; +} spinlock_t; +#define SPIN_LOCK_UNLOCKED { 0, 0, NO_PROC_ID } +#define spin_lock_init(__lock) \ +do { (__lock)->lock = 0; \ + (__lock)->owner_pc = 0; \ + (__lock)->owner_cpu = NO_PROC_ID; \ +} while(0) +#define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0) +#define spin_unlock_wait(__lock) \ +do { \ + membar("#LoadLoad"); \ +} while(*((volatile unsigned char *)(&((__lock)->lock)))) + +extern void _do_spin_lock (spinlock_t *lock, char *str); +extern void _do_spin_unlock (spinlock_t *lock); +extern int _spin_trylock (spinlock_t *lock); + +#define spin_trylock(lp) _spin_trylock(lp) +#define spin_lock(lock) _do_spin_lock(lock, "spin_lock") +#define spin_lock_irq(lock) do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0) +#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0) +#define spin_unlock(lock) _do_spin_unlock(lock) +#define spin_unlock_irq(lock) do { _do_spin_unlock(lock); __sti(); } while(0) +#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0) + +#endif /* SPIN_LOCK_DEBUG */ + /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */ +#ifndef SPIN_LOCK_DEBUG + typedef unsigned long rwlock_t; #define RW_LOCK_UNLOCKED 0 @@ -277,6 +314,58 @@ do { __save_and_cli(flags); write_lock(lock); } while (0) #define write_unlock_irqrestore(lock, flags) \ do { write_unlock(lock); __restore_flags(flags); } while (0) + +#else /* !(SPIN_LOCK_DEBUG) */ + +typedef struct { + unsigned long lock; + unsigned int writer_pc, writer_cpu; + unsigned int reader_pc[4]; +} rwlock_t; +#define RW_LOCK_UNLOCKED { 0, 0, NO_PROC_ID, { 0, 0, 0, 0 } } + +extern void _do_read_lock(rwlock_t *rw, char *str); +extern void _do_read_unlock(rwlock_t *rw, char *str); +extern void _do_write_lock(rwlock_t *rw, char *str); +extern void _do_write_unlock(rwlock_t *rw); + +#define read_lock(lock) \ +do { unsigned long flags; \ + __save_and_cli(flags); \ + _do_read_lock(lock, "read_lock"); \ + __restore_flags(flags); \ +} while(0) +#define read_lock_irq(lock) do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0) +#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0) + +#define read_unlock(lock) \ +do { unsigned long flags; \ + __save_and_cli(flags); \ + _do_read_unlock(lock, "read_unlock"); \ + __restore_flags(flags); \ +} while(0) +#define read_unlock_irq(lock) do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0) +#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0) + +#define write_lock(lock) \ +do { unsigned long flags; \ + __save_and_cli(flags); \ + _do_write_lock(lock, "write_lock"); \ + __restore_flags(flags); \ +} while(0) +#define write_lock_irq(lock) do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0) +#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0) + +#define write_unlock(lock) \ +do { unsigned long flags; \ + __save_and_cli(flags); \ + _do_write_unlock(lock); \ + __restore_flags(flags); \ +} while(0) +#define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0) +#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0) + +#endif /* SPIN_LOCK_DEBUG */ #endif /* __SMP__ */ diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/string.h linux/include/asm-sparc64/string.h --- v2.1.126/linux/include/asm-sparc64/string.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/string.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: string.h,v 1.12 1998/10/04 08:44:27 davem Exp $ +/* $Id: string.h,v 1.14 1998/10/20 03:09:18 jj Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * @@ -65,23 +65,7 @@ #define __HAVE_ARCH_MEMSET -extern inline void *__constant_c_and_count_memset(void *s, char c, __kernel_size_t count) -{ - extern __kernel_size_t __bzero(void *, __kernel_size_t); - extern void *__bzero_1page(void *); - - if(!c) { - if (count == 8192) - __bzero_1page(s); - else - __bzero(s, count); - } else { - __memset(s, c, count); - } - return s; -} - -extern inline void *__constant_c_memset(void *s, char c, __kernel_size_t count) +extern inline void *__constant_memset(void *s, char c, __kernel_size_t count) { extern __kernel_size_t __bzero(void *, __kernel_size_t); @@ -100,10 +84,9 @@ #undef memset #define memset(s, c, count) \ -(__builtin_constant_p(c) ? (__builtin_constant_p(count) ? \ - __constant_c_and_count_memset((s), (c), (count)) : \ - __constant_c_memset((s), (c), (count))) \ - : __nonconstant_memset((s), (c), (count))) +(__builtin_constant_p(c) ? \ + __constant_memset((s), (c), (count)) : \ + __nonconstant_memset((s), (c), (count))) #define __HAVE_ARCH_MEMSCAN @@ -128,14 +111,19 @@ /* Now the str*() stuff... */ #define __HAVE_ARCH_STRLEN -/* Ugly but it works around a bug in our original sparc64-linux-gcc. */ extern __kernel_size_t __strlen(const char *); + +#if __GNUC__ > 2 || __GNUC_MINOR__ >= 91 +extern __kernel_size_t strlen(const char *); +#else /* !EGCS */ +/* Ugly but it works around a bug in our original sparc64-linux-gcc. */ #undef strlen #define strlen(__arg0) \ ({ int __strlen_res = __strlen(__arg0) + 1; \ __strlen_res -= 1; \ __strlen_res; \ }) +#endif /* !EGCS */ #define __HAVE_ARCH_STRNCMP diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h --- v2.1.126/linux/include/asm-sparc64/system.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/system.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: system.h,v 1.44 1998/09/21 03:57:22 davem Exp $ */ +/* $Id: system.h,v 1.47 1998/10/21 03:21:20 davem Exp $ */ #ifndef __SPARC64_SYSTEM_H #define __SPARC64_SYSTEM_H @@ -76,24 +76,17 @@ #else #ifndef __ASSEMBLY__ -extern unsigned char global_irq_holder; -#endif - -#define save_flags(x) \ -do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \ - ((getipl() != 0) ? 2 : 0))); } while(0) - -#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) - -#ifndef __ASSEMBLY__ extern void __global_cli(void); extern void __global_sti(void); +extern unsigned long __global_save_flags(void); extern void __global_restore_flags(unsigned long flags); #endif #define cli() __global_cli() #define sti() __global_sti() +#define save_flags(x) ((x) = __global_save_flags()) #define restore_flags(flags) __global_restore_flags(flags) +#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) #endif @@ -107,6 +100,12 @@ #define flushw_all() __asm__ __volatile__("flushw") +/* Performance counter register access. */ +#define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p)) +#define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)); +#define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) +#define reset_pic() __asm__ __volatile__("wr %g0, 0x0, %pic"); + #ifndef __ASSEMBLY__ extern void synchronize_user_stack(void); @@ -124,21 +123,6 @@ #define flush_user_windows flushw_user -#define DEBUG_SWITCH - -#ifdef DEBUG_SWITCH -#define SWITCH_CTX_CHECK(__tsk) \ -do { unsigned short ctx_now; \ - ctx_now = spitfire_get_secondary_context(); \ - if(ctx_now != (__tsk)->tss.ctx) \ - printk("[%s:%d] Bogus ctx after switch [%x:%x]\n", \ - (__tsk)->comm, (__tsk)->pid, \ - (__tsk)->tss.ctx, ctx_now); \ -} while(0) -#else -#define SWITCH_CTX_CHECK(__tsk) do { } while(0) -#endif - /* See what happens when you design the chip correctly? * * XXX What we are doing here assumes a lot about gcc reload @@ -156,7 +140,15 @@ * not reference %g6. */ #define switch_to(prev, next) \ -do { save_and_clear_fpu(); \ +do { if (current->tss.flags & SPARC_FLAG_PERFCTR) { \ + unsigned long __tmp; \ + read_pcr(__tmp); \ + current->tss.pcr_reg = __tmp; \ + read_pic(__tmp); \ + current->tss.kernel_cntd0 += (unsigned int)(__tmp); \ + current->tss.kernel_cntd1 += ((__tmp) >> 32); \ + } \ + save_and_clear_fpu(); \ __asm__ __volatile__( \ "flushw\n\t" \ "wrpr %g0, 0x94, %pstate\n\t"); \ @@ -201,7 +193,11 @@ "l2", "l3", "l4", "l5", "l6", "l7", \ "i0", "i1", "i2", "i3", "i4", "i5", \ "o0", "o1", "o2", "o3", "o4", "o5", "o7"); \ - SWITCH_CTX_CHECK(current); \ + /* If you fuck with this, update ret_from_syscall code too. */ \ + if (current->tss.flags & SPARC_FLAG_PERFCTR) { \ + write_pcr(current->tss.pcr_reg); \ + reset_pic(); \ + } \ } while(0) extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h --- v2.1.126/linux/include/asm-sparc64/uaccess.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/uaccess.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: uaccess.h,v 1.27 1998/09/23 02:04:57 davem Exp $ */ +/* $Id: uaccess.h,v 1.28 1998/10/11 06:58:34 davem Exp $ */ #ifndef _ASM_UACCESS_H #define _ASM_UACCESS_H @@ -45,10 +45,8 @@ #define set_fs(val) \ do { \ - unsigned long flags; \ if (current->tss.current_ds.seg != val.seg) { \ spin_lock(&scheduler_lock); \ - __save_and_cli(flags); \ current->tss.current_ds = (val); \ if (segment_eq((val), KERNEL_DS)) { \ flushw_user (); \ @@ -58,7 +56,6 @@ } \ spitfire_set_secondary_context(current->tss.ctx); \ __asm__ __volatile__("flush %g6"); \ - __restore_flags(flags); \ spin_unlock(&scheduler_lock); \ } \ } while(0) diff -u --recursive --new-file v2.1.126/linux/include/asm-sparc64/unistd.h linux/include/asm-sparc64/unistd.h --- v2.1.126/linux/include/asm-sparc64/unistd.h Mon Oct 5 13:13:44 1998 +++ linux/include/asm-sparc64/unistd.h Tue Oct 27 09:52:21 1998 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.22 1998/09/13 04:33:14 davem Exp $ */ +/* $Id: unistd.h,v 1.23 1998/10/07 01:28:02 davem Exp $ */ #ifndef _SPARC64_UNISTD_H #define _SPARC64_UNISTD_H @@ -33,7 +33,7 @@ #define __NR_chmod 15 /* Common */ #define __NR_lchown 16 /* Common */ #define __NR_brk 17 /* Common */ -/* #define __NR_ni_syscall 18 ENOSYS under SunOS */ +#define __NR_perfctr 18 /* Performance counter operations */ #define __NR_lseek 19 /* Common */ #define __NR_getpid 20 /* Common */ #define __NR_capget 21 /* Linux Specific */ diff -u --recursive --new-file v2.1.126/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v2.1.126/linux/include/linux/cdrom.h Thu Sep 17 17:53:38 1998 +++ linux/include/linux/cdrom.h Sat Oct 24 10:43:47 1998 @@ -5,6 +5,8 @@ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl * 1997, 1998 Erik Andersen, andersee@debian.org + * 1998 Jens Axboe, axboe@image.dk and + * Chris Zwilling, chris@cloudnet.com */ #ifndef _LINUX_CDROM_H diff -u --recursive --new-file v2.1.126/linux/include/linux/if.h linux/include/linux/if.h --- v2.1.126/linux/include/linux/if.h Sat Sep 5 16:46:41 1998 +++ linux/include/linux/if.h Sat Nov 7 11:00:31 1998 @@ -43,7 +43,9 @@ #define IFF_PORTSEL 0x2000 /* can set media type */ #define IFF_AUTOMEDIA 0x4000 /* auto media select active */ -#define IFF_NODYNARP 0x8000 /* use static ARP only (HIPPI) */ +#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ + +#ifdef __KERNEL__ /* * The ifaddr structure contains information about one address * of an interface. They are maintained by the different address @@ -66,6 +68,8 @@ #define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */ #define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ +#endif /* __KERNEL__ */ + /* * Device mapping structure. I'd just gone off and designed a * beautiful scheme using only loadable modules with arguments @@ -115,7 +119,7 @@ struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ char ifru_newname[IFNAMSIZ]; - __kernel_caddr_t ifru_data; + char * ifru_data; } ifr_ifru; }; @@ -148,7 +152,7 @@ int ifc_len; /* size of buffer */ union { - __kernel_caddr_t ifcu_buf; + char * ifcu_buf; struct ifreq *ifcu_req; } ifc_ifcu; }; diff -u --recursive --new-file v2.1.126/linux/include/linux/kernel.h linux/include/linux/kernel.h --- v2.1.126/linux/include/linux/kernel.h Tue Apr 14 14:29:25 1998 +++ linux/include/linux/kernel.h Tue Oct 27 09:53:09 1998 @@ -11,7 +11,8 @@ #include /* Optimization barrier */ -#define barrier() __asm__("": : :"memory") +/* The "volatile" is due to gcc bugs */ +#define barrier() __asm__ __volatile__("": : :"memory") #define INT_MAX ((int)(~0U>>1)) #define UINT_MAX (~0U) diff -u --recursive --new-file v2.1.126/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.126/linux/include/linux/mm.h Fri Oct 23 22:01:27 1998 +++ linux/include/linux/mm.h Sat Nov 7 11:31:11 1998 @@ -254,12 +254,6 @@ /* memory.c & swap.c*/ -/* - * Decide if we should try to do some swapout.. - */ -extern int free_memory_available(void); -extern struct wait_queue * kswapd_wait; - #define free_page(addr) free_pages((addr),0) extern void FASTCALL(free_pages(unsigned long addr, unsigned long order)); extern void FASTCALL(__free_page(struct page *)); @@ -278,7 +272,7 @@ extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot); extern void vmtruncate(struct inode * inode, unsigned long offset); -extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access); +extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access); extern void make_pages_present(unsigned long addr, unsigned long end); extern int pgt_cache_water[2]; @@ -330,6 +324,11 @@ #define GFP_DMA __GFP_DMA +/* + * Decide if we should try to do some swapout.. + */ +extern int free_memory_available(void); + /* vma is the first one with address < vma->vm_end, * and even address < vma->vm_start. Have to extend vma. */ static inline int expand_stack(struct vm_area_struct * vma, unsigned long address) @@ -378,11 +377,6 @@ if (vma && end_addr <= vma->vm_start) vma = NULL; return vma; -} - -extern __inline__ void kswapd_wakeup(void) -{ - wake_up(&kswapd_wait); } #define buffer_under_min() ((buffermem >> PAGE_SHIFT) * 100 < \ diff -u --recursive --new-file v2.1.126/linux/include/linux/pagemap.h linux/include/linux/pagemap.h --- v2.1.126/linux/include/linux/pagemap.h Fri Jul 31 17:05:53 1998 +++ linux/include/linux/pagemap.h Sat Nov 7 11:31:11 1998 @@ -83,7 +83,6 @@ static inline void __add_page_to_hash_queue(struct page * page, struct page **p) { page_cache_size++; - set_bit(PG_referenced, &page->flags); page->age = PAGE_AGE_VALUE; if((page->next_hash = *p) != NULL) (*p)->pprev_hash = &page->next_hash; diff -u --recursive --new-file v2.1.126/linux/include/linux/parport.h linux/include/linux/parport.h --- v2.1.126/linux/include/linux/parport.h Fri Oct 23 22:01:27 1998 +++ linux/include/linux/parport.h Sat Nov 7 11:30:03 1998 @@ -208,7 +208,7 @@ int number; /* port index - the `n' in `parportn' */ spinlock_t pardevice_lock; spinlock_t waitlist_lock; - spinlock_t cad_lock; + rwlock_t cad_lock; }; /* parport_register_port registers a new parallel port at the given address (if diff -u --recursive --new-file v2.1.126/linux/include/linux/pci.h linux/include/linux/pci.h --- v2.1.126/linux/include/linux/pci.h Fri Oct 23 22:01:27 1998 +++ linux/include/linux/pci.h Sat Nov 7 11:28:41 1998 @@ -841,6 +841,7 @@ #define PCI_DEVICE_ID_ATT_L56XMF 0x0440 #define PCI_VENDOR_ID_SPECIALIX 0x11cb +#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000 #define PCI_DEVICE_ID_SPECIALIX_XIO 0x4000 #define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000 diff -u --recursive --new-file v2.1.126/linux/include/linux/poll.h linux/include/linux/poll.h --- v2.1.126/linux/include/linux/poll.h Fri Jul 31 17:07:03 1998 +++ linux/include/linux/poll.h Sat Nov 7 11:31:12 1998 @@ -103,7 +103,7 @@ memset(fdset, 0, nr); } -extern int do_select(int n, fd_set_buffer *fds, unsigned long timeout); +extern int do_select(int n, fd_set_buffer *fds, long *timeout); #endif /* KERNEL */ diff -u --recursive --new-file v2.1.126/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.126/linux/include/linux/sched.h Mon Oct 5 13:13:46 1998 +++ linux/include/linux/sched.h Sat Nov 7 11:31:11 1998 @@ -119,9 +119,10 @@ extern void show_state(void); extern void trap_init(void); +#define MAX_SCHEDULE_TIMEOUT LONG_MAX +extern signed long FASTCALL(schedule_timeout(signed long timeout)); asmlinkage void schedule(void); - /* * Open file table structure */ @@ -258,7 +259,7 @@ struct task_struct **tarray_ptr; struct wait_queue *wait_chldexit; /* for wait4() */ - unsigned long timeout, policy, rt_priority; + unsigned long policy, rt_priority; unsigned long it_real_value, it_prof_value, it_virt_value; unsigned long it_real_incr, it_prof_incr, it_virt_incr; struct timer_list real_timer; @@ -348,7 +349,7 @@ /* pidhash */ NULL, NULL, \ /* tarray */ &task[0], \ /* chld wait */ NULL, \ -/* timeout */ 0,SCHED_OTHER,0,0,0,0,0,0,0, \ +/* timeout */ SCHED_OTHER,0,0,0,0,0,0,0, \ /* timer */ { NULL, NULL, 0, 0, it_real_fn }, \ /* utime */ {0,0,0,0},0, \ /* per CPU times */ {0, }, {0, }, \ @@ -457,7 +458,10 @@ extern void FASTCALL(__wake_up(struct wait_queue ** p, unsigned int mode)); extern void FASTCALL(sleep_on(struct wait_queue ** p)); +extern void FASTCALL(sleep_on(struct wait_queue ** p)); extern void FASTCALL(interruptible_sleep_on(struct wait_queue ** p)); +extern long FASTCALL(interruptible_sleep_on_timeout(struct wait_queue ** p, + signed long timeout)); extern void FASTCALL(wake_up_process(struct task_struct * tsk)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) diff -u --recursive --new-file v2.1.126/linux/include/linux/serial.h linux/include/linux/serial.h --- v2.1.126/linux/include/linux/serial.h Thu Apr 23 20:21:38 1998 +++ linux/include/linux/serial.h Tue Nov 3 22:05:25 1998 @@ -42,11 +42,11 @@ #define PORT_16450 2 #define PORT_16550 3 #define PORT_16550A 4 -#define PORT_CIRRUS 5 +#define PORT_CIRRUS 5 /* usurped by cyclades.c */ #define PORT_16650 6 #define PORT_16650V2 7 #define PORT_16750 8 -#define PORT_STARTECH 9 +#define PORT_STARTECH 9 /* usurped by cyclades.c */ #define PORT_MAX 9 struct serial_uart_config { @@ -87,7 +87,7 @@ #define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */ -#define ASYNC_FLAGS 0x2FFF /* Possible legal async flags */ +#define ASYNC_FLAGS 0x3FFF /* Possible legal async flags */ #define ASYNC_USR_MASK 0x3430 /* Legal flags that non-privileged * users can set or reset */ diff -u --recursive --new-file v2.1.126/linux/include/linux/socket.h linux/include/linux/socket.h --- v2.1.126/linux/include/linux/socket.h Mon Sep 28 10:51:35 1998 +++ linux/include/linux/socket.h Sat Nov 7 11:00:31 1998 @@ -250,6 +250,7 @@ /* TCP options - this way around because someone left a set in the c library includes */ #define TCP_NODELAY 1 #define TCP_MAXSEG 2 +#define TCP_CORK 3 /* Linux specific (for use with sendfile) */ #ifdef __KERNEL__ extern int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); diff -u --recursive --new-file v2.1.126/linux/include/linux/soundcard.h linux/include/linux/soundcard.h --- v2.1.126/linux/include/linux/soundcard.h Sun Jul 26 11:57:19 1998 +++ linux/include/linux/soundcard.h Sat Oct 24 11:40:16 1998 @@ -771,6 +771,8 @@ #define SOUND_MIXER_CAPS 0xfc # define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */ #define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ +#define SOUND_MIXER_OUTSRC 0xfa /* Arg contains a bit for each input source to output */ +#define SOUND_MIXER_OUTMASK 0xf9 /* Arg contains a bit for each supported input source to output */ /* Device mask bits */ diff -u --recursive --new-file v2.1.126/linux/include/linux/sunrpc/svcsock.h linux/include/linux/sunrpc/svcsock.h --- v2.1.126/linux/include/linux/sunrpc/svcsock.h Fri Jul 31 17:10:04 1998 +++ linux/include/linux/sunrpc/svcsock.h Wed Nov 4 10:21:46 1998 @@ -51,7 +51,7 @@ */ int svc_makesock(struct svc_serv *, int, unsigned short); void svc_delete_socket(struct svc_sock *); -int svc_recv(struct svc_serv *, struct svc_rqst *); +int svc_recv(struct svc_serv *, struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); diff -u --recursive --new-file v2.1.126/linux/include/linux/sysctl.h linux/include/linux/sysctl.h --- v2.1.126/linux/include/linux/sysctl.h Mon Oct 5 13:13:47 1998 +++ linux/include/linux/sysctl.h Tue Oct 27 09:57:19 1998 @@ -163,8 +163,7 @@ NET_IPV4_ROUTE = 18, NET_IPV4_FIB_HASH = 19, -/*32*/ NET_IPV4_TCP_HOE_RETRANSMITS=32, - NET_IPV4_TCP_TIMESTAMPS, +/*33*/ NET_IPV4_TCP_TIMESTAMPS=33, NET_IPV4_TCP_WINDOW_SCALING, NET_IPV4_TCP_SACK, NET_IPV4_TCP_RETRANS_COLLAPSE, diff -u --recursive --new-file v2.1.126/linux/include/linux/timer.h linux/include/linux/timer.h --- v2.1.126/linux/include/linux/timer.h Tue Jun 23 10:01:29 1998 +++ linux/include/linux/timer.h Mon Nov 2 09:34:36 1998 @@ -71,22 +71,26 @@ timer->prev = NULL; } +extern inline int timer_pending(struct timer_list * timer) +{ + return timer->prev != NULL; +} + /* * These inlines deal with timer wrapping correctly. You are * strongly encouraged to use them * 1. Because people otherwise forget * 2. Because if the timer wrap changes in future you wont have to * alter your driver code. + * + * Do this with "<0" and ">=0" to only test the sign of the result. A + * good compiler would generate better code (and a really good compiler + * wouldn't care). Gcc is currently neither. */ +#define time_after(a,b) ((long)(b) - (long)(a) < 0) +#define time_before(a,b) time_after(b,a) -extern inline int time_before(unsigned long a, unsigned long b) -{ - return((long)((a) - (b)) < 0L); -} - -extern inline int time_after(unsigned long a, unsigned long b) -{ - return((long)((a) - (b)) > 0L); -} +#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) +#define time_before_eq(a,b) time_after_eq(b,a) #endif diff -u --recursive --new-file v2.1.126/linux/include/linux/tty.h linux/include/linux/tty.h --- v2.1.126/linux/include/linux/tty.h Mon Sep 28 10:51:36 1998 +++ linux/include/linux/tty.h Sat Nov 7 11:31:10 1998 @@ -355,7 +355,7 @@ extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device, const char *routine); extern char *tty_name(struct tty_struct *tty, char *buf); -extern void tty_wait_until_sent(struct tty_struct * tty, int timeout); +extern void tty_wait_until_sent(struct tty_struct * tty, long timeout); extern int tty_check_change(struct tty_struct * tty); extern void stop_tty(struct tty_struct * tty); extern void start_tty(struct tty_struct * tty); diff -u --recursive --new-file v2.1.126/linux/include/net/scm.h linux/include/net/scm.h --- v2.1.126/linux/include/net/scm.h Tue Mar 10 10:03:35 1998 +++ linux/include/net/scm.h Tue Oct 27 09:57:19 1998 @@ -17,8 +17,6 @@ struct ucred creds; /* Skb credentials */ struct scm_fp_list *fp; /* Passed files */ unsigned long seq; /* Connection seqno */ - struct file *file; /* file for socket */ - struct socket *sock; /* Passed socket */ }; extern void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); @@ -39,7 +37,6 @@ scm->creds.uid = current->uid; scm->creds.gid = current->gid; scm->creds.pid = current->pid; - scm->sock = sock; if (msg->msg_controllen <= 0) return 0; return __scm_send(sock, msg, scm); diff -u --recursive --new-file v2.1.126/linux/include/net/sock.h linux/include/net/sock.h --- v2.1.126/linux/include/net/sock.h Mon Oct 5 13:13:47 1998 +++ linux/include/net/sock.h Sat Nov 7 11:31:12 1998 @@ -535,7 +535,7 @@ struct sock *sklist_prev; void (*close)(struct sock *sk, - unsigned long timeout); + long timeout); int (*connect)(struct sock *sk, struct sockaddr *uaddr, int addr_len); diff -u --recursive --new-file v2.1.126/linux/include/net/tcp.h linux/include/net/tcp.h --- v2.1.126/linux/include/net/tcp.h Thu Sep 17 17:53:39 1998 +++ linux/include/net/tcp.h Sat Nov 7 11:31:13 1998 @@ -511,7 +511,7 @@ unsigned len); extern void tcp_close(struct sock *sk, - unsigned long timeout); + long timeout); extern struct sock * tcp_accept(struct sock *sk, int flags); extern unsigned int tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait); extern void tcp_write_space(struct sock *sk); @@ -675,7 +675,7 @@ * scaling applied to the result. The caller does these things * if necessary. This is a "raw" window selection. */ -extern u32 __tcp_select_window(struct sock *sk, u32 cur_win); +extern u32 __tcp_select_window(struct sock *sk); /* Chose a new window to advertise, update state in tcp_opt for the * socket, and return result with RFC1323 scaling applied. The return @@ -686,13 +686,20 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); u32 cur_win = tcp_receive_window(tp); - u32 new_win = __tcp_select_window(sk, cur_win); + u32 new_win = __tcp_select_window(sk); /* Never shrink the offered window */ - if(new_win < cur_win) + if(new_win < cur_win) { + /* Danger Will Robinson! + * Don't update rcv_wup/rcv_wnd here or else + * we will not be able to advertise a zero + * window in time. --DaveM + */ new_win = cur_win; - tp->rcv_wnd = new_win; - tp->rcv_wup = tp->rcv_nxt; + } else { + tp->rcv_wnd = new_win; + tp->rcv_wup = tp->rcv_nxt; + } /* RFC1323 scaling applied */ return new_win >> tp->rcv_wscale; @@ -706,7 +713,7 @@ { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); u32 cur_win = tcp_receive_window(tp); - u32 new_win = __tcp_select_window(sk, cur_win); + u32 new_win = __tcp_select_window(sk); return (new_win && (new_win > (cur_win << 1))); } @@ -790,8 +797,11 @@ * * Don't use the nagle rule for urgent data. */ - if (!sk->nonagle && skb->len < (tp->mss_cache >> 1) && tp->packets_out && - !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG)) + if ((sk->nonagle == 2 && (skb->len < tp->mss_cache)) || + (!sk->nonagle && + skb->len < (tp->mss_cache >> 1) && + tp->packets_out && + !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_URG))) nagle_check = 0; return (nagle_check && diff -u --recursive --new-file v2.1.126/linux/init/main.c linux/init/main.c --- v2.1.126/linux/init/main.c Fri Oct 23 22:01:27 1998 +++ linux/init/main.c Thu Nov 5 15:29:43 1998 @@ -194,6 +194,7 @@ extern void in2000_setup(char *str, int *ints); extern void NCR53c406a_setup(char *str, int *ints); extern void wd7000_setup(char *str, int *ints); +extern void dc390_setup(char* str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void scsi_logging_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); @@ -704,6 +705,9 @@ #ifdef CONFIG_SCSI_IBMMCA { "ibmmcascsi=", ibmmca_scsi_setup }, #endif +#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP) + { "tmscsim=", dc390_setup }, +#endif #ifdef CONFIG_BLK_DEV_XD { "xd=", xd_setup }, { "xd_geo=", xd_manual_geo_init }, @@ -1304,8 +1308,8 @@ */ extern struct inode *pseudo_root; if (pseudo_root != NULL){ - current->fs->root = pseudo_root; - current->fs->pwd = pseudo_root; + current->fs->root = pseudo_root->i_sb->s_root; + current->fs->pwd = pseudo_root->i_sb->s_root; } } #endif diff -u --recursive --new-file v2.1.126/linux/kernel/acct.c linux/kernel/acct.c --- v2.1.126/linux/kernel/acct.c Fri Oct 23 22:01:27 1998 +++ linux/kernel/acct.c Sat Oct 24 08:54:33 1998 @@ -87,7 +87,7 @@ if (!acct_file || !acct_needcheck) return; - sb = acct_file->f_dentry->f_inode->i_sb; + sb = acct_file->f_dentry->d_inode->i_sb; if (!sb->s_op || !sb->s_op->statfs) return; diff -u --recursive --new-file v2.1.126/linux/kernel/itimer.c linux/kernel/itimer.c --- v2.1.126/linux/kernel/itimer.c Mon Dec 8 23:58:05 1997 +++ linux/kernel/itimer.c Sat Oct 31 10:17:21 1998 @@ -102,11 +102,9 @@ send_sig(SIGALRM, p, 1); interval = p->it_real_incr; if (interval) { - unsigned long timeout = jiffies + interval; - /* check for overflow */ - if (timeout < interval) - timeout = ULONG_MAX; - p->real_timer.expires = timeout; + if (interval > (unsigned long) LONG_MAX) + interval = LONG_MAX; + p->real_timer.expires = jiffies + interval; add_timer(&p->real_timer); } } @@ -127,10 +125,9 @@ current->it_real_incr = i; if (!j) break; + if (j > (unsigned long) LONG_MAX) + j = LONG_MAX; i = j + jiffies; - /* check for overflow.. */ - if (i < j) - i = ULONG_MAX; current->real_timer.expires = i; add_timer(¤t->real_timer); break; diff -u --recursive --new-file v2.1.126/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.126/linux/kernel/ksyms.c Fri Oct 23 22:01:27 1998 +++ linux/kernel/ksyms.c Sat Oct 31 10:17:21 1998 @@ -317,7 +317,9 @@ EXPORT_SYMBOL(__wake_up); EXPORT_SYMBOL(sleep_on); EXPORT_SYMBOL(interruptible_sleep_on); +EXPORT_SYMBOL(interruptible_sleep_on_timeout); EXPORT_SYMBOL(schedule); +EXPORT_SYMBOL(schedule_timeout); EXPORT_SYMBOL(jiffies); EXPORT_SYMBOL(xtime); EXPORT_SYMBOL(do_gettimeofday); diff -u --recursive --new-file v2.1.126/linux/kernel/sched.c linux/kernel/sched.c --- v2.1.126/linux/kernel/sched.c Sat Sep 5 16:46:42 1998 +++ linux/kernel/sched.c Fri Nov 6 17:15:02 1998 @@ -230,7 +230,7 @@ * "current->state = TASK_RUNNING" to mark yourself runnable * without the overhead of this. */ -inline void wake_up_process(struct task_struct * p) +void wake_up_process(struct task_struct * p) { unsigned long flags; @@ -248,7 +248,6 @@ { struct task_struct * p = (struct task_struct *) __data; - p->timeout = 0; wake_up_process(p); } @@ -372,12 +371,12 @@ } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) { int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK; insert_timer(timer, tv4.vec, i); - } else if (expires < timer_jiffies) { + } else if ((signed long) idx < 0) { /* can happen if you add a timer with expires == jiffies, * or you set a timer to go off in the past */ insert_timer(timer, tv1.vec, tv1.index); - } else if (idx < 0xffffffffUL) { + } else if (idx <= 0xffffffffUL) { int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK; insert_timer(timer, tv5.vec, i); } else { @@ -445,6 +444,74 @@ #endif +signed long schedule_timeout(signed long timeout) +{ + struct timer_list timer; + unsigned long expire; + + /* + * PARANOID. + */ + if (current->state == TASK_UNINTERRUPTIBLE) + { + printk(KERN_WARNING "schedule_timeout: task not interrutible " + "from %p\n", __builtin_return_address(0)); + /* + * We don' t want to interrupt a not interruptible task + * risking to cause corruption. Better a a deadlock ;-). + */ + timeout = MAX_SCHEDULE_TIMEOUT; + } + + /* + * Here we start for real. + */ + switch (timeout) + { + case MAX_SCHEDULE_TIMEOUT: + /* + * These two special cases are useful to be comfortable + * in the caller. Nothing more. We could take + * MAX_SCHEDULE_TIMEOUT from one of the negative value + * but I' d like to return a valid offset (>=0) to allow + * the caller to do everything it want with the retval. + */ + schedule(); + goto out; + default: + /* + * Another bit of PARANOID. Note that the retval will be + * 0 since no piece of kernel is supposed to do a check + * for a negative retval of schedule_timeout() (since it + * should never happens anyway). You just have the printk() + * that will tell you if something is gone wrong and where. + */ + if (timeout < 0) + { + printk(KERN_ERR "schedule_timeout: wrong timeout " + "value %lx from %p\n", timeout, + __builtin_return_address(0)); + goto out; + } + } + + expire = timeout + jiffies; + + init_timer(&timer); + timer.expires = expire; + timer.data = (unsigned long) current; + timer.function = process_timeout; + + add_timer(&timer); + schedule(); + del_timer(&timer); + + timeout = expire - jiffies; + + out: + return timeout < 0 ? 0 : timeout; +} + /* * 'schedule()' is the scheduler function. It's a very simple and nice * scheduler: it's not perfect, but certainly works for most things. @@ -458,7 +525,6 @@ asmlinkage void schedule(void) { struct task_struct * prev, * next; - unsigned long timeout; int this_cpu; prev = current; @@ -481,16 +547,10 @@ prev->counter = prev->priority; move_last_runqueue(prev); } - timeout = 0; + switch (prev->state) { case TASK_INTERRUPTIBLE: - if (signal_pending(prev)) - goto makerunnable; - timeout = prev->timeout; - if (timeout && (timeout <= jiffies)) { - prev->timeout = 0; - timeout = 0; - makerunnable: + if (signal_pending(prev)) { prev->state = TASK_RUNNING; break; } @@ -550,21 +610,9 @@ #endif if (prev != next) { - struct timer_list timer; - kstat.context_swtch++; - if (timeout) { - init_timer(&timer); - timer.expires = timeout; - timer.data = (unsigned long) prev; - timer.function = process_timeout; - add_timer(&timer); - } get_mmu_context(next); switch_to(prev,next); - - if (timeout) - del_timer(&timer); } spin_unlock(&scheduler_lock); @@ -702,7 +750,6 @@ schedule(); tsk->state = task_state; } - tsk->state = TASK_RUNNING; remove_wait_queue(&sem->wait, &wait); return ret; @@ -718,32 +765,54 @@ return __do_down(sem,TASK_INTERRUPTIBLE); } - -static void FASTCALL(__sleep_on(struct wait_queue **p, int state)); -static void __sleep_on(struct wait_queue **p, int state) -{ - unsigned long flags; +#define SLEEP_ON_VAR \ + unsigned long flags; \ struct wait_queue wait; - current->state = state; - wait.task = current; - write_lock_irqsave(&waitqueue_lock, flags); - __add_wait_queue(p, &wait); +#define SLEEP_ON_HEAD \ + wait.task = current; \ + write_lock_irqsave(&waitqueue_lock, flags); \ + __add_wait_queue(p, &wait); \ write_unlock(&waitqueue_lock); - schedule(); - write_lock_irq(&waitqueue_lock); - __remove_wait_queue(p, &wait); + +#define SLEEP_ON_TAIL \ + write_lock_irq(&waitqueue_lock); \ + __remove_wait_queue(p, &wait); \ write_unlock_irqrestore(&waitqueue_lock, flags); -} void interruptible_sleep_on(struct wait_queue **p) { - __sleep_on(p,TASK_INTERRUPTIBLE); + SLEEP_ON_VAR + + current->state = TASK_INTERRUPTIBLE; + + SLEEP_ON_HEAD + schedule(); + SLEEP_ON_TAIL +} + +long interruptible_sleep_on_timeout(struct wait_queue **p, long timeout) +{ + SLEEP_ON_VAR + + current->state = TASK_INTERRUPTIBLE; + + SLEEP_ON_HEAD + timeout = schedule_timeout(timeout); + SLEEP_ON_TAIL + + return timeout; } void sleep_on(struct wait_queue **p) { - __sleep_on(p,TASK_UNINTERRUPTIBLE); + SLEEP_ON_VAR + + current->state = TASK_UNINTERRUPTIBLE; + + SLEEP_ON_HEAD + schedule(); + SLEEP_ON_TAIL } void scheduling_functions_end_here(void) { } @@ -803,7 +872,7 @@ break; if (!(mask & timer_active)) continue; - if (tp->expires > jiffies) + if (time_after(tp->expires, jiffies)) continue; timer_active &= ~mask; tp->fn(); @@ -1488,7 +1557,8 @@ { spin_lock(&scheduler_lock); spin_lock_irq(&runqueue_lock); - current->policy |= SCHED_YIELD; + if (current->policy == SCHED_OTHER) + current->policy |= SCHED_YIELD; current->need_resched = 1; move_last_runqueue(current); spin_unlock_irq(&runqueue_lock); @@ -1563,16 +1633,14 @@ return 0; } - expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec) + jiffies; + expire = timespec_to_jiffies(&t) + (t.tv_sec || t.tv_nsec); - current->timeout = expire; current->state = TASK_INTERRUPTIBLE; - schedule(); + expire = schedule_timeout(expire); - if (expire > jiffies) { + if (expire) { if (rmtp) { - jiffies_to_timespec(expire - jiffies - - (expire > jiffies + 1), &t); + jiffies_to_timespec(expire, &t); if (copy_to_user(rmtp, &t, sizeof(struct timespec))) return -EFAULT; } diff -u --recursive --new-file v2.1.126/linux/kernel/signal.c linux/kernel/signal.c --- v2.1.126/linux/kernel/signal.c Thu Sep 17 17:53:39 1998 +++ linux/kernel/signal.c Sat Oct 31 10:17:21 1998 @@ -712,6 +712,7 @@ sigset_t these; struct timespec ts; siginfo_t info; + long timeout = 0; /* XXX: Don't preclude handling different sized sigset_t's. */ if (sigsetsize != sizeof(sigset_t)) @@ -738,22 +739,18 @@ if (!sig) { /* None ready -- temporarily unblock those we're interested in so that we'll be awakened when they arrive. */ - unsigned long expire; sigset_t oldblocked = current->blocked; sigandsets(¤t->blocked, ¤t->blocked, &these); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - expire = ~0UL; - if (uts) { - expire = (timespec_to_jiffies(&ts) - + (ts.tv_sec || ts.tv_nsec)); - expire += jiffies; - } - current->timeout = expire; + timeout = MAX_SCHEDULE_TIMEOUT; + if (uts) + timeout = (timespec_to_jiffies(&ts) + + (ts.tv_sec || ts.tv_nsec)); current->state = TASK_INTERRUPTIBLE; - schedule(); + timeout = schedule_timeout(timeout); spin_lock_irq(¤t->sigmask_lock); sig = dequeue_signal(&these, &info); @@ -770,10 +767,8 @@ } } else { ret = -EAGAIN; - if (current->timeout != 0) { - current->timeout = 0; + if (timeout) ret = -EINTR; - } } return ret; diff -u --recursive --new-file v2.1.126/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.126/linux/kernel/sysctl.c Mon Oct 5 13:13:47 1998 +++ linux/kernel/sysctl.c Wed Nov 4 10:00:50 1998 @@ -38,7 +38,7 @@ /* External variables not in a header file. */ extern int panic_timeout; -extern int console_loglevel, C_A_D, swapout_interval; +extern int console_loglevel, C_A_D; extern int bdf_prm[], bdflush_min[], bdflush_max[]; extern char binfmt_java_interpreter[], binfmt_java_appletviewer[]; extern int sysctl_overcommit_memory; @@ -199,8 +199,6 @@ static ctl_table vm_table[] = { {VM_SWAPCTL, "swapctl", &swap_control, sizeof(swap_control_t), 0644, NULL, &proc_dointvec}, - {VM_SWAPOUT, "swapout_interval", - &swapout_interval, sizeof(int), 0644, NULL, &proc_dointvec}, {VM_FREEPG, "freepages", &freepages, sizeof(freepages_t), 0644, NULL, &proc_dointvec}, {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL, diff -u --recursive --new-file v2.1.126/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.126/linux/mm/filemap.c Fri Oct 23 22:01:27 1998 +++ linux/mm/filemap.c Tue Nov 3 08:39:50 1998 @@ -293,7 +293,7 @@ struct page **hash) { atomic_inc(&page->count); - page->flags &= ~((1 << PG_uptodate) | (1 << PG_error)); + page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced); page->offset = offset; add_page_to_inode_queue(inode, page); __add_page_to_hash_queue(page, hash); @@ -314,7 +314,7 @@ offset &= PAGE_MASK; switch (page_cache) { case 0: - page_cache = __get_free_page(GFP_KERNEL); + page_cache = __get_free_page(GFP_USER); if (!page_cache) break; default: @@ -328,7 +328,6 @@ */ page = mem_map + MAP_NR(page_cache); add_to_page_cache(page, inode, offset, hash); - set_bit(PG_referenced, &page->flags); inode->i_op->readpage(file, page); page_cache = 0; } @@ -737,7 +736,7 @@ * page.. */ if (!page_cache) { - page_cache = __get_free_page(GFP_KERNEL); + page_cache = __get_free_page(GFP_USER); /* * That could have slept, so go around to the * very beginning.. @@ -1003,7 +1002,7 @@ * extra page -- better to overlap the allocation with the I/O. */ if (no_share && !new_page) { - new_page = __get_free_page(GFP_KERNEL); + new_page = __get_free_page(GFP_USER); if (!new_page) goto failure; } @@ -1040,7 +1039,7 @@ return new_page; no_cached_page: - new_page = __get_free_page(GFP_KERNEL); + new_page = __get_free_page(GFP_USER); if (!new_page) goto no_page; @@ -1570,7 +1569,7 @@ hash = page_hash(inode, pgpos); if (!(page = __find_page(inode, pgpos, *hash))) { if (!page_cache) { - page_cache = __get_free_page(GFP_KERNEL); + page_cache = __get_free_page(GFP_USER); if (page_cache) continue; status = -ENOMEM; diff -u --recursive --new-file v2.1.126/linux/mm/memory.c linux/mm/memory.c --- v2.1.126/linux/mm/memory.c Fri Oct 23 22:01:27 1998 +++ linux/mm/memory.c Fri Nov 6 17:40:21 1998 @@ -629,7 +629,7 @@ * change only once the write actually happens. This avoids a few races, * and potentially makes it more efficient. */ -static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, +static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, pte_t *page_table) { pte_t pte; @@ -637,7 +637,7 @@ struct page * page_map; pte = *page_table; - new_page = __get_free_page(GFP_KERNEL); + new_page = __get_free_page(GFP_USER); /* Did someone else copy this page for us while we slept? */ if (pte_val(*page_table) != pte_val(pte)) goto end_wp_page; @@ -655,40 +655,42 @@ * Do we need to copy? */ if (is_page_shared(page_map)) { - if (new_page) { - if (PageReserved(mem_map + MAP_NR(old_page))) - ++vma->vm_mm->rss; - copy_cow_page(old_page,new_page); - flush_page_to_ram(old_page); - flush_page_to_ram(new_page); - flush_cache_page(vma, address); - set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); - free_page(old_page); - flush_tlb_page(vma, address); - return; - } + unlock_kernel(); + if (!new_page) + return 0; + + if (PageReserved(mem_map + MAP_NR(old_page))) + ++vma->vm_mm->rss; + copy_cow_page(old_page,new_page); + flush_page_to_ram(old_page); + flush_page_to_ram(new_page); flush_cache_page(vma, address); - set_pte(page_table, BAD_PAGE); - flush_tlb_page(vma, address); + set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); free_page(old_page); - oom(tsk); - return; + flush_tlb_page(vma, address); + return 1; } + if (PageSwapCache(page_map)) delete_from_swap_cache(page_map); + + /* We can release the kernel lock now.. */ + unlock_kernel(); + flush_cache_page(vma, address); set_pte(page_table, pte_mkdirty(pte_mkwrite(pte))); flush_tlb_page(vma, address); +end_wp_page: if (new_page) free_page(new_page); - return; + return 1; + bad_wp_page: printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page); send_sig(SIGKILL, tsk, 1); -end_wp_page: if (new_page) free_page(new_page); - return; + return 0; } /* @@ -777,30 +779,53 @@ } -static inline void do_swap_page(struct task_struct * tsk, +/* + * This is called with the kernel lock held, we need + * to return without it. + */ +static int do_swap_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, pte_t * page_table, pte_t entry, int write_access) { - pte_t page; - if (!vma->vm_ops || !vma->vm_ops->swapin) { swap_in(tsk, vma, page_table, pte_val(entry), write_access); flush_page_to_ram(pte_page(*page_table)); - return; + } else { + pte_t page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry)); + if (pte_val(*page_table) != pte_val(entry)) { + free_page(pte_page(page)); + } else { + if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 && + !(vma->vm_flags & VM_SHARED)) + page = pte_wrprotect(page); + ++vma->vm_mm->rss; + ++tsk->maj_flt; + flush_page_to_ram(pte_page(page)); + set_pte(page_table, page); + } } - page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry)); - if (pte_val(*page_table) != pte_val(entry)) { - free_page(pte_page(page)); - return; + unlock_kernel(); + return 1; +} + +/* + * This only needs the MM semaphore + */ +static int do_anonymous_page(struct task_struct * tsk, struct vm_area_struct * vma, pte_t *page_table, int write_access) +{ + pte_t entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); + if (write_access) { + unsigned long page = __get_free_page(GFP_USER); + if (!page) + return 0; + clear_page(page); + entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + vma->vm_mm->rss++; + tsk->min_flt++; + flush_page_to_ram(page); } - if (atomic_read(&mem_map[MAP_NR(pte_page(page))].count) > 1 && - !(vma->vm_flags & VM_SHARED)) - page = pte_wrprotect(page); - ++vma->vm_mm->rss; - ++tsk->maj_flt; - flush_page_to_ram(pte_page(page)); - set_pte(page_table, page); - return; + put_page(page_table, entry); + return 1; } /* @@ -811,26 +836,33 @@ * * As this is called only for pages that do not currently exist, we * do not need to flush old virtual caches or the TLB. + * + * This is called with the MM semaphore and the kernel lock held. + * We need to release the kernel lock as soon as possible.. */ -static void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, - unsigned long address, int write_access, pte_t *page_table, pte_t entry) +static int do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, + unsigned long address, int write_access, pte_t *page_table) { unsigned long page; + pte_t entry; + + if (!vma->vm_ops || !vma->vm_ops->nopage) { + unlock_kernel(); + return do_anonymous_page(tsk, vma, page_table, write_access); + } - if (!pte_none(entry)) - goto swap_page; - address &= PAGE_MASK; - if (!vma->vm_ops || !vma->vm_ops->nopage) - goto anonymous_page; /* * The third argument is "no_share", which tells the low-level code * to copy, not share the page even if sharing is possible. It's - * essentially an early COW detection + * essentially an early COW detection. */ - page = vma->vm_ops->nopage(vma, address, + page = vma->vm_ops->nopage(vma, address & PAGE_MASK, (vma->vm_flags & VM_SHARED)?0:write_access); + + unlock_kernel(); if (!page) - goto sigbus; + return 0; + ++tsk->maj_flt; ++vma->vm_mm->rss; /* @@ -852,32 +884,7 @@ entry = pte_wrprotect(entry); put_page(page_table, entry); /* no need to invalidate: a not-present page shouldn't be cached */ - return; - -anonymous_page: - entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); - if (write_access) { - unsigned long page = __get_free_page(GFP_KERNEL); - if (!page) - goto sigbus; - clear_page(page); - entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - vma->vm_mm->rss++; - tsk->min_flt++; - flush_page_to_ram(page); - } - put_page(page_table, entry); - return; - -sigbus: - force_sig(SIGBUS, current); - put_page(page_table, BAD_PAGE); - /* no need to invalidate, wasn't present */ - return; - -swap_page: - do_swap_page(tsk, vma, address, page_table, entry, write_access); - return; + return 1; } /* @@ -889,54 +896,57 @@ * with external mmu caches can use to update those (ie the Sparc or * PowerPC hashed page tables that act as extended TLBs). */ -static inline void handle_pte_fault(struct task_struct *tsk, +static inline int handle_pte_fault(struct task_struct *tsk, struct vm_area_struct * vma, unsigned long address, int write_access, pte_t * pte) { - pte_t entry = *pte; + pte_t entry; + + lock_kernel(); + entry = *pte; if (!pte_present(entry)) { - do_no_page(tsk, vma, address, write_access, pte, entry); - return; + if (pte_none(entry)) + return do_no_page(tsk, vma, address, write_access, pte); + return do_swap_page(tsk, vma, address, pte, entry, write_access); } + entry = pte_mkyoung(entry); set_pte(pte, entry); flush_tlb_page(vma, address); - if (!write_access) - return; - if (pte_write(entry)) { + if (write_access) { + if (!pte_write(entry)) + return do_wp_page(tsk, vma, address, pte); + entry = pte_mkdirty(entry); set_pte(pte, entry); flush_tlb_page(vma, address); - return; } - do_wp_page(tsk, vma, address, pte); + unlock_kernel(); + return 1; } /* * By the time we get here, we already hold the mm semaphore */ -void handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma, +int handle_mm_fault(struct task_struct *tsk, struct vm_area_struct * vma, unsigned long address, int write_access) { pgd_t *pgd; pmd_t *pmd; - pte_t *pte; pgd = pgd_offset(vma->vm_mm, address); pmd = pmd_alloc(pgd, address); - if (!pmd) - goto no_memory; - pte = pte_alloc(pmd, address); - if (!pte) - goto no_memory; - lock_kernel(); - handle_pte_fault(tsk, vma, address, write_access, pte); - unlock_kernel(); - update_mmu_cache(vma, address, *pte); - return; -no_memory: - oom(tsk); + if (pmd) { + pte_t * pte = pte_alloc(pmd, address); + if (pte) { + if (handle_pte_fault(tsk, vma, address, write_access, pte)) { + update_mmu_cache(vma, address, *pte); + return 1; + } + } + } + return 0; } /* diff -u --recursive --new-file v2.1.126/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.126/linux/mm/mmap.c Wed Aug 26 11:37:45 1998 +++ linux/mm/mmap.c Thu Oct 29 22:35:02 1998 @@ -93,7 +93,21 @@ struct mm_struct *mm = current->mm; down(&mm->mmap_sem); + + /* + * This lock-kernel is one of the main contention points for + * certain normal loads. And it really should not be here: almost + * everything in brk()/mmap()/munmap() is protected sufficiently by + * the mmap semaphore that we got above. + * + * We should move this into the few things that really want the + * lock, namely anything that actually touches a file descriptor + * etc. We can do all the normal anonymous mapping cases without + * ever getting the lock at all - the actual memory management + * code is already completely thread-safe. + */ lock_kernel(); + if (brk < mm->end_code) goto out; newbrk = PAGE_ALIGN(brk); diff -u --recursive --new-file v2.1.126/linux/mm/page_alloc.c linux/mm/page_alloc.c --- v2.1.126/linux/mm/page_alloc.c Fri Oct 23 22:01:27 1998 +++ linux/mm/page_alloc.c Thu Oct 29 12:53:39 1998 @@ -268,14 +268,15 @@ spin_unlock_irqrestore(&page_alloc_lock, flags); /* - * If we failed to find anything, we'll return NULL, but we'll - * wake up kswapd _now_ ad even wait for it synchronously if - * we can.. This way we'll at least make some forward progress - * over time. + * If we can schedule, do so, and make sure to yield. + * We may be a real-time process, and if kswapd is + * waiting for us we need to allow it to run a bit. */ - wake_up(&kswapd_wait); - if (gfp_mask & __GFP_WAIT) + if (gfp_mask & __GFP_WAIT) { + current->policy |= SCHED_YIELD; schedule(); + } + nopage: return 0; } diff -u --recursive --new-file v2.1.126/linux/mm/slab.c linux/mm/slab.c --- v2.1.126/linux/mm/slab.c Fri Oct 23 22:01:27 1998 +++ linux/mm/slab.c Wed Nov 4 14:17:45 1998 @@ -650,9 +650,9 @@ } slabp->s_magic = SLAB_MAGIC_DESTROYED; - kmem_freepages(cachep, slabp->s_mem-slabp->s_offset); if (slabp->s_index) kmem_cache_free(cachep->c_index_cachep, slabp->s_index); + kmem_freepages(cachep, slabp->s_mem-slabp->s_offset); if (SLAB_OFF_SLAB(cachep->c_flags)) kmem_cache_free(cache_slabp, slabp); } @@ -1190,7 +1190,6 @@ cachep->c_dflags = SLAB_CFLGS_GROWN; cachep->c_growing++; -re_try: spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); /* A series of memory allocations for a new slab. @@ -1257,15 +1256,6 @@ kmem_freepages(cachep, objp); failed: spin_lock_irq(&cachep->c_spinlock); - if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) { - /* For large order (>0) slabs, we try again. - * Needed because the gfp() functions are not good at giving - * out contiguous pages unless pushed (but do not push too hard). - */ - if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep)) - goto re_try; - cachep->c_failures = 1; /* Memory is low, don't try as hard next time. */ - } cachep->c_growing--; spin_unlock_irqrestore(&cachep->c_spinlock, save_flags); return 0; diff -u --recursive --new-file v2.1.126/linux/mm/swapfile.c linux/mm/swapfile.c --- v2.1.126/linux/mm/swapfile.c Wed Sep 9 14:51:13 1998 +++ linux/mm/swapfile.c Thu Oct 29 09:38:24 1998 @@ -559,8 +559,17 @@ if (p->swap_device == swap_info[i].swap_device) goto bad_swap; } - } else if (!S_ISREG(swap_dentry->d_inode->i_mode)) + } else if (S_ISREG(swap_dentry->d_inode->i_mode)) { + error = -EBUSY; + for (i = 0 ; i < nr_swapfiles ; i++) { + if (i == type) + continue; + if (p->swap_file == swap_info[i].swap_file) + goto bad_swap; + } + } else goto bad_swap; + swap_header = (void *) __get_free_page(GFP_USER); if (!swap_header) { printk("Unable to start swapping: out of memory :-)\n"); diff -u --recursive --new-file v2.1.126/linux/mm/vmscan.c linux/mm/vmscan.c --- v2.1.126/linux/mm/vmscan.c Fri Oct 23 22:01:27 1998 +++ linux/mm/vmscan.c Fri Nov 6 17:16:48 1998 @@ -29,20 +29,9 @@ #include /* - * When are we next due for a page scan? - */ -static unsigned long next_swap_jiffies = 0; - -/* - * How often do we do a pageout scan during normal conditions? - * Default is four times a second. - */ -int swapout_interval = HZ / 4; - -/* * The wait queue for waking up the pageout daemon: */ -struct wait_queue * kswapd_wait = NULL; +static struct task_struct * kswapd_task = NULL; static void init_swap_timer(void); @@ -123,8 +112,13 @@ } if (pte_young(pte)) { + /* + * Transfer the "accessed" bit from the page + * tables to the global page map. + */ set_pte(page_table, pte_mkold(pte)); - touch_page(page_map); + set_bit(PG_referenced, &page_map->flags); + /* * We should test here to see if we want to recover any * swap cache page here. We do this if the page seeing @@ -137,10 +131,6 @@ return 0; } - age_page(page_map); - if (page_map->age) - return 0; - if (pte_dirty(pte)) { if (vma->vm_ops && vma->vm_ops->swapout) { pid_t pid = tsk->pid; @@ -310,8 +300,9 @@ } static int swap_out_vma(struct task_struct * tsk, struct vm_area_struct * vma, - pgd_t *pgdir, unsigned long start, int gfp_mask) + unsigned long address, int gfp_mask) { + pgd_t *pgdir; unsigned long end; /* Don't swap out areas like shared memory which have their @@ -319,12 +310,14 @@ if (vma->vm_flags & (VM_SHM | VM_LOCKED)) return 0; + pgdir = pgd_offset(tsk->mm, address); + end = vma->vm_end; - while (start < end) { - int result = swap_out_pgd(tsk, vma, pgdir, start, end, gfp_mask); + while (address < end) { + int result = swap_out_pgd(tsk, vma, pgdir, address, end, gfp_mask); if (result) return result; - start = (start + PGDIR_SIZE) & PGDIR_MASK; + address = (address + PGDIR_SIZE) & PGDIR_MASK; pgdir++; } return 0; @@ -344,22 +337,23 @@ * Find the proper vm-area */ vma = find_vma(p->mm, address); - if (!vma) { - p->swap_address = 0; - return 0; + if (vma) { + if (address < vma->vm_start) + address = vma->vm_start; + + for (;;) { + int result = swap_out_vma(p, vma, address, gfp_mask); + if (result) + return result; + vma = vma->vm_next; + if (!vma) + break; + address = vma->vm_start; + } } - if (address < vma->vm_start) - address = vma->vm_start; - for (;;) { - int result = swap_out_vma(p, vma, pgd_offset(p->mm, address), address, gfp_mask); - if (result) - return result; - vma = vma->vm_next; - if (!vma) - break; - address = vma->vm_start; - } + /* We didn't find anything for the process */ + p->swap_cnt = 0; p->swap_address = 0; return 0; } @@ -420,20 +414,12 @@ } pbest->swap_cnt--; - switch (swap_out_process(pbest, gfp_mask)) { - case 0: - /* - * Clear swap_cnt so we don't look at this task - * again until we've tried all of the others. - * (We didn't block, so the task is still here.) - */ - pbest->swap_cnt = 0; - break; - case 1: - return 1; - default: - break; - }; + /* + * Nonzero means we cleared out something, but only "1" means + * that we actually free'd up a page as a result. + */ + if (swap_out_process(pbest, gfp_mask) == 1) + return 1; } out: return 0; @@ -448,16 +434,10 @@ { static int state = 0; int i=6; - int stop; /* Always trim SLAB caches when memory gets low. */ kmem_cache_reap(gfp_mask); - /* We try harder if we are waiting .. */ - stop = 3; - if (gfp_mask & __GFP_WAIT) - stop = 0; - if (buffer_over_borrow() || pgcache_over_borrow()) shrink_mmap(i, gfp_mask); @@ -479,7 +459,7 @@ shrink_dcache_memory(i, gfp_mask); state = 0; i--; - } while ((i - stop) >= 0); + } while (i >= 0); } return 0; } @@ -509,8 +489,6 @@ */ int kswapd(void *unused) { - struct wait_queue wait = { current, NULL }; - current->session = 1; current->pgrp = 1; strcpy(current->comm, "kswapd"); @@ -523,11 +501,12 @@ */ lock_kernel(); - /* Give kswapd a realtime priority. */ - current->policy = SCHED_FIFO; - current->rt_priority = 32; /* Fixme --- we need to standardise our - namings for POSIX.4 realtime scheduling - priorities. */ + /* + * Set the base priority to something smaller than a + * regular process. We will scale up the priority + * dynamically depending on how much memory we need. + */ + current->priority = (DEF_PRIORITY * 2) / 3; /* * Tell the memory management that we're a "memory allocator", @@ -544,9 +523,9 @@ current->flags |= PF_MEMALLOC; init_swap_timer(); - add_wait_queue(&kswapd_wait, &wait); + kswapd_task = current; while (1) { - int tries; + unsigned long end_time; current->state = TASK_INTERRUPTIBLE; flush_signals(current); @@ -554,39 +533,15 @@ schedule(); swapstats.wakeups++; - /* - * Do the background pageout: be - * more aggressive if we're really - * low on free memory. - * - * We try page_daemon.tries_base times, divided by - * an 'urgency factor'. In practice this will mean - * a value of pager_daemon.tries_base / 8 or 4 = 64 - * or 128 pages at a time. - * This gives us 64 (or 128) * 4k * 4 (times/sec) = - * 1 (or 2) MB/s swapping bandwidth in low-priority - * background paging. This number rises to 8 MB/s - * when the priority is highest (but then we'll be - * woken up more often and the rate will be even - * higher). - */ - tries = pager_daemon.tries_base; - tries >>= 4*free_memory_available(); - + /* max one hundreth of a second */ + end_time = jiffies + (HZ-1)/100; do { - do_try_to_free_page(0); - /* - * Syncing large chunks is faster than swapping - * synchronously (less head movement). -- Rik. - */ - if (atomic_read(&nr_async_pages) >= pager_daemon.swap_cluster) - run_task_queue(&tq_disk); - if (free_memory_available() > 1) + if (!do_try_to_free_page(0)) break; - } while (--tries > 0); + } while (time_before_eq(jiffies,end_time)); } /* As if we could ever get here - maybe we want to make this killable */ - remove_wait_queue(&kswapd_wait, &wait); + kswapd_task = NULL; unlock_kernel(); return 0; } @@ -620,41 +575,63 @@ return retval; } +/* + * Wake up kswapd according to the priority + * 0 - no wakeup + * 1 - wake up as a low-priority process + * 2 - wake up as a normal process + * 3 - wake up as an almost real-time process + * + * This plays mind-games with the "goodness()" + * function in kernel/sched.c. + */ +static inline void kswapd_wakeup(struct task_struct *p, int priority) +{ + if (priority) { + p->counter = p->priority << priority; + wake_up_process(p); + } +} + /* * The swap_tick function gets called on every clock tick. */ void swap_tick(void) { - unsigned long now, want; - int want_wakeup = 0; - - want = next_swap_jiffies; - now = jiffies; + struct task_struct *p = kswapd_task; /* - * Examine the memory queues. Mark memory low - * if there is nothing available in the three - * highest queues. - * - * Schedule for wakeup if there isn't lots - * of free memory. + * Only bother to try to wake kswapd up + * if the task exists and can be woken. */ - switch (free_memory_available()) { - case 0: - want = now; - /* Fall through */ - case 1: - want_wakeup = 1; - default: - } - - if ((long) (now - want) >= 0) { - if (want_wakeup || buffer_over_max() || pgcache_over_max()) { - /* Set the next wake-up time */ - next_swap_jiffies = now + swapout_interval; - kswapd_wakeup(); - } + if (p && (p->state & TASK_INTERRUPTIBLE)) { + unsigned int pages; + int want_wakeup; + + /* + * Schedule for wakeup if there isn't lots + * of free memory or if there is too much + * of it used for buffers or pgcache. + * + * "want_wakeup" is our priority: 0 means + * not to wake anything up, while 3 means + * that we'd better give kswapd a realtime + * priority. + */ + want_wakeup = 0; + if (buffer_over_max() || pgcache_over_max()) + want_wakeup = 1; + pages = nr_free_pages; + if (pages < freepages.high) + want_wakeup = 1; + if (pages < freepages.low) + want_wakeup = 2; + if (pages < freepages.min) + want_wakeup = 3; + + kswapd_wakeup(p,want_wakeup); } + timer_active |= (1<timeout = jiffies + (HZ/10); current->state = TASK_INTERRUPTIBLE; - schedule(); + schedule_timeout(HZ/10); if(atif->status & ATIF_PROBE_FAIL) break; } diff -u --recursive --new-file v2.1.126/linux/net/core/dev.c linux/net/core/dev.c --- v2.1.126/linux/net/core/dev.c Sat Sep 5 16:46:42 1998 +++ linux/net/core/dev.c Sat Nov 7 11:00:32 1998 @@ -1375,7 +1375,7 @@ */ dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_RUNNING|IFF_NOARP| - IFF_NODYNARP|IFF_SLAVE|IFF_MASTER| + IFF_SLAVE|IFF_MASTER|IFF_DYNAMIC| IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) | (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI)); diff -u --recursive --new-file v2.1.126/linux/net/core/scm.c linux/net/core/scm.c --- v2.1.126/linux/net/core/scm.c Sat Sep 5 16:46:42 1998 +++ linux/net/core/scm.c Tue Oct 27 09:57:19 1998 @@ -103,7 +103,6 @@ void __scm_destroy(struct scm_cookie *scm) { struct scm_fp_list *fpl = scm->fp; - struct file *file; int i; if (fpl) { @@ -112,34 +111,18 @@ fput(fpl->fp[i]); kfree(fpl); } - - file = scm->file; - if (file) { - scm->sock = NULL; - scm->file = NULL; - fput(file); - } -} - - - -extern __inline__ int not_one_bit(unsigned val) -{ - return (val-1) & val; } - int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) { struct cmsghdr *cmsg; - struct file *file; - int acc_fd, err; - unsigned int scm_flags=0; + int err; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { err = -EINVAL; + /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ if ((unsigned long)(((char*)cmsg - (char*)msg->msg_control) + cmsg->cmsg_len) > msg->msg_controllen) goto error; @@ -162,30 +145,6 @@ if (err) goto error; break; - case SCM_CONNECT: - if (scm_flags) - goto error; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) - goto error; - memcpy(&acc_fd, CMSG_DATA(cmsg), sizeof(int)); - p->sock = NULL; - if (acc_fd != -1) { - err = -EBADF; - file = fget(acc_fd); - if (!file) - goto error; - p->file = file; - err = -ENOTSOCK; - if (!file->f_dentry->d_inode || - !file->f_dentry->d_inode->i_sock) - goto error; - p->sock = &file->f_dentry->d_inode->u.socket_i; - err = -EINVAL; - if (p->sock->state != SS_UNCONNECTED) - goto error; - } - scm_flags |= MSG_SYN; - break; default: goto error; } @@ -196,16 +155,13 @@ kfree(p->fp); p->fp = NULL; } - - err = -EINVAL; - msg->msg_flags |= scm_flags; - scm_flags = msg->msg_flags&MSG_CTLFLAGS; - if (not_one_bit(scm_flags)) - goto error; - if (!(scm_flags && p->fp)) - return 0; + err = -EINVAL; + if (msg->msg_flags & MSG_CTLFLAGS) + goto error; + return 0; + error: scm_destroy(p); return err; diff -u --recursive --new-file v2.1.126/linux/net/core/sock.c linux/net/core/sock.c --- v2.1.126/linux/net/core/sock.c Mon Oct 5 13:13:47 1998 +++ linux/net/core/sock.c Sat Nov 7 11:00:32 1998 @@ -7,7 +7,7 @@ * handler for protocols to use and generic option handler. * * - * Version: $Id: sock.c,v 1.73 1998/10/03 16:08:10 freitag Exp $ + * Version: $Id: sock.c,v 1.75 1998/11/07 10:54:38 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -294,6 +294,10 @@ { char devname[IFNAMSIZ]; + /* Sorry... */ + if (!capable(CAP_NET_RAW)) + return -EPERM; + /* Bind this socket to a particular device like "eth0", * as specified in the passed interface name. If the * name is "" or the option length is zero the socket @@ -965,8 +969,7 @@ void sock_def_error_report(struct sock *sk) { - if (!sk->dead) - { + if (!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,0); } @@ -974,8 +977,7 @@ void sock_def_readable(struct sock *sk, int len) { - if(!sk->dead) - { + if(!sk->dead) { wake_up_interruptible(sk->sleep); sock_wake_async(sk->socket,1); } @@ -983,11 +985,14 @@ void sock_def_write_space(struct sock *sk) { - if(!sk->dead) - { + /* Do not wake up a writer until he can make "significant" + * progress. --DaveM + */ + if(!sk->dead && + ((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf)) { wake_up_interruptible(sk->sleep); - /* Should agree with poll, otherwise some programs break */ + /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) sock_wake_async(sk->socket, 2); } diff -u --recursive --new-file v2.1.126/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c --- v2.1.126/linux/net/core/sysctl_net_core.c Mon Oct 5 13:13:47 1998 +++ linux/net/core/sysctl_net_core.c Sat Nov 7 11:00:32 1998 @@ -25,6 +25,7 @@ extern int sysctl_optmem_max; ctl_table core_table[] = { +#ifdef CONFIG_NET {NET_CORE_WMEM_MAX, "wmem_max", &sysctl_wmem_max, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -54,6 +55,7 @@ {NET_CORE_OPTMEM_MAX, "optmem_max", &sysctl_optmem_max, sizeof(int), 0644, NULL, &proc_dointvec}, +#endif /* CONFIG_NET */ { 0 } }; #endif diff -u --recursive --new-file v2.1.126/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v2.1.126/linux/net/ipv4/af_inet.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/af_inet.c Tue Nov 3 12:20:11 1998 @@ -464,7 +464,7 @@ struct sock *sk = sock->sk; if (sk) { - unsigned long timeout; + long timeout; /* Begin closedown and wake up sleepers. */ if (sock->state != SS_UNCONNECTED) @@ -483,11 +483,11 @@ */ timeout = 0; if (sk->linger && !(current->flags & PF_EXITING)) { - timeout = ~0UL; + timeout = MAX_SCHEDULE_TIMEOUT; /* XXX This makes no sense whatsoever... -DaveM */ if (!sk->lingertime) - timeout = jiffies + HZ*sk->lingertime; + timeout = HZ*sk->lingertime; } sock->sk = NULL; sk->socket = NULL; diff -u --recursive --new-file v2.1.126/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v2.1.126/linux/net/ipv4/arp.c Fri Oct 9 13:27:17 1998 +++ linux/net/ipv4/arp.c Sat Nov 7 11:00:32 1998 @@ -1,6 +1,6 @@ /* linux/net/inet/arp.c * - * Version: $Id: arp.c,v 1.70 1998/08/26 12:03:18 davem Exp $ + * Version: $Id: arp.c,v 1.74 1998/11/01 22:15:06 davem Exp $ * * Copyright (C) 1994 by Florian La Roche * @@ -431,7 +431,7 @@ * No arp on this interface. */ - if (dev->flags&(IFF_NOARP|IFF_NODYNARP)) + if (dev->flags&IFF_NOARP) return; /* @@ -547,7 +547,7 @@ */ if (in_dev == NULL || arp->ar_hln != dev->addr_len || - dev->flags & (IFF_NOARP|IFF_NODYNARP) || + dev->flags & IFF_NOARP || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || arp->ar_pln != 4) @@ -1027,7 +1027,7 @@ "%-17s0x%-10x0x%-10x%s", in_ntoa(*(u32*)n->key), hatype, - ATF_PUBL|ATF_PERM, + ATF_PUBL|ATF_PERM, "00:00:00:00:00:00"); size += sprintf(buffer+len+size, " %-17s %s\n", diff -u --recursive --new-file v2.1.126/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v2.1.126/linux/net/ipv4/icmp.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/icmp.c Tue Oct 27 09:57:19 1998 @@ -3,7 +3,7 @@ * * Alan Cox, * - * Version: $Id: icmp.c,v 1.46 1998/10/03 09:37:15 davem Exp $ + * Version: $Id: icmp.c,v 1.47 1998/10/21 05:32:24 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -359,6 +359,11 @@ * This function is generic and could be used for other purposes * too. It uses a Token bucket filter as suggested by Alexey Kuznetsov. * + * Note that the same dst_entry fields are modified by functions in + * route.c too, but these work for packet destinations while xrlim_allow + * works for icmp destinations. This means the rate limiting information + * for one "ip object" is shared. + * * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate * SHOULD allow setting of rate limits * @@ -374,6 +379,7 @@ if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout) dst->rate_tokens = XRLIM_BURST_FACTOR*timeout; if (dst->rate_tokens >= timeout) { + dst->rate_last = now; dst->rate_tokens -= timeout; return 1; } diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c --- v2.1.126/linux/net/ipv4/ip_masq.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/ip_masq.c Sat Nov 7 11:00:32 1998 @@ -4,7 +4,7 @@ * * Copyright (c) 1994 Pauline Middelink * - * $Id: ip_masq.c,v 1.26 1998/09/24 03:38:58 davem Exp $ + * $Id: ip_masq.c,v 1.27 1998/11/07 14:59:24 davem Exp $ * * * See ip_fw.c for original log @@ -1011,14 +1011,19 @@ switch (skb->ip_summed) { case CHECKSUM_NONE: + { + int datasz; doff = proto_doff(iph->protocol, h.raw); - csum = csum_partial(h.raw + doff, size - doff, 0); + datasz = size - doff; + if (datasz < 0) + return -1; + csum = csum_partial(h.raw + doff, datasz, 0); IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n", masq_proto_name(iph->protocol), csum); skb->csum = csum_partial(h.raw , doff, csum); - + } case CHECKSUM_HW: if (csum_tcpudp_magic(iph->saddr, iph->daddr, size, iph->protocol, skb->csum)) diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_cuseeme.c linux/net/ipv4/ip_masq_cuseeme.c --- v2.1.126/linux/net/ipv4/ip_masq_cuseeme.c Fri Oct 9 13:27:17 1998 +++ linux/net/ipv4/ip_masq_cuseeme.c Tue Oct 27 09:57:19 1998 @@ -2,7 +2,7 @@ * IP_MASQ_FTP CUSeeMe masquerading module * * - * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.3 1998/08/29 23:51:18 davem Exp $ + * Version: @(#)$Id: ip_masq_cuseeme.c,v 1.4 1998/10/06 04:48:57 davem Exp $ * * Author: Richard Lynch * diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_raudio.c linux/net/ipv4/ip_masq_raudio.c --- v2.1.126/linux/net/ipv4/ip_masq_raudio.c Fri Oct 9 13:27:17 1998 +++ linux/net/ipv4/ip_masq_raudio.c Tue Oct 27 09:57:19 1998 @@ -2,7 +2,7 @@ * IP_MASQ_RAUDIO - Real Audio masquerading module * * - * Version: @(#)$Id: ip_masq_raudio.c,v 1.10 1998/08/29 23:51:17 davem Exp $ + * Version: @(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $ * * Author: Nigel Metheringham * Real Time Streaming code by Progressive Networks diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_masq_vdolive.c linux/net/ipv4/ip_masq_vdolive.c --- v2.1.126/linux/net/ipv4/ip_masq_vdolive.c Fri Oct 9 13:27:17 1998 +++ linux/net/ipv4/ip_masq_vdolive.c Tue Oct 27 09:57:19 1998 @@ -2,7 +2,7 @@ * IP_MASQ_VDOLIVE - VDO Live masquerading module * * - * Version: @(#)$Id: ip_masq_vdolive.c,v 1.3 1998/08/29 23:51:18 davem Exp $ + * Version: @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $ * * Author: Nigel Metheringham * PLAnet Online Ltd diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c --- v2.1.126/linux/net/ipv4/ip_nat_dumb.c Fri Oct 9 13:27:17 1998 +++ linux/net/ipv4/ip_nat_dumb.c Tue Oct 27 09:57:19 1998 @@ -5,7 +5,7 @@ * * Dumb Network Address Translation. * - * Version: $Id: ip_nat_dumb.c,v 1.6 1998/10/03 09:37:25 davem Exp $ + * Version: $Id: ip_nat_dumb.c,v 1.7 1998/10/06 04:49:09 davem Exp $ * * Authors: Alexey Kuznetsov, * diff -u --recursive --new-file v2.1.126/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.1.126/linux/net/ipv4/ipconfig.c Tue Jul 28 14:21:10 1998 +++ linux/net/ipv4/ipconfig.c Tue Oct 27 09:57:19 1998 @@ -1,5 +1,5 @@ /* - * $Id: ipconfig.c,v 1.15 1998/06/19 13:22:33 davem Exp $ + * $Id: ipconfig.c,v 1.16 1998/10/21 22:27:26 davem Exp $ * * Automatic Configuration of IP -- use BOOTP or RARP or user-supplied * information to configure own IP address and routes. @@ -260,12 +260,12 @@ root_server_addr = ic_servaddr; if (ic_netmask == INADDR_NONE) { - if (IN_CLASSA(ic_myaddr)) - ic_netmask = IN_CLASSA_NET; - else if (IN_CLASSB(ic_myaddr)) - ic_netmask = IN_CLASSB_NET; - else if (IN_CLASSC(ic_myaddr)) - ic_netmask = IN_CLASSC_NET; + if (IN_CLASSA(ntohl(ic_myaddr))) + ic_netmask = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(ic_myaddr))) + ic_netmask = htonl(IN_CLASSB_NET); + else if (IN_CLASSC(ntohl(ic_myaddr))) + ic_netmask = htonl(IN_CLASSC_NET); else { printk(KERN_ERR "IP-Config: Unable to guess netmask for address %08x\n", ic_myaddr); return -1; diff -u --recursive --new-file v2.1.126/linux/net/ipv4/proc.c linux/net/ipv4/proc.c --- v2.1.126/linux/net/ipv4/proc.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/proc.c Tue Oct 27 09:57:19 1998 @@ -7,7 +7,7 @@ * PROC file system. It is mainly used for debugging and * statistics. * - * Version: $Id: proc.c,v 1.32 1998/10/03 09:37:42 davem Exp $ + * Version: $Id: proc.c,v 1.33 1998/10/21 05:44:35 davem Exp $ * * Authors: Fred N. van Kempen, * Gerald J. Heim, @@ -55,21 +55,22 @@ char *tmpbuf, int i) { - /* FIXME: I'm not sure if the timer fields are correct. */ sprintf(tmpbuf, "%4d: %08lX:%04X %08lX:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu", + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u", i, (long unsigned int)req->af.v4_req.loc_addr, ntohs(sk->sport), (long unsigned int)req->af.v4_req.rmt_addr, - req->rmt_port, + ntohs(req->rmt_port), TCP_SYN_RECV, - 0,0, /* use sizeof(struct open_request) here? */ - 0, (unsigned long)(req->expires - jiffies), /* ??? */ + 0,0, /* could print option size, but that is af dependent. */ + 1, /* timers active (only the expire timer) */ + (unsigned long)(req->expires - jiffies), req->retrans, sk->socket ? sk->socket->inode->i_uid : 0, - 0, /* ??? */ - sk->socket ? sk->socket->inode->i_ino:0); + 0, /* non standard timer */ + 0 /* open_requests have no inode */ + ); } /* Format a single socket into tmpbuf. */ @@ -157,6 +158,9 @@ * KNOWN BUGS * As in get_unix_netinfo, the buffer might be too small. If this * happens, get__netinfo returns only part of the available infos. + * + * Assumes that buffer length is a multiply of 128 - if not it will + * write past the end. */ static int get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t offset, int length) @@ -172,17 +176,6 @@ " sl local_address rem_address st tx_queue " "rx_queue tr tm->when retrnsmt uid timeout inode"); pos = 128; -/* - * This was very pretty but didn't work when a socket is destroyed - * at the wrong moment (eg a syn recv socket getting a reset), or - * a memory timer destroy. Instead of playing with timers we just - * concede defeat and do a start_bh_atomic(). - * Why not just use lock_sock()? As far as I can see all timer routines - * check for sock_readers before doing anything. -AK - * [Disabled for now again, because it hard-locked my machine, and there - * is an theoretical situation then, where an user could prevent - * sockets from being destroyed by constantly reading /proc/net/tcp.] - */ SOCKHASH_LOCK(); sp = pro->sklist_next; while(sp != (struct sock *)pro) { @@ -196,8 +189,8 @@ continue; get__openreq(sp, req, tmpbuf, i); len += sprintf(buffer+len, "%-127s\n", tmpbuf); - if(len >= length) - break; + if(len >= length) + goto out; } } @@ -215,6 +208,7 @@ sp = next; i++; } +out: SOCKHASH_UNLOCK(); begin = len - (pos - offset); @@ -222,6 +216,8 @@ len -= begin; if(len>length) len = length; + if (len<0) + len = 0; return len; } @@ -265,6 +261,8 @@ len -= offset; if (len > length) len = length; + if (len < 0) + len = 0; return len; } @@ -343,6 +341,8 @@ len -= offset; if (len > length) len = length; + if (len < 0) + len = 0; return len; } @@ -379,5 +379,7 @@ len -= offset; if (len > length) len = length; + if (len < 0) + len = 0; return len; } diff -u --recursive --new-file v2.1.126/linux/net/ipv4/raw.c linux/net/ipv4/raw.c --- v2.1.126/linux/net/ipv4/raw.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/raw.c Sat Oct 31 11:32:05 1998 @@ -400,7 +400,7 @@ return err<0 ? err : len; } -static void raw_close(struct sock *sk, unsigned long timeout) +static void raw_close(struct sock *sk, long timeout) { /* Observation: when raw_close is called, processes have no access to socket anymore. But net still has. diff -u --recursive --new-file v2.1.126/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c --- v2.1.126/linux/net/ipv4/sysctl_net_ipv4.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/sysctl_net_ipv4.c Tue Oct 27 09:57:19 1998 @@ -1,7 +1,7 @@ /* * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. * - * $Id: sysctl_net_ipv4.c,v 1.35 1998/10/03 09:37:54 davem Exp $ + * $Id: sysctl_net_ipv4.c,v 1.36 1998/10/21 05:26:59 davem Exp $ * * Begun April 1, 1996, Mike Shaver. * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] @@ -43,7 +43,6 @@ /* From ip_masq.c */ extern int sysctl_ip_masq_debug; -extern int sysctl_tcp_hoe_retransmits; extern int sysctl_tcp_timestamps; extern int sysctl_tcp_window_scaling; extern int sysctl_tcp_sack; @@ -92,9 +91,6 @@ ctl_table ipv4_table[] = { - {NET_IPV4_TCP_HOE_RETRANSMITS, "tcp_hoe_retransmits", - &sysctl_tcp_hoe_retransmits, sizeof(int), 0644, NULL, - &proc_dointvec}, {NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps", &sysctl_tcp_timestamps, sizeof(int), 0644, NULL, &proc_dointvec}, diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v2.1.126/linux/net/ipv4/tcp.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/tcp.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp.c,v 1.127 1998/10/04 07:04:32 davem Exp $ + * Version: $Id: tcp.c,v 1.130 1998/11/07 14:36:10 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -860,8 +860,8 @@ if(copy > seglen) copy = seglen; + /* Determine how large of a buffer to allocate. */ tmp = MAX_HEADER + sk->prot->max_header; - queue_it = 0; if (copy < min(mss_now, tp->max_window >> 1) && !(flags & MSG_OOB)) { tmp += min(mss_now, tp->max_window); @@ -876,6 +876,7 @@ queue_it = 1; } else { tmp += copy; + queue_it = 0; } skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL); @@ -1452,7 +1453,7 @@ tcp_synq_init(tp); } -void tcp_close(struct sock *sk, unsigned long timeout) +void tcp_close(struct sock *sk, long timeout) { struct sk_buff *skb; int data_was_unread = 0; @@ -1522,7 +1523,6 @@ struct task_struct *tsk = current; struct wait_queue wait = { tsk, NULL }; - tsk->timeout = timeout; add_wait_queue(sk->sleep, &wait); release_sock(sk); @@ -1530,12 +1530,11 @@ tsk->state = TASK_INTERRUPTIBLE; if (!closing(sk)) break; - schedule(); - if (signal_pending(tsk) || !tsk->timeout) + timeout = schedule_timeout(timeout); + if (signal_pending(tsk) || !timeout) break; } - tsk->timeout=0; tsk->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); @@ -1547,8 +1546,8 @@ */ tcp_check_fin_timer(sk); - sk->dead = 1; release_sock(sk); + sk->dead = 1; } /* @@ -1619,6 +1618,8 @@ req->class->destructor(req); tcp_openreq_free(req); sk->ack_backlog--; + if(sk->keepopen) + tcp_inc_slow_timer(TCP_SLT_KEEPALIVE); /* * This does not pass any already set errors on the new socket @@ -1657,48 +1658,86 @@ return -EFAULT; switch(optname) { - case TCP_MAXSEG: -/* values greater than interface MTU won't take effect. however at - * the point when this call is done we typically don't yet know - * which interface is going to be used - */ - if(val<1||val>MAX_WINDOW) - return -EINVAL; - tp->user_mss=val; - return 0; - case TCP_NODELAY: - sk->nonagle=(val==0)?0:1; - return 0; - default: - return(-ENOPROTOOPT); + case TCP_MAXSEG: + /* values greater than interface MTU won't take effect. however at + * the point when this call is done we typically don't yet know + * which interface is going to be used + */ + if(val < 1 || val > MAX_WINDOW) + return -EINVAL; + tp->user_mss = val; + return 0; + + case TCP_NODELAY: + /* You cannot try to use this and TCP_CORK in + * tandem, so let the user know. + */ + if (sk->nonagle == 2) + return -EINVAL; + sk->nonagle = (val == 0) ? 0 : 1; + return 0; + + case TCP_CORK: + /* When set indicates to always queue non-full frames. + * Later the user clears this option and we transmit + * any pending partial frames in the queue. This is + * meant to be used alongside sendfile() to get properly + * filled frames when the user (for example) must write + * out headers with a write() call first and then use + * sendfile to send out the data parts. + * + * You cannot try to use TCP_NODELAY and this mechanism + * at the same time, so let the user know. + */ + if (sk->nonagle == 1) + return -EINVAL; + if (val != 0) { + sk->nonagle = 2; + } else { + sk->nonagle = 0; + + if (tp->send_head) { + lock_sock(sk); + if (tp->send_head && + tcp_snd_test (sk, tp->send_head)) + tcp_write_xmit(sk); + release_sock(sk); + } + } + return 0; + + default: + return -ENOPROTOOPT; }; } -int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, +int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - int val; - int len; + int val, len; if(level != SOL_TCP) return tp->af_specific->getsockopt(sk, level, optname, optval, optlen); - + if(get_user(len,optlen)) return -EFAULT; - - len = min(len,sizeof(int)); + + len = min(len, sizeof(int)); switch(optname) { - case TCP_MAXSEG: - val=tp->user_mss; - break; - case TCP_NODELAY: - val=sk->nonagle; - break; - default: - return(-ENOPROTOOPT); + case TCP_MAXSEG: + val = tp->user_mss; + break; + case TCP_NODELAY: + val = (sk->nonagle == 1); + break; + case TCP_CORK: + val = (sk->nonagle == 2); + break; + default: + return -ENOPROTOOPT; }; if(put_user(len, optlen)) diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c --- v2.1.126/linux/net/ipv4/tcp_input.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/tcp_input.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.130 1998/10/04 07:06:47 davem Exp $ + * Version: $Id: tcp_input.c,v 1.136 1998/11/07 14:36:18 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -53,6 +53,8 @@ * Andi Kleen: Add tcp_measure_rcv_mss to make * connections with MSS @@ -75,7 +77,6 @@ int sysctl_tcp_timestamps = 1; int sysctl_tcp_window_scaling = 1; int sysctl_tcp_sack = 1; -int sysctl_tcp_hoe_retransmits = 1; int sysctl_tcp_syncookies = SYNC_INIT; int sysctl_tcp_stdurg; @@ -566,14 +567,6 @@ /* This is Jacobson's slow start and congestion avoidance. * SIGCOMM '88, p. 328. - * - * FIXME: What happens when the congestion window gets larger - * than the maximum receiver window by some large factor - * Suppose the pipeline never looses packets for a long - * period of time, then traffic increases causing packet loss. - * The congestion window should be reduced, but what it should - * be reduced to is not clear, since 1/2 the old window may - * still be larger than the maximum sending rate we ever achieved. */ static void tcp_cong_avoid(struct tcp_opt *tp) { @@ -1139,7 +1132,7 @@ /* Zap SWALK, by moving every further SACK up by one slot. * Decrease num_sacks. */ - for(this_sack += 1; this_sack < num_sacks; this_sack++, swalk++) { + for(this_sack += 1; this_sack < num_sacks-1; this_sack++, swalk++) { struct tcp_sack_block *next = (swalk + 1); swalk->start_seq = next->start_seq; swalk->end_seq = next->end_seq; @@ -1524,7 +1517,7 @@ * - delay time <= 0.5 HZ * - we don't have a window update to send * - must send at least every 2 full sized packets - * - must send an ACK if we have any SACKs + * - must send an ACK if we have any out of order data * * With an extra heuristic to handle loss of packet * situations and also helping the sender leave slow @@ -1537,8 +1530,8 @@ tcp_raise_window(sk) || /* We entered "quick ACK" mode or... */ tcp_in_quickack_mode(tp) || - /* We have pending SACKs */ - (tp->sack_ok && tp->num_sacks)) { + /* We have out of order data */ + (skb_peek(&tp->out_of_order_queue) != NULL)) { /* Then ack it now */ tcp_send_ack(sk); } else { @@ -1654,8 +1647,11 @@ return 0; } - /* Now continue with the receive queue if it wasn't enough */ - while ((skb = skb_peek_tail(&sk->receive_queue))) { + /* Now continue with the receive queue if it wasn't enough. + * But only do this if we are really being abused. + */ + while ((atomic_read(&sk->rmem_alloc) >= (sk->rcvbuf * 2)) && + (skb = skb_peek_tail(&sk->receive_queue))) { /* Never toss anything when we've seen the FIN. * It's just too complex to recover from it. */ @@ -1678,8 +1674,6 @@ TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, tp->copied_seq); kfree_skb(skb); - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) - break; } return 0; } @@ -1745,14 +1739,15 @@ } } - flg = *(((u32 *)th) + 3); - + flg = *(((u32 *)th) + 3) & ~htonl(0x8 << 16); + /* pred_flags is 0xS?10 << 16 + snd_wnd * if header_predition is to be made * 'S' will always be tp->tcp_header_len >> 2 * '?' will be 0 else it will be !0 * (when there are holes in the receive * space for instance) + * PSH flag is ignored. */ if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { @@ -1769,7 +1764,7 @@ goto discard; } } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una && - atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { + atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { /* Bulk data transfer: receiver */ __skb_pull(skb,th->doff*4); diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c --- v2.1.126/linux/net/ipv4/tcp_ipv4.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/tcp_ipv4.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_ipv4.c,v 1.161 1998/10/03 09:38:05 davem Exp $ + * Version: $Id: tcp_ipv4.c,v 1.162 1998/11/07 11:50:26 davem Exp $ * * IPv4 specific functions * @@ -1633,6 +1633,9 @@ /* Count it even if it's bad */ tcp_statistics.TcpInSegs++; + if (len < sizeof(struct tcphdr)) + goto bad_packet; + /* Try to use the device checksum if provided. */ switch (skb->ip_summed) { case CHECKSUM_NONE: @@ -1647,6 +1650,7 @@ ntohs(th->dest), len, skb->len, ntohs(skb->nh.iph->tot_len)); + bad_packet: tcp_statistics.TcpInErrs++; goto discard_it; } diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c --- v2.1.126/linux/net/ipv4/tcp_output.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/tcp_output.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_output.c,v 1.95 1998/09/27 12:57:13 freitag Exp $ + * Version: $Id: tcp_output.c,v 1.96 1998/11/07 10:54:40 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -390,7 +390,7 @@ * * Note, we don't "adjust" for TIMESTAMP or SACK option bytes. */ -u32 __tcp_select_window(struct sock *sk, u32 cur_win) +u32 __tcp_select_window(struct sock *sk) { struct tcp_opt *tp = &sk->tp_pinfo.af_tcp; unsigned int mss = tp->mss_cache; diff -u --recursive --new-file v2.1.126/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c --- v2.1.126/linux/net/ipv4/tcp_timer.c Thu Sep 17 17:53:40 1998 +++ linux/net/ipv4/tcp_timer.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_timer.c,v 1.53 1998/09/15 02:11:39 davem Exp $ + * Version: $Id: tcp_timer.c,v 1.55 1998/11/07 11:55:42 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -183,8 +183,8 @@ return; if (atomic_read(&sk->sock_readers)) { - /* Try again in second. */ - tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ); + /* Try again later. */ + tcp_reset_xmit_timer(sk, TIME_PROBE0, HZ/5); return; } @@ -229,6 +229,9 @@ sk->err = ETIMEDOUT; tcp_set_state(sk, TCP_CLOSE); + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) + sk->state_change(sk); } else { tp->probes_out++; tp->pending = TIME_KEEPOPEN; @@ -433,8 +436,8 @@ } if (atomic_read(&sk->sock_readers)) { - /* Try again in a second. */ - tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ); + /* Try again later */ + tcp_reset_xmit_timer(sk, TIME_RETRANS, HZ/20); return; } lock_sock(sk); @@ -463,10 +466,14 @@ tp->fackets_out = 0; tp->retrans_out = 0; if (tp->retransmits == 0) { - /* remember window where we lost + /* Remember window where we lost: * "one half of the current window but at least 2 segments" + * + * Here "current window" means the effective one, which + * means it must be an accurate representation of our current + * sending rate _and_ the snd_wnd. */ - tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2); + tp->snd_ssthresh = max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2); tp->snd_cwnd_cnt = 0; tp->snd_cwnd = 1; } diff -u --recursive --new-file v2.1.126/linux/net/ipv4/timer.c linux/net/ipv4/timer.c --- v2.1.126/linux/net/ipv4/timer.c Thu Sep 17 17:53:40 1998 +++ linux/net/ipv4/timer.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * * TIMER - implementation of software timers for IP. * - * Version: $Id: timer.c,v 1.12 1998/08/28 01:15:29 davem Exp $ + * Version: $Id: timer.c,v 1.14 1998/11/07 11:55:43 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -74,7 +74,8 @@ /* Only process if socket is not in use. */ if (atomic_read(&sk->sock_readers)) { - sk->timer.expires = jiffies+HZ; + /* Try again later. */ + sk->timer.expires = jiffies+HZ/20; add_timer(&sk->timer); return; } @@ -111,11 +112,10 @@ case TIME_CLOSE: /* We've waited long enough, close the socket. */ - sk->state = TCP_CLOSE; - net_delete_timer (sk); + tcp_set_state(sk, TCP_CLOSE); + sk->shutdown = SHUTDOWN_MASK; if (!sk->dead) sk->state_change(sk); - sk->shutdown = SHUTDOWN_MASK; net_reset_timer (sk, TIME_DONE, TCP_DONE_TIME); break; diff -u --recursive --new-file v2.1.126/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v2.1.126/linux/net/ipv4/udp.c Mon Oct 5 13:13:48 1998 +++ linux/net/ipv4/udp.c Sat Oct 31 10:37:14 1998 @@ -1015,7 +1015,7 @@ } -static void udp_close(struct sock *sk, unsigned long timeout) +static void udp_close(struct sock *sk, long timeout) { /* See for explanation: raw_close in ipv4/raw.c */ sk->state = TCP_CLOSE; diff -u --recursive --new-file v2.1.126/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c --- v2.1.126/linux/net/ipv6/tcp_ipv6.c Mon Oct 5 13:13:49 1998 +++ linux/net/ipv6/tcp_ipv6.c Sat Nov 7 11:00:32 1998 @@ -5,7 +5,7 @@ * Authors: * Pedro Roque * - * $Id: tcp_ipv6.c,v 1.93 1998/10/03 09:38:50 davem Exp $ + * $Id: tcp_ipv6.c,v 1.94 1998/11/07 11:50:33 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -1331,6 +1331,9 @@ tcp_statistics.TcpInSegs++; + if (len < sizeof(struct tcphdr)) + goto bad_packet; + /* * Try to use the device checksum if provided. */ @@ -1341,6 +1344,7 @@ case CHECKSUM_HW: if (tcp_v6_check(th,len,saddr,daddr,skb->csum)) { printk(KERN_DEBUG "tcp csum failed\n"); + bad_packet: tcp_statistics.TcpInErrs++; goto discard_it; } diff -u --recursive --new-file v2.1.126/linux/net/netlink/af_netlink.c linux/net/netlink/af_netlink.c --- v2.1.126/linux/net/netlink/af_netlink.c Mon Oct 5 13:13:49 1998 +++ linux/net/netlink/af_netlink.c Sat Nov 7 11:00:33 1998 @@ -427,7 +427,7 @@ continue; if (failure) { - sk->err = -ENOBUFS; + sk->err = ENOBUFS; sk->state_change(sk); continue; } @@ -442,12 +442,12 @@ } } if (skb2 == NULL) { - sk->err = -ENOBUFS; + sk->err = ENOBUFS; sk->state_change(sk); /* Clone failed. Notify ALL listeners. */ failure = 1; } else if (netlink_broadcast_deliver(sk, skb2)) { - sk->err = -ENOBUFS; + sk->err = ENOBUFS; sk->state_change(sk); } else skb2 = NULL; diff -u --recursive --new-file v2.1.126/linux/net/protocols.c linux/net/protocols.c --- v2.1.126/linux/net/protocols.c Thu Jul 16 18:09:32 1998 +++ linux/net/protocols.c Tue Oct 27 09:57:19 1998 @@ -22,6 +22,10 @@ #endif #endif /* INET */ +#ifdef CONFIG_ECONET +extern void econet_proto_init(struct net_proto *pro); +#endif + #ifdef CONFIG_NETLINK extern void netlink_proto_init(struct net_proto *pro); #endif @@ -151,6 +155,10 @@ #ifdef CONFIG_X25 { "X.25", x25_proto_init }, /* CCITT X.25 Packet Layer */ +#endif + +#ifdef CONFIG_ECONET + { "Econet", econet_proto_init }, /* Acorn Econet */ #endif { NULL, NULL } /* End marker */ diff -u --recursive --new-file v2.1.126/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c --- v2.1.126/linux/net/sunrpc/sched.c Wed Sep 9 14:51:13 1998 +++ linux/net/sunrpc/sched.c Sat Oct 31 10:17:23 1998 @@ -127,7 +127,7 @@ task->tk_pid, task->tk_timeout * 1000 / HZ); if (!timer) timer = __rpc_default_timer; - if (expires < jiffies) { + if (time_before(expires, jiffies)) { printk(KERN_ERR "RPC: bad timeout value %ld - setting to 10 sec!\n", task->tk_timeout); expires = jiffies + 10 * HZ; @@ -413,7 +413,6 @@ task->tk_pid); if (current->pid == rpciod_pid) printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); - current->timeout = 0; sleep_on(&task->tk_wait); /* @@ -552,9 +551,8 @@ } if (flags & RPC_TASK_ASYNC) return NULL; - current->timeout = jiffies + (HZ >> 4); current->state = TASK_INTERRUPTIBLE; - schedule(); + schedule_timeout(HZ>>4); } while (!signalled()); return NULL; @@ -846,9 +844,7 @@ if (all_tasks) { dprintk("rpciod_killall: waiting for tasks to exit\n"); current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); - current->timeout = 0; + schedule_timeout(1); } } @@ -919,9 +915,7 @@ */ current->sigpending = 0; current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1; - schedule(); - current->timeout = 0; + schedule_timeout(1); /* * Display a message if we're going to wait longer. */ diff -u --recursive --new-file v2.1.126/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c --- v2.1.126/linux/net/sunrpc/svcsock.c Mon Oct 5 13:13:49 1998 +++ linux/net/sunrpc/svcsock.c Sat Oct 31 10:17:23 1998 @@ -731,14 +731,14 @@ * Receive the next request on any socket. */ int -svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp) +svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout) { struct svc_sock *svsk; int len; struct wait_queue wait = { current, NULL }; dprintk("svc: server %p waiting for data (to = %ld)\n", - rqstp, current->timeout); + rqstp, timeout); if (rqstp->rq_sock) printk(KERN_ERR @@ -772,7 +772,7 @@ current->state = TASK_INTERRUPTIBLE; add_wait_queue(&rqstp->rq_wait, &wait); end_bh_atomic(); - schedule(); + schedule_timeout(timeout); remove_wait_queue(&rqstp->rq_wait, &wait); diff -u --recursive --new-file v2.1.126/linux/scripts/Configure linux/scripts/Configure --- v2.1.126/linux/scripts/Configure Sat Sep 5 16:46:42 1998 +++ linux/scripts/Configure Sun Oct 25 14:30:47 1998 @@ -53,6 +53,9 @@ # # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help # texts. +# +# 102598 Michael Chastain (mec@shout.net) - put temporary files in +# current directory, not in /tmp. # # Make sure we're really running bash. @@ -506,9 +509,9 @@ echo "# Using defaults found in" $DEFAULTS echo "#" . $DEFAULTS - sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > /tmp/conf.$$ - . /tmp/conf.$$ - rm /tmp/conf.$$ + sed -e 's/# \(.*\) is not.*/\1=n/' < $DEFAULTS > .config-is-not.$$ + . .config-is-not.$$ + rm .config-is-not.$$ else echo "#" echo "# No defaults found"