diff -u --recursive --new-file v1.3.92/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v1.3.92/linux/Documentation/Configure.help Sun Apr 21 12:38:59 1996 +++ linux/Documentation/Configure.help Sun Apr 21 12:30:28 1996 @@ -3179,6 +3179,21 @@ different D-channel protocol, or non-standard irq/port/shmem settings. +PCBIT-D support +CONFIG_ISDN_DRV_PCBIT + This enables support for the PCBIT ISDN-cards. This card is + manufactured in Portugal by Octal. For running this card, + additional firmware is necessary, which has to be downloaded into + the card using a utility which is distributed separately. + See Documentation/isdn/README for more information. + +Support for AP1000 multicomputer +CONFIG_AP1000 + This enables support for a sparc based parallel multi-computer + called an AP1000+. For details on our efforts to port Linux to this + machine see http://cap.anu.edu.au/cap/projects/linux or mail to + hackers@cafe.anu.edu.au + # need an empty line after last entry, for sed script in Configure. # diff -u --recursive --new-file v1.3.92/linux/Documentation/devices.tex linux/Documentation/devices.tex --- v1.3.92/linux/Documentation/devices.tex Sun Apr 21 12:38:59 1996 +++ linux/Documentation/devices.tex Sun Apr 21 11:56:13 1996 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: April 10, 1996} +\date{Last revised: April 20, 1996} \maketitle % \noindent @@ -74,6 +74,9 @@ permission of the author, assuming the author can be contacted without an unreasonable effort. +In particular, please don't sent patches for this list to Linus, at +least not without contacting me first. + \section{Major numbers} \begin{devicelist} @@ -160,7 +163,9 @@ \major{45}{}{char }{isdn4linux ISDN BRI driver} \major{46}{}{char }{Comtrol Rocketport serial card} \major{47}{}{char }{Comtrol Rocketport serial card -- alternate devices} -\major{48}{--59}{}{Unallocated} +\major{48}{}{char }{SDL RISCom serial card} +\major{49}{}{char }{SDL RISCom serial card -- alternate devices} +\major{50}{--59}{}{Unallocated} \major{60}{--63}{}{Local/experimental use} \major{64}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} @@ -417,6 +422,9 @@ \minor{133}{/dev/exttrp}{External device trap} \minor{134}{/dev/apm\_bios}{Advanced Power Management BIOS} \minor{135}{/dev/rtc}{Real Time Clock} + \minor{136}{/dev/qcam0}{QuickCam on {\file lp0}} + \minor{137}{/dev/qcam1}{QuickCam on {\file lp1}} + \minor{138}{/dev/qcam2}{QuickCam on {\file lp2}} \end{devicelist} \noindent @@ -557,10 +565,7 @@ \minor{0}{/dev/ttyC0}{First Cyclades port} \minordots \minor{31}{/dev/ttyC31}{32nd Cyclades port} -\end{devicelist} -\noindent -It would make more sense for these to start at 0... -\begin{devicelist} +\\ \major{ }{}{block}{``Double'' compressed disk} \minor{0}{/dev/double0}{First compressed disk} \minordots @@ -960,25 +965,28 @@ \major{43}{}{char }{isdn4linux virtual modem} \minor{0}{/dev/ttyI0}{First virtual modem} \minordots - \minor{15}{/dev/ttyI15}{16th virtual modem} + \minor{63}{/dev/ttyI63}{64th virtual modem} \end{devicelist} \begin{devicelist} \major{44}{}{char }{isdn4linux virtual modem -- alternate devices} \minor{0}{/dev/cui0}{Callout device corresponding to {\file ttyI0}} \minordots - \minor{15}{/dev/cui15}{Callout device corresponding to {\file ttyI15}} + \minor{63}{/dev/cui63}{Callout device corresponding to {\file ttyI63}} \end{devicelist} \begin{devicelist} \major{45}{}{char }{isdn4linux ISDN BRI driver} \minor{0}{/dev/isdn0}{First virtual B channel raw data} \minordots - \minor{15}{/dev/isdn15}{16th virtual B channel raw data} - \minor{16}{/dev/isdnctrl0}{First channel control/debug} + \minor{63}{/dev/isdn63}{64th virtual B channel raw data} + \minor{64}{/dev/isdnctrl0}{First channel control/debug} + \minordots + \minor{127}{/dev/isdnctrl63}{64th channel control/debug} + \minor{128}{/dev/ippp0}{First SyncPPP device} \minordots - \minor{31}{/dev/isdnctrl15}{16th channel control/debug} - \minor{128}{/dev/isdninfo}{ISDN monitor interface} + \minor{191}{/dev/ippp63}{64th SyncPPP device} + \minor{255}{/dev/isdninfo}{ISDN monitor interface} \end{devicelist} \begin{devicelist} @@ -996,7 +1004,21 @@ \end{devicelist} \begin{devicelist} -\major{48}{--59}{}{Unallocated} +\major{48}{}{char }{SDL RISCom serial card} + \minor{0}{/dev/ttyL0}{First RISCom port} + \minor{1}{/dev/ttyL1}{Second RISCom port} + \minordots +\end{devicelist} + +\begin{devicelist} +\major{49}{}{char }{SDL RISCom serial card -- alternate devices} + \minor{0}{/dev/cul0}{Callout device corresponding to {\file ttyL0}} + \minor{1}{/dev/cul1}{Callout device corresponding to {\file ttyL1}} + \minordots +\end{devicelist} + +\begin{devicelist} +\major{50}{--59}{}{Unallocated} \end{devicelist} \begin{devicelist} diff -u --recursive --new-file v1.3.92/linux/Documentation/devices.txt linux/Documentation/devices.txt --- v1.3.92/linux/Documentation/devices.txt Sun Apr 21 12:38:59 1996 +++ linux/Documentation/devices.txt Sun Apr 21 11:56:13 1996 @@ -2,14 +2,14 @@ Maintained by H. Peter Anvin - Last revised: April 10, 1996 + Last revised: April 20, 1996 This list is the successor to Rick Miller's Linux Device List, which he stopped maintaining when he got busy with other things in 1993. It is a registry of allocated major device numbers, as well as the recommended /dev directory nodes for these devices. -The latest version of this list is included with the Linux kernel +The lastest version of this list is included with the Linux kernel sources in LaTeX and ASCII form. In case of discrepancy, the LaTeX version is authoritative. @@ -31,6 +31,9 @@ permission of the author, assuming the author can be contacted without an unreasonable effort. +In particular, please don't sent patches for this list to Linus, at +least not without contacting me first. + 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device number @@ -243,6 +246,9 @@ 133 = /dev/exttrp External device trap 134 = /dev/apm_bios Advanced Power Management BIOS 135 = /dev/rtc Real Time Clock + 136 = /dev/qcam0 QuickCam on lp0 + 137 = /dev/qcam1 QuickCam on lp1 + 138 = /dev/qcam2 QuickCam on lp2 11 char Raw keyboard device 0 = /dev/kbd Raw keyboard device @@ -342,12 +348,9 @@ 0 = /dev/sjcd Sanyo CD-ROM 19 char Cyclades serial card - 0 = /dev/ttyC0 First Cyclades port + 0 = /dev/ttyC0 First Cyclades port ... 31 = /dev/ttyC31 32nd Cyclades port - - It would make more sense for these to start at 0... - block "Double" compressed disk 0 = /dev/double0 First compressed disk ... @@ -360,7 +363,7 @@ mirror devices. 20 char Cyclades serial card - alternate devices - 0 = /dev/cub0 Callout device corresponding to ttyC0 + 0 = /dev/cub0 Callout device corresponding to ttyC0 ... 31 = /dev/cub31 Callout device corresponding to ttyC31 block Hitachi CD-ROM (under development) @@ -658,21 +661,26 @@ 43 char isdn4linux virtual modem 0 = /dev/ttyI0 First virtual modem ... - 15 = /dev/ttyI15 16th virtual modem + 63 = /dev/ttyI63 64th virtual modem 44 char isdn4linux virtual modem - alternate devices 0 = /dev/cui0 Callout device corresponding to ttyI0 ... - 15 = /dev/cui15 Callout device corresponding to ttyI15 + 63 = /dev/cui63 Callout device corresponding to ttyI63 45 char isdn4linux ISDN BRI driver 0 = /dev/isdn0 First virtual B channel raw data ... - 15 = /dev/isdn15 16th virtual B channel raw data - 16 = /dev/isdnctrl0 First channel control/debug + 63 = /dev/isdn63 64th virtual B channel raw data + 64 = /dev/isdnctrl0 First channel control/debug + ... + 127 = /dev/isdnctrl63 64th channel control/debug + + 128 = /dev/ippp0 First SyncPPP device ... - 31 = /dev/isdnctrl15 16th channel control/debug - 128 = /dev/isdninfo ISDN monitor interface + 191 = /dev/ippp63 64th SyncPPP device + + 255 = /dev/isdninfo ISDN monitor interface 46 char Comtrol Rocketport serial card 0 = /dev/ttyR0 First Rocketport port @@ -684,7 +692,17 @@ 1 = /dev/cur1 Callout device corresponding to ttyR1 ... - 48-59 UNALLOCATED + 48 char SDL RISCom serial card + 0 = /dev/ttyL0 First RISCom port + 1 = /dev/ttyL1 Second RISCom port + ... + + 49 char SDL RISCom serial card - alternate devices + 0 = /dev/cul0 Callout device corresponding to ttyL0 + 1 = /dev/cul1 Callout device corresponding to ttyL1 + ... + + 50-59 UNALLOCATED 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not diff -u --recursive --new-file v1.3.92/linux/Documentation/isdn/CREDITS linux/Documentation/isdn/CREDITS --- v1.3.92/linux/Documentation/isdn/CREDITS Mon Feb 26 11:58:03 1996 +++ linux/Documentation/isdn/CREDITS Sun Apr 21 11:56:13 1996 @@ -5,7 +5,7 @@ Thomas Bogendörfer (tsbogend@bigbug.franken.de) Tester, lots of bugfixes and hints. -Alan Cox () +Alan Cox (alan@cymru.net) For help getting into standard-kernel. Volker Götz (volker@oops.franken.de) @@ -24,8 +24,11 @@ Andreas Kool (akool@Kool.f.EUnet.de) For contribution of the isdnlog/isdnrep-tool -Pedro Roque Marques - For lot of new ideas and writing a new driver coming soon. +Pedro Roque Marques (roque@di.fc.ul.pt) + For lot of new ideas and the pcbit driver. + +Eberhard Moenkeberg (emoenke@gwdg.de) + For testing and help to get into kernel. Jan den Ouden (denouden@groovin.xs4all.nl) For contribution of the teles-driver diff -u --recursive --new-file v1.3.92/linux/Documentation/isdn/README linux/Documentation/isdn/README --- v1.3.92/linux/Documentation/isdn/README Fri Apr 12 15:51:44 1996 +++ linux/Documentation/isdn/README Sun Apr 21 11:56:14 1996 @@ -44,7 +44,7 @@ term to that one, which applies to your local ISDN-environment. When the link-level-module isdn.o is loaded, it supports up to 16 - low-level-modules with up to 16 channels. (The number 16 is arbitrarily + low-level-modules with up to 64 channels. (The number 64 is arbitrarily chosen and can be configured at compile-time --ISDN_MAX in isdn.h). A low-level-driver can register itself through an interface (which is defined in isdnif.h) and gets assigned a slot. @@ -65,7 +65,7 @@ In addition the following devices are made available: - 32 tty-devices (16 cuix and 16 ttyIx) with integrated modem-emulator: + 128 tty-devices (64 cuix and 64 ttyIx) with integrated modem-emulator: The functionality is almost the same as that of a serial device (the line-discs are handled by the kernel, which lets you run SLIP, CSLIP and asynchronous PPP through the devices. We have tested @@ -473,6 +473,14 @@ In this case use ping with the option -i to increase the interval between echo-packets. + "isdnctrl cbdelay [seconds]" + Sets the delay (default 5 sec) between an incoming call and start of + dialing when callback is enabled. + + "isdnctrl cbhup [on|off]" + This enables (default) or disables an active hangup (reject) when getting an + incoming call for an interface which is configured for callback. + "isdnctrl encap " Selects the type of packet-encapsulation. The encapsulation can be changed only while an interface is down. @@ -489,6 +497,8 @@ The Ethernet-address of the interface is faked, from it's IP-address: fc:fc:i1:i2:i3:i4, where i1-4 are the IP-addr.-values. syncppp Synchronous PPP + + uihdlc HDLC with UI-frame-header (for use with DOS ISPA, option -h1) Watching packets, using standard-tcpdump will fail for all encapsulations except ethernet because tcpdump does not know how to handle packets diff -u --recursive --new-file v1.3.92/linux/Documentation/isdn/README.pcbit linux/Documentation/isdn/README.pcbit --- v1.3.92/linux/Documentation/isdn/README.pcbit Thu Jan 1 02:00:00 1970 +++ linux/Documentation/isdn/README.pcbit Sun Apr 21 11:56:14 1996 @@ -0,0 +1,40 @@ +------------------------------------------------------------------------------ + README file for the PCBIT-D Device Driver. +------------------------------------------------------------------------------ + +The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and +developed in cooperation with Portugal Telecom and Inesc. +The driver interfaces with the standard kernel isdn facilities +originaly developed by Fritz Elfert in the isdn4linux project. + +The common versions of the pcbit board require a firmware that is +distributed (and copyrighted) by the manufacturer. To load this +firmware you need "pcbitctl" availiable on the standard isdn4k-utils +package or in the pcbit package availiable in: + +ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn + +Known Limitations: + +- The board reset proceeding is at the moment incorrect and will only +allow you to load the firmware after a hard reset. + +- Only HDLC in B-channels is supported at the moment. There is now +current support to X.25 in B or D channels nor LAPD in B +channels. The main reason is that this two other protocol modes have, +to my knowledge, very little use. If you want to see them implemented +*do* send me a mail. + +- The driver often triggers errors in the board that i and the +manufacturer believe to be caused by bugs in the firmware. The current +version includes several proceedings for error recovery that should +allow normal operation. Plans for the future include cooperation with +the manufacturer in order to solve this problems. + +Information/hints/help can be obtained in the linux isdn +mailing list (isdn4linux@hub-wue.franken.de) or directly from me. + +regards, + Pedro. + + diff -u --recursive --new-file v1.3.92/linux/Documentation/isdn/README.syncppp linux/Documentation/isdn/README.syncppp --- v1.3.92/linux/Documentation/isdn/README.syncppp Fri Apr 12 15:51:44 1996 +++ linux/Documentation/isdn/README.syncppp Sun Apr 21 11:56:14 1996 @@ -12,7 +12,8 @@ to answer the appropriate question when doing a "make config" Don't forget to load the slhc.o module before the isdn.o module, if VJ-compression support -is not compiled into your kernel. +is not compiled into your kernel. (e.g if you have PPP or +CSLIP in the kernel) Using isdn4linux with sync PPP: ------------------------------- @@ -35,18 +36,20 @@ I've implemented one additional option for the ipppd: 'useifip' will get (if set to not 0.0.0.0) the IP address for the negotiation from the attached network-interface. +(also: ipppd will try to negotiate pointopoint IP as remote IP) You must disable BSD-compression, this implementation can't handle compressed packets. -Check the rc.isdn.syncppp file for an example setup script. +Check the etc/rc.isdn.syncppp in the isdn4kernel-util package +for an example setup script. + +To use the MPPP stuff, you must configure a slave device +with isdn4linux. Now call the ipppd with the '+mp' option. +To increase the number of links, you must use the +'addlink' option of the isdnctrl tool. enjoy it, michael -PS: I also implemented generic MP (RFC 1717). But in the -current isdn4linux link-level driver there is no -(or better say: another) way of doing channel bundling. So, -don't call the ipppd with the `+mp` option to enable -MP negotiation. diff -u --recursive --new-file v1.3.92/linux/Documentation/isdn/syncPPP.FAQ linux/Documentation/isdn/syncPPP.FAQ --- v1.3.92/linux/Documentation/isdn/syncPPP.FAQ Thu Jan 1 02:00:00 1970 +++ linux/Documentation/isdn/syncPPP.FAQ Sun Apr 21 11:56:14 1996 @@ -0,0 +1,50 @@ +simple isdn4linux PPP FAQ .. to be continued .. not 'debugged' + +Q: pppd,ipppd, syncPPP , asyncPPP .. what is that ? + what should I use? +A: The pppd is for asynchronous PPP .. asynchron means +here, the framing is character based. (e.g when +using ttyI* or tty* devices) + +The ipppd handles PPP packets coming in HDLC +frames (bit based protocol) ... The PPP driver +in isdn4linux pushs all IP packets direct +to the network layer and all PPP protocol +frames to the /dev/ippp* device. +So, the ipppd is a simple externel network +protocol handler. + +If you login into a remote machine using the +/dev/ttyI* devices and then enable PPP on the +remote terminal server -> use the 'old' pppd + +If your remote side immediately starts to send +frames ... you probably connect to a +syncPPP machine .. use the network device part +of isdn4linux with the 'syncppp' encapsulation +and make sure, that the ipppd is running and +conneted to at least one /dev/ippp*. Check the +isdn4linux manual on how to configure a network device. + +Q: when I start the ipppd .. I only get the + error message "this systems lacks PPP support" +A: check that at least the device 'ippp0' exists. + (you can check this e.g with the program 'ifconfig') + The ipppd NEEDS this device under THIS name .. + If this device doesn't exists, use: + isdnctrl addif ippp0 + isdnctrl encap ippp0 syncppp + ... (see isdn4linux doc for more) ... +A: Maybe you have compiled the ipppd with another + kernel source tree than the kernel you currently + run ... + +Q: when I list the netdevices with ifconfig I see, that + my ISDN interface has a HWaddr and IRQ=0 and Base + address = 0 +A: The device is a fake ethernetdevice .. ignore IRQ and baseaddr + You need the HWaddr only for ethernet encapsulation. + + + + diff -u --recursive --new-file v1.3.92/linux/MAINTAINERS linux/MAINTAINERS --- v1.3.92/linux/MAINTAINERS Sun Apr 21 12:38:59 1996 +++ linux/MAINTAINERS Sun Apr 21 11:11:13 1996 @@ -248,6 +248,13 @@ L: linux-kernel@vger.rutgers.edu S: Maintained +VFAT FILESYSTEM: +P: Gordon Chaffee +M: chaffee@plateau.cs.berkeley.edu +L: linux-kernel@vger.rutgers.edu +W: http://www-plateau.cs.berkeley.edu/people/chaffee +S: Maintained + DIGIBOARD DRIVER: P: Christoph Lameter M: clameter@fuller.edu diff -u --recursive --new-file v1.3.92/linux/Makefile linux/Makefile --- v1.3.92/linux/Makefile Sun Apr 21 12:38:59 1996 +++ linux/Makefile Sun Apr 21 12:19:53 1996 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 92 +SUBLEVEL = 93 ARCH = i386 @@ -116,14 +116,15 @@ ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o net/network.a FILESYSTEMS =fs/filesystems.a DRIVERS =drivers/block/block.a \ - drivers/char/char.a \ - drivers/net/net.a + drivers/char/char.a LIBS =$(TOPDIR)/lib/lib.a SUBDIRS =kernel drivers mm fs net ipc lib ifeq ($(CONFIG_ISDN),y) -DRIVERS := $(DRIVERS) drivers/isdn/isdn.a +DRIVERS := $(DRIVERS) drivers/isdn/isdn.a endif + +DRIVERS := $(DRIVERS) drivers/net/net.a ifdef CONFIG_CD_NO_IDESCSI DRIVERS := $(DRIVERS) drivers/cdrom/cdrom.a diff -u --recursive --new-file v1.3.92/linux/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c --- v1.3.92/linux/arch/i386/kernel/signal.c Fri Apr 19 10:07:57 1996 +++ linux/arch/i386/kernel/signal.c Sun Apr 21 11:17:58 1996 @@ -61,7 +61,7 @@ } #endif current->used_math = 1; - current->flags &= PF_USEDFPU; + current->flags &= ~PF_USEDFPU; memcpy_fromfs(¤t->tss.i387.hard, buf, sizeof(*buf)); } @@ -133,7 +133,7 @@ if (current->flags & PF_USEDFPU) { __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard)); stts(); - current->flags &= PF_USEDFPU; + current->flags &= ~PF_USEDFPU; } #else if (current == last_task_used_math) { diff -u --recursive --new-file v1.3.92/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v1.3.92/linux/arch/sparc/Makefile Sat Nov 25 02:57:32 1995 +++ linux/arch/sparc/Makefile Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.6 1995/11/25 00:57:30 davem Exp $ +# $Id: Makefile,v 1.20 1996/04/16 08:02:50 davem Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -30,8 +30,11 @@ LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \ $(TOPDIR)/arch/sparc/lib/lib.a -aoutimage: vmlinux - elftoaout -o aoutimage vmlinux +ifdef CONFIG_AP1000 +SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 +ARCHIVES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o $(ARCHIVES) +DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a +endif archclean: rm -f $(TOPDIR)/arch/sparc/boot/boot diff -u --recursive --new-file v1.3.92/linux/arch/sparc/boot/README linux/arch/sparc/boot/README --- v1.3.92/linux/arch/sparc/boot/README Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/boot/README Sun Apr 21 12:30:29 1996 @@ -17,5 +17,5 @@ More will come.... Hopefully I can write this such that it will work on almost all SUN -machines in existence. We'll see ;( +machines in existance. We'll see ;( diff -u --recursive --new-file v1.3.92/linux/arch/sparc/boot/empirical.h linux/arch/sparc/boot/empirical.h --- v1.3.92/linux/arch/sparc/boot/empirical.h Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/boot/empirical.h Sun Apr 21 17:32:01 1996 @@ -1,4 +1,4 @@ -/* $Id: empirical.h,v 1.2 1995/11/25 00:57:42 davem Exp $ +/* $Id: empirical.h,v 1.1 1996/04/21 10:17:46 davem Exp $ * empirical.h: Nasty hacks.... * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v1.3.92/linux/arch/sparc/boot/init_me.c linux/arch/sparc/boot/init_me.c --- v1.3.92/linux/arch/sparc/boot/init_me.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/boot/init_me.c Sun Apr 21 17:32:01 1996 @@ -1,4 +1,4 @@ -/* $Id: init_me.c,v 1.2 1995/11/25 00:57:44 davem Exp $ +/* $Id: init_me.c,v 1.3 1996/04/21 10:30:09 davem Exp $ * init_me.c: Initialize empirical constants and gather some info from * the boot prom. * @@ -11,7 +11,7 @@ #include "empirical.h" /* Don't ask... */ -#define DEBUG_INIT_ME /* Tell me what's goin on */ +#define DEBUG_INIT_ME /* Tell me what's going on */ unsigned int nwindows; /* Set in bare.S */ unsigned int nwindowsm1; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/config.in linux/arch/sparc/config.in --- v1.3.92/linux/arch/sparc/config.in Mon Mar 4 08:49:54 1996 +++ linux/arch/sparc/config.in Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.8 1996/03/01 07:15:47 davem Exp $ +# $Id: config.in,v 1.9 1996/04/04 16:30:03 tridge Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -7,15 +7,23 @@ mainmenu_option next_comment comment 'General setup' -# Global things across all Sparc machines. -define_bool CONFIG_SBUS y -define_bool CONFIG_SUN_MOUSE y -define_bool CONFIG_SERIAL y -define_bool CONFIG_SUN_SERIAL y -define_bool CONFIG_SUN_KEYBOARD y -define_bool CONFIG_SUN_CONSOLE y +bool 'Support for AP1000 multicomputer' CONFIG_AP1000 + +if [ "$CONFIG_AP1000" = "n" ]; then + # Global things across all Sun machines. + define_bool CONFIG_SBUS y + define_bool CONFIG_SUN_MOUSE y + define_bool CONFIG_SERIAL y + define_bool CONFIG_SUN_SERIAL y + define_bool CONFIG_SUN_KEYBOARD y + define_bool CONFIG_SUN_CONSOLE y + define_bool CONFIG_SUN_AUXIO y + define_bool CONFIG_SUN_IO y +fi + define_bool CONFIG_NET_ALIAS n define_bool CONFIG_BINFMT_AOUT y + bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC diff -u --recursive --new-file v1.3.92/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v1.3.92/linux/arch/sparc/defconfig Mon Mar 4 08:49:54 1996 +++ linux/arch/sparc/defconfig Sun Apr 21 12:30:29 1996 @@ -5,21 +5,28 @@ # # General setup # +# CONFIG_AP1000 is not set CONFIG_SBUS=y CONFIG_SUN_MOUSE=y +CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y CONFIG_SUN_KEYBOARD=y CONFIG_SUN_CONSOLE=y +CONFIG_SUN_AUXIO=y +CONFIG_SUN_IO=y # CONFIG_NET_ALIAS is not set CONFIG_BINFMT_AOUT=y CONFIG_NET=y CONFIG_SYSVIPC=y -# CONFIG_BINFMT_ELF is not set +CONFIG_BINFMT_ELF=y # # Floppy, IDE, and other block devices # # CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_INITRD is not set +# CONFIG_BLK_DEV_LOOP is not set # # Networking options @@ -46,6 +53,7 @@ # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_AX25 is not set +# CONFIG_BRIDGE is not set # CONFIG_NETLINK is not set # @@ -58,7 +66,7 @@ # CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set -# CONFIG_BLK_DEV_SR is not set +CONFIG_BLK_DEV_SR=y # CONFIG_CHR_DEV_SG is not set # @@ -66,6 +74,7 @@ # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y +# CONFIG_SCSI_AUTO_BIOSP is not set # # SCSI low-level drivers @@ -96,8 +105,10 @@ CONFIG_PROC_FS=y CONFIG_NFS_FS=y CONFIG_ROOT_NFS=y +CONFIG_RNFS_BOOTP=y +CONFIG_RNFS_RARP=y # CONFIG_SMB_FS is not set -# CONFIG_ISO9660_FS is not set +CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile --- v1.3.92/linux/arch/sparc/kernel/Makefile Mon Mar 4 08:49:54 1996 +++ linux/arch/sparc/kernel/Makefile Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.22 1996/03/01 07:15:52 davem Exp $ +# $Id: Makefile,v 1.29 1996/04/04 16:30:17 tridge Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,23 +7,56 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +ifdef SMP + +.S.s: + $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s + +.S.o: + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o + + +else + .S.s: $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + .S.o: $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + +endif + all: kernel.o head.o O_TARGET := kernel.o -O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o irq.o \ - process.o signal.o ioport.o setup.o idprom.o mp.o c_mp.o \ +IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o +O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o ${IRQ_OBJS} \ + process.o signal.o ioport.o setup.o idprom.o \ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ - sunos_ioctl.o time.o windows.o cpu.o auxio.o devices.o ksyms.o \ - sclow.o + sunos_ioctl.o time.o windows.o cpu.o devices.o ksyms.o \ + sclow.o solaris.o tadpole.o tick14.o + +ifdef SMP +O_OBJS += trampoline.o smp.o rirq.o +endif + +ifdef CONFIG_SUN_AUXIO +O_OBJS += auxio.o +endif all: kernel.o head.o +ifdef SMP + +head.o: head.S + $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o + +else + head.o: head.S $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o + +endif include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/auxio.c linux/arch/sparc/kernel/auxio.c --- v1.3.92/linux/arch/sparc/kernel/auxio.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/auxio.c Sun Apr 21 12:30:29 1996 @@ -31,7 +31,7 @@ /* Map the register both read and write */ auxio_register = (unsigned char *) sparc_alloc_io(auxregs[0].phys_addr, 0, auxregs[0].reg_size, - "auxiliaryIO", + "auxilliaryIO", auxregs[0].which_io, 0x0); /* Fix the address on sun4m and sun4c. */ if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/c_mp.c linux/arch/sparc/kernel/c_mp.c --- v1.3.92/linux/arch/sparc/kernel/c_mp.c Sat Nov 25 02:57:52 1995 +++ linux/arch/sparc/kernel/c_mp.c Thu Jan 1 02:00:00 1970 @@ -1,50 +0,0 @@ -/* $Id: c_mp.c,v 1.3 1995/11/25 00:57:50 davem Exp $ - * mp.c: SMP cpu idling and dispatch on the Sparc. - * - * Copyright (C) 1995 David S. Miller - */ - -#include - -#include -#include - -struct sparc_percpu *percpu_table; - -void -sparc_cpu_init(void) -{ - /* We now have our per-cpu mappings ok, and we should - * be good to go. - */ - - /* Do cache crap here. */ - - /* CPU initted, idle the puppy. */ - - return; -} - -extern thiscpus_mid; - -void -sparc_cpu_idle(void) -{ - int cpuid; - -/* cpuid = get_cpuid(); */ - cpuid = (thiscpus_mid&(~8)); -/* printk("SMP: cpu%d has entered idle loop", cpuid); */ - - /* Say that we exist and set up. */ - percpu_table[cpuid].cpuid = cpuid; - percpu_table[cpuid].cpu_is_alive = 0x1; - percpu_table[cpuid].cpu_is_idling = 0x1; - - /* Let other cpus catch up. */ - while(linux_smp_still_initting) ; - printk("cpu%d done spinning\n", get_cpuid()); - for(;;) ; /* Do something useful here... */ - - return; -} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c --- v1.3.92/linux/arch/sparc/kernel/cpu.c Mon Mar 4 08:49:54 1996 +++ linux/arch/sparc/kernel/cpu.c Sun Apr 21 12:30:29 1996 @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c --- v1.3.92/linux/arch/sparc/kernel/devices.c Mon Mar 4 08:49:54 1996 +++ linux/arch/sparc/kernel/devices.c Sun Apr 21 12:30:29 1996 @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -15,7 +16,7 @@ int linux_num_cpus; extern void cpu_probe(void); -extern void auxio_probe(void); +extern void clock_stop_probe(void); /* tadpole.c */ unsigned long device_scan(unsigned long mem_start) @@ -25,13 +26,21 @@ int cpu_nds[NCPUS]; /* One node for each cpu */ int cpu_ctr = 0; +#if CONFIG_AP1000 + printk("Not scanning device list for CPUs\n"); + linux_num_cpus = 1; + return; +#endif + 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++; } 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)); @@ -40,6 +49,9 @@ linux_cpus[cpu_ctr].prom_node = scan; prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; + prom_printf("Found CPU %d \n", + cpu_ctr, (unsigned long) scan, + thismid); cpu_ctr++; } }; @@ -55,7 +67,13 @@ linux_num_cpus = cpu_ctr; cpu_probe(); - auxio_probe(); +#if CONFIG_SUN_AUXIO + { + extern void auxio_probe(void); + auxio_probe(); + } +#endif + clock_stop_probe(); return mem_start; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S --- v1.3.92/linux/arch/sparc/kernel/entry.S Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/entry.S Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.79 1996/03/01 07:15:54 davem Exp $ +/* $Id: entry.S,v 1.90 1996/04/18 01:00:37 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -20,25 +21,9 @@ #include #include -#define NR_SYSCALLS 255 /* Each OS is different... */ +#include -/* All trap entry points _must_ begin with this macro or else you - * lose. It makes sure the kernel has a proper window so that - * c-code can be called. Some day for SMP we'll grab klock here. - */ -#define SAVE_ALL \ - sethi %hi(trap_setup), %l4; \ - jmpl %l4 + %lo(trap_setup), %l6; \ - nop; - -/* All traps low-level code here must end with this macro. - * For SMP configurations the ret_trap_entry routine will - * have to appropriate code to actually release the kernel - * entry lock. - */ -#define RESTORE_ALL \ - b ret_trap_entry; \ - nop; +#define NR_SYSCALLS 255 /* Each OS is different... */ /* First, KGDB low level things. This is a rewrite * of the routines found in the sparc-stub.c asm() statement @@ -63,6 +48,7 @@ C_LABEL(trap_low): rd %wim, %l3 SAVE_ALL + ENTER_SYSCALL sethi %hi(in_trap_handler), %l4 ld [%lo(in_trap_handler) + %l4], %l5 @@ -228,18 +214,30 @@ /* Flip terminal count pin */ set C_LABEL(auxio_register), %l4 ld [%l4], %l4 - ldub [%l4], %l5 - or %l5, 0xf4, %l5 + + set C_LABEL(sparc_cpu_model), %l5 + ld [%l5], %l5 + subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */ + be 1f + ldub [%l4], %l5 + + or %l5, 0xc2, %l5 stb %l5, [%l4] + andn %l5, 0x02, %l5 + b 2f + nop + +1: + or %l5, 0xf4, %l5 + stb %l5, [%l4] + andn %l5, 0x04, %l5 +2: /* Kill some time so the bits set */ WRITE_PAUSE WRITE_PAUSE - ldub [%l4], %l5 - andn %l5, 0x04, %l5 - or %l5, 0xf0, %l5 - stb %l5, [%l4] + stb %l5, [%l4] /* Prevent recursion */ sethi %hi(C_LABEL(doing_pdma)), %l4 @@ -277,6 +275,7 @@ floppy_dosoftint: rd %wim, %l3 SAVE_ALL + ENTER_IRQ /* Set all IRQs off. */ or %l0, PSR_PIL, %l4 @@ -288,6 +287,7 @@ call C_LABEL(floppy_interrupt) add %sp, REGWIN_SZ, %o1 ! struct pt_regs *regs + LEAVE_IRQ RESTORE_ALL #endif /* (CONFIG_BLK_DEV_FD) */ @@ -296,6 +296,7 @@ .globl bad_trap_handler bad_trap_handler: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -316,6 +317,52 @@ .globl real_irq_entry real_irq_entry: SAVE_ALL +#ifdef __SMP__ + cmp %l7, 9 + bne 1f + nop + + GET_PROCESSOR_MID(l4, l5) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %l5 + sethi %hi(0x02000000), %l6 + sll %l4, 12, %l4 + add %l5, %l4, %l5 + ld [%l5], %l4 + andcc %l4, %l6, %g0 + be 1f + nop + + b linux_trap_ipi9_sun4m + nop + +1: +#endif + ENTER_IRQ + +#ifdef __SMP__ + cmp %l7, 13 + bne 1f + nop + + /* This is where we catch the level 13 reschedule soft-IRQ. */ + GET_PROCESSOR_MID(o3, o2) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sethi %hi(0x20000000), %o4 + sll %o3, 12, %o3 + add %o5, %o3, %o5 + ld [%o5], %o1 ! read processor irq pending reg + andcc %o1, %o4, %g0 + be 1f + nop + + b linux_trap_ipi13_sun4m + nop + +1: + +#endif /* start atomic operation with respect to software interrupts */ sethi %hi(C_LABEL(intr_count)), %l4 @@ -328,7 +375,9 @@ * to work around a MicroSPARC bug of sorts. */ or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE wr %l4, PSR_ET, %psr WRITE_PAUSE @@ -351,13 +400,6 @@ be 2f nop - /* do_bottom_half must run at normal kernel priority, ie. all - * IRQ's on. - */ - rd %psr, %g4 - andn %g4, PSR_PIL, %g4 - wr %g4, 0x0, %psr - WRITE_PAUSE call C_LABEL(do_bottom_half) nop @@ -368,15 +410,17 @@ 2: st %l5, [%l4 + %lo(C_LABEL(intr_count))] + LEAVE_IRQ RESTORE_ALL - /* This routine handles illegal instructions and privileged + /* This routine handles illegal isntructions and privileged * instruction attempts from user code. */ .align 4 .globl bad_instruction bad_instruction: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -386,12 +430,14 @@ mov %l2, %o2 call C_LABEL(do_illegal_instruction) mov %l0, %o3 + RESTORE_ALL .align 4 .globl priv_instruction priv_instruction: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -410,6 +456,7 @@ .globl mna_handler mna_handler: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -427,6 +474,7 @@ .globl fpd_trap_handler fpd_trap_handler: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -445,16 +493,28 @@ fpe_trap_handler: set fpsave_magic, %l5 cmp %l1, %l5 - bne 1f - sethi %hi(fpsave_catch), %l5 + be 1f + sethi %hi(C_LABEL(fpsave)), %l5 + or %l5, %lo(C_LABEL(fpsave)), %l5 + cmp %l1, %l5 + bne 2f + sethi %hi(fpsave_catch2), %l5 + or %l5, %lo(fpsave_catch2), %l5 + wr %l0, 0x0, %psr + WRITE_PAUSE + jmp %l5 + rett %l5 + 4 +1: + sethi %hi(fpsave_catch), %l5 or %l5, %lo(fpsave_catch), %l5 wr %l0, 0x0, %psr WRITE_PAUSE jmp %l5 rett %l5 + 4 -1: +2: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -472,6 +532,7 @@ .globl do_tag_overflow do_tag_overflow: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -489,6 +550,7 @@ .globl do_watchpoint do_watchpoint: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -506,6 +568,7 @@ .globl do_reg_access do_reg_access: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -523,6 +586,7 @@ .globl do_cp_disabled do_cp_disabled: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -540,6 +604,7 @@ .globl do_bad_flush do_bad_flush: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -557,6 +622,7 @@ .globl do_cp_exception do_cp_exception: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -574,6 +640,7 @@ .globl do_hw_divzero do_hw_divzero: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr ! re-enable traps WRITE_PAUSE @@ -590,6 +657,7 @@ .globl do_flush_windows do_flush_windows: SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -612,6 +680,13 @@ /* We get these for debugging routines using __builtin_return_address() */ dfw_kernel: FLUSH_ALL_KERNEL_WINDOWS + + /* Advance over the trap instruction. */ + ld [%sp + REGWIN_SZ + PT_NPC], %l1 + add %l1, 0x4, %l2 + st %l1, [%sp + REGWIN_SZ + PT_PC] + st %l2, [%sp + REGWIN_SZ + PT_NPC] + RESTORE_ALL /* The getcc software trap. The user wants the condition codes from @@ -650,9 +725,10 @@ .globl linux_trap_nmi_sun4c linux_trap_nmi_sun4c: SAVE_ALL + ENTER_SYSCALL /* Ugh, we need to clear the IRQ line. This is now - * a very sun4c specific trap handler... + * a very sun4c specific trap hanler... */ sethi %hi(C_LABEL(interrupt_enable)), %l5 ld [%l5 + %lo(C_LABEL(interrupt_enable))], %l5 @@ -683,57 +759,153 @@ RESTORE_ALL -#if 0 /* WIP */ - /* Inter-Processor Interrupts on the Sun4m. */ +#ifdef __SMP__ + .align 4 - .globl sun4m_ipi -sun4m_ipi: - SAVE_ALL_IPI4M - - set MAILBOX_ADDRESS, %l4 - ldub [%l4], %l5 - subcc %l5, MBOX_STOPCPU, %g0 - bne,a 1f - subcc %l5, MBOX_STOPCPU2, %g0 - - call C_LABEL(prom_stopcpu) - mov 0, %o0 - ba,a 2f + .globl linux_trap_ipi9_sun4m +linux_trap_ipi9_sun4m: + sethi %hi(0x02000000), %o2 + GET_PROCESSOR_MID(o0, o1) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sll %o0, 12, %o0 + add %o5, %o0, %o5 + st %o2, [%o5 + 4] + WRITE_PAUSE -1: - bne,a 1f - subcc %l5, MBOX_IDLECPU, %g0 + ld [%o5], %g0 + WRITE_PAUSE - call C_LABEL(prom_stopcpu) - mov 0, %o0 - ba,a 2f + /* IRQ's off else we deadlock. */ + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE -1: - bne,a 1f - subcc %l5, MBOX_IDLECPU2, %g0 + wr %l4, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(smp_message_irq) + nop - call C_LABEL(prom_idlecpu) - mov 0, %o0 - ba,a 2f + RESTORE_ALL_FASTIRQ -1: - bne,a 2f + .align 4 + .globl linux_trap_ipi13_sun4m +linux_trap_ipi13_sun4m: + /* NOTE: real_irq_entry saved state and grabbed klock already. */ + + /* start atomic operation with respect to software interrupts */ + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + add %l5, 0x1, %l5 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] + + sethi %hi(0x20000000), %o2 + GET_PROCESSOR_MID(o0, o1) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sll %o0, 12, %o0 + add %o5, %o0, %o5 + st %o2, [%o5 + 4] + WRITE_PAUSE + + ld [%o5], %g0 + WRITE_PAUSE + + /* IRQ's off else we deadlock. */ + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + + wr %l4, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(smp_reschedule_irq) nop - call C_LABEL(prom_idlecpu) - mov 0, %o0 - ba,a 2f + sethi %hi(C_LABEL(intr_count)), %l4 + ld [%l4 + %lo(C_LABEL(intr_count))], %l5 + sub %l5, 0x1, %l5 + st %l5, [%l4 + %lo(C_LABEL(intr_count))] -2: - call C_LABEL(smp_callin) + LEAVE_IRQ + RESTORE_ALL + + .align 4 + .globl linux_trap_ipi15_sun4m +linux_trap_ipi15_sun4m: + SAVE_ALL + + /* First check for hard NMI memory error. */ + sethi %hi(0xf0000000), %o2 + set C_LABEL(sun4m_interrupts), %l5 + set 0x4000, %o3 + ld [%l5], %l5 + add %l5, %o3, %l5 + ld [%l5], %l6 + andcc %o2, %l6, %o2 + be 1f + nop + + /* Asyncronous fault, why you little ?!#&%@... */ + sethi %hi(0x80000000), %o2 + st %o2, [%l5 + 0xc] + WRITE_PAUSE + ld [%l5], %g0 + WRITE_PAUSE + + /* All interrupts are off... now safe to enable traps + * and call C-code. + */ + or %l0, PSR_PIL, %l4 ! I am very paranoid... + wr %l4, 0x0, %psr + WRITE_PAUSE + wr %l4, PSR_ET, %psr + WRITE_PAUSE + call C_LABEL(sun4m_nmi) + nop + + sethi %hi(0x80000000), %o2 + st %o2, [%l5 + 0x8] + WRITE_PAUSE + ld [%l5], %g0 + WRITE_PAUSE + + RESTORE_ALL_FASTIRQ + +1: + sethi %hi(0x80000000), %o2 + GET_PROCESSOR_MID(o0, o1) + set C_LABEL(sun4m_interrupts), %l5 + ld [%l5], %o5 + sll %o0, 12, %o0 + add %o5, %o0, %o5 + st %o2, [%o5 + 4] + WRITE_PAUSE + + ld [%o5], %g0 + WRITE_PAUSE + + /* IRQ's off else we deadlock. */ + or %l0, PSR_PIL, %l4 + wr %l4, 0x0, %psr + WRITE_PAUSE + + wr %l4, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(smp_message_irq) + nop + + RESTORE_ALL_FASTIRQ - RESTORE_ALL_IPI4M #endif .align 4 .globl sun4c_fault sun4c_fault: SAVE_ALL + ENTER_SYSCALL /* XXX This needs to be scheduled better */ sethi %hi(AC_SYNC_ERR), %l4 @@ -755,26 +927,22 @@ .align 4 .globl C_LABEL(srmmu_fault) C_LABEL(srmmu_fault): - /* Slot 1 */ mov 0x400, %l5 mov 0x300, %l4 - /* Slot 2 */ lda [%l5] ASI_M_MMUREGS, %l6 ! read sfar first lda [%l4] ASI_M_MMUREGS, %l5 ! read sfsr last - /* Slot 3 */ andn %l6, 0xfff, %l6 srl %l5, 6, %l5 ! and encode all info into l7 - /* Slot 4 */ and %l5, 2, %l5 or %l5, %l6, %l6 - /* Slot 5 */ or %l6, %l7, %l7 ! l7 = [addr,write,txtfault] SAVE_ALL + ENTER_SYSCALL mov %l7, %o1 mov %l7, %o2 @@ -814,11 +982,12 @@ ld [%sp + REGWIN_SZ + PT_I1], %o0 ld [%sp + REGWIN_SZ + PT_I2], %o1 ld [%sp + REGWIN_SZ + PT_I3], %o2 + mov %o7, %l5 ld [%sp + REGWIN_SZ + PT_I4], %o3 call %l6 ld [%sp + REGWIN_SZ + PT_I5], %o4 - b scall_store_args /* so stupid... */ + jmp %l5 + 0x8 /* so stupid... */ nop #if 0 /* work in progress */ @@ -834,19 +1003,22 @@ .align 4 .globl C_LABEL(sys_execve) C_LABEL(sys_execve): + mov %o7, %l5 call C_LABEL(sparc_execve) add %sp, REGWIN_SZ, %o0 ! pt_regs *regs arg - b scall_store_args + jmp %l5 + 0x8 nop .align 4 .globl C_LABEL(sys_pipe) C_LABEL(sys_pipe): + mov %o7, %l5 + call C_LABEL(sparc_pipe) add %sp, REGWIN_SZ, %o0 ! pt_regs *regs arg - b C_LABEL(ret_sys_call) + jmp %l5 + 0x8 nop .align 4 @@ -857,18 +1029,15 @@ add %sp, REGWIN_SZ, %o1 /* We are returning to a signal handler. */ - RESTORE_ALL .align 4 .globl C_LABEL(sys_sigsuspend) C_LABEL(sys_sigsuspend): - ld [%sp + REGWIN_SZ + PT_I0], %o0 call C_LABEL(do_sigsuspend) - add %sp, REGWIN_SZ, %o1 + add %sp, REGWIN_SZ, %o0 /* We are returning to a signal handler. */ - RESTORE_ALL .align 4 @@ -890,6 +1059,8 @@ .globl C_LABEL(sys_fork), C_LABEL(sys_vfork) C_LABEL(sys_vfork): C_LABEL(sys_fork): + mov %o7, %l5 + /* Save the kernel state as of now. */ FLUSH_ALL_KERNEL_WINDOWS; STORE_WINDOW(sp) @@ -903,12 +1074,14 @@ call C_LABEL(do_fork) add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr - b scall_store_args + jmp %l5 + 0x8 nop /* Whee, kernel threads! */ .globl C_LABEL(sys_clone) C_LABEL(sys_clone): + mov %o7, %l5 + /* Save the kernel state as of now. */ FLUSH_ALL_KERNEL_WINDOWS; STORE_WINDOW(sp) @@ -925,10 +1098,10 @@ call C_LABEL(do_fork) add %sp, REGWIN_SZ, %o2 ! arg2: pt_regs ptr - b scall_store_args + jmp %l5 + 0x8 nop - /* All system calls enter here... */ + /* Linux native and SunOS system calls enter here... */ .align 4 .globl linux_sparc_syscall linux_sparc_syscall: @@ -953,8 +1126,9 @@ blu,a 1f sll %g1, 2, %l4 + set C_LABEL(sys_ni_syscall), %l7 b syscall_is_too_hard - set C_LABEL(sys_ni_syscall), %l7 + nop 1: ld [%l7 + %l4], %l7 @@ -974,6 +1148,7 @@ syscall_is_too_hard: rd %wim, %l3 SAVE_ALL + ENTER_SYSCALL wr %l0, PSR_ET, %psr WRITE_PAUSE @@ -985,7 +1160,6 @@ call %l7 ldd [%sp + REGWIN_SZ + PT_I4], %o4 -scall_store_args: st %o0, [%sp + REGWIN_SZ + PT_I0] .globl C_LABEL(ret_sys_call) @@ -1019,6 +1193,192 @@ RESTORE_ALL + /* Solaris system calls enter here... */ + .align 4 + .globl solaris_syscall +solaris_syscall: + /* While we are here trying to optimize our lives + * away, handle the easy bogus cases like a + * ni_syscall or sysnum > NR_SYSCALLS etc. + * In the cases where we cannot optimize the + * call inline we don't really lose anything + * performance wise because we are doing here + * things which we did anyway in the original + * routine. The only added complexity is a + * bit test, compare, and branch to decide + * if we need to save process state or not. + */ + + /* XXX TODO: When we have ptrace working test + * XXX test for PF_TRACESYS in task flags. + */ + + /* Direct access to user regs, must faster. */ + cmp %g1, NR_SYSCALLS + blu,a 1f + sll %g1, 2, %l4 + + set C_LABEL(sys_ni_syscall), %l7 + b solaris_is_too_hard + nop + +1: + ld [%l7 + %l4], %l7 + + /* If bit-1 is set, this is a "fast" syscall. + * This is the _complete_ overhead of this optimization, + * and we save ourselves a load, so it evens out to nothing. + */ + andcc %l7, 0x1, %g0 + be solaris_is_too_hard + andn %l7, 0x1, %l7 + + jmpl %l7, %g0 + nop + + .globl solaris_is_too_hard +solaris_is_too_hard: + rd %wim, %l3 + SAVE_ALL + ENTER_SYSCALL + + wr %l0, PSR_ET, %psr + WRITE_PAUSE + +2: + ldd [%sp + REGWIN_SZ + PT_I0], %o0 + st %o0, [%sp + REGWIN_SZ + PT_G0] ! for restarting syscalls + ldd [%sp + REGWIN_SZ + PT_I2], %o2 + call %l7 + ldd [%sp + REGWIN_SZ + PT_I4], %o4 + + st %o0, [%sp + REGWIN_SZ + PT_I0] + set PSR_C, %l6 + cmp %o0, -ENOIOCTLCMD + bgeu 1f + ld [%sp + REGWIN_SZ + PT_PSR], %l5 + + /* System call success, clear Carry condition code. */ + andn %l5, %l6, %l5 + b 2f + st %l5, [%sp + REGWIN_SZ + PT_PSR] + +1: + /* System call failure, set Carry condition code. + * Also, get abs(errno) to return to the process. + */ + sub %g0, %o0, %o0 + sethi %hi(C_LABEL(solaris_xlatb_rorl)), %o3 + or %o3, %lo(C_LABEL(solaris_xlatb_rorl)), %o3 + sll %o0, 2, %o0 + ld [%o3 + %o0], %o0 + st %o0, [%sp + REGWIN_SZ + PT_I0] + or %l5, %l6, %l5 + st %l5, [%sp + REGWIN_SZ + PT_PSR] + + /* Advance the pc and npc over the trap instruction. */ +2: + ld [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc = npc */ + add %l1, 0x4, %l2 /* npc = npc+4 */ + st %l1, [%sp + REGWIN_SZ + PT_PC] + st %l2, [%sp + REGWIN_SZ + PT_NPC] + + RESTORE_ALL + + /* {net, open}bsd system calls enter here... */ + .align 4 + .globl bsd_syscall +bsd_syscall: + /* While we are here trying to optimize our lives + * away, handle the easy bogus cases like a + * ni_syscall or sysnum > NR_SYSCALLS etc. + * In the cases where we cannot optimize the + * call inline we don't really lose anything + * performance wise because we are doing here + * things which we did anyway in the original + * routine. The only added complexity is a + * bit test, compare, and branch to decide + * if we need to save process state or not. + */ + + /* XXX TODO: When we have ptrace working test + * XXX test for PF_TRACESYS in task flags. + */ + + /* Direct access to user regs, must faster. */ + cmp %g1, NR_SYSCALLS + blu,a 1f + sll %g1, 2, %l4 + + set C_LABEL(sys_ni_syscall), %l7 + b bsd_is_too_hard + nop + +1: + ld [%l7 + %l4], %l7 + + /* If bit-1 is set, this is a "fast" syscall. + * This is the _complete_ overhead of this optimization, + * and we save ourselves a load, so it evens out to nothing. + */ + andcc %l7, 0x1, %g0 + be bsd_is_too_hard + andn %l7, 0x1, %l7 + + jmpl %l7, %g0 + nop + + .globl bsd_is_too_hard +bsd_is_too_hard: + rd %wim, %l3 + SAVE_ALL + ENTER_SYSCALL + + wr %l0, PSR_ET, %psr + WRITE_PAUSE + +2: + ldd [%sp + REGWIN_SZ + PT_I0], %o0 + st %o0, [%sp + REGWIN_SZ + PT_G0] ! for restarting syscalls + ldd [%sp + REGWIN_SZ + PT_I2], %o2 + call %l7 + ldd [%sp + REGWIN_SZ + PT_I4], %o4 + + st %o0, [%sp + REGWIN_SZ + PT_I0] + set PSR_C, %l6 + cmp %o0, -ENOIOCTLCMD + bgeu 1f + ld [%sp + REGWIN_SZ + PT_PSR], %l5 + + /* System call success, clear Carry condition code. */ + andn %l5, %l6, %l5 + b 2f + st %l5, [%sp + REGWIN_SZ + PT_PSR] + +1: + /* System call failure, set Carry condition code. + * Also, get abs(errno) to return to the process. + */ + sub %g0, %o0, %o0 +#if 0 /* XXX todo XXX */ + sethi %hi(C_LABEL(bsd_xlatb_rorl), %o3 + or %o3, %lo(C_LABEL(bsd_xlatb_rorl)), %o3 + sll %o0, 2, %o0 + ld [%o3 + %o0], %o0 +#endif + st %o0, [%sp + REGWIN_SZ + PT_I0] + or %l5, %l6, %l5 + st %l5, [%sp + REGWIN_SZ + PT_PSR] + + /* Advance the pc and npc over the trap instruction. */ +2: + ld [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc = npc */ + add %l1, 0x4, %l2 /* npc = npc+4 */ + st %l1, [%sp + REGWIN_SZ + PT_PC] + st %l2, [%sp + REGWIN_SZ + PT_NPC] + + RESTORE_ALL + /* Saving and restoring the FPU state is best done from lowlevel code. * * void fpsave(unsigned long *fpregs, unsigned long *fsr, @@ -1027,7 +1387,7 @@ .globl C_LABEL(fpsave) C_LABEL(fpsave): - st %fsr, [%o1] + st %fsr, [%o1] ! this can trap on us if fpu is in bogon state ld [%o1], %g1 set 0x2000, %g4 andcc %g1, %g4, %g0 @@ -1075,6 +1435,10 @@ b fpsave_magic + 4 st %fsr, [%o1] +fpsave_catch2: + b C_LABEL(fpsave) + 4 + st %fsr, [%o1] + /* void fpload(unsigned long *fpregs, unsigned long *fsr); */ .globl C_LABEL(fpload) @@ -1106,9 +1470,16 @@ sethi %hi(0x10c6), %o1 call .umul or %o1, %lo(0x10c6), %o1 +#ifndef __SMP__ sethi %hi(C_LABEL(loops_per_sec)), %o3 call .umul ld [%o3 + %lo(C_LABEL(loops_per_sec))], %o1 +#else + GET_PROCESSOR_OFFSET(o4) + set C_LABEL(cpu_data), %o3 + call .umul + ld [%o3 + %o4], %o1 +#endif cmp %o1, 0x0 1: diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S --- v1.3.92/linux/arch/sparc/kernel/etrap.S Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/etrap.S Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.16 1996/02/20 07:45:01 davem Exp $ +/* $Id: etrap.S,v 1.17 1996/03/07 06:26:43 davem Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * @@ -65,7 +65,7 @@ * T == Window entered when trap occurred * S == Window we will need to save if (1< +#include #include #include @@ -80,6 +81,9 @@ _stext: start: C_LABEL(trapbase): +#ifdef __SMP__ +C_LABEL(trapbase_cpu0): +#endif /* We get control passed to us here at t_zero. */ t_zero: b gokernel; nop; nop; nop; t_tflt: SPARC_TFAULT /* Inst. Access Exception */ @@ -108,7 +112,11 @@ t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ +#ifndef __SMP__ t_nmi: NMI_TRAP /* Level 15 (NMI) */ +#else + TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) +#endif t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) @@ -116,7 +124,7 @@ t_uflsh:TRAP_ENTRY(0x25, do_bad_flush) /* Unimplemented FLUSH inst. */ t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ -t_dacce:BAD_TRAP(0x29) /* Data Access Error */ +t_dacce:SPARC_DFAULT /* Data Access Error */ t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ @@ -181,6 +189,214 @@ .globl C_LABEL(end_traptable) C_LABEL(end_traptable): +#ifdef __SMP__ + /* Trap tables for the other cpus. */ + .globl C_LABEL(trapbase_cpu1), C_LABEL(trapbase_cpu2), C_LABEL(trapbase_cpu3) +C_LABEL(trapbase_cpu1): + BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) + TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) + WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) + TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT + TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) + BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) + TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) + TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) + TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) + TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) + TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) + TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) + TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) + TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) + TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) + BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush) + BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) + SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) + BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) + BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) + BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) + BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) + BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) + BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) + BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) + BAD_TRAP(0x50) + BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) + BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) + BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) + BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) + BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) + BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) + BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) + BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) + BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) + BAD_TRAP(0x7e) BAD_TRAP(0x7f) + SUNOS_SYSCALL_TRAP BAD_TRAP(0x81) BAD_TRAP(0x82) + TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) + BAD_TRAP(0x86) BAD_TRAP(0x87) SOLARIS_SYSCALL_TRAP + NETBSD_SYSCALL_TRAP BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) + BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) + LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) + BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) + BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP + BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) + BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) + BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) + BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) + BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) + BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) + BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) + BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) + BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) + BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) + BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) + BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) + BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) + BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) + BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) + BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) + BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) + BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) + +C_LABEL(trapbase_cpu2): + BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) + TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) + WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) + TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT + TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) + BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) + TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) + TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) + TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) + TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) + TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) + TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) + TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) + TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) + TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) + BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush) + BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) + SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) + BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) + BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) + BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) + BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) + BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) + BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) + BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) + BAD_TRAP(0x50) + BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) + BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) + BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) + BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) + BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) + BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) + BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) + BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) + BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) + BAD_TRAP(0x7e) BAD_TRAP(0x7f) + SUNOS_SYSCALL_TRAP BAD_TRAP(0x81) BAD_TRAP(0x82) + TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) + BAD_TRAP(0x86) BAD_TRAP(0x87) SOLARIS_SYSCALL_TRAP + NETBSD_SYSCALL_TRAP BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) + BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) + LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) + BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) + BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP + BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) + BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) + BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) + BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) + BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) + BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) + BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) + BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) + BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) + BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) + BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) + BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) + BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) + BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) + BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) + BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) + BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) + BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) + +C_LABEL(trapbase_cpu3): + BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) + TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) + WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) + TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT + TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) + BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) + TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) + TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) + TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) + TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) + TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) + TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) + TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) + TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) + TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) + BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) TRAP_ENTRY(0x25, do_bad_flush) + BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) + SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) + BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) + BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) + BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) + BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) + BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) + BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) + BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) + BAD_TRAP(0x50) + BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) + BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) + BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) + BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) + BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) + BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) + BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) + BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) + BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) + BAD_TRAP(0x7e) BAD_TRAP(0x7f) + SUNOS_SYSCALL_TRAP BAD_TRAP(0x81) BAD_TRAP(0x82) + TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) + BAD_TRAP(0x86) BAD_TRAP(0x87) SOLARIS_SYSCALL_TRAP + NETBSD_SYSCALL_TRAP BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) + BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) + LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) + BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) + BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) + BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP + BAD_TRAP(0xa2) BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) + BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) + BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) + BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) + BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) + BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) + BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) + BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) + BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) + BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) + BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) + BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) + BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) + BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) + BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) + BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) + BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) + BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) + BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) + + .globl C_LABEL(cpu0_stack), C_LABEL(cpu1_stack), C_LABEL(cpu2_stack) + .globl C_LABEL(cpu3_stack) +C_LABEL(cpu0_stack): .skip 0x2000 +C_LABEL(cpu1_stack): .skip 0x2000 +C_LABEL(cpu2_stack): .skip 0x2000 +C_LABEL(cpu3_stack): .skip 0x2000 +#endif .skip 4096 /* This was the only reasonable way I could think of to properly align @@ -193,8 +409,8 @@ .globl C_LABEL(empty_bad_page_table) .globl C_LABEL(empty_zero_page) .globl C_LABEL(swapper_pg_dir) -C_LABEL(bootup_user_stack): .skip 0x1000 -C_LABEL(bootup_kernel_stack): .skip 0x1000 +C_LABEL(bootup_user_stack): .skip 0x2000 +C_LABEL(bootup_kernel_stack): .skip 0x2000 C_LABEL(swapper_pg_dir): .skip 0x1000 C_LABEL(pg0): .skip 0x1000 C_LABEL(empty_bad_page): .skip 0x1000 @@ -218,8 +434,6 @@ * label, then see what %o7 has. */ - /* XXX Sparc V9 detection goes here XXX */ - mov %o7, %g4 ! Save %o7 /* Jump to it, and pray... */ @@ -258,6 +472,19 @@ /* Copy over the Prom's level 14 clock handler. */ copy_prom_lvl14: +#if 1 + /* DJHR + * preserve our linked/calculated instructions + */ + set C_LABEL(lvl14_save), %g1 + set t_irq14, %g3 + sub %g1, %l6, %g1 ! translate to physical + sub %g3, %l6, %g3 ! translate to physical + ldd [%g3], %g4 + std %g4, [%g1] + ldd [%g3+8], %g4 + std %g4, [%g1+8] +#endif rd %tbr, %g1 andn %g1, 0xfff, %g1 ! proms trap table base or %g0, (0x1e<<4), %g2 ! offset to lvl14 intr @@ -272,8 +499,6 @@ /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT * MMU so we can remap ourselves properly. DONT TOUCH %l0 thru %l5 in these * remapping routines, we need their values afterwards! - * - * XXX UGH, need to write some sun4u SpitFire remapping V9 code RSN... XXX */ /* Now check whether we are already mapped, if we * are we can skip all this garbage coming up. @@ -357,7 +582,7 @@ /* Calculate to KERNBASE entry. * - * XXX Should not use empirical constant, but Gas gets an XXX + * XXX Should not use imperical constant, but Gas gets an XXX * XXX upset stomach with the bitshift I would have to use XXX */ add %o1, 0x3c0, %o3 @@ -404,7 +629,7 @@ sll %g1, 0x8, %g1 ! make phys addr for l1 tbl lda [%g1] ASI_M_BYPASS, %g2 ! get level1 entry for 0x0 - add %g1, 0x3c0, %g3 ! XXX AWAY WITH EMPIRICALS + add %g1, 0x3c0, %g3 ! XXX AWAY WITH IMPERICALS sta %g2, [%g3] ASI_M_BYPASS ! place at KERNBASE entry b go_to_highmem nop ! wheee.... @@ -469,6 +694,11 @@ * I figure out and store nwindows and nwindowsm1 later on. */ execute_in_high_mem: +#if CONFIG_AP1000 + /* we don't have a prom :-( */ + b sun4m_init + nop +#endif mov %l0, %o0 ! put back romvec mov %l1, %o1 ! and debug_vec @@ -582,7 +812,7 @@ * be sitting in the fault status/address registers. Read them all to * clear them so we don't get magic faults later on. */ -/* This sucks, apparently this makes Vikings call prom panic, will fix later */ +/* This sucks, aparently this makes Vikings call prom panic, will fix later */ rd %psr, %o1 srl %o1, 28, %o1 ! Get a type of the CPU @@ -647,11 +877,9 @@ set C_LABEL(current_set), %g2 st %g4, [%g2] - /* So now this should work. */ - LOAD_CURRENT(g2, g4) - set C_LABEL(bootup_kernel_stack), %g4 - st %g4, [%g2 + TASK_KSTACK_PG] - st %g0, [%g2 + THREAD_UMASK] + set C_LABEL(bootup_kernel_stack), %g3 + st %g3, [%g4 + TASK_KSTACK_PG] + st %g0, [%g4 + THREAD_UMASK] /* Compute NWINDOWS and stash it away. Now uses %wim trick explained * in the V8 manual. Ok, this method seems to work, Sparc is cool... @@ -712,6 +940,17 @@ PATCH_INSN(rtrap_7win_patch4, rtrap_patch4) PATCH_INSN(rtrap_7win_patch5, rtrap_patch5) +#ifdef __SMP__ + + /* Patch for returning from an ipi... */ + PATCH_INSN(rirq_7win_patch1, rirq_patch1) + PATCH_INSN(rirq_7win_patch2, rirq_patch2) + PATCH_INSN(rirq_7win_patch3, rirq_patch3) + PATCH_INSN(rirq_7win_patch4, rirq_patch4) + PATCH_INSN(rirq_7win_patch5, rirq_patch5) + +#endif + 2: sethi %hi( C_LABEL(nwindows) ), %g4 st %g3, [%g4 + %lo( C_LABEL(nwindows) )] ! store final value @@ -727,6 +966,8 @@ /* Finally, turn on traps so that we can call c-code. */ rd %psr, %g3 wr %g3, 0x0, %psr + WRITE_PAUSE + wr %g3, PSR_ET, %psr WRITE_PAUSE @@ -821,4 +1062,13 @@ .word 0 .word 0 - .align 4 + .align 8 + + .globl C_LABEL(lvl14_save) +C_LABEL(lvl14_save): + .word 0 + .word 0 + .word 0 + .word 0 + .word t_irq14 + diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c --- v1.3.92/linux/arch/sparc/kernel/idprom.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/idprom.c Sun Apr 21 12:30:29 1996 @@ -21,7 +21,7 @@ /* Here is the master table of Sun machines which use some implementation * of the Sparc CPU and have a meaningful IDPROM machtype value that we - * know about. See asm-sparc/machines.h for empirical constants. + * know about. See asm-sparc/machines.h for imperical constants. */ struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { /* First, Sun4's */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/ioport.c linux/arch/sparc/kernel/ioport.c --- v1.3.92/linux/arch/sparc/kernel/ioport.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/ioport.c Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.14 1996/01/03 03:34:41 davem Exp $ +/* $Id: ioport.c,v 1.17 1996/03/23 02:39:13 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -31,7 +31,7 @@ static long dvma_next_free = DVMA_VADDR; /* - * sparc_alloc_dev: + * sparc_alloc_io: * Map and allocates an obio device. * Implements a simple linear allocator, you can force the function * to use your own mapping, but in practice this should not be used. @@ -61,7 +61,7 @@ len += offset; if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) { - prom_printf("alloc_io: Mapping outside IOBASE area\n"); + prom_printf("alloc_io: Mapping ouside IOBASE area\n"); prom_halt(); } if(check_region ((vaddr | offset), len)) { @@ -84,11 +84,11 @@ return (void *) (base_address | offset); } -/* Does DVMA allocations with PAGE_SIZE granularity. How this basically +/* Does DVMA allocations with PAGE_SIZE granulatity. How this basically * works is that the ESP chip can do DVMA transfers at ANY address with - * certain size and boundary restrictions. But other devices that are + * certain size and boundry restrictions. But other devices that are * attached to it and would like to do DVMA have to set things up in - * a special way, if the DVMA sees a device attached to it transfer data + * a special way, if the DVMA see's a device attached to it transfer data * at addresses above DVMA_VADDR it will grab them, this way it does not * now have to know the peculiarities of where to read the Lance data * from. (for example) diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c --- v1.3.92/linux/arch/sparc/kernel/irq.c Mon Mar 4 08:49:55 1996 +++ linux/arch/sparc/kernel/irq.c Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.34 1996/02/20 07:45:04 davem Exp $ +/* $Id: irq.c,v 1.43 1996/04/17 12:37:45 zaitcev 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 @@ -6,9 +6,11 @@ * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@jamica.lab.ipmce.su) + * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su) + * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) */ +#include #include #include #include @@ -22,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -30,146 +33,74 @@ #include #include -/* Pointer to the interrupt enable byte */ -unsigned char *interrupt_enable = 0; -struct sun4m_intregs *sun4m_interrupts; - -void sun4c_disable_irq(unsigned int irq_nr) -{ - unsigned long flags; - unsigned char current_mask, new_mask; - - if(sparc_cpu_model != sun4c) - return; - save_flags(flags); cli(); - current_mask = *interrupt_enable; - switch(irq_nr) { - case 1: - new_mask = ((current_mask) & (~(SUN4C_INT_E1))); - break; - case 8: - new_mask = ((current_mask) & (~(SUN4C_INT_E8))); - break; - case 10: - new_mask = ((current_mask) & (~(SUN4C_INT_E10))); - break; - case 14: - new_mask = ((current_mask) & (~(SUN4C_INT_E14))); - break; - default: - restore_flags(flags); - return; - } - *interrupt_enable = new_mask; - restore_flags(flags); -} - -void sun4m_disable_irq(unsigned int irq_nr) -{ -#if 0 - printk("IRQ routines not yet written for the sun4m\n"); - panic("disable_irq: Unsupported arch."); -#endif -} - -void disable_irq(unsigned int irq_nr) -{ - switch(sparc_cpu_model) { - case sun4c: - sun4c_disable_irq(irq_nr); - break; - case sun4m: - sun4m_disable_irq(irq_nr); - break; - default: - panic("disable_irq: Unsupported arch."); - } -} - -void sun4c_enable_irq(unsigned int irq_nr) -{ - unsigned long flags; - unsigned char current_mask, new_mask; - - if(sparc_cpu_model != sun4c) - return; - save_flags(flags); cli(); - current_mask = *interrupt_enable; - switch(irq_nr) { - case 1: - new_mask = ((current_mask) | SUN4C_INT_E1); - break; - case 8: - new_mask = ((current_mask) | SUN4C_INT_E8); - break; - case 10: - new_mask = ((current_mask) | SUN4C_INT_E10); - break; - case 14: - new_mask = ((current_mask) | SUN4C_INT_E14); - break; - default: - restore_flags(flags); - return; - } - *interrupt_enable = new_mask; - restore_flags(flags); -} +/* + * Dave Redman (djhr@tadpole.co.uk) + * + * IRQ numbers.. These are no longer restricted to 15.. + * + * this is done to enable SBUS cards and onboard IO to be masked + * correctly. using the interrupt level isn't good enough. + * + * For example: + * A device interrupting at sbus level6 and the Floppy both come in + * at IRQ11, but enabling and disabling them requires writing to + * different bits in the SLAVIO/SEC. + * + * As a result of these changes sun4m machines could now support + * directed CPU interrupts using the existing enable/disable irq code + * with tweaks. + * + */ -void sun4m_enable_irq(unsigned int irq_nr) +static void irq_panic(void) { -#if 0 - printk("IRQ routines not written for the sun4m yet.\n"); - panic("IRQ unsupported arch."); + extern char *cputypval; + prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval); + prom_halt(); +} + +void (*enable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; +void (*disable_irq)(unsigned int) = (void (*)(unsigned int)) irq_panic; +void (*clear_clock_irq)( void ) = irq_panic; +void (*clear_profile_irq)( void ) = irq_panic; +void (*load_profile_irq)( unsigned int ) = (void (*)(unsigned int)) irq_panic; +void (*init_timers)( void (*)(int, void *,struct pt_regs *)) = + (void (*)( void (*)(int, void *,struct pt_regs *))) irq_panic; + +#ifdef __SMP__ +void (*set_cpu_int)(int, int); +void (*clear_cpu_int)(int, int); +void (*set_irq_udt)(int); #endif -} - -void enable_irq(unsigned int irq_nr) -{ - switch(sparc_cpu_model) { - case sun4c: - sun4c_enable_irq(irq_nr); - break; - case sun4m: - sun4m_enable_irq(irq_nr); - break; - default: - panic("IRQ unsupported arch."); - } -} /* - * Initial irq handlers. + * Dave Redman (djhr@tadpole.co.uk) + * + * There used to be extern calls and hard coded values here.. very sucky! + * instead, because some of the devices attach very early, I do something + * equally sucky but at least we'll never try to free statically allocated + * space or call kmalloc before kmalloc_init :(. + * + * In fact its the timer10 that attaches first.. then timer14 + * then kmalloc_init is called.. then the tty interrupts attach. + * hmmm.... + * */ -extern void timer_interrupt(int, void *, struct pt_regs *); -extern void rs_interrupt(int, void *, struct pt_regs *); +#define MAX_STATIC_ALLOC 4 +static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; +static int static_irq_count = 0; -static struct irqaction timer_irq = { - timer_interrupt, - SA_INTERRUPT, - 0, "timer", - NULL, NULL -}; - -static struct irqaction serial_irq = { - rs_interrupt, - SA_INTERRUPT, - 0, "zilog serial", - NULL, NULL -}; - -static struct irqaction *irq_action[16] = { +static struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, - NULL, NULL, &timer_irq, NULL, &serial_irq, NULL , NULL, NULL + NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; - int get_irq_list(char *buf) { int i, len = 0; struct irqaction * action; - for (i = 0 ; i < 16 ; i++) { + for (i = 0 ; i < (NR_IRQS+1) ; i++) { action = *(i + irq_action); if (!action) continue; @@ -189,11 +120,14 @@ void free_irq(unsigned int irq, void *dev_id) { - struct irqaction * action = *(irq + irq_action); + struct irqaction * action; struct irqaction * tmp = NULL; unsigned long flags; - - if (irq > 14) { /* 14 irq levels on the sparc */ + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + action = *(cpu_irq + irq_action); + if (cpu_irq > 14) { /* 14 irq levels on the sparc */ printk("Trying to free bogus IRQ %d\n", irq); return; } @@ -214,15 +148,25 @@ printk("Trying to free shared IRQ%d with NULL device ID\n", irq); return; } + if (action->flags & SA_STATIC_ALLOC) + { + /* This interrupt is marked as specially allocted + * so it is a bad idea to free it. + */ + printk("Attempt to free statically allocated IRQ%d (%s)\n", + irq, action->name); + return; + } + save_flags(flags); cli(); if (action && tmp) tmp->next = action->next; else - *(irq + irq_action) = action->next; + *(cpu_irq + irq_action) = action->next; kfree_s(action, sizeof(struct irqaction)); - if (!(*(irq + irq_action))) + if (!(*(cpu_irq + irq_action))) disable_irq(irq); restore_flags(flags); @@ -231,7 +175,11 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs) { int i; - struct irqaction * action = *(irq + irq_action); + struct irqaction * action; + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + action = *(cpu_irq + irq_action); printk("IO device interrupt, irq = %d\n", irq); printk("PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc, @@ -247,9 +195,15 @@ void handler_irq(int irq, struct pt_regs * regs) { - struct irqaction * action = *(irq + irq_action); - - kstat.interrupts[irq]++; + struct irqaction * action; + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + action = *(cpu_irq + irq_action); + kstat.interrupts[cpu_irq]++; +#if 0 + printk("I<%d,%d,%d>", smp_processor_id(), irq, smp_proc_in_lock[smp_processor_id()]); +#endif while (action) { if (!action->handler) unexpected_irq(irq, action->dev_id, regs); @@ -268,9 +222,12 @@ */ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { - struct irqaction * action = *(irq + irq_action); - - kstat.interrupts[irq]++; + struct irqaction * action; + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + action = *(cpu_irq + irq_action); + kstat.interrupts[cpu_irq]++; while (action) { action->handler(irq, action->dev_id, regs); action = action->next; @@ -284,7 +241,7 @@ */ asmlinkage void do_fast_IRQ(int irq) { - kstat.interrupts[irq]++; + kstat.interrupts[irq&NR_IRQS]++; printk("Got FAST_IRQ number %04lx\n", (long unsigned int) irq); return; } @@ -292,17 +249,20 @@ /* Fast IRQ's on the Sparc can only have one routine attached to them, * thus no sharing possible. */ -int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +int request_fast_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *devname) { struct irqaction *action; unsigned long flags; - - if(irq > 14) + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + if(cpu_irq > 14) return -EINVAL; if(!handler) return -EINVAL; - action = *(irq + irq_action); + action = *(cpu_irq + irq_action); if(action) { if(action->flags & SA_SHIRQ) panic("Trying to register fast irq when already shared.\n"); @@ -315,20 +275,32 @@ save_flags(flags); cli(); - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); - + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + 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), + GFP_KERNEL); + if (!action) { restore_flags(flags); return -ENOMEM; } /* Dork with trap table if we get this far. */ - sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one = + sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_BRANCH((unsigned long) handler, (unsigned long) &sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_one); - sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_two = SPARC_RD_PSR_L0; - sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_three = SPARC_NOP; - sparc_ttable[SP_TRAP_IRQ1+(irq-1)].inst_four = SPARC_NOP; + sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = SPARC_RD_PSR_L0; + sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_NOP; + sparc_ttable[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP; action->handler = handler; action->flags = irqflags; @@ -336,24 +308,28 @@ action->name = devname; action->dev_id = NULL; - *(irq + irq_action) = action; + *(cpu_irq + irq_action) = action; + enable_irq(irq); restore_flags(flags); return 0; } -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), +int request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { struct irqaction * action, *tmp = NULL; unsigned long flags; - - if(irq > 14) + unsigned int cpu_irq; + + cpu_irq = irq & NR_IRQS; + if(cpu_irq > 14) return -EINVAL; if (!handler) return -EINVAL; - action = *(irq + irq_action); + action = *(cpu_irq + irq_action); if (action) { if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) { for (tmp = action; tmp->next; tmp = tmp->next); @@ -367,8 +343,20 @@ } save_flags(flags); cli(); - action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + /* If this is flagged as statically allocated then we use our + * private struct which is never freed. + */ + 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), + GFP_KERNEL); + if (!action) { restore_flags(flags); return -ENOMEM; @@ -384,7 +372,7 @@ if (tmp) tmp->next = action; else - *(irq + irq_action) = action; + *(cpu_irq + irq_action) = action; enable_irq(irq); restore_flags(flags); @@ -404,65 +392,33 @@ return 0; } -void sun4c_init_IRQ(void) -{ - struct linux_prom_registers int_regs[2]; - int ie_node; - - ie_node = prom_searchsiblings (prom_getchild(prom_root_node), - "interrupt-enable"); - if(ie_node == 0) - panic("Cannot find /interrupt-enable node"); - /* Depending on the "address" property is bad news... */ - prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); - interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0, - int_regs[0].reg_size, - "sun4c_interrupts", - int_regs[0].which_io, 0x0); - *interrupt_enable = (SUN4C_INT_ENABLE); - sti(); -} - -void sun4m_init_IRQ(void) -{ - int ie_node; - - struct linux_prom_registers int_regs[PROMREG_MAX]; - int num_regs; - - cli(); - if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || - (ie_node = prom_getchild (ie_node)) == 0 || - (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) - panic("Cannot find /obio/interrupt node\n"); - num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, - sizeof(int_regs)); - num_regs = (num_regs/sizeof(struct linux_prom_registers)); - - /* Apply the obio ranges to these registers. */ - prom_apply_obio_ranges(int_regs, num_regs); - - /* Map the interrupt registers for all possible cpus. */ - sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "interrupts_percpu", - int_regs[0].which_io, 0x0); - - /* Map the system interrupt control registers. */ - sparc_alloc_io(int_regs[num_regs-1].phys_addr, 0, - int_regs[num_regs-1].reg_size, "interrupts_system", - int_regs[num_regs-1].which_io, 0x0); - sti(); -} +/* djhr + * This could probably be made indirect too and assigned in the CPU + * bits of the code. That would be much nicer I think and would also + * fit in with the idea of being able to tune your kernel for your machine + * by removing unrequired machine and device support. + * + */ void init_IRQ(void) { + extern void sun4c_init_IRQ( void ); + extern void sun4m_init_IRQ( void ); +#if CONFIG_AP1000 + extern void ap_init_IRQ(void); + ap_init_IRQ(); + return; +#endif + switch(sparc_cpu_model) { case sun4c: sun4c_init_IRQ(); break; + case sun4m: sun4m_init_IRQ(); break; + default: prom_printf("Cannot initialize IRQ's on this Sun machine..."); break; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/mp.S linux/arch/sparc/kernel/mp.S --- v1.3.92/linux/arch/sparc/kernel/mp.S Sat Nov 25 02:58:12 1995 +++ linux/arch/sparc/kernel/mp.S Thu Jan 1 02:00:00 1970 @@ -1,92 +0,0 @@ -/* $Id: mp.S,v 1.2 1995/11/25 00:58:11 davem Exp $ - * mp.S: Multiprocessor low-level routines on the Sparc. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include -#include -#include - - - .text - .align 4 - -/* When we start up a cpu for the first time it enters this routine. - * This initializes the chip from whatever state the prom left it - * in and sets PIL in %psr to 15, no irqs. - */ - - .globl C_LABEL(sparc_cpu_startup) -C_LABEL(sparc_cpu_startup): - /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */ - set (PSR_PIL | PSR_S | PSR_PS), %g1 - wr %g1, 0x0, %psr ! traps off though - WRITE_PAUSE - - /* Our %wim is one behind CWP */ - wr %g0, 0x2, %wim - - rd %tbr, %g4 - or %g0, 0x3, %g5 - sll %g5, 20, %g5 - and %g4, %g5, %g4 ! Mask cpu-id bits - - /* Give ourselves a stack. */ - set PERCPU_VADDR, %g1 - add %g1, %g4, %g1 - set PERCPU_KSTACK_OFFSET, %g5 - add %g1, %g5, %g1 - set 0x1000, %g5 - add %g1, %g5, %g1 ! end of stack - sub %g1, (96+96+80), %g1 ! set up a frame - andn %g1, 0x7, %g1 - or %g1, 0x0, %fp ! bottom of frame - add %fp, (96+80), %sp ! top of frame - - /* Set up per-cpu trap table pointer. In actuality, the virtual - * address for the trap table on every cpu points to the same - * physical address, this virtual address is only used for cpu - * identification purposes. - */ -#if 0 -/* set PERCPU_VADDR, %g1 */ -/* add %g1, %g4, %g1 */ -/* add %g1, PERCPU_TBR_OFFSET, %g1 */ - set C_LABEL(thiscpus_tbr), %g1 - ld [%g1], %g1 - wr %g1, 0x0, %tbr - WRITE_PAUSE -#else - set C_LABEL(trapbase), %g3 - wr %g3, 0x0, %tbr - WRITE_PAUSE -#endif - - /* Turn on traps (PSR_ET). */ - rd %psr, %g1 - wr %g1, PSR_ET, %psr ! traps on - -#if 0 -1: nop - b 1b - nop -#endif - - /* Call C-code to do the rest of the real work. */ - call C_LABEL(sparc_cpu_init) - nop - - /* Call cpu-idle routine so we can start it up later on. */ - call C_LABEL(sparc_cpu_idle) - nop - - /* Done... This cpu should me spinning in a test loop. - * If execution gets here, something really bad happened. - */ - call C_LABEL(prom_halt) ! Seems reasonable... - nop - diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/probe.c linux/arch/sparc/kernel/probe.c --- v1.3.92/linux/arch/sparc/kernel/probe.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/probe.c Sun Apr 21 12:30:29 1996 @@ -380,7 +380,7 @@ } } -/* Probe and map in the Auxiliary I/O register */ +/* Probe and map in the Auxiliaary I/O register */ void probe_auxio(void) { @@ -402,7 +402,7 @@ prom_apply_obio_ranges(auxregs, 0x1); /* Map the register both read and write */ sparc_alloc_io(auxregs[0].phys_addr, (void *) AUXIO_VADDR, - auxregs[0].reg_size, "auxiliaryIO", auxregs[0].which_io, 0x0); + auxregs[0].reg_size, "auxilliaryIO", auxregs[0].which_io, 0x0); } extern unsigned long probe_memory(void); diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v1.3.92/linux/arch/sparc/kernel/process.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/process.c Sun Apr 21 12:30:29 1996 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.42 1996/02/20 07:45:08 davem Exp $ +/* $Id: process.c,v 1.49 1996/04/20 07:37:20 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,9 @@ * This file handles the architecture-dependent parts of process handling.. */ +#define __KERNEL_SYSCALLS__ +#include + #include #include #include @@ -29,11 +32,14 @@ #include #include #include +#include extern void fpsave(unsigned long *, unsigned long *, void *, unsigned long *); int active_ds = USER_DS; +#ifndef __SMP__ + /* * the idle loop on a Sparc... ;) */ @@ -47,8 +53,56 @@ for (;;) { schedule(); } + return 0; +} + +#else + +/* + * the idle loop on a SparcMultiPenguin... + */ +asmlinkage int sys_idle(void) +{ + if (current->pid != 0) + return -EPERM; + + /* endless idle loop with no priority at all */ + current->counter = -100; + schedule(); + return 0; +} + +/* This is being executed in task 0 'user space'. */ +int cpu_idle(void *unused) +{ + volatile int *spap = &smp_process_available; + volatile int cval; + + current->priority = -50; + while(1) { + if(0==read_smp_counter(spap)) + continue; + while(*spap == -1) + ; + cli(); + /* Acquire exclusive access. */ + while((cval = smp_swap(spap, -1)) == -1) + ; + if (0==cval) { + /* ho hum, release it. */ + smp_process_available = 0; + sti(); + continue; + } + /* Something interesting happened, whee... */ + smp_swap(spap, (cval - 1)); + sti(); + idle(); + } } +#endif + extern char saved_command_line[]; void hard_reset_now(void) @@ -94,12 +148,20 @@ void exit_thread(void) { flush_user_windows(); +#ifndef __SMP__ if(last_task_used_math == current) { +#else + if(current->flags & PF_USEDFPU) { +#endif /* Keep process from leaving FPU in a bogon state. */ put_psr(get_psr() | PSR_EF); fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); +#ifndef __SMP__ last_task_used_math = NULL; +#else + current->flags &= ~PF_USEDFPU; +#endif } mmu_exit_hook(); } @@ -122,11 +184,20 @@ current->tss.sstk_info.cur_status = 0; current->tss.sstk_info.the_stack = 0; +#ifndef __SMP__ if(last_task_used_math == current) { +#else + if(current->flags & PF_USEDFPU) { +#endif /* Clean the fpu. */ put_psr(get_psr() | PSR_EF); fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr, ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth); +#ifndef __SMP__ + last_task_used_math = NULL; +#else + current->flags &= ~PF_USEDFPU; +#endif } memset(¤t->tss.reg_window[0], 0, @@ -144,7 +215,7 @@ * Parent --> %o0 == childs pid, %o1 == 0 * Child --> %o0 == parents pid, %o1 == 1 * - * NOTE: We have a separate fork kpsr/kwim because + * NOTE: We have a seperate fork kpsr/kwim because * the parent could change these values between * sys_fork invocation and when we reach here * if the parent should sleep while trying to @@ -160,14 +231,25 @@ struct reg_window *old_stack, *new_stack; unsigned long stack_offset; +#ifndef __SMP__ if(last_task_used_math == current) { +#else + if(current->flags & PF_USEDFPU) { +#endif put_psr(get_psr() | PSR_EF); fpsave(&p->tss.float_regs[0], &p->tss.fsr, &p->tss.fpqueue[0], &p->tss.fpqdepth); +#ifdef __SMP__ + current->flags &= ~PF_USEDFPU; +#endif } /* Calculate offset to stack_frame & pt_regs */ - stack_offset = ((PAGE_SIZE*2) - TRACEREG_SZ); + if(sparc_cpu_model == sun4c) + stack_offset = ((PAGE_SIZE*3) - TRACEREG_SZ); + else + stack_offset = ((PAGE_SIZE<<2) - TRACEREG_SZ); + if(regs->psr & PSR_PS) stack_offset -= REGWIN_SZ; childregs = ((struct pt_regs *) (p->kernel_stack_page + stack_offset)); diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/rirq.S linux/arch/sparc/kernel/rirq.S --- v1.3.92/linux/arch/sparc/kernel/rirq.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/rirq.S Sun Apr 21 12:30:30 1996 @@ -0,0 +1,295 @@ +/* rirq.S: Needed to return from an interrupt on SMP with no + * locks held or released. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define t_psr l0 +#define t_pc l1 +#define t_npc l2 +#define t_wim l3 +#define twin_tmp1 l4 +#define twin_tmp2 l5 +#define twin_tmp3 l6 + + /* 7 WINDOW SPARC PATCH INSTRUCTIONS */ + .globl rirq_7win_patch1, rirq_7win_patch2, rirq_7win_patch3 + .globl rirq_7win_patch4, rirq_7win_patch5 +rirq_7win_patch1: srl %t_wim, 0x6, %twin_tmp2 +rirq_7win_patch2: and %twin_tmp2, 0x7f, %twin_tmp2 +rirq_7win_patch3: srl %g1, 7, %g2 +rirq_7win_patch4: srl %g2, 6, %g2 +rirq_7win_patch5: and %g1, 0x7f, %g1 + /* END OF PATCH INSTRUCTIONS */ + + .globl ret_irq_entry, rirq_patch1, rirq_patch2 + .globl rirq_patch3, rirq_patch4, rirq_patch5 +ret_irq_entry: + ld [%sp + REGWIN_SZ + PT_PSR], %t_psr + andcc %t_psr, PSR_PS, %g0 + bne ret_irq_kernel + nop + +ret_irq_user: + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + LOAD_CURRENT(twin_tmp2, twin_tmp1) + ld [%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1 + orcc %g0, %twin_tmp1, %g0 + be ret_irq_nobufwins + nop + + /* User has toasty windows, must grab klock. */ + ENTER_SYSCALL + + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + mov 1, %o1 + call C_LABEL(try_to_clear_window_buffer) + add %sp, REGWIN_SZ, %o0 + + /* We have klock, so we must return just like a normal trap. */ + b ret_trap_entry + nop + +ret_irq_nobufwins: + /* Load up the user's out registers so we can pull + * a window from the stack, if necessary. + */ + LOAD_PT_INS(sp) + + /* If there are already live user windows in the + * set we can return from trap safely. + */ + ld [%twin_tmp2 + THREAD_UMASK], %twin_tmp1 + orcc %g0, %twin_tmp1, %g0 + bne ret_irq_userwins_ok + nop + + /* Calculate new %wim, we have to pull a register + * window from the users stack. + */ +ret_irq_pull_one_window: + rd %wim, %t_wim + sll %t_wim, 0x1, %twin_tmp1 +rirq_patch1: srl %t_wim, 0x7, %twin_tmp2 + or %twin_tmp2, %twin_tmp1, %twin_tmp2 +rirq_patch2: and %twin_tmp2, 0xff, %twin_tmp2 + + wr %twin_tmp2, 0x0, %wim + WRITE_PAUSE + + /* Here comes the architecture specific + * branch to the user stack checking routine + * for return from traps. + */ + .globl C_LABEL(rirq_mmu_patchme) +C_LABEL(rirq_mmu_patchme): b C_LABEL(sun4c_reti_stackchk) + andcc %fp, 0x7, %g0 + +ret_irq_userwins_ok: + LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) + or %t_pc, %t_npc, %g2 + andcc %g2, 0x3, %g0 + bne ret_irq_unaligned_pc + nop + + LOAD_PT_YREG(sp, g1) + LOAD_PT_GLOBALS(sp) + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +ret_irq_unaligned_pc: + add %sp, REGWIN_SZ, %o0 + ld [%sp + REGWIN_SZ + PT_PC], %o1 + ld [%sp + REGWIN_SZ + PT_NPC], %o2 + ld [%sp + REGWIN_SZ + PT_PSR], %o3 + + wr %t_wim, 0x0, %wim ! or else... + WRITE_PAUSE + + /* User has unaligned crap, must grab klock. */ + ENTER_SYSCALL + + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(do_memaccess_unaligned) + nop + + /* We have klock, so we must return just like a normal trap. */ + b ret_trap_entry + nop + +ret_irq_kernel: + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + /* Will the rett land us in the invalid window? */ + mov 2, %g1 + sll %g1, %t_psr, %g1 +rirq_patch3: srl %g1, 8, %g2 + or %g1, %g2, %g1 + rd %wim, %g2 + andcc %g2, %g1, %g0 + be 1f ! Nope, just return from the trap + nop + + /* We have to grab a window before returning. */ + sll %g2, 0x1, %g1 +rirq_patch4: srl %g2, 7, %g2 + or %g1, %g2, %g1 +rirq_patch5: and %g1, 0xff, %g1 + + wr %g1, 0x0, %wim + WRITE_PAUSE + + restore %g0, %g0, %g0 + LOAD_WINDOW(sp) + save %g0, %g0, %g0 + + /* Reload the entire frame in case this is from a + * kernel system call or whatever... + */ +1: + LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) + + wr %t_psr, 0x0, %psr + WRITE_PAUSE + + jmp %t_pc + rett %t_npc + +ret_irq_user_stack_is_bolixed: + wr %t_wim, 0x0, %wim + WRITE_PAUSE + + /* User has a toasty window, must grab klock. */ + ENTER_SYSCALL + + wr %t_psr, PSR_ET, %psr + WRITE_PAUSE + + call C_LABEL(window_ret_fault) + add %sp, REGWIN_SZ, %o0 + + /* We have klock, so we must return just like a normal trap. */ + b ret_trap_entry + nop + + .globl C_LABEL(sun4c_reti_stackchk) +C_LABEL(sun4c_reti_stackchk): + be 1f + and %fp, 0xfff, %g1 ! delay slot + + b ret_irq_user_stack_is_bolixed + nop + + /* See if we have to check the sanity of one page or two */ +1: + add %g1, 0x38, %g1 + sra %fp, 29, %g2 + add %g2, 0x1, %g2 + andncc %g2, 0x1, %g0 + be 1f + andncc %g1, 0xff8, %g0 + + /* %sp is in vma hole, yuck */ + b ret_irq_user_stack_is_bolixed + nop + +1: + be sun4c_reti_onepage /* Only one page to check */ + lda [%fp] ASI_PTE, %g2 + +sun4c_reti_twopages: + add %fp, 0x38, %g1 + sra %g1, 29, %g2 + add %g2, 0x1, %g2 + andncc %g2, 0x1, %g0 + be 1f + lda [%g1] ASI_PTE, %g2 + + /* Second page is in vma hole */ + b ret_irq_user_stack_is_bolixed + nop + +1: + srl %g2, 29, %g2 + andcc %g2, 0x4, %g0 + bne sun4c_reti_onepage + lda [%fp] ASI_PTE, %g2 + + /* Second page has bad perms */ + b ret_irq_user_stack_is_bolixed + nop + +sun4c_reti_onepage: + srl %g2, 29, %g2 + andcc %g2, 0x4, %g0 + bne 1f + nop + + /* A page had bad page permissions, losing... */ + b ret_irq_user_stack_is_bolixed + nop + + /* Whee, things are ok, load the window and continue. */ +1: + restore %g0, %g0, %g0 + + LOAD_WINDOW(sp) + + save %g0, %g0, %g0 + b ret_irq_userwins_ok + nop + + .globl C_LABEL(srmmu_reti_stackchk) +C_LABEL(srmmu_reti_stackchk): + bne ret_irq_user_stack_is_bolixed + sethi %hi(KERNBASE), %g1 + cmp %g1, %fp + bleu ret_irq_user_stack_is_bolixed + mov AC_M_SFSR, %g1 + lda [%g1] ASI_M_MMUREGS, %g0 + + lda [%g0] ASI_M_MMUREGS, %g1 + or %g1, 0x2, %g1 + sta %g1, [%g0] ASI_M_MMUREGS + + restore %g0, %g0, %g0 + + LOAD_WINDOW(sp) + + save %g0, %g0, %g0 + + andn %g1, 0x2, %g1 + sta %g1, [%g0] ASI_M_MMUREGS + + mov AC_M_SFAR, %g2 + lda [%g2] ASI_M_MMUREGS, %g2 + + mov AC_M_SFSR, %g1 + lda [%g1] ASI_M_MMUREGS, %g1 + andcc %g1, 0x2, %g0 + bne ret_irq_user_stack_is_bolixed + nop + + b ret_irq_userwins_ok + nop diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S --- v1.3.92/linux/arch/sparc/kernel/rtrap.S Mon Mar 4 08:49:55 1996 +++ linux/arch/sparc/kernel/rtrap.S Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.21 1996/02/20 07:45:11 davem Exp $ +/* $Id: rtrap.S,v 1.27 1996/04/03 02:14:41 davem Exp $ * rtrap.S: Return from Sparc trap low-level code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #define t_psr l0 #define t_pc l1 @@ -90,19 +92,7 @@ wr %t_psr, 0x0, %psr WRITE_PAUSE - /* If not current fpu proc, disable fp-ops */ LOAD_CURRENT(twin_tmp2, twin_tmp1) - set C_LABEL(last_task_used_math), %twin_tmp1 - ld [%twin_tmp1], %twin_tmp1 - cmp %twin_tmp2, %twin_tmp1 - be 1f - nop - - set PSR_EF, %twin_tmp1 - andn %t_psr, %twin_tmp1, %t_psr - st %t_psr, [%sp + REGWIN_SZ + PT_PSR] - -1: ld [%twin_tmp2 + THREAD_W_SAVED], %twin_tmp1 orcc %g0, %twin_tmp1, %g0 be ret_trap_nobufwins @@ -163,22 +153,14 @@ LOAD_PT_YREG(sp, g1) LOAD_PT_GLOBALS(sp) + LEAVE_SYSCALL + wr %t_psr, 0x0, %psr WRITE_PAUSE jmp %t_pc rett %t_npc - /* HyperSparc special nop patching, if we are on a hypersparc - * we nop the top two instructions and the first nop coming - * up to be: - * rd %iccr, %g0 <-- flush on-chip instruction cache - * jmp %t_pc - * rett %t_npc - */ - nop - nop - ret_trap_unaligned_pc: add %sp, REGWIN_SZ, %o0 ld [%sp + REGWIN_SZ + PT_PC], %o1 @@ -230,6 +212,8 @@ */ 1: LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1) + + LEAVE_SYSCALL wr %t_psr, 0x0, %psr WRITE_PAUSE diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sclow.S linux/arch/sparc/kernel/sclow.S --- v1.3.92/linux/arch/sparc/kernel/sclow.S Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/sclow.S Sun Apr 21 12:30:31 1996 @@ -1,5 +1,5 @@ /* sclow.S: Low level special syscall handling. - * Basically these are cases where we can completely + * Basically these are cases where we can completly * handle the system call without saving any state * because we know that the process will not sleep. * diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c --- v1.3.92/linux/arch/sparc/kernel/setup.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/setup.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.54 1996/02/25 06:49:18 davem Exp $ +/* $Id: setup.c,v 1.60 1996/04/04 16:30:28 tridge Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,6 @@ 16 /* orig-video-points */ }; -char wp_works_ok = 0; unsigned int phys_bytes_of_ram, end_of_phys_memory; unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) @@ -55,7 +55,7 @@ return memory_start; } -/* Typing sync at the prom prompt calls the function pointed to by +/* Typing sync at the prom promptcalls the function pointed to by * romvec->pv_synchook which I set to the following function. * This should sync all filesystems and return, for now it just * prints out pretty messages and returns. @@ -63,7 +63,9 @@ extern unsigned long trapbase; extern void breakpoint(void); +#if CONFIG_SUN_CONSOLE extern void console_restore_palette(void); +#endif asmlinkage void sys_sync(void); /* it's really int */ /* Pretty sick eh? */ @@ -78,10 +80,12 @@ "nop\n\t" "nop\n\t" : : "r" (&trapbase)); +#if CONFIG_SUN_CONSOLE console_restore_palette (); +#endif prom_printf("PROM SYNC COMMAND...\n"); show_free_areas(); - if(current != task[0]) { + if(current->pid != 0) { sti(); sys_sync(); cli(); @@ -104,6 +108,29 @@ #define BOOTME_SINGLE 0x2 #define BOOTME_KGDB 0x4 +void kernel_enter_debugger(void) +{ + if (boot_flags & BOOTME_KGDB) { + printk("KGDB: Entered\n"); + breakpoint(); + } +} + +int obp_system_intr(void) +{ + if (boot_flags & BOOTME_KGDB) { + printk("KGDB: system interrupted\n"); + breakpoint(); + return 1; + } + if (boot_flags & BOOTME_DEBUG) { + printk("OBP: system interrupted\n"); + prom_halt(); + return 1; + } + return 0; +} + /* This routine does no error checking, make sure your string is sane * before calling this! * XXX This is cheese, make generic and better. @@ -138,11 +165,19 @@ printk("KGDB: Using serial line /dev/tty%c for " "session\n", commands[i+8]); boot_flags |= BOOTME_KGDB; +#if CONFIG_SUN_SERIAL if(commands[i+8]=='a') rs_kgdb_hook(0); else if(commands[i+8]=='b') rs_kgdb_hook(1); - else { + else +#endif +#if CONFIG_AP1000 + if(commands[i+8]=='c') + printk("KGDB: ap1000+ debugging\n"); + else +#endif + { printk("KGDB: whoops bogon tty line " "requested, disabling session\n"); boot_flags &= (~BOOTME_KGDB); @@ -177,14 +212,21 @@ void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - int total, i, panic_stuff[2]; + int total, i, panic_stuff[2], packed; + +#if CONFIG_AP1000 + register_console(prom_printf); + ((char *)(&cputypval))[4] = 'm'; /* ugly :-( */ +#endif +#if 0 /* Always reboot on panic, but give 5 seconds to hit L1-A * and look at debugging info if desired. */ panic_stuff[0] = 1; panic_stuff[1] = 5; panic_setup(0, panic_stuff); +#endif sparc_ttable = (struct tt_entry *) &start; @@ -200,20 +242,25 @@ if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; } if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; } printk("ARCH: "); + packed = 0; switch(sparc_cpu_model) { case sun4c: printk("SUN4C\n"); sun4c_probe_vac(); + packed = 0; break; case sun4m: printk("SUN4M\n"); + packed = 1; break; case sun4d: printk("SUN4D\n"); + packed = 1; break; case sun4e: printk("SUN4E\n"); + packed = 0; break; case sun4u: printk("SUN4U\n"); @@ -238,18 +285,18 @@ load_mmu(); total = prom_probe_memory(); *memory_start_p = (((unsigned long) &end)); -#if 0 - prom_printf("Physical Memory: %d bytes (in hex %08lx)\n", (int) total, - (unsigned long) total); -#endif - for(i=0; sp_banks[i].num_bytes != 0; i++) { -#if 0 - printk("Bank %d: base 0x%x bytes %d\n", i, - (unsigned int) sp_banks[i].base_addr, - (int) sp_banks[i].num_bytes); -#endif - end_of_phys_memory = sp_banks[i].base_addr + sp_banks[i].num_bytes; + if(!packed) { + for(i=0; sp_banks[i].num_bytes != 0; i++) + end_of_phys_memory = sp_banks[i].base_addr + + sp_banks[i].num_bytes; + } else { + unsigned int sum = 0; + + for(i = 0; sp_banks[i].num_bytes != 0; i++) + sum += sp_banks[i].num_bytes; + + end_of_phys_memory = sum; } prom_setsync(prom_sync_me); @@ -266,6 +313,9 @@ { extern int serial_console; /* in console.c, of course */ +#if !CONFIG_SUN_SERIAL + serial_console = 0; +#else int idev = prom_query_input_device(); int odev = prom_query_output_device(); if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) { @@ -279,6 +329,7 @@ prom_printf("Inconsistent console\n"); prom_halt(); } +#endif } #if 1 /* XXX ROOT_DEV hack for kgdb - davem XXX */ @@ -301,6 +352,8 @@ extern char *sparc_cpu_type[]; extern char *sparc_fpu_type[]; +extern char *smp_info(void); + int get_cpuinfo(char *buffer) { int cpuid=get_cpuid(); @@ -308,23 +361,46 @@ return sprintf(buffer, "cpu\t\t: %s\n" "fpu\t\t: %s\n" "promlib\t\t: Version %d Revision %d\n" - "wp\t\t: %s\n" "type\t\t: %s\n" "Elf Support\t: %s\n" /* I can't remember when I do --ralp */ +#ifndef __SMP__ "BogoMips\t: %lu.%02lu\n" - "%s", +#else + "Cpu0Bogo\t: %lu.%02lu\n" + "Cpu1Bogo\t: %lu.%02lu\n" + "Cpu2Bogo\t: %lu.%02lu\n" + "Cpu3Bogo\t: %lu.%02lu\n" +#endif + "%s" +#ifdef __SMP__ + "%s" +#endif + , sparc_cpu_type[cpuid], sparc_fpu_type[cpuid], +#if CONFIG_AP1000 + 0, 0, +#else romvec->pv_romvers, prom_rev, - wp_works_ok ? "yes" : "no", +#endif &cputypval, #if CONFIG_BINFMT_ELF "yes", #else "no", #endif +#ifndef __SMP__ loops_per_sec/500000, (loops_per_sec/5000) % 100, +#else + cpu_data[0].udelay_val/500000, (cpu_data[0].udelay_val/5000)%100, + cpu_data[1].udelay_val/500000, (cpu_data[1].udelay_val/5000)%100, + cpu_data[2].udelay_val/500000, (cpu_data[2].udelay_val/5000)%100, + cpu_data[3].udelay_val/500000, (cpu_data[3].udelay_val/5000)%100, +#endif mmu_info() +#ifdef __SMP__ + , smp_info() +#endif ); } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c --- v1.3.92/linux/arch/sparc/kernel/signal.c Mon Mar 11 09:39:34 1996 +++ linux/arch/sparc/kernel/signal.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.28 1995/12/29 21:47:18 davem Exp $ +/* $Id: signal.c,v 1.31 1996/04/18 01:00:41 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -58,24 +58,25 @@ _sigpause_common(set, regs); } -asmlinkage void do_sigsuspend(unsigned int *sigmaskp, struct pt_regs *regs) +asmlinkage void do_sigsuspend (struct pt_regs *regs) { - unsigned int set; + unsigned long mask; + unsigned long set; - /* Manual does not state what is supposed to happen if - * the sigmask ptr is bogus. It does state that EINTR - * is the only valid return value and it indicates - * successful signal delivery. Must investigate. - */ - if(verify_area(VERIFY_READ, sigmaskp, sizeof(unsigned int))) { - regs->pc = regs->npc; - regs->npc += 4; - regs->u_regs[UREG_I0] = EFAULT; - regs->psr |= PSR_C; - return; + set = regs->u_regs [UREG_I0]; + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + regs->pc = regs->npc; + regs->npc += 4; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(mask,regs)){ + regs->psr |= PSR_C; + regs->u_regs [UREG_I0] = EINTR; + return; + } } - set = *sigmaskp; - _sigpause_common(set, regs); } asmlinkage void do_sigreturn(struct pt_regs *regs) @@ -152,10 +153,12 @@ (((unsigned long) sframep) >= KERNBASE) || ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) && ((unsigned long) sframep < 0xe0000000 && (unsigned long) sframep >= 0x20000000))) { +#if 0 /* fills up the console logs... */ printk("%s [%d]: User has trashed signal stack\n", current->comm, current->pid); printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n", sframep, pc, signr); +#endif /* Don't change signal code and address, so that * post mortem debuggers can have a look. */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c --- v1.3.92/linux/arch/sparc/kernel/smp.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/smp.c Sun Apr 21 12:30:31 1996 @@ -3,241 +3,655 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include +#include + #include +#include #include -int smp_num_cpus; -int smp_threads_ready; -volatile unsigned long smp_msg_data; -volatile int smp_src_cpu; -volatile int smp_msg_id; - -static volatile int smp_commenced = 0; +#include +#include +#include +#include +#include + +extern ctxd_t *srmmu_ctx_table_phys; +extern int linux_num_cpus; + +struct tlog { + unsigned long pc; + unsigned long psr; +}; + +struct tlog trap_log[4][256]; +unsigned long trap_log_ent[4] = { 0, 0, 0, 0, }; + +extern void calibrate_delay(void); + +volatile unsigned long stuck_pc = 0; +volatile int smp_processors_ready = 0; + +int smp_found_config = 0; +unsigned long cpu_present_map = 0; +int smp_num_cpus = 1; +int smp_threads_ready=0; +unsigned char mid_xlate[NR_CPUS] = { 0, 0, 0, 0, }; +volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; +volatile unsigned long smp_invalidate_needed[NR_CPUS] = { 0, }; +volatile unsigned long smp_spinning[NR_CPUS] = { 0, }; +struct cpuinfo_sparc cpu_data[NR_CPUS]; +unsigned char boot_cpu_id = 0; +static int smp_activated = 0; +static volatile unsigned char smp_cpu_in_msg[NR_CPUS]; +static volatile unsigned long smp_msg_data; +static volatile int smp_src_cpu; +static volatile int smp_msg_id; +volatile int cpu_number_map[NR_CPUS]; +volatile int cpu_logical_map[NR_CPUS]; -/* The only guaranteed locking primitive available on all Sparc - * processors is 'ldstub [%addr_reg + imm], %dest_reg' which atomically +/* The only guarenteed locking primitive available on all Sparc + * processors is 'ldstub [%reg + immediate], %dest_reg' which atomicly * places the current byte at the effective address into dest_reg and * places 0xff there afterwards. Pretty lame locking primitive * compared to the Alpha and the intel no? Most Sparcs have 'swap' * instruction which is much better... */ -klock_t kernel_lock; +klock_t kernel_flag = KLOCK_CLEAR; +volatile unsigned char active_kernel_processor = NO_PROC_ID; +volatile unsigned long kernel_counter = 0; +volatile unsigned long syscall_count = 0; +volatile unsigned long ipi_count; +#ifdef __SMP_PROF__ +volatile unsigned long smp_spins[NR_CPUS]={0}; +volatile unsigned long smp_spins_syscall[NR_CPUS]={0}; +volatile unsigned long smp_spins_syscall_cur[NR_CPUS]={0}; +volatile unsigned long smp_spins_sys_idle[NR_CPUS]={0}; +volatile unsigned long smp_idle_count[1+NR_CPUS]={0,}; +#endif +#if defined (__SMP_PROF__) +volatile unsigned long smp_idle_map=0; +#endif + +volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,}; +volatile int smp_process_available=0; + +/*#define SMP_DEBUG*/ + +#ifdef SMP_DEBUG +#define SMP_PRINTK(x) printk x +#else +#define SMP_PRINTK(x) +#endif + +static volatile int smp_commenced = 0; + +static char smp_buf[512]; + +char *smp_info(void) +{ + sprintf(smp_buf, +"\n CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" +"State: %s\t\t%s\t\t%s\t\t%s\n" +"Lock: %08lx\t\t%08lx\t%08lx\t\t%08lx\n" +"\n" +"klock: %x\n", + (cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline", + (cpu_present_map & 2) ? ((active_kernel_processor == 1) ? "akp" : "online") : "offline", + (cpu_present_map & 4) ? ((active_kernel_processor == 2) ? "akp" : "online") : "offline", + (cpu_present_map & 8) ? ((active_kernel_processor == 3) ? "akp" : "online") : "offline", + smp_proc_in_lock[0], smp_proc_in_lock[1], smp_proc_in_lock[2], + smp_proc_in_lock[3], + kernel_flag); + return smp_buf; +} + +static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val) +{ + __asm__ __volatile__("swap [%1], %0\n\t" : + "=&r" (val), "=&r" (ptr) : + "0" (val), "1" (ptr)); + return val; +} + +/* + * The bootstrap kernel entry code has set these up. Save them for + * a given CPU + */ + +void smp_store_cpu_info(int id) +{ + cpu_data[id].udelay_val = loops_per_sec; /* this is it on sparc. */ +} + +/* + * Architecture specific routine called by the kernel just before init is + * fired off. This allows the BP to have everything in order [we hope]. + * At the end of this all the AP's will hit the system scheduling and off + * we go. Each AP will load the system gdt's and jump through the kernel + * init into idle(). At this point the scheduler will one day take over + * and give them jobs to do. smp_callin is a standard routine + * we use to track CPU's as they power up. + */ void smp_commence(void) { /* * Lets the callin's below out of their loop. */ + local_flush_cache_all(); + local_flush_tlb_all(); smp_commenced = 1; + local_flush_cache_all(); + local_flush_tlb_all(); } void smp_callin(void) { - int cpuid = smp_get_processor_id(); - - /* XXX Clear the software interrupts _HERE_. */ + int cpuid = smp_processor_id(); sti(); + local_flush_cache_all(); + local_flush_tlb_all(); calibrate_delay(); smp_store_cpu_info(cpuid); - set_bit(cpuid, (unsigned long *)&cpu_callin_map[0]); - local_invalidate_all(); - while(!smp_commenced); - if(cpu_number_map[cpuid] == -1) - while(1); - local_invalidate_all(); + local_flush_cache_all(); + local_flush_tlb_all(); + cli(); + + /* Allow master to continue. */ + swap((unsigned long *)&cpu_callin_map[cpuid], 1); + local_flush_cache_all(); + local_flush_tlb_all(); + while(!smp_commenced) + barrier(); + local_flush_cache_all(); + local_flush_tlb_all(); + + /* Fix idle thread fields. */ + current->mm->mmap->vm_page_prot = PAGE_SHARED; + current->mm->mmap->vm_start = KERNBASE; + current->mm->mmap->vm_end = init_task.mm->mmap->vm_end; + + local_flush_cache_all(); + local_flush_tlb_all(); + + sti(); } +void cpu_panic(void) +{ + printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id()); + panic("SMP bolixed\n"); +} + +/* + * Cycle through the processors asking the PROM to start each one. + */ + +extern struct prom_cpuinfo linux_cpus[NCPUS]; +static struct linux_prom_registers penguin_ctable; + void smp_boot_cpus(void) { + int cpucount = 0; + int i = 0; + + printk("Entering SparclinuxMultiPenguin(SMP) Mode...\n"); + + penguin_ctable.which_io = 0; + penguin_ctable.phys_addr = (char *) srmmu_ctx_table_phys; + penguin_ctable.reg_size = 0; + + sti(); + cpu_present_map |= (1 << smp_processor_id()); + cpu_present_map = 0; + for(i=0; i < linux_num_cpus; i++) + cpu_present_map |= (1< 0) + barrier(); + if(!ccall_info.processors_in[i]) + goto procs_time_out; + } +#ifdef DEBUG_CCALL + printk("I"); +#endif + + /* Run local copy. */ + func(arg1, arg2, arg3, arg4, arg5); + + /* Spin on proc dispersion. */ + timeout = CCALL_TIMEOUT; + for(i = 0; i < smp_num_cpus; i++) { + while(!ccall_info.processors_out[i] && timeout-- > 0) + barrier(); + if(!ccall_info.processors_out[i]) + goto procs_time_out; + } +#ifdef DEBUG_CCALL + printk("O>"); +#endif + /* See wait case 3 in smp_message_pass()... */ + smp_cpu_in_msg[me]--; + smp_swap(&message_cpu, NO_PROC_ID); /* store buffers... */ + restore_flags(flags); + return; /* made it... */ + +procs_time_out: + printk("smp: Wheee, penguin drops off the bus\n"); + smp_cpu_in_msg[me]--; + message_cpu = NO_PROC_ID; + restore_flags(flags); + return; /* why me... why me... */ + } + + /* Just need to run local copy. */ + func(arg1, arg2, arg3, arg4, arg5); + return; + +cross_call_not_master: + printk("Cross call initiated by non master cpu\n"); + printk("akp=%x me=%08lx\n", active_kernel_processor, me); restore_flags(flags); + panic("penguin cross call"); } -void smp_invalidate_all(void) -{ - smp_invalidate(0, 0, 0, 0); +void smp_flush_cache_all(void) +{ xc0((smpfunc_t) local_flush_cache_all); } + +void smp_flush_tlb_all(void) +{ xc0((smpfunc_t) local_flush_tlb_all); } + +void smp_flush_cache_mm(struct mm_struct *mm) +{ + if(mm->context != NO_CONTEXT) + xc1((smpfunc_t) local_flush_cache_mm, (unsigned long) mm); } -void smp_invalidate_mm(struct mm_struct *mm) +void smp_flush_tlb_mm(struct mm_struct *mm) { - smp_invalidate(1, (unsigned long) mm, 0, 0); + if(mm->context != NO_CONTEXT) + xc1((smpfunc_t) local_flush_tlb_mm, (unsigned long) mm); } -void smp_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +void smp_flush_cache_range(struct mm_struct *mm, unsigned long start, + unsigned long end) { - smp_invalidate(2, (unsigned long) mm, start, end); + if(mm->context != NO_CONTEXT) + xc3((smpfunc_t) local_flush_cache_range, (unsigned long) mm, + start, end); } -void smp_invalidate_page(struct vm_area_struct *vmap, unsigned long page) +void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) { - smp_invalidate(3, (unsigned long)vmap->vm_mm, page, 0); + if(mm->context != NO_CONTEXT) + xc3((smpfunc_t) local_flush_tlb_range, (unsigned long) mm, + start, end); } -void smp_reschedule_irq(int cpl, struct pt_regs *regs) +void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ xc2((smpfunc_t) local_flush_cache_page, (unsigned long) vma, page); } + +void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ xc2((smpfunc_t) local_flush_tlb_page, (unsigned long) vma, page); } + +void smp_flush_page_to_ram(unsigned long page) +{ xc1((smpfunc_t) local_flush_page_to_ram, page); } + +/* Reschedule call back. */ +void smp_reschedule_irq(void) { if(smp_processor_id() != active_kernel_processor) panic("SMP Reschedule on CPU #%d, but #%d is active.\n", smp_processor_id(), active_kernel_processor); - if(user_mode(regs)) { - current->utime++; - if (current->pid) { - if (current->priority < 15) - kstat.cpu_nice++; - else - kstat.cpu_user++; - } - /* Update ITIMER_VIRT for current task if not in a system call */ - if (current->it_virt_value && !(--current->it_virt_value)) { - current->it_virt_value = current->it_virt_incr; - send_sig(SIGVTALRM,current,1); - } - } else { - current->stime++; - if(current->pid) - kstat.cpu_system++; -#ifdef CONFIG_PROFILE - if (prof_buffer && current->pid) { - extern int _stext; - unsigned long eip = regs->eip - (unsigned long) &_stext; - eip >>= CONFIG_PROFILE_SHIFT; - if (eip < prof_len) - prof_buffer[eip]++; - } + + need_resched=1; +} + +/* XXX FIXME: this still doesn't work right... XXX */ + +/* #define DEBUG_CAPTURE */ + +static volatile unsigned long release = 1; +static volatile int capture_level = 0; + +void smp_capture(void) +{ + unsigned long flags; + + if(!smp_activated || !smp_commenced) + return; +#ifdef DEBUG_CAPTURE + printk("C<%d>", smp_processor_id()); #endif + save_flags(flags); cli(); + if(!capture_level) { + release = 0; + smp_message_pass(MSG_ALL_BUT_SELF, MSG_CAPTURE, 0, 1); } + capture_level++; + restore_flags(flags); +} - /* - * check the cpu time limit on the process. - */ - if ((current->rlim[RLIMIT_CPU].rlim_max != RLIM_INFINITY) && - (((current->stime + current->utime) / HZ) >= current->rlim[RLIMIT_CPU].rlim_max)) - send_sig(SIGKILL, current, 1); - if ((current->rlim[RLIMIT_CPU].rlim_cur != RLIM_INFINITY) && - (((current->stime + current->utime) % HZ) == 0)) { - unsigned long psecs = (current->stime + current->utime) / HZ; - /* send when equal */ - if (psecs == current->rlim[RLIMIT_CPU].rlim_cur) - send_sig(SIGXCPU, current, 1); - /* and every five seconds thereafter. */ - else if ((psecs > current->rlim[RLIMIT_CPU].rlim_cur) && - ((psecs - current->rlim[RLIMIT_CPU].rlim_cur) % 5) == 0) - send_sig(SIGXCPU, current, 1); - } - - /* Update ITIMER_PROF for the current task */ - if (current->it_prof_value && !(--current->it_prof_value)) { - current->it_prof_value = current->it_prof_incr; - send_sig(SIGPROF,current,1); - } - - if(0 > --current->counter || current->pid == 0) { - current->counter = 0; - need_resched = 1; +void smp_release(void) +{ + unsigned long flags; + int i; + + if(!smp_activated || !smp_commenced) + return; +#ifdef DEBUG_CAPTURE + printk("R<%d>", smp_processor_id()); +#endif + save_flags(flags); cli(); + if(!(capture_level - 1)) { + release = 1; + for(i = 0; i < smp_num_cpus; i++) + while(cpu_callin_map[i]) + barrier(); } + capture_level -= 1; + restore_flags(flags); } -void smp_message_irq(int cpl, struct pt_regs *regs) +/* Park a processor, we must watch for more IPI's to invalidate + * our cache's and TLB's. And also note we can only wait for + * "lock-less" IPI's and process those, as a result of such IPI's + * being non-maskable traps being on is enough to receive them. + */ + +/* Message call back. */ +void smp_message_irq(void) { int i=smp_processor_id(); -/* static int n=0; - if(n++%d(%d,%ld)\n",smp_src_cpu,i,smp_msg_id,smp_msg_data);*/ - switch(smp_msg_id) - { - case 0: /* IRQ 13 testing - boring */ - return; - - /* - * A TLB flush is needed. - */ - - case MSG_INVALIDATE_TLB: - if(clear_bit(i,(unsigned long *)&smp_invalidate_needed)) - local_invalidate(); - set_bit(i, (unsigned long *)&cpu_callin_map[0]); - cpu_callin_map[0]|=1< +#include +#include + +#include +#include + +unsigned long solaris_xlatb_rorl[] = { + 0, SOL_EPERM, SOL_ENOENT, SOL_ESRCH, SOL_EINTR, SOL_EIO, + SOL_ENXIO, SOL_E2BIG, SOL_ENOEXEC, SOL_EBADF, SOL_ECHILD, + SOL_EAGAIN, SOL_ENOMEM, SOL_EACCES, SOL_EFAULT, + SOL_ENOTBLK, SOL_EBUSY, SOL_EEXIST, SOL_EXDEV, SOL_ENODEV, + SOL_ENOTDIR, SOL_EISDIR, SOL_EINVAL, SOL_ENFILE, SOL_EMFILE, + SOL_ENOTTY, SOL_ETXTBSY, SOL_EFBIG, SOL_ENOSPC, SOL_ESPIPE, + SOL_EROFS, SOL_EMLINK, SOL_EPIPE, SOL_EDOM, SOL_ERANGE, + SOL_EWOULDBLOCK, SOL_EINPROGRESS, SOL_EALREADY, SOL_ENOTSOCK, + SOL_EDESTADDRREQ, SOL_EMSGSIZE, SOL_EPROTOTYPE, SOL_ENOPROTOOPT, + SOL_EPROTONOSUPPORT, SOL_ESOCKTNOSUPPORT, SOL_EOPNOTSUPP, + SOL_EPFNOSUPPORT, SOL_EAFNOSUPPORT, SOL_EADDRINUSE, + SOL_EADDRNOTAVAIL, SOL_ENETDOWN, SOL_ENETUNREACH, SOL_ENETRESET, + SOL_ECONNABORTED, SOL_ECONNRESET, SOL_ENOBUFS, SOL_EISCONN, + SOL_ENOTCONN, SOL_ESHUTDOWN, SOL_ETOOMANYREFS, SOL_ETIMEDOUT, + SOL_ECONNREFUSED, SOL_ELOOP, SOL_ENAMETOOLONG, SOL_EHOSTDOWN, + SOL_EHOSTUNREACH, SOL_ENOTEMPTY, SOL_EUSERS, SOL_EUSERS, + SOL_EDQUOT, SOL_ESTALE, SOL_EREMOTE, SOL_ENOSTR, SOL_ETIME, + SOL_ENOSR, SOL_ENOMSG, SOL_EBADMSG, SOL_EIDRM, SOL_EDEADLK, + SOL_ENOLCK, SOL_ENONET, SOL_EINVAL, SOL_ENOLINK, SOL_EADV, + SOL_ESRMNT, SOL_ECOMM, SOL_EPROTO, SOL_EMULTIHOP, SOL_EINVAL, + SOL_EREMCHG, SOL_ENOSYS +}; + +extern asmlinkage int sys_open(const char *,int,int); + +asmlinkage int solaris_open(const char *filename, int flags, int mode) +{ + int newflags = flags & 0xf; + + flags &= ~0xf; + if(flags & 0x8050) + newflags |= FASYNC; + if(flags & 0x80) + newflags |= O_NONBLOCK; + if(flags & 0x100) + newflags |= O_CREAT; + if(flags & 0x200) + newflags |= O_TRUNC; + if(flags & 0x400) + newflags |= O_EXCL; + if(flags & 0x800) + newflags |= O_NOCTTY; + return sys_open(filename, newflags, mode); +} + + diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sparc-stub.c linux/arch/sparc/kernel/sparc-stub.c --- v1.3.92/linux/arch/sparc/kernel/sparc-stub.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/sparc-stub.c Sun Apr 21 12:30:31 1996 @@ -1,10 +1,10 @@ -/* $Id: sparc-stub.c,v 1.10 1996/02/15 09:12:09 davem Exp $ +/* $Id: sparc-stub.c,v 1.15 1996/04/04 12:41:35 davem Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * - * This file originally came from the gdb sources, and the + * This file origionally came from the gdb sources, and the * copyright notices have been retained below. */ @@ -106,7 +106,7 @@ #include #include #include - +#include /* * * external low-level support routines @@ -163,6 +163,10 @@ return entry; } +static void flush_cache_all_nop(void) +{ +} + /* Place where we save old trap entries for restoration */ struct tt_entry kgdb_savettable[256]; typedef void (*trapfunc_t)(void); @@ -363,8 +367,12 @@ set_debug_traps(void) { struct hard_trap_info *ht; + unsigned long flags; unsigned char c; + save_flags(flags); cli(); + flush_cache_all = flush_cache_all_nop; + /* Initialize our copy of the Linux Sparc trap table */ eh_init(); @@ -386,6 +394,7 @@ putDebugChar('+'); /* ack it */ initialized = 1; /* connect! */ + restore_flags(flags); } /* Convert the SPARC hardware trap type code to a unix signal number. */ @@ -430,7 +439,7 @@ } /* - * This function does all command processing for interfacing to gdb. It + * This function does all command procesing for interfacing to gdb. It * returns 1 if you should skip the instruction at the trap address, 0 * otherwise. */ @@ -636,18 +645,7 @@ * breakpoint, and the icache probably has no way of knowing that a data ref to * some location may have changed something that is in the instruction cache. */ - /* Only instruction cache flushing on the sun4c/sun4 - * for now. We assume control flow during the kgdb - * transaction has not left the context in which it - * was entered. - */ - if((sparc_cpu_model==sun4 || sparc_cpu_model==sun4c) && - (sun4c_vacinfo.num_bytes && sun4c_vacinfo.on)) - sun4c_flush_context(); - /* XXX SRMMU and on-chip v8 instruction cache - * XXX flushing goes here! - */ - + flush_cache_all(); return; /* kill the program */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c --- v1.3.92/linux/arch/sparc/kernel/sun4c_irq.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sun4c_irq.c Sun Apr 21 12:30:31 1996 @@ -0,0 +1,185 @@ +/* sun4c_irq.c + * arch/sparc/kernel/sun4c_irq.c: + * + * djhr: Hacked out of irq.c into a CPU dependant version. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su) + * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Pointer to the interrupt enable byte + * + * Dave Redman (djhr@tadpole.co.uk) + * What you may not be aware of is that entry.S requires this variable. + * + * --- linux_trap_nmi_sun4c -- + * + * so don't go making it static, like I tried. sigh. + */ +unsigned char *interrupt_enable = 0; + +static void sun4c_disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + unsigned char current_mask, new_mask; + + save_flags(flags); cli(); + irq_nr &= NR_IRQS; + current_mask = *interrupt_enable; + switch(irq_nr) { + case 1: + new_mask = ((current_mask) & (~(SUN4C_INT_E1))); + break; + case 8: + new_mask = ((current_mask) & (~(SUN4C_INT_E8))); + break; + case 10: + new_mask = ((current_mask) & (~(SUN4C_INT_E10))); + break; + case 14: + new_mask = ((current_mask) & (~(SUN4C_INT_E14))); + break; + default: + restore_flags(flags); + return; + } + *interrupt_enable = new_mask; + restore_flags(flags); +} + +static void sun4c_enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + unsigned char current_mask, new_mask; + + save_flags(flags); cli(); + irq_nr &= NR_IRQS; + current_mask = *interrupt_enable; + switch(irq_nr) { + case 1: + new_mask = ((current_mask) | SUN4C_INT_E1); + break; + case 8: + new_mask = ((current_mask) | SUN4C_INT_E8); + break; + case 10: + new_mask = ((current_mask) | SUN4C_INT_E10); + break; + case 14: + new_mask = ((current_mask) | SUN4C_INT_E14); + break; + default: + restore_flags(flags); + return; + } + *interrupt_enable = new_mask; + restore_flags(flags); +} + +#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ +#define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */ + +volatile struct sun4c_timer_info *sun4c_timers; + +static void sun4c_clear_clock_irq(void) +{ + volatile unsigned int clear_intr; + clear_intr = sun4c_timers->timer_limit10; +} + +static void sun4c_clear_profile_irq(void ) +{ + /* Errm.. not sure how to do this.. */ +} + +static void sun4c_load_profile_irq(unsigned int limit) +{ + /* Errm.. not sure how to do this.. */ +} + +static void sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)) +{ + int irq; + + /* Map the Timer chip, this is implemented in hardware inside + * the cache chip on the sun4c. + */ + sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0, + sizeof(struct sun4c_timer_info), + "timer", 0x0, 0x0); + + /* Have the level 10 timer tick at 100HZ. We don't touch the + * level 14 timer limit since we are letting the prom handle + * them until we have a real console driver so L1-A works. + */ + sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); + + irq = request_irq(TIMER_IRQ, + counter_fn, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", NULL); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); + prom_halt(); + } + + claim_ticker14(NULL, PROFILE_IRQ, 0); +} + +static void sun4c_nop(void) +{ +} + +void sun4c_init_IRQ(void) +{ + struct linux_prom_registers int_regs[2]; + int ie_node; + + ie_node = prom_searchsiblings (prom_getchild(prom_root_node), + "interrupt-enable"); + if(ie_node == 0) + panic("Cannot find /interrupt-enable node"); + + /* Depending on the "address" property is bad news... */ + prom_getproperty(ie_node, "reg", (char *) int_regs, sizeof(int_regs)); + interrupt_enable = (char *) sparc_alloc_io(int_regs[0].phys_addr, 0, + int_regs[0].reg_size, + "sun4c_interrupts", + int_regs[0].which_io, 0x0); + enable_irq = sun4c_enable_irq; + disable_irq = sun4c_disable_irq; + clear_clock_irq = sun4c_clear_clock_irq; + clear_profile_irq = sun4c_clear_profile_irq; + load_profile_irq = sun4c_load_profile_irq; + init_timers = sun4c_init_timers; +#ifdef __SMP__ + set_cpu_int = sun4c_nop; + clear_cpu_int = sun4c_nop; + set_irq_udt = sun4c_nop; +#endif + *interrupt_enable = (SUN4C_INT_ENABLE); + sti(); +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c --- v1.3.92/linux/arch/sparc/kernel/sun4m_irq.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/sun4m_irq.c Sun Apr 21 12:30:31 1996 @@ -0,0 +1,335 @@ +/* sun4m_irq.c + * arch/sparc/kernel/sun4m_irq.c: + * + * djhr: Hacked out of irq.c into a CPU dependant version. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@ipmce.su) + * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long dummy; + +extern int linux_num_cpus; +struct sun4m_intregs *sun4m_interrupts; +unsigned long *irq_rcvreg = &dummy; + +/* These tables only apply for interrupts greater than 15.. + * + * any intr value below 0x10 is considered to be a soft-int + * this may be useful or it may not.. but thats how I've done it. + * and it won't clash with what OBP is telling us about devices. + * + * take an encoded intr value and lookup if its valid + * then get the mask bits that match from irq_mask + */ +static unsigned char irq_xlate[32] = { + /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ + 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 0, 0, 7, + 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 +}; + +static unsigned long irq_mask[] = { + 0, /* illegal index */ + SUN4M_INT_SCSI, /* 1 irq 4 */ + SUN4M_INT_ETHERNET, /* 2 irq 6 */ + SUN4M_INT_VIDEO, /* 3 irq 8 */ + SUN4M_INT_REALTIME, /* 4 irq 10 */ + SUN4M_INT_FLOPPY, /* 5 irq 11 */ + (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ + SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ + SUN4M_INT_SBUS(1), /* 8 irq 2 */ + SUN4M_INT_SBUS(2), /* 9 irq 3 */ + SUN4M_INT_SBUS(3), /* 10 irq 5 */ + SUN4M_INT_SBUS(4), /* 11 irq 7 */ + SUN4M_INT_SBUS(5), /* 12 irq 9 */ + SUN4M_INT_SBUS(6), /* 13 irq 11 */ + SUN4M_INT_SBUS(7) /* 14 irq 13 */ +}; + +inline unsigned long sun4m_get_irqmask(unsigned int irq) +{ + unsigned long mask; + + if (irq > 0x20) { + /* OBIO/SBUS interrupts */ + irq &= 0x1f; + mask = irq_mask[irq_xlate[irq]]; + if (!mask) + printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); + } else { + /* Soft Interrupts will come here + * Currently there is no way to trigger them but I'm sure something + * could be cooked up. + */ + irq &= 0xf; + mask = SUN4M_SOFT_INT(irq); + } + return mask; +} + +static void sun4m_disable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + int cpu = smp_processor_id(); + + mask = sun4m_get_irqmask(irq_nr); + save_flags(flags); cli(); + if (irq_nr > 15) + sun4m_interrupts->set = mask; + else + sun4m_interrupts->cpu_intregs[cpu].set = mask; + restore_flags(flags); +} + +static void sun4m_enable_irq(unsigned int irq_nr) +{ + unsigned long mask, flags; + int cpu = smp_processor_id(); + + /* Dreadful floppy hack. When we use 0x2b instead of + * 0x0b the system blows (it starts to whistle!). + * So we continue to use 0x0b. Fixme ASAP. --P3 + */ + if (irq_nr != 0x0b) { + mask = sun4m_get_irqmask(irq_nr); + save_flags(flags); cli(); + if (irq_nr > 15) + sun4m_interrupts->clear = mask; + else + sun4m_interrupts->cpu_intregs[cpu].clear = mask; + restore_flags(flags); + } else { + save_flags(flags); cli(); + sun4m_interrupts->clear = SUN4M_INT_FLOPPY; + restore_flags(flags); + } +} + +void sun4m_send_ipi(int cpu, int level) +{ + unsigned long mask; + + mask = sun4m_get_irqmask(level); + sun4m_interrupts->cpu_intregs[cpu].set = mask; +} + +void sun4m_clear_ipi(int cpu, int level) +{ + unsigned long mask; + + mask = sun4m_get_irqmask(level); + sun4m_interrupts->cpu_intregs[cpu].clear = mask; +} + +void sun4m_set_udt(int cpu) +{ + sun4m_interrupts->undirected_target = cpu; +} + +#define OBIO_INTR 0x20 +#define TIMER_IRQ (OBIO_INTR | 10) +#define PROFILE_IRQ (OBIO_INTR | 14) + +struct sun4m_timer_regs *sun4m_timers; +unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); + +static void sun4m_clear_clock_irq(void) +{ + volatile unsigned int clear_intr; + clear_intr = sun4m_timers->l10_timer_limit; +} + +static void sun4m_clear_profile_irq(void) +{ + volatile unsigned int clear; + + clear = sun4m_timers->cpu_timers[0].l14_timer_limit; +} + +static void sun4m_load_profile_irq(unsigned int limit) +{ + sun4m_timers->cpu_timers[0].l14_timer_limit = limit; +} + +static void sun4m_lvl14_handler(int irq, void *dev_id, struct pt_regs * regs) +{ + volatile unsigned int clear; + + printk("CPU[%d]: TOOK A LEVEL14!\n", smp_processor_id()); + /* we do nothing with this at present + * this is purely to prevent OBP getting its mucky paws + * in linux. + */ + clear = sun4m_timers->cpu_timers[0].l14_timer_limit; /* clear interrupt */ + + /* reload with value, this allows on the fly retuning of the level14 + * timer + */ + sun4m_timers->cpu_timers[0].l14_timer_limit = lvl14_resolution; +} + +static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)) +{ + int reg_count, irq, cpu; + struct linux_prom_registers cnt_regs[PROMREG_MAX]; + int obio_node, cnt_node; + + cnt_node = 0; + if((obio_node = + prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || + (obio_node = prom_getchild (obio_node)) == 0 || + (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { + prom_printf("Cannot find /obio/counter node\n"); + prom_halt(); + } + reg_count = prom_getproperty(cnt_node, "reg", + (void *) cnt_regs, sizeof(cnt_regs)); + reg_count = (reg_count/sizeof(struct linux_prom_registers)); + + /* Apply the obio ranges to the timer registers. */ + prom_apply_obio_ranges(cnt_regs, reg_count); + + cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; + cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; + cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; + for(obio_node = 1; obio_node < 4; obio_node++) { + cnt_regs[obio_node].phys_addr = + cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; + cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; + cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; + } + + /* Map the per-cpu Counter registers. */ + sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0, + PAGE_SIZE*NCPUS, "counters_percpu", + cnt_regs[0].which_io, 0x0); + + /* Map the system Counter register. */ + sparc_alloc_io(cnt_regs[4].phys_addr, 0, + cnt_regs[4].reg_size, + "counters_system", + cnt_regs[4].which_io, 0x0); + + sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); + + irq = request_irq(TIMER_IRQ, + counter_fn, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", NULL); + if (irq) { + prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); + prom_halt(); + } + + /* Can't cope with multiple CPUS yet so no level14 tick events */ +#if 0 + if (linux_num_cpus > 1) + claim_ticker14(NULL, PROFILE_IRQ, 0); + else + claim_ticker14(sun4m_lvl14_handler, PROFILE_IRQ, lvl14_resolution); +#endif + if(linux_num_cpus > 1) { + for(cpu = 0; cpu < 4; cpu++) + sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; + sun4m_interrupts->set = SUN4M_INT_E14; + } else { + sun4m_timers->cpu_timers[0].l14_timer_limit = 0; + } +} + +void sun4m_init_IRQ(void) +{ + int ie_node,i; + struct linux_prom_registers int_regs[PROMREG_MAX]; + int num_regs; + + cli(); + if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || + (ie_node = prom_getchild (ie_node)) == 0 || + (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { + prom_printf("Cannot find /obio/interrupt node\n"); + prom_halt(); + } + num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, + sizeof(int_regs)); + num_regs = (num_regs/sizeof(struct linux_prom_registers)); + + /* Apply the obio ranges to these registers. */ + prom_apply_obio_ranges(int_regs, num_regs); + + int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; + int_regs[4].reg_size = int_regs[num_regs-1].reg_size; + int_regs[4].which_io = int_regs[num_regs-1].which_io; + for(ie_node = 1; ie_node < 4; ie_node++) { + int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; + int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; + int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; + } + + /* Map the interrupt registers for all possible cpus. */ + sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0, + PAGE_SIZE*NCPUS, "interrupts_percpu", + int_regs[0].which_io, 0x0); + + /* Map the system interrupt control registers. */ + sparc_alloc_io(int_regs[4].phys_addr, 0, + int_regs[4].reg_size, "interrupts_system", + int_regs[4].which_io, 0x0); + + sun4m_interrupts->set = ~SUN4M_INT_MASKALL; + for (i=0; icpu_intregs[i].clear = ~0x17fff; + + if (linux_num_cpus > 1) { + /* system wide interrupts go to cpu 0, this should always + * be safe because it is guarenteed to be fitted or OBP doesn't + * come up + * + * Not sure, but writing here on SLAVIO systems may puke + * so I don't do it unless there is more than 1 cpu. + */ +#if 0 + printk("Warning:" + "sun4m multiple CPU interrupt code requires work\n"); +#endif + irq_rcvreg = &sun4m_interrupts->undirected_target; + sun4m_interrupts->undirected_target = 0; + } + enable_irq = sun4m_enable_irq; + disable_irq = sun4m_disable_irq; + clear_clock_irq = sun4m_clear_clock_irq; + clear_profile_irq = sun4m_clear_profile_irq; + load_profile_irq = sun4m_load_profile_irq; + init_timers = sun4m_init_timers; +#ifdef __SMP__ + set_cpu_int = sun4m_send_ipi; + clear_cpu_int = sun4m_clear_ipi; + set_irq_udt = sun4m_set_udt; +#endif + sti(); +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sunos_asm.S linux/arch/sparc/kernel/sunos_asm.S --- v1.3.92/linux/arch/sparc/kernel/sunos_asm.S Mon Mar 4 08:49:56 1996 +++ linux/arch/sparc/kernel/sunos_asm.S Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: sunos_asm.S,v 1.10 1995/12/26 04:09:33 davem Exp $ +/* $Id: sunos_asm.S,v 1.12 1996/04/03 02:14:57 davem Exp $ * sunos_asm.S: SunOS system calls which must have a low-level * entry point to operate correctly. * @@ -73,8 +73,8 @@ call C_LABEL(sparc_execve) add %sp, REGWIN_SZ, %o0 - st %o0, [%sp + REGWIN_SZ + PT_I0] - b C_LABEL(ret_sys_call) nop + + diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sunos_ioctl.c linux/arch/sparc/kernel/sunos_ioctl.c --- v1.3.92/linux/arch/sparc/kernel/sunos_ioctl.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/sunos_ioctl.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.17 1996/02/10 04:29:20 davem Exp $ +/* $Id: sunos_ioctl.c,v 1.18 1996/04/04 12:41:38 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -52,7 +53,7 @@ } } - /* Binary compatibility is good American knowhow fuckin' up. */ + /* Binary compatability is good American knowhow fuckin' up. */ if(cmd == TIOCNOTTY) return sys_setsid(); diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/switch.S linux/arch/sparc/kernel/switch.S --- v1.3.92/linux/arch/sparc/kernel/switch.S Mon Mar 4 08:49:56 1996 +++ linux/arch/sparc/kernel/switch.S Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: switch.S,v 1.14 1995/12/29 21:47:22 davem Exp $ +/* $Id: switch.S,v 1.18 1996/04/03 02:15:00 davem Exp $ * switch.S: Sparc task switch code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -40,8 +41,14 @@ /* Load new kernel state. */ wr %sw_psr, PSR_ET, %psr WRITE_PAUSE +#ifdef __SMP__ + GET_PROCESSOR_OFFSET(sw_psr) + set C_LABEL(current_set), %sw_tmp + st %sw_ntask, [%sw_tmp + %sw_psr] +#else sethi %hi(C_LABEL(current_set)), %sw_tmp st %sw_ntask, [%sw_tmp + %lo(C_LABEL(current_set))] +#endif ldd [%sw_ntask + THREAD_KPSR], %sw_psr wr %sw_psr, PSR_ET, %psr WRITE_PAUSE @@ -55,3 +62,35 @@ retl nop + + +#ifdef __SMP__ + /* Because of nasty register windows this is the only way + * to start a processor into it's cpu_idle() thread. + */ + + .globl C_LABEL(sparc_cpusched) +C_LABEL(sparc_cpusched): + LOAD_CURRENT(g1, g2) + rd %psr, %g7 + + wr %g7, PSR_ET, %psr + WRITE_PAUSE + + ldd [%g1 + THREAD_KPSR], %g2 + + wr %g2, PSR_ET, %psr + WRITE_PAUSE + + wr %g3, 0x0, %wim + WRITE_PAUSE + + ldd [%g1 + THREAD_KSP], %sp + LOAD_WINDOW(sp) + + wr %g2, 0x0, %psr + WRITE_PAUSE + + retl + nop +#endif diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sys_bsd.c linux/arch/sparc/kernel/sys_bsd.c --- v1.3.92/linux/arch/sparc/kernel/sys_bsd.c Mon Mar 4 08:49:56 1996 +++ linux/arch/sparc/kernel/sys_bsd.c Thu Jan 1 02:00:00 1970 @@ -1,48 +0,0 @@ -/* sys_bsd.c: {net, open}bsd specific system call handling. - * - * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu) - */ -#include - -#include -#include - -static int errno_trans[] = { - 0, - BSD_EPERM, BSD_ENOENT, BSD_ESRCH, BSD_EINTR, BSD_EIO, - BSD_ENXIO, BSD_E2BIG, BSD_ENOEXEC, BSD_EBADF, BSD_ECHILD, - BSD_EAGAIN, BSD_ENOMEM, BSD_EACCES, BSD_EFAULT, BSD_ENOTBLK, - BSD_EBUSY, BSD_EEXIST, BSD_EXDEV, BSD_ENODEV, BSD_ENOTDIR, - BSD_EISDIR, BSD_EINVAL, BSD_ENFILE, BSD_EMFILE, BSD_ENOTTY, - BSD_ETXTBSY, BSD_EFBIG, BSD_ENOSPC, BSD_ESPIPE, BSD_EROFS, - BSD_EMLINK, BSD_EPIPE, BSD_EDOM, BSD_ERANGE, BSD_EWOULDBLOCK, - BSD_EINPROGRESS, BSD_EALREADY, BSD_ENOTSOCK, BSD_EDESTADDRREQ, - BSD_EMSGSIZE, BSD_EPROTOTYPE, BSD_ENOPROTOOPT, BSD_EPROTONOSUPPORT, - BSD_ESOCKTNOSUPPORT, BSD_EOPNOTSUPP, BSD_EPFNOSUPPORT, BSD_EAFNOSUPPORT, - BSD_EADDRINUSE, - BSD_EADDRNOTAVAIL, BSD_ENETDOWN, BSD_ENETUNREACH, BSD_ENETRESET, - BSD_ECONNABORTED, BSD_ECONNRESET, BSD_ENOBUFS, BSD_EISCONN, - BSD_ENOTCONN, BSD_ESHUTDOWN, BSD_ETOOMANYREFS, BSD_ETIMEDOUT, - BSD_ECONNREFUSED, BSD_ELOOP, BSD_ENAMETOOLONG, BSD_EHOSTDOWN, - BSD_EHOSTUNREACH, BSD_ENOTEMPTY, BSD_EPROCLIM, BSD_EUSERS, - BSD_EDQUOT, BSD_ESTALE, BSD_EREMOTE, BSD_ENOSTR, BSD_ETIME, - BSD_ENOSR, BSD_ENOMSG, BSD_EBADMSG, BSD_EIDRM, BSD_EDEADLK, - BSD_ENOLCK, BSD_ENONET, BSD_ERREMOTE, BSD_ENOLINK, BSD_EADV, - BSD_ESRMNT, BSD_ECOMM, BSD_EPROTO, BSD_EMULTIHOP, BSD_EDOTDOT, - BSD_EREMCHG, BSD_ENOSYS -}; - -asmlinkage int netbsd_nosys(void) -{ - struct pt_regs *regs; - - regs = (struct pt_regs *) (current->saved_kernel_stack + - sizeof(struct reg_window)); - current->tss.sig_address = regs->pc; - current->tss.sig_desc = regs->u_regs[UREG_G1]; - send_sig(SIGSYS, current, 1); - printk("Process makes ni_syscall number %d, register dump:\n", - (int) regs->u_regs[UREG_G1]); - show_regs(regs); - return -BSD_ENOSYS; -} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c --- v1.3.92/linux/arch/sparc/kernel/sys_sparc.c Fri Apr 12 15:51:48 1996 +++ linux/arch/sparc/kernel/sys_sparc.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.7 1996/03/01 07:15:58 davem Exp $ +/* $Id: sys_sparc.c,v 1.10 1996/04/20 08:33:55 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that @@ -27,19 +27,19 @@ /* * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix traditionally does this, though. + * a pipe. It's not the way unix tranditionally does this, though. */ -asmlinkage void sparc_pipe(struct pt_regs *regs) +asmlinkage int sparc_pipe(struct pt_regs *regs) { int fd[2]; int error; error = do_pipe(fd); if (error) { - regs->u_regs[UREG_I0] = error; + return error; } else { - regs->u_regs[UREG_I0] = fd[0]; regs->u_regs[UREG_I1] = fd[1]; + return fd[0]; } } @@ -164,4 +164,44 @@ return -EINVAL; } return -EINVAL; +} + +unsigned long get_sparc_unmapped_area(unsigned long len) +{ + unsigned long addr = 0xE8000000UL; + struct vm_area_struct * vmm; + + if (len > TASK_SIZE) + return 0; + for (vmm = find_vma(current, addr); ; vmm = vmm->vm_next) { + /* At this point: (!vmm || addr < vmm->vm_end). */ + if (TASK_SIZE - len < addr) + return 0; + if (!vmm || addr + len <= vmm->vm_start) + return addr; + addr = vmm->vm_end; + } +} + +/* Linux version of mmap */ +asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long off) +{ + struct file * file = NULL; + long retval; + + if (!(flags & MAP_ANONYMOUS)) { + if (fd >= NR_OPEN || !(file = current->files->fd[fd])){ + return -EBADF; + } + } + if(!(flags & MAP_FIXED) && !addr) { + addr = get_sparc_unmapped_area(len); + if(!addr){ + return -ENOMEM; + } + } + retval = do_mmap(file, addr, len, prot, flags, off); + return retval; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v1.3.92/linux/arch/sparc/kernel/sys_sunos.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/kernel/sys_sunos.c Sun Apr 21 12:30:31 1996 @@ -1,5 +1,5 @@ -/* $Id: sys_sunos.c,v 1.33 1996/03/01 07:16:00 davem Exp $ - * sys_sunos.c: SunOS specific syscall compatibility support. +/* $Id: sys_sunos.c,v 1.37 1996/04/19 16:52:38 miguel Exp $ + * sys_sunos.c: SunOS specific syscall compatability support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -7,13 +7,30 @@ * Based upon preliminary work which is: * * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) + * + * The sunos_poll routine is based on iBCS2's poll routine, this + * is the copyright message for that file: + * + * This file contains the procedures for the handling of poll. + * + * Copyright (C) 1994 Eric Youngdale + * + * Created for Linux based loosely upon linux select code, which + * in turn is loosely based upon Mathius Lattner's minix + * patches by Peter MacDonald. Heavily edited by Linus. + * + * Poll is used by SVr4 instead of select, and it has considerably + * more functionality. Parts of it are related to STREAMS, and since + * we do not have streams, we fake it. In fact, select() still exists + * under SVr4, but libc turns it into a poll() call instead. We attempt + * to do the inverse mapping. */ +#include #include #include #include #include -#include #include #include #include @@ -23,12 +40,21 @@ #include #include #include +#include +#include +#include + +#include +#ifndef KERNEL_DS +#include +#endif #include #include #include #include /* for gethostid() */ #include +#include /* For the nfs mount emulation */ #include @@ -40,22 +66,7 @@ #include #include -static unsigned long get_sparc_unmapped_area(unsigned long len) -{ - unsigned long addr = 0xE8000000UL; - struct vm_area_struct * vmm; - - if (len > TASK_SIZE) - return 0; - for (vmm = find_vma(current, addr); ; vmm = vmm->vm_next) { - /* At this point: (!vmm || addr < vmm->vm_end). */ - if (TASK_SIZE - len < addr) - return 0; - if (!vmm || addr + len <= vmm->vm_start) - return addr; - addr = vmm->vm_end; - } -} +extern unsigned long get_sparc_unmapped_area(unsigned long len); /* We use the SunOS mmap() semantics. */ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len, @@ -150,11 +161,13 @@ * simple, it hopefully works in most obvious cases.. Easy to * fool it, but this should catch most mistakes. */ - freepages = buffermem >> 12; + freepages = buffermem >> PAGE_SHIFT; + freepages += page_cache_size; + freepages >>= 1; freepages += nr_free_pages; freepages += nr_swap_pages; freepages -= MAP_NR(high_memory) >> 4; - freepages -= (newbrk-oldbrk) >> 12; + freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; if (freepages < 0) return -ENOMEM; /* @@ -180,7 +193,7 @@ } /* XXX Completely undocumented, and completely magic... - * XXX I believe it is to increase the size of the stack by + * XXX I belive it is to increase the size of the stack by * XXX argument 'increment' and return the new end of stack * XXX area. Wheee... */ @@ -249,7 +262,7 @@ * low-bit is one == Page is currently residing in core * All other bits are undefined within the character so there... * Also, if you try to get stats on an area outside of the user vm area - * *or* the passed base address is not aligned on a page boundary you + * *or* the passed base address is not aligned on a page boundry you * get an error. */ asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array) @@ -288,7 +301,7 @@ } /* This just wants the soft limit (ie. rlim_cur element) of the RLIMIT_NOFILE - * resource limit and is for backwards compatibility with older sunos + * resource limit and is for backwards compatability with older sunos * revs. */ asmlinkage long sunos_getdtablesize(void) @@ -400,7 +413,7 @@ return cnt - buf.count; } -/* Old sunos getdirentries, severely broken compatibility stuff here. */ +/* Old sunos getdirentries, severely broken compatability stuff here. */ struct sunos_direntry { unsigned long d_ino; unsigned short d_reclen; @@ -688,7 +701,7 @@ return error; /* Ok, here comes the fun part: Linux's nfs mount needs a * socket connection to the server, but SunOS mount does not - * require this, so we use the information on the destination + * requiere this, so we use the information on the destination * address to create a socket and bind it to a reserved * port on this system */ @@ -847,3 +860,154 @@ } return -1; } + +#define POLL_ROUND_UP(x,y) (((x)+(y)-1)/(y)) + +#define POLLIN 1 +#define POLLPRI 2 +#define POLLOUT 4 +#define POLLERR 8 +#define POLLHUP 16 +#define POLLNVAL 32 +#define POLLRDNORM 64 +#define POLLWRNORM POLLOUT +#define POLLRDBAND 128 +#define POLLWRBAND 256 + +#define LINUX_POLLIN (POLLRDNORM | POLLRDBAND | POLLIN) +#define LINUX_POLLOUT (POLLWRBAND | POLLWRNORM | POLLOUT) +#define LINUX_POLLERR (POLLERR) + +static inline void free_wait(select_table * p) +{ + struct select_table_entry * entry = p->entry + p->nr; + + while (p->nr > 0) { + p->nr--; + entry--; + remove_wait_queue(entry->wait_address,&entry->wait); + } +} + + +/* Copied directly from fs/select.c */ +static int check(int flag, select_table * wait, struct file * file) +{ + struct inode * inode; + struct file_operations *fops; + int (*select) (struct inode *, struct file *, int, select_table *); + + inode = file->f_inode; + if ((fops = file->f_op) && (select = fops->select)) + return select(inode, file, flag, wait) + || (wait && select(inode, file, flag, NULL)); + if (S_ISREG(inode->i_mode)) + return 1; + return 0; +} + +struct poll { + int fd; + short events; + short revents; +}; + +int sunos_poll(struct poll * ufds, size_t nfds, int timeout) +{ + int i,j, count, fdcount, error, retflag; + struct poll * fdpnt; + struct poll * fds, *fds1; + select_table wait_table, *wait; + struct select_table_entry *entry; + + if ((error = verify_area(VERIFY_READ, ufds, nfds*sizeof(struct poll)))) + return error; + + if (nfds > NR_OPEN) + return -EINVAL; + + if (!(entry = (struct select_table_entry*)__get_free_page(GFP_KERNEL)) + || !(fds = (struct poll *)kmalloc(nfds*sizeof(struct poll), GFP_KERNEL))) + return -ENOMEM; + + memcpy_fromfs(fds, ufds, nfds*sizeof(struct poll)); + + if (timeout < 0) + current->timeout = 0x7fffffff; + else { + current->timeout = jiffies + POLL_ROUND_UP(timeout, (1000/HZ)); + if (current->timeout <= jiffies) + current->timeout = 0; + } + + count = 0; + wait_table.nr = 0; + wait_table.entry = entry; + wait = &wait_table; + + for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { + i = fdpnt->fd; + fdpnt->revents = 0; + if (!current->files->fd[i] || !current->files->fd[i]->f_inode) + fdpnt->revents = POLLNVAL; + } +repeat: + current->state = TASK_INTERRUPTIBLE; + for(fdpnt = fds, j = 0; j < (int)nfds; j++, fdpnt++) { + i = fdpnt->fd; + + if(i < 0) continue; + if (!current->files->fd[i] || !current->files->fd[i]->f_inode) continue; + + if ((fdpnt->events & LINUX_POLLIN) + && check(SEL_IN, wait, current->files->fd[i])) { + if (fdpnt->events & POLLIN) + retflag = POLLIN; + if (fdpnt->events & POLLRDNORM) + retflag = POLLRDNORM; + fdpnt->revents |= retflag; + count++; + wait = NULL; + } + + if ((fdpnt->events & LINUX_POLLOUT) && + check(SEL_OUT, wait, current->files->fd[i])) { + fdpnt->revents |= (LINUX_POLLOUT & fdpnt->events); + count++; + wait = NULL; + } + + if (check(SEL_EX, wait, current->files->fd[i])) { + fdpnt->revents |= POLLHUP; + count++; + wait = NULL; + } + } + + if ((current->signal & (~current->blocked))) + return -EINTR; + + wait = NULL; + if (!count && current->timeout > jiffies) { + schedule(); + goto repeat; + } + + free_wait(&wait_table); + free_page((unsigned long) entry); + + /* OK, now copy the revents fields back to user space. */ + fds1 = fds; + fdcount = 0; + for(i=0; i < (int)nfds; i++, ufds++, fds++) { + if (fds->revents) { + fdcount++; + } + put_fs_word(fds->revents, &ufds->revents); + } + kfree(fds1); + current->timeout = 0; + current->state = TASK_RUNNING; + return fdcount; +} + diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S --- v1.3.92/linux/arch/sparc/kernel/systbls.S Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/kernel/systbls.S Sun Apr 21 12:30:31 1996 @@ -1,5 +1,5 @@ -/* $Id: systbls.S,v 1.29 1996/03/01 07:16:02 davem Exp $ - * systbls.S: System call entry point tables for OS compatibility. +/* $Id: systbls.S,v 1.38 1996/04/20 08:43:26 davem Exp $ + * systbls.S: System call entry point tables for OS compatability. * The native Linux system call table lives here also. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -43,16 +43,18 @@ .globl C_LABEL(sys_call_table) C_LABEL(sys_call_table): /*0*/ .long C_LABEL(sys_setup), C_LABEL(sys_exit), C_LABEL(sys_fork) - .long C_LABEL(sys_read), C_LABEL(sys_write), C_LABEL(sys_open) - .long C_LABEL(sys_close), C_LABEL(sys_wait4), C_LABEL(sys_creat) - .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv) - .long C_LABEL(sys_chdir), C_LABEL(sys_ni_syscall), C_LABEL(sys_mknod) - .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_lseek), C_LABEL(sys_getpid) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_setuid) - .long C_LABEL(sys_getuid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_alarm), C_LABEL(sys_ni_syscall), C_LABEL(sys_pause) - .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty) + .long C_LABEL(sys_read), C_LABEL(sys_write) +/*5*/ .long C_LABEL(sys_open), C_LABEL(sys_close), C_LABEL(sys_wait4) + .long C_LABEL(sys_creat), C_LABEL(sys_link) +/*10*/ .long C_LABEL(sys_unlink), C_LABEL(sunos_execv), C_LABEL(sys_chdir) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_mknod) +/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_lseek) +/*20*/ .long C_LABEL(sys_getpid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_setuid), C_LABEL(sys_getuid) +/*25*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_alarm) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_pause) +/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_stty), C_LABEL(sys_gtty) .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_ftime) .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) .long C_LABEL(sys_ni_syscall), C_LABEL(sys_newlstat), C_LABEL(sys_dup) @@ -66,7 +68,7 @@ .long C_LABEL(sys_newfstat), C_LABEL(sys_ni_syscall), C_LABEL(sys_getpagesize) .long C_LABEL(sys_ni_syscall), C_LABEL(sys_vfork), C_LABEL(sys_ni_syscall) .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sunos_mmap), C_LABEL(sys_ni_syscall), C_LABEL(sys_munmap) + .long C_LABEL(sys_mmap), C_LABEL(sys_ni_syscall), C_LABEL(sys_munmap) .long C_LABEL(sys_mprotect), C_LABEL(sys_ni_syscall), C_LABEL(sys_vhangup) .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_getgroups) .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_ni_syscall) @@ -106,7 +108,7 @@ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) .long C_LABEL(sys_ni_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_ni_syscall) .long C_LABEL(sys_setpgid), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) - .long C_LABEL(sys_ni_syscall), C_LABEL(sys_uname), C_LABEL(sys_init_module) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module) .long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break) .long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit) .long C_LABEL(sys_getppid), C_LABEL(sys_sigaction), C_LABEL(sys_sgetmask) @@ -143,22 +145,22 @@ .long C_LABEL(sys_link), C_LABEL(sys_unlink), C_LABEL(sunos_execv) .long C_LABEL(sys_chdir), C_LABEL(sunos_nosys), C_LABEL(sys_mknod) .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk) - .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), LOWSYS(sunosgetpid) + .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long LOWSYS(sunosgetuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) + .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat) .long C_LABEL(sunos_nosys), C_LABEL(sys_newlstat), C_LABEL(sys_dup) .long C_LABEL(sys_pipe), C_LABEL(sunos_nosys), C_LABEL(sys_profil) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), LOWSYS(sunosgetgid) + .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_getgid) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) /*50*/ .long C_LABEL(sunos_nosys), C_LABEL(sys_acct), C_LABEL(sunos_nosys) - .long LOWSYS(sunosmctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot) + .long C_LABEL(sunos_mctl), C_LABEL(sunos_ioctl), C_LABEL(sys_reboot) .long C_LABEL(sunos_nosys), C_LABEL(sys_symlink), C_LABEL(sys_readlink) - .long C_LABEL(sys_execve), LOWSYS(umask), C_LABEL(sys_chroot) - .long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), LOWSYS(getpagesize) + .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot) + .long C_LABEL(sys_newfstat), C_LABEL(sunos_nosys), C_LABEL(sys_getpagesize) .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_sbrk), C_LABEL(sunos_sstk) .long C_LABEL(sunos_mmap), C_LABEL(sunos_vadvise), C_LABEL(sys_munmap) @@ -167,14 +169,14 @@ .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sunos_setpgrp) .long C_LABEL(sys_setitimer), C_LABEL(sunos_nosys), C_LABEL(sys_swapon) .long C_LABEL(sys_getitimer), C_LABEL(sys_gethostname), C_LABEL(sys_sethostname) - .long LOWSYS(sunosgdtsize), C_LABEL(sys_dup2), LOWSYS(sunosnop) - .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), LOWSYS(sunosnop) + .long C_LABEL(sunos_getdtablesize), C_LABEL(sys_dup2), C_LABEL(sunos_nop) + .long C_LABEL(sys_fcntl), C_LABEL(sunos_select), C_LABEL(sunos_nop) .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket) .long C_LABEL(sys_connect), C_LABEL(sys_accept) /*100*/ .long C_LABEL(sys_getpriority), C_LABEL(sys_send), C_LABEL(sys_recv) .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sys_setsockopt) .long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sys_sigaction) - .long LOWSYS(sunossblock), LOWSYS(sunossmask), C_LABEL(sys_sigpause) + .long C_LABEL(sunos_sigblock), C_LABEL(sunos_sigsetmask), C_LABEL(sys_sigpause) .long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg) .long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage) .long C_LABEL(sys_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sys_readv) @@ -189,7 +191,7 @@ .long C_LABEL(sys_setrlimit), C_LABEL(sunos_killpg), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) /*150*/ .long C_LABEL(sys_getsockname), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) + .long C_LABEL(sunos_poll), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_getdirentries), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs) .long C_LABEL(sys_umount), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname) @@ -366,3 +368,109 @@ .long C_LABEL(sunos_nosys)/*MINHERIT*/, C_LABEL(sunos_nosys)/*RFORK*/ /* One thing left, Solaris syscall table, TODO */ + .globl C_LABEL(solaris_sys_table) +C_LABEL(solaris_sys_table): +/*0*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_exit), C_LABEL(sys_fork) + .long C_LABEL(sys_read), C_LABEL(sys_write) +/*5*/ .long C_LABEL(solaris_open), C_LABEL(sys_close), C_LABEL(sys_wait4) + .long C_LABEL(sys_creat), C_LABEL(sys_link) +/*10*/ .long C_LABEL(sys_unlink), C_LABEL(sys_ni_syscall), C_LABEL(sys_chdir) + .long C_LABEL(sys_time), C_LABEL(sys_mknod) +/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sys_brk) + .long C_LABEL(sys_stat), C_LABEL(sys_lseek) +/*20*/ .long C_LABEL(sunos_getpid), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_setuid), C_LABEL(sunos_getuid) +/*25*/ .long C_LABEL(sys_stime), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_alarm), C_LABEL(sys_ni_syscall), C_LABEL(sys_pause) +/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_access), C_LABEL(sys_nice) +/*35*/ .long C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall) +/*40*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*45*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*50*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*55*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*60*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*65*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*70*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*75*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*80*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*85*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*90*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*95*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*100*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*105*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*110*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*115*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*120*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*125*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*130*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*135*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*140*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*145*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*150*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*155*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*160*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*165*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*170*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*175*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*180*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*185*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*190*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*195*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*200*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*205*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*210*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*215*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*220*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*225*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*230*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*235*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*240*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*245*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*250*/ .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) + .long C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall), C_LABEL(sys_ni_syscall) +/*255*/ .long C_LABEL(sys_ni_syscall) diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/tadpole.c linux/arch/sparc/kernel/tadpole.c --- v1.3.92/linux/arch/sparc/kernel/tadpole.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/tadpole.c Sun Apr 21 12:30:31 1996 @@ -0,0 +1,122 @@ +/* tadpole.c: Probing for the tadpole clock stopping h/w at boot time. + * + * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) + */ + +#include + +#include +#include +#include + +#define MACIO_SCSI_CSR_ADDR 0x78400000 +#define MACIO_EN_DMA 0x00000200 +#define CLOCK_INIT_DONE 1 + +static int clk_state; +static volatile unsigned char *clk_ctrl; +void (*cpu_pwr_save)(void); + +static inline unsigned int ldphys(unsigned int addr) +{ + unsigned long data; + + __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : + "=r" (data) : + "r" (addr), "i" (ASI_M_BYPASS)); + return data; +} + +static void clk_init(void) +{ + __asm__ __volatile__("mov 0x6c, %%g1\n\t" + "mov 0x4c, %%g2\n\t" + "mov 0xdf, %%g3\n\t" + "stb %%g1, [%0+3]\n\t" + "stb %%g2, [%0+3]\n\t" + "stb %%g3, [%0+3]\n\t" : : + "r" (clk_ctrl) : + "g1", "g2", "g3"); +} + +static void clk_slow(void) +{ + __asm__ __volatile__("save %sp, -0x68, %sp\n\t" + "set _clk_ctrl, %l0\n\t" + "ld [%l0], %l0\n\t" + "mov 0xcc, %l1\n\t" + "mov 0x4c, %l2\n\t" + "mov 0xcf, %l3\n\t" + "mov 0xdf, %l4\n\t" + "stb %l1, [%l0+3]\n\t" + "stb %l2, [%l0+3]\n\t" + "stb %l3, [%l0+3]\n\t" + "stb %l4, [%l0+3]\n\t" + "restore\n\t"); +} + +static void tsu_clockstop(void) +{ + unsigned int mcsr; + unsigned long flags; + + if (!clk_ctrl) + return; + if (!(clk_state & CLOCK_INIT_DONE)) { + save_flags(flags); cli(); + clk_init(); + clk_state |= CLOCK_INIT_DONE; /* all done */ + restore_flags(flags); + return; + } + if (!(clk_ctrl[2] & 1)) + return; /* no speed up yet */ + + save_flags(flags); cli(); + + /* if SCSI DMA in progress, don't slow clock */ + mcsr = ldphys(MACIO_SCSI_CSR_ADDR); + if ((mcsr&MACIO_EN_DMA) != 0) { + restore_flags(flags); + return; + } + /* TODO... the minimum clock setting ought to increase the + * memory refresh interval.. + */ + clk_slow(); + restore_flags(flags); +} + +static void swift_clockstop(void) +{ + if (!clk_ctrl) + return; + clk_ctrl[0] = 0; +} + +void clock_stop_probe(void) +{ + unsigned int node, clk_nd; + char name[20]; + + prom_getstring(prom_root_node, "name", name, sizeof(name)); + if (strncmp(name, "Tadpole", 7)) + return; + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(node, "obio"); + node = prom_getchild(node); + clk_nd = prom_searchsiblings(node, "clk-ctrl"); + if (!clk_nd) + return; + printk("Clock Stopping h/w detected... "); + clk_ctrl = (char *) prom_getint(clk_nd, "address"); + clk_state = 0; + if (name[10] == '\0') { + cpu_pwr_save = tsu_clockstop; + printk("enabled (S3)\n"); + } else if ((name[10] == 'X') || (name[10] == 'G')) { + cpu_pwr_save = swift_clockstop; + printk("enabled (%s)\n",name+7); + } else + printk("disabled %s\n",name+7); +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/tick14.c linux/arch/sparc/kernel/tick14.c --- v1.3.92/linux/arch/sparc/kernel/tick14.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/tick14.c Sun Apr 21 12:30:31 1996 @@ -0,0 +1,84 @@ +/* tick14.c + * linux/arch/sparc/kernel/tick14.c + * + * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) + * + * This file handles the Sparc specific level14 ticker + * This is really useful for profiling OBP uses it for keyboard + * aborts and other stuff. + * + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long lvl14_save[5]; +static unsigned long *linux_lvl14 = NULL; +static unsigned long obp_lvl14[4]; + +void install_linux_ticker(void) +{ + unsigned long flags; + + if (!linux_lvl14) + return; + save_flags(flags); cli(); + linux_lvl14[0] = lvl14_save[0]; + linux_lvl14[1] = lvl14_save[1]; + linux_lvl14[2] = lvl14_save[2]; + linux_lvl14[3] = lvl14_save[3]; + restore_flags(flags); +} + +void install_obp_ticker(void) +{ + unsigned long flags; + + if (!linux_lvl14) + return; + save_flags(flags); cli(); + linux_lvl14[0] = obp_lvl14[0]; + linux_lvl14[1] = obp_lvl14[1]; + linux_lvl14[2] = obp_lvl14[2]; + linux_lvl14[3] = obp_lvl14[3]; + restore_flags(flags); +} + +void claim_ticker14(void (*handler)(int, void *, struct pt_regs *), + int irq_nr, unsigned int timeout ) +{ + /* first we copy the obp handler instructions + */ + disable_irq(irq_nr); + if (!handler) + return; + + linux_lvl14 = (unsigned long *)lvl14_save[4]; + obp_lvl14[0] = linux_lvl14[0]; + obp_lvl14[1] = linux_lvl14[1]; + obp_lvl14[2] = linux_lvl14[2]; + obp_lvl14[3] = linux_lvl14[3]; + + if (!request_irq(irq_nr, + handler, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "counter14", + NULL)) { + install_linux_ticker(); + load_profile_irq(timeout); + enable_irq(irq_nr); + } +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c --- v1.3.92/linux/arch/sparc/kernel/time.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/kernel/time.c Sun Apr 21 12:30:31 1996 @@ -1,10 +1,11 @@ -/* $Id: time.c,v 1.7 1996/03/01 07:16:05 davem Exp $ +/* $Id: time.c,v 1.12 1996/04/04 16:30:30 tridge Exp $ * linux/arch/sparc/kernel/time.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * * This file handles the Sparc specific time handling details. */ +#include #include #include #include @@ -21,15 +22,9 @@ #include #include -#define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ - enum sparc_clock_type sp_clock_typ; struct mostek48t02 *mstk48t02_regs = 0; struct mostek48t08 *mstk48t08_regs = 0; -volatile unsigned int *master_l10_limit = 0; -volatile unsigned int *master_l10_counter = 0; -struct sun4m_timer_regs *sun4m_timers; - static int set_rtc_mmss(unsigned long); /* @@ -40,10 +35,8 @@ { /* last time the cmos clock got updated */ static long last_rtc_update=0; - volatile unsigned int clear_intr; - /* First, clear the interrupt. */ - clear_intr = *master_l10_limit; + clear_clock_irq(); do_timer(regs); @@ -100,13 +93,13 @@ /* This will basically traverse the node-tree of the prom to see * which timer chip is on this machine. */ - node = 0; if(sparc_cpu_model == sun4) { printk("clock_probe: No SUN4 Clock/Timer support yet...\n"); return; } - if(sparc_cpu_model == sun4c) node=prom_getchild(prom_root_node); + if(sparc_cpu_model == sun4c) + node = prom_getchild(prom_root_node); else if(sparc_cpu_model == sun4m) node=prom_getchild(prom_searchsiblings(prom_getchild(prom_root_node), "obio")); @@ -154,73 +147,6 @@ return; } } - - if(sparc_cpu_model == sun4c) { - /* Map the Timer chip, this is implemented in hardware inside - * the cache chip on the sun4c. - */ - sun4c_timers = sparc_alloc_io ((void *) SUN4C_TIMER_PHYSADDR, 0, - sizeof(struct sun4c_timer_info), - "timer", 0x0, 0x0); - - /* Have the level 10 timer tick at 100HZ. We don't touch the - * level 14 timer limit since we are letting the prom handle - * them until we have a real console driver so L1-A works. - */ - sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); - master_l10_limit = &(sun4c_timers->timer_limit10); - master_l10_counter = &(sun4c_timers->cur_count10); - } else { - /* XXX Fix this SHIT... UP and MP sun4m configurations - * XXX have completely different layouts for the counter - * XXX registers. AIEEE!!! - */ - - int reg_count; - struct linux_prom_registers cnt_regs[PROMREG_MAX]; - volatile unsigned long *real_limit; - int obio_node, cnt_node; - - cnt_node = 0; - if((obio_node = - prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || - (obio_node = prom_getchild (obio_node)) == 0 || - (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { - prom_printf("Cannot find /obio/counter node\n"); - prom_halt(); - } - reg_count = prom_getproperty(cnt_node, "reg", - (void *) cnt_regs, sizeof(cnt_regs)); - reg_count = (reg_count/sizeof(struct linux_prom_registers)); - - /* Apply the obio ranges to the timer registers. */ - prom_apply_obio_ranges(cnt_regs, reg_count); - - /* Map the per-cpu Counter registers. */ - sparc_alloc_io(cnt_regs[0].phys_addr, 0, - PAGE_SIZE*NCPUS, "counters_percpu", - cnt_regs[0].which_io, 0x0); - - /* Map the system Counter register. */ - sun4m_timers = sparc_alloc_io(cnt_regs[reg_count-1].phys_addr, 0, - cnt_regs[reg_count-1].reg_size, - "counters_system", - cnt_regs[reg_count-1].which_io, 0x0); - - real_limit = &sun4m_timers->l10_timer_limit; - if(reg_count < 4) { - /* Uniprocessor timers, ugh. */ - real_limit = (volatile unsigned long *) sun4m_timers; - } - - /* Avoid interrupt bombs... */ - foo_limit = (volatile) *real_limit; - - /* Must set the master pointer first or we will lose badly. */ - master_l10_limit = real_limit; - master_l10_counter = real_limit + 1; - *master_l10_limit = (((1000000/HZ) + 1) << 10); - } } #ifndef BCD_TO_BIN @@ -236,9 +162,14 @@ unsigned int year, mon, day, hour, min, sec; struct mostek48t02 *mregs; +#if CONFIG_AP1000 + init_timers(timer_interrupt); + return; +#endif + clock_probe(); - /* request_irq(TIMER_IRQ, timer_interrupt, SA_INTERRUPT, "timer", NULL); */ - enable_irq(TIMER_IRQ); + init_timers(timer_interrupt); + mregs = mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); @@ -256,6 +187,7 @@ mregs->creg &= ~MSTK_CREG_READ; return; } + /* Nothing fancy on the Sparc yet. */ void do_gettimeofday(struct timeval *tv) { @@ -263,6 +195,9 @@ save_flags(flags); cli(); +#if CONFIG_AP1000 + ap_gettimeofday(&xtime); +#endif *tv = xtime; restore_flags(flags); } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/trampoline.S linux/arch/sparc/kernel/trampoline.S --- v1.3.92/linux/arch/sparc/kernel/trampoline.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/kernel/trampoline.S Sun Apr 21 12:30:31 1996 @@ -0,0 +1,90 @@ +/* $Id: trampoline.S,v 1.3 1996/04/03 02:15:05 davem Exp $ + * mp.S: Multiprocessor low-level routines on the Sparc. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include + + + .text + .align 4 + +/* When we start up a cpu for the first time it enters this routine. + * This initializes the chip from whatever state the prom left it + * in and sets PIL in %psr to 15, no irqs. + */ + + .globl C_LABEL(sparc_cpu_startup) +C_LABEL(sparc_cpu_startup): +cpu1_startup: + sethi %hi(C_LABEL(trapbase_cpu1)), %g7 + or %g7, %lo(C_LABEL(trapbase_cpu1)), %g7 + sethi %hi(C_LABEL(cpu1_stack)), %g6 + or %g6, %lo(C_LABEL(cpu1_stack)), %g6 + b 1f + nop + +cpu2_startup: + sethi %hi(C_LABEL(trapbase_cpu2)), %g7 + or %g7, %lo(C_LABEL(trapbase_cpu2)), %g7 + sethi %hi(C_LABEL(cpu2_stack)), %g6 + or %g6, %lo(C_LABEL(cpu2_stack)), %g6 + b 1f + nop + +cpu3_startup: + sethi %hi(C_LABEL(trapbase_cpu3)), %g7 + or %g7, %lo(C_LABEL(trapbase_cpu3)), %g7 + sethi %hi(C_LABEL(cpu3_stack)), %g6 + or %g6, %lo(C_LABEL(cpu3_stack)), %g6 + b 1f + nop + +1: + /* Set up a sane %psr -- PIL<0xf> S<0x1> PS<0x1> CWP<0x0> */ + set (PSR_PIL | PSR_S | PSR_PS), %g1 + wr %g1, 0x0, %psr ! traps off though + WRITE_PAUSE + + /* Our %wim is one behind CWP */ + mov 2, %g1 + wr %g1, 0x0, %wim + WRITE_PAUSE + + /* This identifies "this cpu". */ + wr %g7, 0x0, %tbr + WRITE_PAUSE + + /* Give ourselves a stack. */ + set 0x2000, %g5 + add %g6, %g5, %g6 ! end of stack + sub %g6, REGWIN_SZ, %sp + mov 0, %fp + + /* Turn on traps (PSR_ET). */ + rd %psr, %g1 + wr %g1, PSR_ET, %psr ! traps on + WRITE_PAUSE + + /* Init our caches, etc. */ + set C_LABEL(poke_srmmu), %g5 + ld [%g5], %g5 + call %g5 + nop + + /* Start this processor. */ + call C_LABEL(smp_callin) + nop + + call C_LABEL(cpu_idle) + mov 0, %o0 + + call C_LABEL(cpu_panic) + nop diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c --- v1.3.92/linux/arch/sparc/kernel/traps.c Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/kernel/traps.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.32 1996/03/01 07:16:08 davem Exp $ +/* $Id: traps.c,v 1.42 1996/04/16 08:24:44 davem Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -10,6 +10,7 @@ #include /* for jiffies */ #include +#include #include #include @@ -18,9 +19,11 @@ #include #include #include -#include #include #include +#include + +/* #define TRAP_DEBUG */ struct trap_trace_entry { unsigned long pc; @@ -41,20 +44,47 @@ { } +void sun4m_nmi(struct pt_regs *regs) +{ + unsigned long afsr, afar; + + printk("Aieee: sun4m NMI received!\n"); + /* XXX HyperSparc hack XXX */ + __asm__ __volatile__("mov 0x500, %%g1\n\t" + "lda [%%g1] 0x4, %0\n\t" + "mov 0x600, %%g1\n\t" + "lda [%%g1] 0x4, %1\n\t" : + "=r" (afsr), "=r" (afar)); + printk("afsr=%08lx afar=%08lx\n", afsr, afar); + printk("you lose buddy boy...\n"); + show_regs(regs); + prom_halt(); +} + void die_if_kernel(char *str, struct pt_regs *regs) { unsigned long i; unsigned long *pc; - if(regs->psr & PSR_PS) - do_exit(SIGKILL); + /* Amuse the user. */ + printk( +" \\|/ ____ \\|/\n" +" \"@'/ ,. \\`@\"\n" +" /_| \\__/ |_\\\n" +" \\__U_/\n"); + printk("%s(%d): %s\n", current->comm, current->pid, str); show_regs(regs); +#if CONFIG_AP1000 + ap_panic(); +#endif printk("Instruction DUMP:"); pc = (unsigned long *) regs->pc; for(i = -3; i < 6; i++) printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>'); printk("\n"); + if(regs->psr & PSR_PS) + do_exit(SIGKILL); do_exit(SIGSEGV); } @@ -63,7 +93,7 @@ if(type < 0x80) { /* Sun OS's puke from bad traps, Linux survives! */ printk("Unimplemented Sparc TRAP, type = %02lx\n", type); - panic("Whee... Hello Mr. Penguin"); + die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs); } current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80); current->tss.sig_address = pc; @@ -75,6 +105,10 @@ { if(psr & PSR_PS) die_if_kernel("Kernel illegal instruction", regs); +#ifdef TRAP_DEBUG + printk("Ill instr. at pc=%08lx instruction is %08lx\n", + regs->pc, *(unsigned long *)regs->pc); +#endif current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); @@ -95,8 +129,12 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - if(regs->psr & PSR_PS) - die_if_kernel("Kernel MNA access", regs); + if(regs->psr & PSR_PS) { + printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc, + regs->u_regs[UREG_RETPC]); + die_if_kernel("BOGUS", regs); + /* die_if_kernel("Kernel MNA access", regs); */ + } current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); @@ -118,10 +156,11 @@ { /* Sanity check... */ if(psr & PSR_PS) - die_if_kernel("Kernel gets Penguin-FPU disabled trap", regs); + die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs); put_psr(get_psr() | PSR_EF); /* Allow FPU ops. */ regs->psr |= PSR_EF; +#ifndef __SMP__ if(last_task_used_math == current) return; if(last_task_used_math) { @@ -138,6 +177,15 @@ fpload(&init_fregs[0], &init_fsr); current->used_math = 1; } +#else + if(!current->used_math) { + fpload(&init_fregs[0], &init_fsr); + current->used_math = 1; + } else { + fpload(¤t->tss.float_regs[0], ¤t->tss.fsr); + } + current->flags |= PF_USEDFPU; +#endif } static unsigned long fake_regs[32] __attribute__ ((aligned (8))); @@ -149,22 +197,33 @@ unsigned long psr) { static calls = 0; +#ifndef __SMP__ struct task_struct *fpt = last_task_used_math; +#else + struct task_struct *fpt = current; +#endif put_psr(get_psr() | PSR_EF); /* If nobody owns the fpu right now, just clear the * error into our fake static buffer and hope it don't * happen again. Thank you crashme... */ +#ifndef __SMP__ if(!fpt) { +#else + if(!(fpt->flags & PF_USEDFPU)) { +#endif fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth); regs->psr &= ~PSR_EF; return; } fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr, &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth); - last_task_used_math->tss.sig_address = pc; - last_task_used_math->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */ + fpt->tss.sig_address = pc; + fpt->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */ +#ifdef __SMP__ + fpt->flags &= ~PF_USEDFPU; +#endif if(psr & PSR_PS) { /* The first fsr store/load we tried trapped, * the second one will not (we hope). @@ -179,8 +238,10 @@ regs); return; } - send_sig(SIGFPE, last_task_used_math, 1); + send_sig(SIGFPE, fpt, 1); +#ifndef __SMP__ last_task_used_math = NULL; +#endif regs->psr &= ~PSR_EF; if(calls > 0) calls=0; @@ -199,8 +260,10 @@ void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { +#ifdef TRAP_DEBUG printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); +#endif if(psr & PSR_PS) panic("Tell me what a watchpoint trap is, and I'll then deal " "with such a beast..."); @@ -209,8 +272,10 @@ void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { +#ifdef TRAP_DEBUG printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); +#endif send_sig(SIGILL, current, 1); } @@ -223,24 +288,27 @@ void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { +#ifdef TRAP_DEBUG printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); +#endif + printk("INSTRUCTION=%08lx\n", *((unsigned long *) regs->pc)); send_sig(SIGILL, current, 1); } void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { +#ifdef TRAP_DEBUG printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n", pc, npc, psr); +#endif send_sig(SIGILL, current, 1); } void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n", - pc, npc, psr); send_sig(SIGILL, current, 1); } @@ -251,7 +319,7 @@ extern void sparc_cpu_startup(void); extern int linux_num_cpus; -extern pgd_t **srmmu_context_table; +extern ctxd_t *srmmu_ctx_table_phys; int linux_smp_still_initting; unsigned int thiscpus_tbr; @@ -259,49 +327,4 @@ void trap_init(void) { - struct linux_prom_registers ctx_reg; - int i; - - if(linux_num_cpus == 1) { - printk("trap_init: Uniprocessor detected.\n"); - return; - } - if(sparc_cpu_model != sun4m) { - prom_printf("trap_init: Multiprocessor on a non-sun4m! Aieee...\n"); - prom_printf("trap_init: Cannot continue, bailing out.\n"); - prom_halt(); - } - /* Ok, we are on a sun4m with multiple cpu's */ - prom_printf("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n", - linux_num_cpus); - linux_smp_still_initting = 1; - ctx_reg.which_io = 0x0; /* real ram */ - ctx_reg.phys_addr = (char *) (((unsigned long) srmmu_context_table) - PAGE_OFFSET); - ctx_reg.reg_size = 0x0; - /* This basically takes every cpu, loads up our Linux context table - * into it's context table pointer register, inits it at the low level - * and then makes it spin in an endless loop... - */ - for(i=0; i200) - break; - __delay(200000); - } - } - } - - linux_smp_still_initting = 1; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S --- v1.3.92/linux/arch/sparc/kernel/wof.S Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/kernel/wof.S Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: wof.S,v 1.20 1996/02/20 07:45:18 davem Exp $ +/* $Id: wof.S,v 1.22 1996/04/03 02:15:10 davem Exp $ * wof.S: Sparc window overflow handler. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include /* WARNING: This routine is hairy and _very_ complicated, but it * must be as fast as possible as it handles the allocation @@ -244,18 +246,14 @@ mov %saved_g6, %g6 STORE_PT_ALL(sp, t_psr, t_pc, t_npc, g1) + ENTER_SYSCALL + /* Turn on traps and call c-code to deal with it. */ wr %t_psr, PSR_ET, %psr WRITE_PAUSE -#if 0 - mov 0, %o1 - call C_LABEL(try_to_clear_window_buffer) - add %sp, REGWIN_SZ, %o0 -#else call C_LABEL(window_overflow_fault) nop -#endif /* Return from trap if C-code actually fixes things, if it * doesn't then we never get this far as the process will diff -u --recursive --new-file v1.3.92/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S --- v1.3.92/linux/arch/sparc/kernel/wuf.S Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/kernel/wuf.S Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.20 1996/02/20 07:45:22 davem Exp $ +/* $Id: wuf.S,v 1.22 1996/04/03 02:15:13 davem Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include /* Just like the overflow handler we define macros for registers * with fixed meanings in this routine. @@ -178,6 +180,8 @@ st %g5, [%twin_tmp1 + THREAD_UMASK] ! one live user window still st %g0, [%twin_tmp1 + THREAD_W_SAVED] ! no windows in the buffer + ENTER_SYSCALL + wr %t_psr, PSR_ET, %psr ! enable traps WRITE_PAUSE @@ -230,7 +234,7 @@ * check routines in wof.S, these routines are free to use * any of the local registers they want to as this window * does not belong to anyone at this point, however the - * outs and ins are still verboten as they are part of + * outs and ins are still verbotten as they are part of * 'someone elses' window possibly. */ @@ -341,7 +345,7 @@ be fwin_user_finish_up nop - /* Did I ever tell you about my window lobotomy? + /* Did I ever tell you about my window labotomy? * anyways... fwin_user_stack_is_bolixed expects * to be in window 'W' so make it happy or else * we watchdog badly. diff -u --recursive --new-file v1.3.92/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile --- v1.3.92/linux/arch/sparc/lib/Makefile Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/lib/Makefile Sun Apr 21 12:30:31 1996 @@ -1,10 +1,11 @@ -# $Id: Makefile,v 1.7 1995/12/10 06:25:02 davem Exp $ +# $Id: Makefile,v 1.9 1996/03/23 01:37:15 davem Exp $ # Makefile for Sparc library files.. # CFLAGS := $(CFLAGS) -ansi -OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o +OBJS = mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ + strlen.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) @@ -12,6 +13,9 @@ memcpy.o: memcpy.S $(CC) -ansi -c -o memcpy.o memcpy.S + +strlen.o: strlen.S + $(CC) -ansi -c -o strlen.o strlen.S mul.o: mul.S $(CC) -c -o mul.o mul.S diff -u --recursive --new-file v1.3.92/linux/arch/sparc/lib/memset.c linux/arch/sparc/lib/memset.c --- v1.3.92/linux/arch/sparc/lib/memset.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/lib/memset.c Sun Apr 21 12:30:31 1996 @@ -0,0 +1,71 @@ +/* linux/arch/sparc/lib/memset.c + * + * This is from GNU libc. + */ + +#include + +#define op_t unsigned long int +#define OPSIZ (sizeof(op_t)) + +typedef unsigned char byte; + +void *memset(void *dstpp, char c, size_t len) +{ + long int dstp = (long int) dstpp; + + if (len >= 8) { + size_t xlen; + op_t cccc; + + cccc = (unsigned char) c; + cccc |= cccc << 8; + cccc |= cccc << 16; + + /* There are at least some bytes to set. + No need to test for LEN == 0 in this alignment loop. */ + while (dstp % OPSIZ != 0) { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + /* Write 8 `op_t' per iteration until less + * than 8 `op_t' remain. + */ + xlen = len / (OPSIZ * 8); + while (xlen > 0) { + ((op_t *) dstp)[0] = cccc; + ((op_t *) dstp)[1] = cccc; + ((op_t *) dstp)[2] = cccc; + ((op_t *) dstp)[3] = cccc; + ((op_t *) dstp)[4] = cccc; + ((op_t *) dstp)[5] = cccc; + ((op_t *) dstp)[6] = cccc; + ((op_t *) dstp)[7] = cccc; + dstp += 8 * OPSIZ; + xlen -= 1; + } + len %= OPSIZ * 8; + + /* Write 1 `op_t' per iteration until less than + * OPSIZ bytes remain. + */ + xlen = len / OPSIZ; + while (xlen > 0) { + ((op_t *) dstp)[0] = cccc; + dstp += OPSIZ; + xlen -= 1; + } + len %= OPSIZ; + } + + /* Write the last few bytes. */ + while (len > 0) { + ((byte *) dstp)[0] = c; + dstp += 1; + len -= 1; + } + + return dstpp; +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/lib/strlen.S linux/arch/sparc/lib/strlen.S --- v1.3.92/linux/arch/sparc/lib/strlen.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/lib/strlen.S Sun Apr 21 12:30:31 1996 @@ -0,0 +1,88 @@ +/* strlen.S: Sparc optimized strlen(). + * + * This was hand optimized by davem@caip.rutgers.edu from + * the C-code in GNU-libc. + */ + +#include + +#define LO_MAGIC 0x01010101 +#define HI_MAGIC 0x80808080 + + .align 4 + .global C_LABEL(strlen) +C_LABEL(strlen): + mov %o0,%o1 + andcc %o0,3,%g0 ! and with %o0 so no dependency problems + be scan_words + sethi %hi(HI_MAGIC),%g2 ! common case and most Sparcs predict taken + + ldsb [%o0],%g2 +still_not_word_aligned: + cmp %g2,0 + bne,a 1f + add %o0,1,%o0 + + /* Ok, so there are tons of quick interlocks above for the + * < 4 length string unaligned... not too common so I'm not + * very concerned. + */ + retl + sub %o0,%o1,%o0 + +1: + andcc %o0,3,%g0 + bne,a still_not_word_aligned + ldsb [%o0],%g2 + + /* HyperSparc executes each sethi/or pair in 1 cycle. */ + sethi %hi(HI_MAGIC),%g2 +scan_words: + or %g2,%lo(HI_MAGIC),%o3 + sethi %hi(LO_MAGIC),%g3 + or %g3,%lo(LO_MAGIC),%o2 +next_word: + ld [%o0],%g2 ! no dependancies +next_word_preloaded: + sub %g2,%o2,%g2 ! lots of locks here + andcc %g2,%o3,%g0 ! and I dont like it... + be next_word + add %o0,4,%o0 + + /* Check every byte. */ +byte_zero: + ldsb [%o0-4],%g2 + cmp %g2,0 + bne byte_one + add %o0,-4,%g3 + + retl + sub %g3,%o1,%o0 + +byte_one: + ldsb [%o0-3],%g2 + cmp %g2,0 + bne,a byte_two_and_three + ldsb [%o0-2],%g2 + + sub %g3,%o1,%o0 + retl + add %o0,1,%o0 + +byte_two_and_three: + cmp %g2,0 + be,a found_it + sub %g3,%o1,%o0 + + ldsb [%o0-1],%g2 + cmp %g2,0 + bne,a next_word_preloaded + ld [%o0],%g2 + + sub %g3,%o1,%o0 + retl + add %o0,3,%o0 + +found_it: + retl + add %o0,2,%o0 diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile --- v1.3.92/linux/arch/sparc/mm/Makefile Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/mm/Makefile Sun Apr 21 17:32:01 1996 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.17 1996/01/03 03:35:15 davem Exp $ +# $Id: Makefile,v 1.20 1996/04/21 10:30:43 davem Exp $ # Makefile for the linux Sparc-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -8,6 +8,6 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := fault.o init.o sun4c.o srmmu.o loadmmu.o +O_OBJS := fault.o init.o sun4c.o srmmu.o loadmmu.o generic.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c --- v1.3.92/linux/arch/sparc/mm/fault.c Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/mm/fault.c Sun Apr 21 12:30:31 1996 @@ -1,13 +1,17 @@ -/* $Id: fault.c,v 1.53 1996/03/01 07:16:17 davem Exp $ +/* $Id: fault.c,v 1.61 1996/04/12 06:52:35 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include + #include #include #include #include +#include +#include #include #include @@ -20,6 +24,7 @@ #include #include #include +#include #include #include @@ -81,6 +86,12 @@ sp_banks[i].base_addr = 0xdeadbeef; sp_banks[i].num_bytes = 0; + /* Now mask all bank sizes on a page boundry, it is all we can + * use anyways. + */ + for(i=0; sp_banks[i].num_bytes != 0; i++) + sp_banks[i].num_bytes &= PAGE_MASK; + return tally; } @@ -122,6 +133,13 @@ struct vm_area_struct *vma; int from_user = !(regs->psr & PSR_PS); +#if 0 + printk("CPU[%d]: fpid, text_fault, + write, address); + printk(",pc=%08lx> ", regs->pc); +#endif + if(text_fault) address = regs->pc; @@ -131,8 +149,15 @@ * we'd fault recursively until all our stack is gone. ;-( */ if(!from_user && address >= KERNBASE) { +#ifdef __SMP__ + printk("CPU[%d]: Kernel faults at addr=%08lx\n", + smp_processor_id(), address); + while(1) + ; +#else quick_kernel_fault(address); return; +#endif } vma = find_vma(current, address); @@ -165,19 +190,13 @@ */ bad_area: if(from_user) { +#if 0 + printk("%s [%d]: segfaults at %08lx pc=%08lx\n", + current->comm, current->pid, address, regs->pc); +#endif current->tss.sig_address = address; current->tss.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, current, 1); - return; - } - /* Uh oh, a kernel fault. Check for bootup wp_test... */ - if (wp_works_ok < 0 && address == 0x0) { - wp_works_ok = 1; - printk("This Sparc honours the WP bit even when in supervisor mode. " - "Good.\n"); - /* Advance program counter over the store. */ - regs->pc = regs->npc; - regs->npc += 4; return; } if((unsigned long) address < PAGE_SIZE) { diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/generic.c linux/arch/sparc/mm/generic.c --- v1.3.92/linux/arch/sparc/mm/generic.c Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/mm/generic.c Sun Apr 21 17:32:01 1996 @@ -0,0 +1,102 @@ +/* generic.c: Generic Sparc mm routines that are not dependant upon + * MMU type but are Sparc specific. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + +#include +#include + +static inline void forget_pte(pte_t page) +{ + if (pte_none(page)) + return; + if (pte_present(page)) { + unsigned long addr = pte_page(page); + if (addr >= high_memory || PageReserved(mem_map+MAP_NR(addr))) + return; + free_page(addr); + if (current->mm->rss <= 0) + return; + current->mm->rss--; + return; + } + swap_free(pte_val(page)); +} + +/* Remap IO memory, the same way as remap_page_range(), but use + * the obio memory space. + * + * They use a pgprot that sets PAGE_IO and does not check the + * mem_map table as this is independent of normal memory. + */ +static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsigned long size, + unsigned long offset, pgprot_t prot, int space) +{ + unsigned long end; + + address &= ~PMD_MASK; + end = address + size; + if (end > PMD_SIZE) + end = PMD_SIZE; + do { + pte_t oldpage = *pte; + pte_clear(pte); + set_pte(pte, mk_pte_io(offset, prot, space)); + forget_pte(oldpage); + address += PAGE_SIZE; + offset += PAGE_SIZE; + pte++; + } while (address < end); +} + +static inline int io_remap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, + unsigned long offset, pgprot_t prot, int space) +{ + unsigned long end; + + address &= ~PGDIR_MASK; + end = address + size; + if (end > PGDIR_SIZE) + end = PGDIR_SIZE; + offset -= address; + do { + pte_t * pte = pte_alloc(pmd, address); + if (!pte) + return -ENOMEM; + io_remap_pte_range(pte, address, end - address, address + offset, prot, space); + address = (address + PMD_SIZE) & PMD_MASK; + pmd++; + } while (address < end); + return 0; +} + +int io_remap_page_range(unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space) +{ + int error = 0; + pgd_t * dir; + unsigned long beg = from; + unsigned long end = from + size; + + pgprot_val(prot) = pg_iobits; + offset -= from; + dir = pgd_offset(current->mm, from); + flush_cache_range(current->mm, beg, end); + while (from < end) { + pmd_t *pmd = pmd_alloc(dir, from); + error = -ENOMEM; + if (!pmd) + break; + error = io_remap_pmd_range(pmd, from, end - from, offset + from, prot, space); + if (error) + break; + from = (from + PGDIR_SIZE) & PGDIR_MASK; + dir++; + } + flush_tlb_range(current->mm, beg, end); + return error; +} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c --- v1.3.92/linux/arch/sparc/mm/init.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/mm/init.c Sun Apr 21 12:30:31 1996 @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.33 1996/03/01 07:16:20 davem Exp $ +/* $Id: init.c,v 1.36 1996/04/16 08:02:54 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -64,7 +64,7 @@ i = MAP_NR(high_memory); while (i-- > 0) { total++; - if (mem_map[i].reserved) + if (PageReserved(mem_map + i)) reserved++; else if (!mem_map[i].count) free++; @@ -131,7 +131,7 @@ }; /* Initialize the protection map with non-constant values - * MMU dependent values. + * MMU dependant values. */ protection_map[0] = PAGE_NONE; protection_map[1] = PAGE_READONLY; @@ -152,15 +152,36 @@ return device_scan(start_mem); } -extern void sun4c_test_wp(void); -extern void srmmu_test_wp(void); - struct cache_palias *sparc_aliases; extern int min_free_pages; extern int free_pages_low; extern int free_pages_high; +int physmem_mapped_contig = 1; + +static void taint_real_pages(unsigned long start_mem, unsigned long end_mem) +{ + unsigned long addr, tmp2 = 0; + + if(physmem_mapped_contig) { + for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE) { + for(tmp2=0; sp_banks[tmp2].num_bytes != 0; tmp2++) { + unsigned long phys_addr = (addr - PAGE_OFFSET); + unsigned long base = sp_banks[tmp2].base_addr; + unsigned long limit = base + sp_banks[tmp2].num_bytes; + + if((phys_addr >= base) && (phys_addr < limit) && + ((phys_addr + PAGE_SIZE) < limit)) + mem_map[MAP_NR(addr)].flags &= ~(1<= base) && (phys_addr < limit) && - ((phys_addr + PAGE_SIZE) < limit)) - mem_map[MAP_NR(addr)].reserved = 0; - } - } + taint_real_pages(start_mem, end_mem); for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) { - if(mem_map[MAP_NR(addr)].reserved) { + if(PageReserved(mem_map + MAP_NR(addr))) { if (addr < (unsigned long) &etext) codepages++; else if(addr < start_mem) @@ -218,21 +229,6 @@ free_pages_low = min_free_pages + (min_free_pages >> 1); free_pages_high = min_free_pages + min_free_pages; - switch(sparc_cpu_model) { - case sun4c: - case sun4e: - sun4c_test_wp(); - break; - case sun4m: - case sun4d: - srmmu_test_wp(); - break; - default: - printk("mem_init: Could not test WP bit on this machine.\n"); - printk("mem_init: sparc_cpu_model = %d\n", sparc_cpu_model); - printk("mem_init: Halting...\n"); - panic("mem_init()"); - }; } void si_meminfo(struct sysinfo *val) @@ -245,7 +241,7 @@ val->freeram = nr_free_pages << PAGE_SHIFT; val->bufferram = buffermem; while (i-- > 0) { - if (mem_map[i].reserved) + if (PageReserved(mem_map + i)) continue; val->totalram++; if (!mem_map[i].count) diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c --- v1.3.92/linux/arch/sparc/mm/loadmmu.c Mon Mar 4 08:49:57 1996 +++ linux/arch/sparc/mm/loadmmu.c Sun Apr 21 17:32:01 1996 @@ -1,4 +1,4 @@ -/* $Id: loadmmu.c,v 1.23 1996/02/21 17:56:35 miguel Exp $ +/* $Id: loadmmu.c,v 1.33 1996/04/21 10:32:26 davem Exp $ * loadmmu.c: This code loads up all the mm function pointers once the * machine type has been determined. It also sets the static * mmu values such as PAGE_NONE, etc. @@ -7,6 +7,7 @@ */ #include +#include #include #include @@ -26,18 +27,48 @@ void (*mmu_exit_hook)(void); void (*mmu_flush_hook)(void); +/* translate between physical and virtual addresses */ +unsigned long (*mmu_v2p)(unsigned long); +unsigned long (*mmu_p2v)(unsigned long); + char *(*mmu_lockarea)(char *, unsigned long); void (*mmu_unlockarea)(char *, unsigned long); -char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus); -void (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus); +char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +void (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); +void (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +void (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long address, pte_t pte); -void (*invalidate_all)(void); -void (*invalidate_mm)(struct mm_struct *); -void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end); -void (*invalidate_page)(struct vm_area_struct *, unsigned long address); +#ifdef __SMP__ +void (*local_flush_cache_all)(void); +void (*local_flush_cache_mm)(struct mm_struct *); +void (*local_flush_cache_range)(struct mm_struct *, unsigned long start, + unsigned long end); +void (*local_flush_cache_page)(struct vm_area_struct *, unsigned long address); + +void (*local_flush_tlb_all)(void); +void (*local_flush_tlb_mm)(struct mm_struct *); +void (*local_flush_tlb_range)(struct mm_struct *, unsigned long start, + unsigned long end); +void (*local_flush_tlb_page)(struct vm_area_struct *, unsigned long address); +void (*local_flush_page_to_ram)(unsigned long address); +#endif + +void (*flush_cache_all)(void); +void (*flush_cache_mm)(struct mm_struct *); +void (*flush_cache_range)(struct mm_struct *, unsigned long start, + unsigned long end); +void (*flush_cache_page)(struct vm_area_struct *, unsigned long address); + +void (*flush_tlb_all)(void); +void (*flush_tlb_mm)(struct mm_struct *); +void (*flush_tlb_range)(struct mm_struct *, unsigned long start, + unsigned long end); +void (*flush_tlb_page)(struct vm_area_struct *, unsigned long address); + +void (*flush_page_to_ram)(unsigned long page); void (*set_pte)(pte_t *pteptr, pte_t pteval); @@ -60,26 +91,20 @@ int (*pte_none)(pte_t); int (*pte_present)(pte_t); -int (*pte_inuse)(pte_t *); void (*pte_clear)(pte_t *); -void (*pte_reuse)(pte_t *); int (*pmd_none)(pmd_t); int (*pmd_bad)(pmd_t); int (*pmd_present)(pmd_t); -int (*pmd_inuse)(pmd_t *); void (*pmd_clear)(pmd_t *); -void (*pmd_reuse)(pmd_t *); int (*pgd_none)(pgd_t); int (*pgd_bad)(pgd_t); int (*pgd_present)(pgd_t); -int (*pgd_inuse)(pgd_t *); void (*pgd_clear)(pgd_t *); -void (*pgd_reuse)(pgd_t *); pte_t (*mk_pte)(unsigned long, pgprot_t); -pte_t (*mk_pte_io)(unsigned long, pgprot_t); +pte_t (*mk_pte_io)(unsigned long, pgprot_t, int); void (*pgd_set)(pgd_t *, pmd_t *); pte_t (*pte_modify)(pte_t, pgprot_t); pgd_t * (*pgd_offset)(struct mm_struct *, unsigned long); @@ -132,5 +157,5 @@ printk("load_mmu:sparc_cpu_model = %d\n", (int) sparc_cpu_model); printk("load_mmu:Halting...\n"); panic("load_mmu()"); - }; + } } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/s4cflsh.S linux/arch/sparc/mm/s4cflsh.S --- v1.3.92/linux/arch/sparc/mm/s4cflsh.S Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/mm/s4cflsh.S Thu Jan 1 02:00:00 1970 @@ -1,49 +0,0 @@ -/* s4cflsh.S: Low-level segment cache flush routines, shared by - * the kernel and user in-window tlb refill routines. - * - * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu) - */ - -#include "s4clow.h" - -/* %g1 -- base address of segment to flush - * %g4 -- pc of caller - */ - .text - .align 4 - .globl sun4c_segment_cache_flush -sun4c_segment_cache_flush: - std %g0, [REGSAVE_BASE + FLUSHREGS + 0x0] - std %g2, [REGSAVE_BASE + FLUSHREGS + 0x8] - set C_LABEL(sun4c_vacinfo), %g2 - ld [%g2 + VACINFO_HWFLSH], %g3 - cmp %g3, 0x0 - ld [%g2 + VACINFO_SIZE], %g3 - add %g1, %g3, %g3 - be,a sw_flush - ld [%g2 + VACINFO_LSIZE], %g2 - - /* Hardware flush */ - sethi %hi(PAGE_SIZE), %g2 - sta %g0, [%g1] 0x05 -1: - add %g1, %g2, %g1 - cmp %g1, %g3 - blu,a 1b - sta %g0, [%g1] 0x05 - - ldd [REGSAVE_BASE + FLUSHREGS + 0x0], %g0 - jmpl %g4, %g0 - ldd [REGSAVE_BASE + FLUSHREGS + 0x8], %g2 - -sw_flush: - sta %g0, [%g1] 0x0c -2: - add %g1, %g2, %g1 - cmp %g1, %g3 - blu,a 2b - sta %g0, [%g1] 0x0c - - ldd [REGSAVE_BASE + FLUSHREGS + 0x0], %g0 - jmpl %g4, %g0 - ldd [REGSAVE_BASE + FLUSHREGS + 0x8], %g2 diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/s4ckflt.S linux/arch/sparc/mm/s4ckflt.S --- v1.3.92/linux/arch/sparc/mm/s4ckflt.S Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/mm/s4ckflt.S Thu Jan 1 02:00:00 1970 @@ -1,105 +0,0 @@ -/* s4ckflt.S: Quick in window kernel faults on the sun4c. - * - * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu) - */ - -#include "s4clow.h" - - .text - .align 8 - .globl sun4c_quick_kernel_fault -sun4c_quick_kernel_fault: - sethi %hi(REAL_PGDIR_MASK), %l5 - and %l7, %l5, %l7 - sethi %hi(C_LABEL(invalid_segment)), %l5 - lduba [%l7] 0x3, %l4 - ld [%l5 + %lo(C_LABEL(invalid_segment))], %l5 - cmp %l4, %l5 - bne segment_loaded - nop - - /* We need some breathing room to pull this off, save - * away some globals. - */ - std %g0, [REGSAVE_BASE + KFLTREGS + 0x00] - std %g2, [REGSAVE_BASE + KFLTREGS + 0x08] - std %g4, [REGSAVE_BASE + KFLTREGS + 0x10] - std %g6, [REGSAVE_BASE + KFLTREGS + 0x18] - std %l0, [REGSAVE_BASE + KFLTREGS + 0x20] - std %l2, [REGSAVE_BASE + KFLTREGS + 0x28] - - set C_LABEL(sun4c_kfree_ring), %g1 - ld [%g1 + RING_NENTRIES], %g2 - cmp %g2, 0x0 - be,a pseg_steal - nop - - b distribute_segmap - ld [%g1 + RING_RINGHD + MMU_ENTRY_NEXT], %g2 - -pseg_steal: - /* This is the hard case. */ - set C_LABEL(sun4c_kernel_ring), %g1 - ld [%g1 + RING_RINGHD + MMU_ENTRY_PREV], %g2 - b kernel_segment_cache_flush - ld [%g2 + MMU_ENTRY_VADDR], %l0 - -pseg_steal_after_flush: - ld [%g2 + MMU_ENTRY_VADDR], %l0 - sethi %hi(0x30000000), %l1 - lduba [%l1] 0x02, %g7 - sethi %hi(C_LABEL(num_contexts)), %g6 - mov 0, %g5 - ld [%g6 + %lo(C_LABEL(num_contexts))], %g6 -1: - stba %g5, [%l1] 0x02 - add %g5, 1, %g5 - cmp %g5, %g6 - bl 1b - stba %l5, [%l0] 0x03 - - stba %g7, [%l1] 0x02 - - - -distribute_segmap: - st %l7, [%g2 + MMU_ENTRY_VADDR] - ldub [%g2 + MMU_ENTRY_PSEG], %g3 - sethi %hi(0x30000000), %l0 - lduba [%l0] 0x02, %g7 - sethi %hi(C_LABEL(num_contexts)), %g6 - mov 0, %g5 - ld [%g6 + %lo(C_LABEL(num_contexts))], %g6 -1: - stba %g5, [%l0] 0x02 - add %g5, 1, %g5 - cmp %g5, %g6 - bl 1b - stba %g3, [%l7] 0x03 - - stba %g7, [%l0] 0x02 - -segment_loaded: - sethi %hi(VMALLOC_START), %l4 - cmp %l7, %l4 - bge vmalloc_kernel_fault - nop - - - - - -vmalloc_kernel_fault: - - -qkf_exit: - /* Fault serviced, return from trap, but reload - * registers first. - */ - ldd [REGSAVE_BASE + KFLTREGS + 0x00], %g0 - ldd [REGSAVE_BASE + KFLTREGS + 0x08], %g2 - ldd [REGSAVE_BASE + KFLTREGS + 0x10], %g4 - ldd [REGSAVE_BASE + KFLTREGS + 0x18], %g6 - ldd [REGSAVE_BASE + KFLTREGS + 0x20], %l0 - ldd [REGSAVE_BASE + KFLTREGS + 0x28], %l2 - diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/s4clow.h linux/arch/sparc/mm/s4clow.h --- v1.3.92/linux/arch/sparc/mm/s4clow.h Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/mm/s4clow.h Thu Jan 1 02:00:00 1970 @@ -1,48 +0,0 @@ -/* s4clow.h: Defines for in-window low level tlb refill code. - * - * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu) - */ -#ifndef _SPARC_S4CLOW_H -#define _SPARC_S4CLOW_H - -#define PAGE_SIZE 0x00001000 -#define REAL_PGDIR_MASK 0xfffc0000 -#define VMALLOC_START 0xfe100000 - -#define RING_RINGHD 0x00 -#define RING_NENTRIES 0x10 - -#define MMU_ENTRY_NEXT 0x00 -#define MMU_ENTRY_PREV 0x04 -#define MMU_ENTRY_VADDR 0x08 -#define MMU_ENTRY_PSEG 0x0c -#define MMU_ENTRY_LCK 0x0d - -#define VACINFO_SIZE 0x00 -#define VACINFO_HWFLSH 0x08 -#define VACINFO_LSIZE 0x0c - -/* Each of the routines could get called by any of the - * other low level sun4c tlb routines. Well... at least - * we code it that way. Because we are in window we need - * a way to make a routine completely self contained and - * only need to worry about saving it's own set of registers - * which it in fact uses. With traps off this is difficult - * ... however... - * - * The Sparc can address anywhere in the two ranges - * 0 --> PAGE_SIZE and -PAGE_SIZE --> -1 without any - * address calculation registers. So we pull a trick, - * we map a special page for these low level tlb routines - * since they must be as quick as possible. Since the low - * page is the NULL unmapped page and in user space we use - * the high one for simplicity. Kids, do not try this at - * home. - */ -#define REGSAVE_BASE (-PAGE_SIZE) - -#define FLUSHREGS 0 -#define KFLTREGS 256 -#define UFLTREGS 512 - -#endif /* !(_SPARC_S4CLOW_H) */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/s4cuflt.S linux/arch/sparc/mm/s4cuflt.S --- v1.3.92/linux/arch/sparc/mm/s4cuflt.S Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/mm/s4cuflt.S Thu Jan 1 02:00:00 1970 @@ -1,20 +0,0 @@ -/* s4cuflt.S: Quick in window user tlb faults on the sun4c. - * - * Copyright (C) 1995 David S. Miller (davem@caipfs.rutgers.edu) - */ - - .data - - .align 8 -.g0g1: .quad 0 -.g2g3: .quad 0 -.g4g5: .quad 0 -.g6g7: .quad 0 - -#include "srclow.h" - - .text - - .align 8 - .globl sun4c_quick_user_fault -sun4c_quick_user_fault: diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c --- v1.3.92/linux/arch/sparc/mm/srmmu.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/mm/srmmu.c Sun Apr 21 17:32:01 1996 @@ -1,11 +1,14 @@ -/* $Id: srmmu.c,v 1.34 1996/03/01 07:16:23 davem Exp $ +/* $Id: srmmu.c,v 1.59 1996/04/21 10:32:21 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 Peter A. Zaitcev (zaitcev@ithil.mcst.ru) + * Copyright (C) 1996 Eddie C. Dost (ecd@pool.informatik.rwth-aachen.de) */ +#include #include +#include #include #include @@ -13,100 +16,120 @@ #include #include #include -#include +#include #include #include #include #include #include +#include +#include /* Now the cpu specific definitions. */ #include +#include #include #include #include enum mbus_module srmmu_modtype; unsigned int hwbug_bitmask; - int hyper_cache_size; +int hyper_line_size; -ctxd_t *srmmu_context_table; +#ifdef __SMP__ +extern void smp_capture(void); +extern void smp_release(void); +#else +#define smp_capture() +#define smp_release() +#endif /* !(__SMP__) */ + +static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp); +static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep); + +static void (*flush_page_for_dma)(unsigned long page); +static void (*flush_cache_page_to_uncache)(unsigned long page); +static void (*flush_tlb_page_for_cbit)(unsigned long page); +#ifdef __SMP__ +static void (*local_flush_page_for_dma)(unsigned long page); +static void (*local_flush_cache_page_to_uncache)(unsigned long page); +static void (*local_flush_tlb_page_for_cbit)(unsigned long page); +#endif + +static struct srmmu_stats { + int invall; + int invpg; + int invrnge; + int invmm; +} module_stats; -/* In general all page table modifications should use the V8 atomic - * swap instruction. This insures the mmu and the cpu are in sync - * with respect to ref/mod bits in the page tables. - */ -static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value) -{ - __asm__ __volatile__("swap [%1], %0\n\t" : - "=&r" (value), "=&r" (addr) : - "0" (value), "1" (addr)); - return value; -} +static char *srmmu_name; -/* Functions really use this, not srmmu_swap directly. */ -#define srmmu_set_entry(ptr, newentry) \ - srmmu_swap((unsigned long *) (ptr), (newentry)) +ctxd_t *srmmu_ctx_table_phys; +ctxd_t *srmmu_context_table; -/* We still don't use these at all, perhaps we don't need them - * at all. +static struct srmmu_trans { + unsigned long vbase; + unsigned long pbase; + int size; +} srmmu_map[SPARC_PHYS_BANKS]; + +static int can_cache_ptables = 0; +static int viking_mxcc_present = 0; + +/* Physical memory can be _very_ non-contiguous on the sun4m, especially + * the SS10/20 class machines and with the latest openprom revisions. + * So we have to crunch the free page pool. */ -unsigned long (*srmmu_read_physical)(unsigned long paddr); -void (*srmmu_write_physical)(unsigned long paddr, unsigned long word); - -static unsigned long gensrmmu_read_physical(unsigned long paddr) +static inline unsigned long srmmu_v2p(unsigned long vaddr) { - unsigned long word; + int i; - __asm__ __volatile__("lda [%1] %2, %0\n\t" : - "=r" (word) : - "r" (paddr), "i" (ASI_M_BYPASS) : - "memory"); - return word; + for(i=0; srmmu_map[i].size != 0; i++) { + if(srmmu_map[i].vbase <= vaddr && + (srmmu_map[i].vbase + srmmu_map[i].size > vaddr)) + return (vaddr - srmmu_map[i].vbase) + srmmu_map[i].pbase; + } + return 0xffffffffUL; } -static unsigned long msparc_read_physical(unsigned long paddr) +static inline unsigned long srmmu_p2v(unsigned long paddr) { - unsigned long word, flags; + int i; - save_flags(flags); cli(); - __asm__ __volatile__("lda [%%g0] %3, %%g1\n\t" - "or %%g1, %4, %%g2\n\t" - "sta %%g2, [%%g0] %3\n\t" - "lda [%1] %2, %0\n\t" - "sta %%g1, [%%g0] %3\n\t" : - "=r" (word) : - "r" (paddr), "i" (ASI_M_BYPASS), - "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) : - "g1", "g2", "memory"); - restore_flags(flags); - return word; + for(i=0; srmmu_map[i].size != 0; i++) { + if(srmmu_map[i].pbase <= paddr && + (srmmu_map[i].pbase + srmmu_map[i].size > paddr)) + return (paddr - srmmu_map[i].pbase) + srmmu_map[i].vbase; + } + return 0xffffffffUL; } -static void gensrmmu_write_physical(unsigned long paddr, unsigned long word) +/* In general all page table modifications should use the V8 atomic + * swap instruction. This insures the mmu and the cpu are in sync + * with respect to ref/mod bits in the page tables. + */ +static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value) { - __asm__ __volatile__("sta %0, [%1] %2\n\t" : : - "r" (word), "r" (paddr), "i" (ASI_M_BYPASS) : - "memory"); +#if CONFIG_AP1000 + /* the AP1000 has its memory on bus 8, not 0 like suns do */ + if (!(value&0xf0000000)) + value |= 0x80000000; + if (value == 0x80000000) value = 0; +#endif + __asm__ __volatile__("swap [%2], %0\n\t" : + "=&r" (value) : + "0" (value), "r" (addr)); + return value; } -static void msparc_write_physical(unsigned long paddr, unsigned long word) -{ - unsigned long flags; +/* Functions really use this, not srmmu_swap directly. */ +#define srmmu_set_entry(ptr, newentry) \ + srmmu_swap((unsigned long *) (ptr), (newentry)) - save_flags(flags); cli(); - __asm__ __volatile__("lda [%%g0] %3, %%g1\n\t" - "or %%g1, %4, %%g2\n\t" - "sta %%g2, [%%g0] %3\n\t" - "sta %0, [%1] %2\n\t" - "sta %%g1, [%%g0] %3\n\t" : : - "r" (word), "r" (paddr), "i" (ASI_M_BYPASS), - "i" (ASI_M_MMUREGS), "r" (VIKING_ACENABLE) : - "g1", "g2", "memory"); - restore_flags(flags); -} +/* The very generic SRMMU page table operations. */ static unsigned int srmmu_pmd_align(unsigned int addr) { return SRMMU_PMD_ALIGN(addr); } static unsigned int srmmu_pgdir_align(unsigned int addr) { return SRMMU_PGDIR_ALIGN(addr); } @@ -116,27 +139,19 @@ } static unsigned long srmmu_pgd_page(pgd_t pgd) -{ return PAGE_OFFSET + ((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } +{ return srmmu_p2v((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } static unsigned long srmmu_pmd_page(pmd_t pmd) -{ return PAGE_OFFSET + ((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } +{ return srmmu_p2v((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4); } static unsigned long srmmu_pte_page(pte_t pte) -{ return PAGE_OFFSET + ((pte_val(pte) & SRMMU_PTE_PMASK) << 4); } +{ return srmmu_p2v((pte_val(pte) & SRMMU_PTE_PMASK) << 4); } static int srmmu_pte_none(pte_t pte) { return !pte_val(pte); } static int srmmu_pte_present(pte_t pte) { return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); } -static int srmmu_pte_inuse(pte_t *ptep) -{ return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; } - -static void srmmu_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } -static void srmmu_pte_reuse(pte_t *ptep) -{ - if(!mem_map[MAP_NR(ptep)].reserved) - mem_map[MAP_NR(ptep)].count++; -} +static void srmmu_pte_clear(pte_t *ptep) { set_pte(ptep, __pte(0)); } static int srmmu_pmd_none(pmd_t pmd) { return !pmd_val(pmd); } static int srmmu_pmd_bad(pmd_t pmd) @@ -145,15 +160,7 @@ static int srmmu_pmd_present(pmd_t pmd) { return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } -static int srmmu_pmd_inuse(pmd_t *pmdp) -{ return mem_map[MAP_NR(pmdp)].reserved || mem_map[MAP_NR(pmdp)].count != 1; } - -static void srmmu_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } -static void srmmu_pmd_reuse(pmd_t * pmdp) -{ - if (!mem_map[MAP_NR(pmdp)].reserved) - mem_map[MAP_NR(pmdp)].count++; -} +static void srmmu_pmd_clear(pmd_t *pmdp) { set_pte((pte_t *)pmdp, __pte(0)); } static int srmmu_pgd_none(pgd_t pgd) { return !pgd_val(pgd); } static int srmmu_pgd_bad(pgd_t pgd) @@ -162,13 +169,7 @@ static int srmmu_pgd_present(pgd_t pgd) { return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } -static int srmmu_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; } -static void srmmu_pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; } -static void srmmu_pgd_reuse(pgd_t *pgdp) -{ - if (!mem_map[MAP_NR(pgdp)].reserved) - mem_map[MAP_NR(pgdp)].count++; -} +static void srmmu_pgd_clear(pgd_t * pgdp) { set_pte((pte_t *)pgdp, __pte(0)); } static int srmmu_pte_write(pte_t pte) { return pte_val(pte) & SRMMU_WRITE; } static int srmmu_pte_dirty(pte_t pte) { return pte_val(pte) & SRMMU_DIRTY; } @@ -186,19 +187,29 @@ * and a page entry and page directory to the page they refer to. */ static pte_t srmmu_mk_pte(unsigned long page, pgprot_t pgprot) -{ pte_t pte; pte_val(pte) = ((page - PAGE_OFFSET) >> 4) | pgprot_val(pgprot); return pte; } +{ pte_t pte; pte_val(pte) = ((srmmu_v2p(page)) >> 4) | pgprot_val(pgprot); return pte; } -static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot) -{ pte_t pte; pte_val(pte) = ((page) >> 4) | pgprot_val(pgprot); return pte; } +static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) +{ + pte_t pte; + pte_val(pte) = ((page) >> 4) | (space << 28) | pgprot_val(pgprot); + return pte; +} static void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) -{ srmmu_set_entry(ctxp, (SRMMU_ET_PTD | ((((unsigned long) pgdp) - PAGE_OFFSET) >> 4))); } +{ + srmmu_set_entry(ctxp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))); +} static void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) -{ srmmu_set_entry(pgdp, (SRMMU_ET_PTD | ((((unsigned long) pmdp) - PAGE_OFFSET) >> 4))); } +{ + srmmu_set_entry(pgdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pmdp) >> 4))); +} static void srmmu_pmd_set(pmd_t * pmdp, pte_t * ptep) -{ srmmu_set_entry(pmdp, (SRMMU_ET_PTD | ((((unsigned long) ptep) - PAGE_OFFSET) >> 4))); } +{ + srmmu_set_entry(pmdp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) ptep) >> 4))); +} static pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & ~0xff) | pgprot_val(newprot); return pte; } @@ -212,22 +223,70 @@ /* Find an entry in the second-level page table.. */ static pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address) { - return (pmd_t *) pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); + return (pmd_t *) srmmu_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); } /* Find an entry in the third-level page table.. */ static pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) { - return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); + return (pte_t *) srmmu_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); } /* This must update the context table entry for this process. */ static void srmmu_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { if(tsk->mm->context != NO_CONTEXT) - srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); + ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); +} + +static inline void srmmu_uncache_page(unsigned long addr) +{ + pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, addr); + pmd_t *pmdp = srmmu_pmd_offset(pgdp, addr); + pte_t *ptep = srmmu_pte_offset(pmdp, addr); + + flush_cache_page_to_uncache(addr); + set_pte(ptep, __pte((pte_val(*ptep) & ~SRMMU_CACHE))); + flush_tlb_page_for_cbit(addr); +} + +static inline void srmmu_recache_page(unsigned long addr) +{ + pgd_t *pgdp = srmmu_pgd_offset(init_task.mm, addr); + pmd_t *pmdp = srmmu_pmd_offset(pgdp, addr); + pte_t *ptep = srmmu_pte_offset(pmdp, addr); + + set_pte(ptep, __pte((pte_val(*ptep) | SRMMU_CACHE))); + flush_tlb_page_for_cbit(addr); +} + +static inline unsigned long srmmu_getpage(void) +{ + unsigned long page = get_free_page(GFP_KERNEL); + + if (can_cache_ptables) + return page; + + if(page) + srmmu_uncache_page(page); + return page; } +static inline void srmmu_putpage(unsigned long page) +{ + if (!can_cache_ptables) + srmmu_recache_page(page); + free_page(page); +} + +/* The easy versions. */ +#define NEW_PGD() (pgd_t *) srmmu_getpage() +#define NEW_PMD() (pmd_t *) srmmu_getpage() +#define NEW_PTE() (pte_t *) srmmu_getpage() +#define FREE_PGD(chunk) srmmu_putpage((unsigned long)(chunk)) +#define FREE_PMD(chunk) srmmu_putpage((unsigned long)(chunk)) +#define FREE_PTE(chunk) srmmu_putpage((unsigned long)(chunk)) + /* * Allocate and free page tables. The xxx_kernel() versions are * used to allocate a kernel page table - this turns on ASN bits @@ -235,29 +294,27 @@ */ static void srmmu_pte_free_kernel(pte_t *pte) { - mem_map[MAP_NR(pte)].reserved = 0; - free_page((unsigned long) pte); + FREE_PTE(pte); } static pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1); if(srmmu_pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_free_page(GFP_KERNEL); + pte_t *page = NEW_PTE(); if(srmmu_pmd_none(*pmd)) { if(page) { - srmmu_pmd_set(pmd, page); - mem_map[MAP_NR(page)].reserved = 1; + pmd_set(pmd, page); return page + address; } - srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PAGETABLE); return NULL; } - free_page((unsigned long) page); + FREE_PTE(page); } if(srmmu_pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PAGETABLE); return NULL; } return (pte_t *) srmmu_pmd_page(*pmd) + address; @@ -265,29 +322,27 @@ static void srmmu_pmd_free_kernel(pmd_t *pmd) { - mem_map[MAP_NR(pmd)].reserved = 0; - free_page((unsigned long) pmd); + FREE_PMD(pmd); } static pmd_t *srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address) { address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1); if(srmmu_pgd_none(*pgd)) { - pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL); + pmd_t *page = NEW_PMD(); if(srmmu_pgd_none(*pgd)) { if(page) { - srmmu_pgd_set(pgd, page); - mem_map[MAP_NR(page)].reserved = 1; + pgd_set(pgd, page); return page + address; } - srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); return NULL; } - free_page((unsigned long) page); + FREE_PMD(page); } if(srmmu_pgd_bad(*pgd)) { printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); return NULL; } return (pmd_t *) pgd_page(*pgd) + address; @@ -295,56 +350,56 @@ static void srmmu_pte_free(pte_t *pte) { - free_page((unsigned long) pte); + FREE_PTE(pte); } static pte_t *srmmu_pte_alloc(pmd_t * pmd, unsigned long address) { address = (address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1); if(srmmu_pmd_none(*pmd)) { - pte_t *page = (pte_t *) get_free_page(GFP_KERNEL); + pte_t *page = NEW_PTE(); if(srmmu_pmd_none(*pmd)) { if(page) { - srmmu_pmd_set(pmd, page); + pmd_set(pmd, page); return page + address; } - srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PAGETABLE); return NULL; } - free_page((unsigned long) page); + FREE_PTE(page); } if(srmmu_pmd_bad(*pmd)) { printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - srmmu_pmd_set(pmd, (pte_t *) BAD_PAGETABLE); + pmd_set(pmd, BAD_PAGETABLE); return NULL; } - return (pte_t *) pmd_page(*pmd) + address; + return ((pte_t *) srmmu_pmd_page(*pmd)) + address; } /* Real three-level page tables on SRMMU. */ static void srmmu_pmd_free(pmd_t * pmd) { - free_page((unsigned long) pmd); + FREE_PMD(pmd); } static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address) { address = (address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1); if(srmmu_pgd_none(*pgd)) { - pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL); + pmd_t *page = NEW_PMD(); if(srmmu_pgd_none(*pgd)) { if(page) { - srmmu_pgd_set(pgd, page); + pgd_set(pgd, page); return page + address; } - srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); return NULL; } - free_page((unsigned long) page); + FREE_PMD(page); } if(srmmu_pgd_bad(*pgd)) { printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd)); - srmmu_pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); + pgd_set(pgd, (pmd_t *) BAD_PAGETABLE); return NULL; } return (pmd_t *) srmmu_pgd_page(*pgd) + address; @@ -352,395 +407,876 @@ static void srmmu_pgd_free(pgd_t *pgd) { - free_page((unsigned long) pgd); + FREE_PGD(pgd); } static pgd_t *srmmu_pgd_alloc(void) { - return (pgd_t *) get_free_page(GFP_KERNEL); + return NEW_PGD(); } -/* Tsunami invalidates. It's page level tlb invalidation is not very - * useful at all, you must be in the context that page exists in to - * get a match. It might be worthwhile to try someday though... +static void srmmu_set_pte(pte_t *ptep, pte_t pteval) +{ + srmmu_set_entry(ptep, pte_val(pteval)); +} + +static void srmmu_quick_kernel_fault(unsigned long address) +{ + printk("Penguin faults at address %08lx\n", address); + panic("Srmmu bolixed..."); +} + +static inline void alloc_context(struct mm_struct *mm) +{ + struct ctx_list *ctxp; + + ctxp = ctx_free.next; + if(ctxp != &ctx_free) { + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + mm->context = ctxp->ctx_number; + ctxp->ctx_mm = mm; + return; + } + ctxp = ctx_used.next; + if(ctxp->ctx_mm == current->mm) + ctxp = ctxp->next; + if(ctxp == &ctx_used) + panic("out of mmu contexts"); + flush_cache_mm(ctxp->ctx_mm); + flush_tlb_mm(ctxp->ctx_mm); + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + ctxp->ctx_mm->context = NO_CONTEXT; + ctxp->ctx_mm = mm; + mm->context = ctxp->ctx_number; +} + +static void srmmu_switch_to_context(struct task_struct *tsk) +{ + /* Kernel threads can execute in any context and so can tasks + * sleeping in the middle of exiting. If this task has already + * been allocated a piece of the mmu realestate, just jump to + * it. + */ + if((tsk->tss.flags & SPARC_FLAG_KTHREAD) || + (tsk->flags & PF_EXITING)) + return; + if(tsk->mm->context == NO_CONTEXT) { + alloc_context(tsk->mm); + ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); + } + srmmu_set_context(tsk->mm->context); +} + +/* Low level IO area allocation on the SRMMU. */ +void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) +{ + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + unsigned long tmp; + + physaddr &= PAGE_MASK; + pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); + pmdp = srmmu_pmd_offset(pgdp, virt_addr); + ptep = srmmu_pte_offset(pmdp, virt_addr); + tmp = (physaddr >> 4) | SRMMU_ET_PTE; + + /* I need to test whether this is consistant over all + * sun4m's. The bus_type represents the upper 4 bits of + * 36-bit physical address on the I/O space lines... + */ + tmp |= (bus_type << 28); + if(rdonly) + tmp |= SRMMU_PRIV_RDONLY; + else + tmp |= SRMMU_PRIV; + flush_page_to_ram(virt_addr); + srmmu_set_entry(ptep, tmp); + flush_tlb_all(); +} + +static char *srmmu_lockarea(char *vaddr, unsigned long len) +{ + return vaddr; +} + +static void srmmu_unlockarea(char *vaddr, unsigned long len) +{ +} + +/* On the SRMMU we do not have the problems with limited tlb entries + * for mapping kernel pages, so we just take things from the free page + * pool. As a side effect we are putting a little too much pressure + * on the gfp() subsystem. This setup also makes the logic of the + * iommu mapping code a lot easier as we can transparently handle + * mappings on the kernel stack without any special code as we did + * need on the sun4c. */ -/* static */ inline void tsunami_invalidate_all(void) +struct task_struct *srmmu_alloc_task_struct(void) { - tsunami_invalidate_icache(); - tsunami_invalidate_dcache(); - srmmu_flush_whole_tlb(); + unsigned long page; + + page = get_free_page(GFP_KERNEL); + if(!page) + return (struct task_struct *) 0; + return (struct task_struct *) page; } -static void tsunami_invalidate_mm(struct mm_struct *mm) + +unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk) { - tsunami_invalidate_all(); + unsigned long pages; + + pages = __get_free_pages(GFP_KERNEL, 2, 0); + if(!pages) + return 0; + memset((void *) pages, 0, (PAGE_SIZE << 2)); + return pages; } -static void tsunami_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void srmmu_free_task_struct(struct task_struct *tsk) { - tsunami_invalidate_all(); + free_page((unsigned long) tsk); } -/* XXX do page level tlb flushes at some point XXX */ -static void tsunami_invalidate_page(struct vm_area_struct *vmp, unsigned long page) +static void srmmu_free_kernel_stack(unsigned long stack) { - tsunami_invalidate_all(); + free_pages(stack, 2); } -/* Swift invalidates. It has the recommended SRMMU specification flushing - * facilities, so we can do things in a more fine grained fashion than we - * could on the tsunami. Let's watch out for HARDWARE BUGS... +/* Tsunami flushes. It's page level tlb invalidation is not very + * useful at all, you must be in the context that page exists in to + * get a match. */ -static inline void swift_invalidate_all(void) +static void tsunami_flush_cache_all(void) { - unsigned long addr = 0; + flush_user_windows(); + tsunami_flush_icache(); + tsunami_flush_dcache(); +} - /* Invalidate all cache tags */ - for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) { - swift_inv_insn_tag(addr); /* whiz- */ - swift_inv_data_tag(addr); /* bang */ +static void tsunami_flush_cache_mm(struct mm_struct *mm) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + tsunami_flush_icache(); + tsunami_flush_dcache(); +#ifndef __SMP__ } +#endif +} + +static void tsunami_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + tsunami_flush_icache(); + tsunami_flush_dcache(); +#ifndef __SMP__ + } +#endif +} + +static void tsunami_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ +#ifndef __SMP__ + struct mm_struct *mm = vma->vm_mm; + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + tsunami_flush_icache(); + tsunami_flush_dcache(); +#ifndef __SMP__ + } +#endif +} + +static void tsunami_flush_cache_page_to_uncache(unsigned long page) +{ + tsunami_flush_dcache(); +} + +/* Tsunami does not have a Copy-back style virtual cache. */ +static void tsunami_flush_page_to_ram(unsigned long page) +{ +} + +/* However, Tsunami is not IO coherent. */ +static void tsunami_flush_page_for_dma(unsigned long page) +{ + tsunami_flush_dcache(); +} + +/* TLB flushes seem to upset the tsunami sometimes, I can't figure out + * what the hell is going on. All I see is a tlb flush (page or whole, + * there is no consistant pattern) and then total local variable corruption + * in the procedure who called us after return. Usually triggerable + * by "cool" programs like crashme and bonnie. I played around a bit + * and adding a bunch of forced nops seems to make the problems all + * go away. (missed instruction fetches possibly? ugh...) + */ +#define TSUNAMI_SUCKS do { nop(); nop(); nop(); nop(); nop(); \ + nop(); nop(); nop(); nop(); nop(); } while(0) + +static void tsunami_flush_tlb_all(void) +{ + module_stats.invall++; srmmu_flush_whole_tlb(); + TSUNAMI_SUCKS; } -static void swift_invalidate_mm(struct mm_struct *mm) +static void tsunami_flush_tlb_mm(struct mm_struct *mm) { - unsigned long flags; - int cc, ncc = mm->context; + module_stats.invmm++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + srmmu_flush_whole_tlb(); + TSUNAMI_SUCKS; +#ifndef __SMP__ + } +#endif +} - if(ncc == NO_CONTEXT) - return; +static void tsunami_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + module_stats.invrnge++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + srmmu_flush_whole_tlb(); + TSUNAMI_SUCKS; +#ifndef __SMP__ + } +#endif +} - /* have context will travel... */ - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + int octx; + struct mm_struct *mm = vma->vm_mm; - swift_flush_context(); /* POOF! */ - srmmu_flush_tlb_ctx(); /* POW! */ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); + srmmu_set_context(mm->context); + srmmu_flush_tlb_page(page); + TSUNAMI_SUCKS; + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif + module_stats.invpg++; } -static void swift_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void tsunami_flush_tlb_page_for_cbit(unsigned long page) { - unsigned long flags, addr; - int cc, ncc = mm->context; + srmmu_flush_tlb_page(page); +} - if(ncc == NO_CONTEXT) - return; +/* Swift flushes. It has the recommended SRMMU specification flushing + * facilities, so we can do things in a more fine grained fashion than we + * could on the tsunami. Let's watch out for HARDWARE BUGS... + */ + +static void swift_flush_cache_all(void) +{ + flush_user_windows(); + swift_idflash_clear(); +} + +static void swift_flush_cache_mm(struct mm_struct *mm) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + swift_idflash_clear(); +#ifndef __SMP__ + } +#endif +} - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void swift_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + swift_idflash_clear(); +#ifndef __SMP__ + } +#endif +} - /* XXX Inefficient, we don't do the best we can... XXX */ - addr = start & SRMMU_PGDIR_MASK; - while(addr < end) { - swift_flush_region(addr); - srmmu_flush_tlb_region(addr); - addr += SRMMU_PGDIR_SIZE; +static void swift_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ +#ifndef __SMP__ + struct mm_struct *mm = vma->vm_mm; + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + if(vma->vm_flags & VM_EXEC) + swift_flush_icache(); + swift_flush_dcache(); +#ifndef __SMP__ } +#endif +} - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); +/* Not copy-back on swift. */ +static void swift_flush_page_to_ram(unsigned long page) +{ } -static void swift_invalidate_page(struct vm_area_struct *vmp, unsigned long page) +/* But not IO coherent either. */ +static void swift_flush_page_for_dma(unsigned long page) { - unsigned long flags; - int cc, ncc = vmp->vm_mm->context; + swift_flush_dcache(); +} - if(ncc == NO_CONTEXT) - return; +static void swift_flush_cache_page_to_uncache(unsigned long page) +{ + swift_flush_dcache(); +} - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void swift_flush_tlb_all(void) +{ + module_stats.invall++; + srmmu_flush_whole_tlb(); +} - swift_flush_page(page); - srmmu_flush_tlb_page(page); +static void swift_flush_tlb_mm(struct mm_struct *mm) +{ + module_stats.invmm++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) +#endif + srmmu_flush_whole_tlb(); +} + +static void swift_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + module_stats.invrnge++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) +#endif + srmmu_flush_whole_tlb(); +} + +static void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ +#ifndef __SMP__ + struct mm_struct *mm = vma->vm_mm; + if(mm->context != NO_CONTEXT) +#endif + srmmu_flush_whole_tlb(); + module_stats.invpg++; +} - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); +static void swift_flush_tlb_page_for_cbit(unsigned long page) +{ + srmmu_flush_whole_tlb(); } /* The following are all MBUS based SRMMU modules, and therefore could - * be found in a multiprocessor configuration. + * be found in a multiprocessor configuration. On the whole, these + * chips seems to be much more touchy about DVMA and page tables + * with respect to cache coherency. */ -/* Viking invalidates. For Sun's mainline MBUS processor it is pretty much +/* Viking flushes. For Sun's mainline MBUS processor it is pretty much * a crappy mmu. The on-chip I&D caches only have full flushes, no fine * grained cache invalidations. It only has these "flash clear" things * just like the MicroSparcI. Added to this many revs of the chip are - * teaming with hardware buggery. - * - * XXX need to handle SMP broadcast invalidations! XXX + * teaming with hardware buggery. Someday maybe we'll do direct + * diagnostic tag accesses for page level flushes as those should + * be painless and will increase performance due to the frequency of + * page level flushes. This is a must to _really_ flush the caches, + * crazy hardware ;-) */ -static inline void viking_invalidate_all(void) + +static void viking_flush_cache_all(void) { viking_flush_icache(); - viking_flush_dcache(); - srmmu_flush_whole_tlb(); } -static void viking_invalidate_mm(struct mm_struct *mm) + +static void viking_flush_cache_mm(struct mm_struct *mm) { - unsigned long flags; - int cc, ncc = mm->context; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + viking_flush_icache(); +#ifndef __SMP__ + } +#endif +} - if(ncc == NO_CONTEXT) - return; +static void viking_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + viking_flush_icache(); +#ifndef __SMP__ + } +#endif +} - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void viking_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ +#ifndef __SMP__ + struct mm_struct *mm = vma->vm_mm; + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + if(vma->vm_flags & VM_EXEC) + viking_flush_icache(); +#ifndef __SMP__ + } +#endif +} - viking_flush_icache(); - viking_flush_dcache(); - srmmu_flush_tlb_ctx(); +/* Non-mxcc vikings are copy-back but are pure-physical so no flushing. */ +static void viking_flush_page_to_ram(unsigned long page) +{ +} - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); +/* Viking is IO cache coherent. */ +static void viking_flush_page_for_dma(unsigned long page) +{ } -static void viking_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void viking_mxcc_flush_page(unsigned long page) { - unsigned long flags, addr; - int cc, ncc = mm->context; + unsigned long ppage = srmmu_hwprobe(page); + unsigned long paddr0, paddr1; - if(ncc == NO_CONTEXT) + if (!ppage) return; - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); - - /* XXX Inefficient, we don't do the best we can... XXX */ - viking_flush_icache(); - viking_flush_dcache(); - addr = start & SRMMU_PGDIR_MASK; - while(addr < end) { - srmmu_flush_tlb_region(addr); - addr += SRMMU_PGDIR_SIZE; - } + paddr0 = (ppage >> 28) | 0x10; /* Set cacheable bit. */ + paddr1 = (ppage << 4) & PAGE_MASK; - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); + /* Read the page's data through the stream registers, + * and write it back to memory. This will issue + * coherent write invalidates to all other caches, thus + * should also be sufficient in an MP system. + */ + __asm__ __volatile__ ("or %%g0, %0, %%g2\n\t" + "or %%g0, %1, %%g3\n" + "1:\n\t" + "stda %%g2, [%2] %5\n\t" + "stda %%g2, [%3] %5\n\t" + "add %%g3, %4, %%g3\n\t" + "btst 0xfff, %%g3\n\t" + "bne 1b\n\t" + "nop\n\t" : : + "r" (paddr0), "r" (paddr1), + "r" (MXCC_SRCSTREAM), + "r" (MXCC_DESSTREAM), + "r" (MXCC_STREAM_SIZE), + "i" (ASI_M_MXCC) : "g2", "g3"); + + /* This was handcoded after a look at the gcc output from + * + * do { + * mxcc_set_stream_src(paddr); + * mxcc_set_stream_dst(paddr); + * paddr[1] += MXCC_STREAM_SIZE; + * } while (paddr[1] & ~PAGE_MASK); + */ } -static void viking_invalidate_page(struct vm_area_struct *vmp, unsigned long page) + +static void viking_no_mxcc_flush_page(unsigned long page) { - unsigned long flags; - int cc, ncc = vmp->vm_mm->context; + unsigned long ppage = srmmu_hwprobe(page) >> 8; + int set, block; + unsigned long ptag[2]; + unsigned long vaddr; + int i; - if(ncc == NO_CONTEXT) + if (!ppage) return; - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); + for (set = 0; set < 128; set++) { + for (block = 0; block < 4; block++) { - viking_flush_icache(); - viking_flush_dcache(); - srmmu_flush_tlb_page(page); + viking_get_dcache_ptag(set, block, ptag); + + if (ptag[1] != ppage) + continue; + if (!(ptag[0] & VIKING_PTAG_VALID)) + continue; + if (!(ptag[0] & VIKING_PTAG_DIRTY)) + continue; + + /* There was a great cache from TI + * with comfort as much as vi, + * 4 pages to flush, + * 4 pages, no rush, + * since anything else makes him die. + */ + vaddr = (KERNBASE + PAGE_SIZE) | (set << 5); + for (i = 0; i < 8; i++) { + __asm__ __volatile__ ("ld [%0], %%g2\n\t" : : + "r" (vaddr) : "g2"); + vaddr += PAGE_SIZE; + } - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); + /* Continue with next set. */ + break; + } + } } -/* Cypress invalidates. */ -static inline void cypress_invalidate_all(void) +static void viking_flush_tlb_all(void) { + module_stats.invall++; srmmu_flush_whole_tlb(); } -static void cypress_invalidate_mm(struct mm_struct *mm) + +static void viking_flush_tlb_mm(struct mm_struct *mm) { - unsigned long flags; - int cc, ncc = mm->context; + int octx; + module_stats.invmm++; - if(ncc == NO_CONTEXT) - return; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_ctx(); + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif +} - /* have context will travel... */ - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + int octx; + module_stats.invrnge++; - cypress_flush_context(); /* POOF! */ - srmmu_flush_whole_tlb(); /* POW! */ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + start &= SRMMU_PMD_MASK; + while(start < end) { + srmmu_flush_tlb_segment(start); + start += SRMMU_PMD_SIZE; + } + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif +} + +static void viking_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + int octx; + struct mm_struct *mm = vma->vm_mm; - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); + module_stats.invpg++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_page(page); + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif } -static void cypress_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) + +static void viking_flush_tlb_page_for_cbit(unsigned long page) { - unsigned long flags, addr; - int cc, ncc = mm->context; + srmmu_flush_tlb_page(page); +} - if(ncc == NO_CONTEXT) - return; +/* Cypress flushes. */ - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); - - /* XXX Inefficient, we don't do the best we can... XXX */ - addr = start & SRMMU_PGDIR_MASK; - while(addr < end) { - cypress_flush_region(addr); - addr += SRMMU_PGDIR_SIZE; - } +static void cypress_flush_tlb_all(void) +{ + module_stats.invall++; srmmu_flush_whole_tlb(); +} - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); +static void cypress_flush_tlb_mm(struct mm_struct *mm) +{ + int octx; + + module_stats.invmm++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_ctx(); + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif } -static void cypress_invalidate_page(struct vm_area_struct *vmp, unsigned long page) +static void cypress_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - unsigned long flags; - int cc, ncc = vmp->vm_mm->context; + int octx; - if(ncc == NO_CONTEXT) - return; + module_stats.invrnge++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + start &= SRMMU_PMD_MASK; + while(start < end) { + srmmu_flush_tlb_segment(start); + start += SRMMU_PMD_SIZE; + } + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif +} - save_flags(flags); cli(); - cc = srmmu_get_context(); - if(cc != ncc) - srmmu_set_context(ncc); +static void cypress_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + int octx; + struct mm_struct *mm = vma->vm_mm; - swift_flush_page(page); - srmmu_flush_whole_tlb(); + module_stats.invpg++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_page(page); + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif +} - if(cc != ncc) - srmmu_set_context(cc); - restore_flags(flags); +/* Hypersparc flushes. Very nice chip... */ +static void hypersparc_flush_cache_all(void) +{ + flush_user_windows(); + hyper_flush_unconditional_combined(); + hyper_flush_whole_icache(); } -/* Hypersparc invalidates. */ -static inline void hypersparc_invalidate_all(void) +static void hypersparc_flush_cache_mm(struct mm_struct *mm) { +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + hyper_flush_unconditional_combined(); + hyper_flush_whole_icache(); +#ifndef __SMP__ + } +#endif +} - hyper_flush_whole_icache(); - srmmu_flush_whole_tlb(); +static void hypersparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + flush_user_windows(); + hyper_flush_unconditional_combined(); + hyper_flush_whole_icache(); +#ifndef __SMP__ + } +#endif } -static void hypersparc_invalidate_mm(struct mm_struct *mm) +/* HyperSparc requires a valid mapping where we are about to flush + * in order to check for a physical tag match during the flush. + */ +static void hypersparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page) { + struct mm_struct *mm = vma->vm_mm; + volatile unsigned long clear; + int octx; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = srmmu_get_context(); + flush_user_windows(); + srmmu_set_context(mm->context); + hyper_flush_whole_icache(); + if(!srmmu_hwprobe(page)) + goto no_mapping; + hyper_flush_cache_page(page); + no_mapping: + clear = srmmu_get_fstatus(); + srmmu_set_context(octx); +#ifndef __SMP__ + } +#endif } -static void hypersparc_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +/* HyperSparc is copy-back. */ +static void hypersparc_flush_page_to_ram(unsigned long page) { + volatile unsigned long clear; + if(srmmu_hwprobe(page)) + hyper_flush_cache_page(page); + clear = srmmu_get_fstatus(); } -static void hypersparc_invalidate_page(struct vm_area_struct *vmp, unsigned long page) +/* HyperSparc is IO cache coherent. */ +static void hypersparc_flush_page_for_dma(unsigned long page) { + volatile unsigned long clear; + if(srmmu_hwprobe(page)) + hyper_flush_cache_page(page); + clear = srmmu_get_fstatus(); } -static void srmmu_set_pte(pte_t *ptep, pte_t pteval) +static void hypersparc_flush_cache_page_to_uncache(unsigned long page) { - srmmu_set_entry(ptep, pte_val(pteval)); + volatile unsigned long clear; + + if(srmmu_hwprobe(page)) + hyper_flush_cache_page(page); + clear = srmmu_get_fstatus(); } -static void srmmu_quick_kernel_fault(unsigned long address) +static void hypersparc_flush_tlb_all(void) { - printk("SRMMU: quick_kernel_fault called for %08lx\n", address); - panic("Srmmu bolixed..."); + module_stats.invall++; + srmmu_flush_whole_tlb(); } -static inline void alloc_context(struct mm_struct *mm) +static void hypersparc_flush_tlb_mm(struct mm_struct *mm) { - struct ctx_list *ctxp; + int octx; - ctxp = ctx_free.next; - if(ctxp != &ctx_free) { - remove_from_ctx_list(ctxp); - add_to_used_ctxlist(ctxp); - mm->context = ctxp->ctx_number; - ctxp->ctx_mm = mm; - return; + module_stats.invmm++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_ctx(); + srmmu_set_context(octx); + +#ifndef __SMP__ } - ctxp = ctx_used.next; - if(ctxp->ctx_mm == current->mm) - ctxp = ctxp->next; - if(ctxp == &ctx_used) - panic("out of mmu contexts"); - remove_from_ctx_list(ctxp); - add_to_used_ctxlist(ctxp); - ctxp->ctx_mm->context = NO_CONTEXT; - ctxp->ctx_mm = mm; - mm->context = ctxp->ctx_number; +#endif } -static void srmmu_switch_to_context(struct task_struct *tsk) +static void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - /* Kernel threads can execute in any context and so can tasks - * sleeping in the middle of exiting. If this task has already - * been allocated a piece of the mmu realestate, just jump to - * it. - */ - if((tsk->tss.flags & SPARC_FLAG_KTHREAD) || - (tsk->flags & PF_EXITING)) - return; - if(tsk->mm->context == NO_CONTEXT) { - alloc_context(tsk->mm); - srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); + int octx; + + module_stats.invrnge++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + start &= SRMMU_PMD_MASK; + while(start < end) { + srmmu_flush_tlb_segment(start); + start += SRMMU_PMD_SIZE; + } + srmmu_set_context(octx); + +#ifndef __SMP__ } - srmmu_set_context(tsk->mm->context); +#endif } -/* Low level IO area allocation on the SRMMU. */ -void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) +static void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - unsigned long tmp; + struct mm_struct *mm = vma->vm_mm; + int octx; - physaddr &= PAGE_MASK; - pgdp = srmmu_pgd_offset(init_task.mm, virt_addr); - pmdp = srmmu_pmd_offset(pgdp, virt_addr); - ptep = srmmu_pte_offset(pmdp, virt_addr); - tmp = (physaddr >> 4) | SRMMU_ET_PTE; + module_stats.invpg++; +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif - /* I need to test whether this is consistent over all - * sun4m's. The bus_type represents the upper 4 bits of - * 36-bit physical address on the I/O space lines... - */ - tmp |= (bus_type << 28); - if(rdonly) - tmp |= SRMMU_PRIV_RDONLY; - else - tmp |= SRMMU_PRIV; - srmmu_set_entry(ptep, tmp); - invalidate_all(); + octx = srmmu_get_context(); + srmmu_set_context(mm->context); + srmmu_flush_tlb_page(page); + srmmu_set_context(octx); + +#ifndef __SMP__ + } +#endif } -static char *srmmu_lockarea(char *vaddr, unsigned long len) +static void hypersparc_flush_tlb_page_for_cbit(unsigned long page) { - return vaddr; + srmmu_flush_tlb_page(page); } -static void srmmu_unlockarea(char *vaddr, unsigned long len) +static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) +{ + hyper_flush_whole_icache(); + srmmu_set_entry(ctxp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4))); +} + +static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) { + if(tsk->mm->context != NO_CONTEXT) { + hyper_flush_whole_icache(); + ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp); + } +} + +static void hypersparc_set_pte(pte_t *ptep, pte_t pteval) +{ + /* xor is your friend */ + __asm__ __volatile__("rd %%psr, %%g1\n\t" + "wr %%g1, %4, %%psr\n\t" + "nop; nop; nop;\n\t" + "swap [%0], %1\n\t" + "wr %%g1, 0x0, %%psr\n\t" + "nop; nop; nop;\n\t" : + "=r" (ptep), "=r" (pteval) : + "0" (ptep), "1" (pteval), "i" (PSR_ET) : + "g1"); +} + +static void hypersparc_switch_to_context(struct task_struct *tsk) +{ + /* Kernel threads can execute in any context and so can tasks + * sleeping in the middle of exiting. If this task has already + * been allocated a piece of the mmu realestate, just jump to + * it. + */ + hyper_flush_whole_icache(); + if((tsk->tss.flags & SPARC_FLAG_KTHREAD) || + (tsk->flags & PF_EXITING)) + return; + if(tsk->mm->context == NO_CONTEXT) { + alloc_context(tsk->mm); + ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd); + } + srmmu_set_context(tsk->mm->context); } /* IOMMU things go here. */ @@ -748,6 +1284,9 @@ #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) static unsigned long first_dvma_page, last_dvma_page; +#define IOPERM (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID) +#define MKIOPTE(phys) (((((phys)>>4) & IOPTE_PAGE) | IOPERM) & ~IOPTE_WAZ) + static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu) { unsigned long first = first_dvma_page; @@ -757,8 +1296,7 @@ iopte = iommu->page_table; iopte += ((DVMA_VADDR - iommu->start) >> PAGE_SHIFT); while(first <= last) { - iopte_val(*iopte++) = ((((first - PAGE_OFFSET) >> 4) & IOPTE_PAGE) | - (IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ); + iopte_val(*iopte++) = MKIOPTE(srmmu_v2p(first)); first += PAGE_SIZE; } } @@ -803,7 +1341,7 @@ tmp |= (IOMMU_RNGE_64MB | IOMMU_CTRL_ENAB); iommu->regs->control = tmp; iommu_invalidate(iommu->regs); - iommu->start = 0xfc000000; + iommu->plow = iommu->start = 0xfc000000; iommu->end = 0xffffffff; /* Allocate IOMMU page table */ @@ -813,16 +1351,17 @@ /* Stupid alignment constraints give me a headache. */ memory_start = PAGE_ALIGN(memory_start); memory_start = (((memory_start) + (ptsize - 1)) & ~(ptsize - 1)); - iommu->page_table = (iopte_t *) memory_start; + iommu->lowest = iommu->page_table = (iopte_t *) memory_start; memory_start += ptsize; /* Initialize new table. */ + flush_cache_all(); + srmmu_uncache_iommu_page_table((unsigned long) iommu->page_table, ptsize); + flush_tlb_all(); memset(iommu->page_table, 0, ptsize); srmmu_map_dvma_pages_for_iommu(iommu); - iommu->regs->base = (((unsigned long) iommu->page_table) - PAGE_OFFSET) >> 4; - srmmu_uncache_iommu_page_table((unsigned long) iommu->page_table, ptsize); + iommu->regs->base = srmmu_v2p((unsigned long) iommu->page_table) >> 4; iommu_invalidate(iommu->regs); - invalidate_all(); sbus->iommu = iommu; printk("IOMMU: impl %d vers %d page table at %p of size %d bytes\n", @@ -830,41 +1369,68 @@ return memory_start; } - -static char *srmmu_get_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static char *srmmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) { struct iommu_struct *iommu = sbus->iommu; unsigned long page = (unsigned long) vaddr; unsigned long start, end, offset; iopte_t *iopte; - if(len > PAGE_SIZE) - panic("Can only handle page sized iommu mappings."); offset = page & ~PAGE_MASK; page &= PAGE_MASK; - start = iommu->start; + start = iommu->plow; end = KADB_DEBUGGER_BEGVM; /* Don't step on kadb/prom. */ - iopte = iommu->page_table; + iopte = iommu->lowest; while(start < end) { if(!(iopte_val(*iopte) & IOPTE_VALID)) break; iopte++; start += PAGE_SIZE; } - if(start == KADB_DEBUGGER_BEGVM) - panic("Could not find free iommu entry in get_scsi_buffer."); + flush_page_for_dma(page); vaddr = (char *) (start | offset); - iopte_val(*iopte) = ((((page - PAGE_OFFSET) >> 4) & IOPTE_PAGE) | - (IOPTE_WRITE | IOPTE_VALID)) & ~(IOPTE_WAZ); - iommu_invalidate(iommu->regs); - invalidate_all(); + iopte_val(*iopte) = MKIOPTE(srmmu_v2p(page)); + iommu_invalidate_page(iommu->regs, start); + iommu->lowest = iopte + 1; + iommu->plow = start + PAGE_SIZE; return vaddr; } -static void srmmu_release_scsi_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus) +static void srmmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + struct iommu_struct *iommu = sbus->iommu; + unsigned long page, start, end, offset; + iopte_t *iopte = iommu->lowest; + + start = iommu->plow; + end = KADB_DEBUGGER_BEGVM; + while(sz >= 0) { + page = ((unsigned long) sg[sz].addr) & PAGE_MASK; + offset = ((unsigned long) sg[sz].addr) & ~PAGE_MASK; + while(start < end) { + if(!(iopte_val(*iopte) & IOPTE_VALID)) + break; + iopte++; + start += PAGE_SIZE; + } + if(start == KADB_DEBUGGER_BEGVM) + panic("Wheee, iomapping overflow."); + flush_page_for_dma(page); + sg[sz].alt_addr = (char *) (start | offset); + iopte_val(*iopte) = MKIOPTE(srmmu_v2p(page)); + iommu_invalidate_page(iommu->regs, start); + iopte++; + start += PAGE_SIZE; + sz--; + } + iommu->lowest = iopte; + iommu->plow = start; +} + +static void srmmu_release_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) { struct iommu_struct *iommu = sbus->iommu; unsigned long page = (unsigned long) vaddr; @@ -875,61 +1441,89 @@ page &= PAGE_MASK; iopte = iommu->page_table + ((page - iommu->start) >> PAGE_SHIFT); iopte_val(*iopte) = 0; - iommu_invalidate(iommu->regs); - invalidate_all(); + iommu_invalidate_page(iommu->regs, page); + if(iopte < iommu->lowest) { + iommu->lowest = iopte; + iommu->plow = page; + } } -/* On the SRMMU we do not have the problems with limited tlb entries - * for mapping kernel pages, so we just take things from the free page - * pool. As a side effect we are putting a little too much pressure - * on the gfp() subsystem and we don't catch stack overflow like we - * did on the sun4c with virtual kstack mappings. This setup also - * makes the logic of the iommu mapping code a lot easier as we can - * transparently handle mappings on the kernel stack without any - * special code as we did need on the sun4c. - */ -struct task_struct *srmmu_alloc_task_struct(void) +static void srmmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { + struct iommu_struct *iommu = sbus->iommu; unsigned long page; + iopte_t *iopte; - page = get_free_page(GFP_KERNEL); - if(!page) - return (struct task_struct *) 0; - return (struct task_struct *) page; + while(sz >= 0) { + page = ((unsigned long)sg[sz].alt_addr) & PAGE_MASK; + iopte = iommu->page_table + ((page - iommu->start) >> PAGE_SHIFT); + iopte_val(*iopte) = 0; + iommu_invalidate_page(iommu->regs, page); + if(iopte < iommu->lowest) { + iommu->lowest = iopte; + iommu->plow = page; + } + sg[sz].alt_addr = 0; + sz--; + } } -unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk) +static unsigned long mempool; + +/* NOTE: All of this startup code assumes the low 16mb (approx.) of + * kernel mappings are done with one single contiguous chunk of + * ram. On small ram machines (classics mainly) we only get + * around 8mb mapped for us. + */ + +static unsigned long kbpage; + +/* Some dirty hacks to abstract away the painful boot up init. */ +static inline unsigned long srmmu_early_paddr(unsigned long vaddr) { - unsigned long pages; + return ((vaddr - PAGE_OFFSET) + kbpage); +} - pages = __get_free_pages(GFP_KERNEL, 1, 0); - if(!pages) - return 0; - memset((void *) pages, 0, (PAGE_SIZE << 1)); - return pages; +static inline void srmmu_early_pgd_set(pgd_t *pgdp, pmd_t *pmdp) +{ + srmmu_set_entry(pgdp, (SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) pmdp) >> 4))); } -static void srmmu_free_task_struct(struct task_struct *tsk) +static inline void srmmu_early_pmd_set(pmd_t *pmdp, pte_t *ptep) { - free_page((unsigned long) tsk); + srmmu_set_entry(pmdp, (SRMMU_ET_PTD | (srmmu_early_paddr((unsigned long) ptep) >> 4))); } -static void srmmu_free_kernel_stack(unsigned long stack) +static inline unsigned long srmmu_early_pgd_page(pgd_t pgd) { - free_pages(stack, 1); + return (((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4) - kbpage) + PAGE_OFFSET; } -static unsigned long mempool; +static inline unsigned long srmmu_early_pmd_page(pmd_t pmd) +{ + return (((pmd_val(pmd) & SRMMU_PTD_PMASK) << 4) - kbpage) + PAGE_OFFSET; +} + +static inline pmd_t *srmmu_early_pmd_offset(pgd_t *dir, unsigned long address) +{ + return (pmd_t *) srmmu_early_pgd_page(*dir) + ((address >> SRMMU_PMD_SHIFT) & (SRMMU_PTRS_PER_PMD - 1)); +} + +static inline pte_t *srmmu_early_pte_offset(pmd_t *dir, unsigned long address) +{ + return (pte_t *) srmmu_early_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SRMMU_PTRS_PER_PTE - 1)); +} /* Allocate a block of RAM which is aligned to its size. * This procedure can be used until the call to mem_init(). */ -static void *srmmu_init_alloc(unsigned long *kbrk, unsigned size) +static void *srmmu_init_alloc(unsigned long *kbrk, unsigned long size) { - register unsigned mask = size - 1; - register unsigned long ret; + unsigned long mask = size - 1; + unsigned long ret; - if(size==0) return 0x0; + if(!size) + return 0x0; if(size & mask) { prom_printf("panic: srmmu_init_alloc botch\n"); prom_halt(); @@ -950,12 +1544,12 @@ pgdp = srmmu_pgd_offset(init_task.mm, start); if(srmmu_pgd_none(*pgdp)) { pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); - srmmu_pgd_set(pgdp, pmdp); + srmmu_early_pgd_set(pgdp, pmdp); } - pmdp = srmmu_pmd_offset(pgdp, start); + pmdp = srmmu_early_pmd_offset(pgdp, start); if(srmmu_pmd_none(*pmdp)) { ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); - srmmu_pmd_set(pmdp, ptep); + srmmu_early_pmd_set(pmdp, ptep); } start = (start + SRMMU_PMD_SIZE) & SRMMU_PMD_MASK; } @@ -965,34 +1559,60 @@ * looking at the prom's page table directly which is what most * other OS's do. Yuck... this is much better. */ -static inline void srmmu_inherit_prom_mappings(void) +void srmmu_inherit_prom_mappings(unsigned long start,unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - unsigned long start, end; + int what = 0; /* 0 = normal-pte, 1 = pmd-level pte, 2 = pgd-level pte */ unsigned long prompte; - start = KADB_DEBUGGER_BEGVM; - end = LINUX_OPPROM_ENDVM; - while(start < end) { - /* Something going wrong here on some ss5's... */ - prompte = srmmu_hwprobe(start); - - if((prompte & SRMMU_ET_MASK) == SRMMU_ET_PTE) { - pgdp = srmmu_pgd_offset(init_task.mm, start); - if(srmmu_pgd_none(*pgdp)) { - pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); - srmmu_pgd_set(pgdp, pmdp); - } - pmdp = srmmu_pmd_offset(pgdp, start); - if(srmmu_pmd_none(*pmdp)) { - ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); - srmmu_pmd_set(pmdp, ptep); - } - ptep = srmmu_pte_offset(pmdp, start); - pte_val(*ptep) = prompte; + while(start <= end) { + if (start == 0) + break; /* probably wrap around */ + if(start == 0xfef00000) + start = KADB_DEBUGGER_BEGVM; + if(!(prompte = srmmu_hwprobe(start))) { + start += PAGE_SIZE; + continue; + } + + /* A red snapper, see what it really is. */ + what = 0; + + if(!(start & ~(SRMMU_PMD_MASK))) { + if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_PMD_SIZE) == prompte) + what = 1; + } + + if(!(start & ~(SRMMU_PGDIR_MASK))) { + if(srmmu_hwprobe((start-PAGE_SIZE) + SRMMU_PGDIR_SIZE) == + prompte) + what = 2; + } + + pgdp = srmmu_pgd_offset(init_task.mm, start); + if(what == 2) { + pgd_val(*pgdp) = prompte; + start += SRMMU_PGDIR_SIZE; + continue; + } + if(srmmu_pgd_none(*pgdp)) { + pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); + srmmu_early_pgd_set(pgdp, pmdp); + } + pmdp = srmmu_early_pmd_offset(pgdp, start); + if(what == 1) { + pmd_val(*pmdp) = prompte; + start += SRMMU_PMD_SIZE; + continue; } + if(srmmu_pmd_none(*pmdp)) { + ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); + srmmu_early_pmd_set(pmdp, ptep); + } + ptep = srmmu_early_pte_offset(pmdp, start); + pte_val(*ptep) = prompte; start += PAGE_SIZE; } } @@ -1006,53 +1626,204 @@ pte_t *ptep; start = DVMA_VADDR; - dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); + if (viking_mxcc_present) + dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); + else + dvma_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV); while(first <= last) { pgdp = srmmu_pgd_offset(init_task.mm, start); pmdp = srmmu_pmd_offset(pgdp, start); ptep = srmmu_pte_offset(pmdp, start); - /* Map with cacheable bit clear. */ srmmu_set_entry(ptep, pte_val(srmmu_mk_pte(first, dvma_prot))); first += PAGE_SIZE; start += PAGE_SIZE; } + + /* Uncache DVMA pages. */ + if (!viking_mxcc_present) { + first = first_dvma_page; + last = last_dvma_page; + while(first <= last) { + pgdp = srmmu_pgd_offset(init_task.mm, first); + pmdp = srmmu_pmd_offset(pgdp, first); + ptep = srmmu_pte_offset(pmdp, first); + pte_val(*ptep) &= ~SRMMU_CACHE; + first += PAGE_SIZE; + } + } } static void srmmu_map_kernel(unsigned long start, unsigned long end) { + unsigned long last_page; + int srmmu_bank, phys_bank, i; pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - end = (PAGE_ALIGN(end) + PAGE_SIZE); - while(start < end) { + end = PAGE_ALIGN(end); + + if(start == (KERNBASE + PAGE_SIZE)) { + unsigned long pte; + unsigned long tmp; + + pgdp = srmmu_pgd_offset(init_task.mm, KERNBASE); + pmdp = srmmu_early_pmd_offset(pgdp, KERNBASE); + ptep = srmmu_early_pte_offset(pmdp, KERNBASE); + + /* Put a real mapping in for the KERNBASE page. */ + tmp = kbpage; + pte = (tmp) >> 4; + pte |= (SRMMU_CACHE | SRMMU_PRIV | SRMMU_VALID); + pte_val(*ptep) = pte; + } + + /* Copy over mappings prom already gave us. */ + last_page = (srmmu_hwprobe(start) & SRMMU_PTE_PMASK) << 4; + while((srmmu_hwprobe(start) & SRMMU_ET_MASK) == SRMMU_ET_PTE) { + unsigned long tmp; + pgdp = srmmu_pgd_offset(init_task.mm, start); - if(srmmu_pgd_none(*pgdp)) { - pmdp = srmmu_init_alloc(&mempool, SRMMU_PMD_TABLE_SIZE); - srmmu_pgd_set(pgdp, pmdp); - } - pmdp = srmmu_pmd_offset(pgdp, start); - if(srmmu_pmd_none(*pmdp)) { - ptep = srmmu_init_alloc(&mempool, SRMMU_PTE_TABLE_SIZE); - srmmu_pmd_set(pmdp, ptep); - } - ptep = srmmu_pte_offset(pmdp, start); - *ptep = srmmu_mk_pte(start, SRMMU_PAGE_KERNEL); + pmdp = srmmu_early_pmd_offset(pgdp, start); + ptep = srmmu_early_pte_offset(pmdp, start); + tmp = srmmu_hwprobe(start); + tmp &= ~(0xff); + tmp |= (SRMMU_CACHE | SRMMU_PRIV | SRMMU_VALID); + pte_val(*ptep) = tmp; + start += PAGE_SIZE; + tmp = (srmmu_hwprobe(start) & SRMMU_PTE_PMASK) << 4; + + /* Never a cross bank boundry, thank you. */ + if(tmp != last_page + PAGE_SIZE) + break; + last_page = tmp; + } + + /* Ok, that was assumed to be one full bank, begin + * construction of srmmu_map[]. + */ + for(phys_bank = 0; sp_banks[phys_bank].num_bytes != 0; phys_bank++) { + if(kbpage >= sp_banks[phys_bank].base_addr && + (kbpage < + (sp_banks[phys_bank].base_addr + sp_banks[phys_bank].num_bytes))) + break; /* found it */ + } + srmmu_bank = 0; + srmmu_map[srmmu_bank].vbase = KERNBASE; + srmmu_map[srmmu_bank].pbase = sp_banks[phys_bank].base_addr; + srmmu_map[srmmu_bank].size = sp_banks[phys_bank].num_bytes; + if(kbpage != sp_banks[phys_bank].base_addr) { + prom_printf("Detected PenguinPages, getting out of here.\n"); + prom_halt(); +#if 0 + srmmu_map[srmmu_bank].pbase = kbpage; + srmmu_map[srmmu_bank].size -= + (kbpage - sp_banks[phys_bank].base_addr); +#endif + } + /* Prom didn't map all of this first bank, fill + * in the rest by hand. + */ + while(start < (srmmu_map[srmmu_bank].vbase + srmmu_map[srmmu_bank].size)) { + unsigned long pteval; + + pgdp = srmmu_pgd_offset(init_task.mm, start); + pmdp = srmmu_early_pmd_offset(pgdp, start); + ptep = srmmu_early_pte_offset(pmdp, start); + + pteval = (start - KERNBASE + srmmu_map[srmmu_bank].pbase) >> 4; + pteval |= (SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV); + pte_val(*ptep) = pteval; start += PAGE_SIZE; } + + /* Mark this sp_bank invalid... */ + sp_banks[phys_bank].base_addr |= 1; + srmmu_bank++; + + /* Now, deal with what is left. */ + while(start < end) { + unsigned long baddr; + int btg; + + /* Find a usable cluster of physical ram. */ + for(i=0; sp_banks[i].num_bytes != 0; i++) + if(!(sp_banks[i].base_addr & 1)) + break; + if(sp_banks[i].num_bytes == 0) + break; + + /* Add it to srmmu_map */ + srmmu_map[srmmu_bank].vbase = start; + srmmu_map[srmmu_bank].pbase = sp_banks[i].base_addr; + srmmu_map[srmmu_bank].size = sp_banks[i].num_bytes; + srmmu_bank++; + + btg = sp_banks[i].num_bytes; + baddr = sp_banks[i].base_addr; + while(btg) { + pgdp = srmmu_pgd_offset(init_task.mm, start); + pmdp = srmmu_early_pmd_offset(pgdp, start); + ptep = srmmu_early_pte_offset(pmdp, start); + pte_val(*ptep) = (SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV); + pte_val(*ptep) |= (baddr >> 4); + + baddr += PAGE_SIZE; + start += PAGE_SIZE; + btg -= PAGE_SIZE; + } + sp_banks[i].base_addr |= 1; + } + if(start < end) { + prom_printf("weird, didn't use all of physical memory... "); + prom_halt(); + } + for(phys_bank = 0; sp_banks[phys_bank].num_bytes != 0; phys_bank++) + sp_banks[phys_bank].base_addr &= ~1; +#if 0 + for(i = 0; srmmu_map[i].size != 0; i++) { + prom_printf("srmmu_map[%d]: vbase=%08lx pbase=%08lx size=%d\n", + i, srmmu_map[i].vbase, + srmmu_map[i].pbase, srmmu_map[i].size); + } + prom_getchar(); + for(i = 0; sp_banks[i].num_bytes != 0; i++) { + prom_printf("sp_banks[%d]: base_addr=%08lx num_bytes=%d\n", + i, + sp_banks[i].base_addr, + sp_banks[i].num_bytes); + } + prom_getchar(); + prom_halt(); +#endif } /* Paging initialization on the Sparc Reference MMU. */ extern unsigned long free_area_init(unsigned long, unsigned long); extern unsigned long sparc_context_init(unsigned long, int); +extern int physmem_mapped_contig; +extern int linux_num_cpus; + +void (*poke_srmmu)(void); + unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem) { + unsigned long ptables_start, first_mapped_page; int i, cpunode; char node_str[128]; + pgd_t *pgdp; + pmd_t *pmdp; + pte_t *ptep; + physmem_mapped_contig = 0; /* for init.c:taint_real_pages() */ + +#if CONFIG_AP1000 + printk("Forcing num_contexts to 1024\n"); + num_contexts = 1024; +#else /* Find the number of contexts on the srmmu. */ cpunode = prom_getchild(prom_root_node); num_contexts = 0; @@ -1063,64 +1834,104 @@ break; } } +#endif if(!num_contexts) { prom_printf("Something wrong, cant find cpu node in paging_init.\n"); prom_halt(); } - prom_printf("Number of MMU contexts %d\n", num_contexts); - mempool = start_mem; + ptables_start = mempool = PAGE_ALIGN(start_mem); memset(swapper_pg_dir, 0, PAGE_SIZE); - srmmu_map_kernel(KERNBASE, end_mem); + first_mapped_page = KERNBASE; + kbpage = srmmu_hwprobe(KERNBASE); + if((kbpage & SRMMU_ET_MASK) != SRMMU_ET_PTE) { + kbpage = srmmu_hwprobe(KERNBASE + PAGE_SIZE); + kbpage = (kbpage & SRMMU_PTE_PMASK) << 4; + kbpage -= PAGE_SIZE; + first_mapped_page += PAGE_SIZE; + } else + kbpage = (kbpage & SRMMU_PTE_PMASK) << 4; + + srmmu_allocate_ptable_skeleton(KERNBASE, end_mem); +#if CONFIG_SUN_IO srmmu_allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_END); srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END); +#endif + + /* Steal DVMA pages now, I still don't like how we waste all this. */ mempool = PAGE_ALIGN(mempool); first_dvma_page = mempool; last_dvma_page = (mempool + (DVMA_LEN) - PAGE_SIZE); mempool = last_dvma_page + PAGE_SIZE; - srmmu_map_dvma_pages_for_cpu(first_dvma_page, last_dvma_page); - srmmu_inherit_prom_mappings(); +#if CONFIG_AP1000 + ap_inherit_mappings(); +#else + srmmu_inherit_prom_mappings(0xfe400000,(LINUX_OPPROM_ENDVM-PAGE_SIZE)); +#endif + srmmu_map_kernel(first_mapped_page, end_mem); +#if CONFIG_SUN_IO + srmmu_map_dvma_pages_for_cpu(first_dvma_page, last_dvma_page); +#endif srmmu_context_table = srmmu_init_alloc(&mempool, num_contexts*sizeof(ctxd_t)); + srmmu_ctx_table_phys = (ctxd_t *) srmmu_v2p((unsigned long) srmmu_context_table); for(i = 0; i < num_contexts; i++) - srmmu_ctxd_set(&srmmu_context_table[i], swapper_pg_dir); - - prom_printf("Taking over MMU from PROM.\n"); - srmmu_flush_whole_tlb(); - srmmu_set_ctable_ptr(((unsigned)srmmu_context_table) - PAGE_OFFSET); - srmmu_flush_whole_tlb(); + ctxd_set(&srmmu_context_table[i], swapper_pg_dir); start_mem = PAGE_ALIGN(mempool); + + /* Some SRMMU's are _very_ stupid indeed. */ + if(!can_cache_ptables) { + for( ; ptables_start < start_mem; ptables_start += PAGE_SIZE) { + pgdp = srmmu_pgd_offset(init_task.mm, ptables_start); + pmdp = srmmu_early_pmd_offset(pgdp, ptables_start); + ptep = srmmu_early_pte_offset(pmdp, ptables_start); + pte_val(*ptep) &= ~SRMMU_CACHE; + } + + pgdp = srmmu_pgd_offset(init_task.mm, (unsigned long)swapper_pg_dir); + pmdp = srmmu_early_pmd_offset(pgdp, (unsigned long)swapper_pg_dir); + ptep = srmmu_early_pte_offset(pmdp, (unsigned long)swapper_pg_dir); + pte_val(*ptep) &= ~SRMMU_CACHE; + } + + flush_cache_all(); + srmmu_set_ctable_ptr((unsigned long) srmmu_ctx_table_phys); + flush_tlb_all(); + poke_srmmu(); + start_mem = sparc_context_init(start_mem, num_contexts); start_mem = free_area_init(start_mem, end_mem); - prom_printf("survived...\n"); return PAGE_ALIGN(start_mem); } -/* Test the WP bit on the Sparc Reference MMU. */ -void srmmu_test_wp(void) -{ - pgd_t *pgdp; - - wp_works_ok = -1; - /* We mapped page zero as a read-only page in paging_init() - * So fire up the test, then invalidate the pgd for page zero. - * It is no longer needed. - */ - - /* Let it rip... */ - __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory"); - if (wp_works_ok < 0) - wp_works_ok = 0; - - pgdp = srmmu_pgd_offset(init_task.mm, 0x0); - pgd_val(*pgdp) = 0x0; -} +static char srmmuinfo[512]; static char *srmmu_mmu_info(void) { - return ""; + sprintf(srmmuinfo, "MMU type\t: %s\n" + "invall\t\t: %d\n" + "invmm\t\t: %d\n" + "invrnge\t\t: %d\n" + "invpg\t\t: %d\n" + "contexts\t: %d\n" + "big_chunks\t: %d\n" + "little_chunks\t: %d\n", + srmmu_name, + module_stats.invall, + module_stats.invmm, + module_stats.invrnge, + module_stats.invpg, + num_contexts, +#if 0 + num_big_chunks, + num_little_chunks +#else + 0, 0 +#endif + ); + return srmmuinfo; } static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) @@ -1133,7 +1944,39 @@ struct mm_struct *mm = current->mm; if(mm->context != NO_CONTEXT) { - srmmu_ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + flush_cache_mm(mm); + ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + flush_tlb_mm(mm); + ctx_old = ctx_list_pool + mm->context; + remove_from_ctx_list(ctx_old); + add_to_free_ctxlist(ctx_old); + mm->context = NO_CONTEXT; + } +} + +static void srmmu_flush_hook(void) +{ + if(current->tss.flags & SPARC_FLAG_KTHREAD) { + alloc_context(current->mm); + ctxd_set(&srmmu_context_table[current->mm->context], current->mm->pgd); + srmmu_set_context(current->mm->context); + } +} + +static void hypersparc_exit_hook(void) +{ + struct ctx_list *ctx_old; + struct mm_struct *mm = current->mm; + + if(mm->context != NO_CONTEXT) { + /* HyperSparc is copy-back, any data for this + * process in a modified cache line is stale + * and must be written back to main memory now + * else we eat shit later big time. + */ + flush_cache_mm(mm); + ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir); + flush_tlb_mm(mm); ctx_old = ctx_list_pool + mm->context; remove_from_ctx_list(ctx_old); add_to_free_ctxlist(ctx_old); @@ -1141,12 +1984,12 @@ } } -static void -srmmu_flush_hook(void) +static void hypersparc_flush_hook(void) { if(current->tss.flags & SPARC_FLAG_KTHREAD) { alloc_context(current->mm); - srmmu_ctxd_set(&srmmu_context_table[current->mm->context], current->mm->pgd); + flush_cache_mm(current->mm); + ctxd_set(&srmmu_context_table[current->mm->context], current->mm->pgd); srmmu_set_context(current->mm->context); } } @@ -1158,56 +2001,96 @@ prom_halt(); } -void init_hypersparc(void) +void poke_hypersparc(void) { + volatile unsigned long clear; unsigned long mreg = srmmu_get_mmureg(); - prom_printf("HyperSparc MMU detected.\n"); - if(mreg & HYPERSPARC_CSIZE) - hyper_cache_size = (256 * 1024); - else - hyper_cache_size = (128 * 1024); + hyper_flush_unconditional_combined(); - srmmu_modtype = HyperSparc; - hwbug_bitmask |= HWBUG_VACFLUSH_BITROT; + mreg &= ~(HYPERSPARC_CWENABLE); + mreg |= (HYPERSPARC_CENABLE | HYPERSPARC_WBENABLE); + mreg |= (HYPERSPARC_CMODE); + + srmmu_set_mmureg(mreg); + hyper_clear_all_tags(); + put_ross_icr(HYPERSPARC_ICCR_FTD | HYPERSPARC_ICCR_ICE); hyper_flush_whole_icache(); - hyper_flush_all_combined(); + clear = srmmu_get_faddr(); + clear = srmmu_get_fstatus(); +} - /* Keep things sane for now, cache in write-through mode. */ - mreg &= ~(HYPERSPARC_CWENABLE | HYPERSPARC_CMODE | HYPERSPARC_WBENABLE); - mreg |= HYPERSPARC_CENABLE; - srmmu_set_mmureg(mreg); - put_ross_icr(get_ross_icr() | 0x3); - invalidate_all = hypersparc_invalidate_all; - invalidate_mm = hypersparc_invalidate_mm; - invalidate_page = hypersparc_invalidate_page; - invalidate_range = hypersparc_invalidate_range; +void init_hypersparc(void) +{ + unsigned long mreg = srmmu_get_mmureg(); + + srmmu_name = "ROSS HyperSparc"; + can_cache_ptables = 0; + if(mreg & HYPERSPARC_CSIZE) { + hyper_cache_size = (256 * 1024); + hyper_line_size = 64; + } else { + hyper_cache_size = (128 * 1024); + hyper_line_size = 32; + } + + flush_cache_all = hypersparc_flush_cache_all; + flush_cache_mm = hypersparc_flush_cache_mm; + flush_cache_range = hypersparc_flush_cache_range; + flush_cache_page = hypersparc_flush_cache_page; + + flush_tlb_all = hypersparc_flush_tlb_all; + flush_tlb_mm = hypersparc_flush_tlb_mm; + flush_tlb_range = hypersparc_flush_tlb_range; + flush_tlb_page = hypersparc_flush_tlb_page; + + flush_page_to_ram = hypersparc_flush_page_to_ram; + flush_page_for_dma = hypersparc_flush_page_for_dma; + flush_cache_page_to_uncache = hypersparc_flush_cache_page_to_uncache; + flush_tlb_page_for_cbit = hypersparc_flush_tlb_page_for_cbit; + + ctxd_set = hypersparc_ctxd_set; + switch_to_context = hypersparc_switch_to_context; + mmu_exit_hook = hypersparc_exit_hook; + mmu_flush_hook = hypersparc_flush_hook; + sparc_update_rootmmu_dir = hypersparc_update_rootmmu_dir; + set_pte = hypersparc_set_pte; + poke_srmmu = poke_hypersparc; } -void init_cypress_common(void) +void poke_cypress(void) { unsigned long mreg = srmmu_get_mmureg(); mreg &= ~CYPRESS_CMODE; mreg |= CYPRESS_CENABLE; srmmu_set_mmureg(mreg); - invalidate_all = cypress_invalidate_all; - invalidate_mm = cypress_invalidate_mm; - invalidate_page = cypress_invalidate_page; - invalidate_range = cypress_invalidate_range; +} + +void init_cypress_common(void) +{ + can_cache_ptables = 0; + flush_tlb_all = cypress_flush_tlb_all; + flush_tlb_mm = cypress_flush_tlb_mm; + flush_tlb_page = cypress_flush_tlb_page; + flush_tlb_range = cypress_flush_tlb_range; + poke_srmmu = poke_cypress; + + /* XXX Need to write cache flushes for this one... XXX */ + } void init_cypress_604(void) { - prom_printf("Cypress 604(UP) MMU detected.\n"); + srmmu_name = "ROSS Cypress-604(UP)"; srmmu_modtype = Cypress; init_cypress_common(); } void init_cypress_605(unsigned long mrev) { - prom_printf("Cypress 605(MP) MMU detected.\n"); + srmmu_name = "ROSS Cypress-605(MP)"; if(mrev == 0xe) { srmmu_modtype = Cypress_vE; hwbug_bitmask |= HWBUG_COPYBACK_BROKEN; @@ -1222,17 +2105,36 @@ init_cypress_common(); } -#define SWIFT_REVISION_ADDR 0x10003000 -void init_swift(void) +void poke_swift(void) { - unsigned long swift_rev, addr; unsigned long mreg = srmmu_get_mmureg(); - prom_printf("Swift MMU detected.\n"); + /* Clear any crap from the cache or else... */ + swift_idflash_clear(); + mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */ + + /* The Swift branch folding logic is completely broken. At + * trap time, if things are just right, if can mistakedly + * think that a trap is coming from kernel mode when in fact + * it is coming from user mode (it mis-executes the branch in + * the trap code). So you see things like crashme completely + * hosing your machine which is completely unacceptable. Turn + * this shit off... nice job Fujitsu. + */ + mreg &= ~(SWIFT_BF); + srmmu_set_mmureg(mreg); +} + +#define SWIFT_MASKID_ADDR 0x10003018 +void init_swift(void) +{ + unsigned long swift_rev; + __asm__ __volatile__("lda [%1] %2, %0\n\t" "srl %0, 0x18, %0\n\t" : "=r" (swift_rev) : - "r" (SWIFT_REVISION_ADDR), "i" (0x20)); + "r" (SWIFT_MASKID_ADDR), "i" (ASI_M_BYPASS)); + srmmu_name = "Fujitsu Swift"; switch(swift_rev) { case 0x11: case 0x20: @@ -1270,103 +2172,172 @@ srmmu_modtype = Swift_ok; break; }; - /* Clear any crap from the cache or else... */ - for(addr = 0; addr < (PAGE_SIZE * 4); addr += 16) { - swift_inv_insn_tag(addr); /* whiz- */ - swift_inv_data_tag(addr); /* bang */ - } - mreg |= (SWIFT_IE | SWIFT_DE); /* I & D caches on */ - - /* The Swift branch folding logic is completely broken. At - * trap time, if things are just right, if can mistakenly - * thing that a trap is coming from kernel mode when in fact - * it is coming from user mode (it misexecutes the branch in - * the trap code). So you see things like crashme completely - * hosing your machine which is completely unacceptable. Turn - * this crap off... nice job Fujitsu. - */ - mreg &= ~(SWIFT_BF); - srmmu_set_mmureg(mreg); - invalidate_all = swift_invalidate_all; - invalidate_mm = swift_invalidate_mm; - invalidate_page = swift_invalidate_page; - invalidate_range = swift_invalidate_range; + flush_cache_all = swift_flush_cache_all; + flush_cache_mm = swift_flush_cache_mm; + flush_cache_page = swift_flush_cache_page; + flush_cache_range = swift_flush_cache_range; + + flush_tlb_all = swift_flush_tlb_all; + flush_tlb_mm = swift_flush_tlb_mm; + flush_tlb_page = swift_flush_tlb_page; + flush_tlb_range = swift_flush_tlb_range; + + flush_page_to_ram = swift_flush_page_to_ram; + flush_page_for_dma = swift_flush_page_for_dma; + flush_cache_page_to_uncache = swift_flush_cache_page_to_uncache; + flush_tlb_page_for_cbit = swift_flush_tlb_page_for_cbit; /* Are you now convinced that the Swift is one of the * biggest VLSI abortions of all time? Bravo Fujitsu! + * Fujitsu, the !#?!%$'d up processor people. I bet if + * you examined the microcode of the Swift you'd find + * XXX's all over the place. */ + poke_srmmu = poke_swift; +} + +void poke_tsunami(void) +{ + unsigned long mreg = srmmu_get_mmureg(); + + tsunami_flush_icache(); + tsunami_flush_dcache(); + mreg &= ~TSUNAMI_ITD; + mreg |= (TSUNAMI_IENAB | TSUNAMI_DENAB); + srmmu_set_mmureg(mreg); } -void init_tsunami(unsigned long mreg) +void init_tsunami(void) { /* Tsunami's pretty sane, Sun and TI actually got it * somewhat right this time. Fujitsu should have * taken some lessons from them. */ - prom_printf("Tsunami MMU detected.\n"); + srmmu_name = "TI Tsunami"; srmmu_modtype = Tsunami; - tsunami_invalidate_icache(); - tsunami_invalidate_dcache(); - mreg &= ~TSUNAMI_ITD; - mreg |= (TSUNAMI_IENAB | TSUNAMI_DENAB); - srmmu_set_mmureg(mreg); - invalidate_all = tsunami_invalidate_all; - invalidate_mm = tsunami_invalidate_mm; - invalidate_page = tsunami_invalidate_page; - invalidate_range = tsunami_invalidate_range; + can_cache_ptables = 1; + + flush_cache_all = tsunami_flush_cache_all; + flush_cache_mm = tsunami_flush_cache_mm; + flush_cache_page = tsunami_flush_cache_page; + flush_cache_range = tsunami_flush_cache_range; + + flush_tlb_all = tsunami_flush_tlb_all; + flush_tlb_mm = tsunami_flush_tlb_mm; + flush_tlb_page = tsunami_flush_tlb_page; + flush_tlb_range = tsunami_flush_tlb_range; + + flush_page_to_ram = tsunami_flush_page_to_ram; + flush_page_for_dma = tsunami_flush_page_for_dma; + flush_cache_page_to_uncache = tsunami_flush_cache_page_to_uncache; + flush_tlb_page_for_cbit = tsunami_flush_tlb_page_for_cbit; + + poke_srmmu = poke_tsunami; } -void init_viking(unsigned long psr_vers, unsigned long mod_rev) +void poke_viking(void) { unsigned long mreg = srmmu_get_mmureg(); + static int smp_catch = 0; - /* Ahhh, the viking. SRMMU VLSI abortion number two... */ + if(viking_mxcc_present) { + unsigned long mxcc_control; - prom_printf("Viking MMU detected.\n"); - if(!psr_vers && ! mod_rev) { - srmmu_modtype = Viking_12; - hwbug_bitmask |= (HWBUG_MODIFIED_BITROT | HWBUG_PC_BADFAULT_ADDR); - - /* On a fault, the chip gets entirely confused. It will - * do one of two things. Either it will set the modified - * bit for a read-only page (!!!) or it will improperly - * report a fault when a dcti/loadstore sequence is the - * last two instructions on a page. Oh baby... - */ + __asm__ __volatile__("set -1, %%g2\n\t" + "set -1, %%g3\n\t" + "stda %%g2, [%1] %2\n\t" + "lda [%3] %2, %0\n\t" : + "=r" (mxcc_control) : + "r" (MXCC_EREG), "i" (ASI_M_MXCC), + "r" (MXCC_CREG) : "g2", "g3"); + mxcc_control |= (MXCC_CTL_ECE | MXCC_CTL_PRE | MXCC_CTL_MCE); + mxcc_control &= ~(MXCC_CTL_PARE | MXCC_CTL_RRC); + mreg &= ~(VIKING_PCENABLE); + __asm__ __volatile__("sta %0, [%1] %2\n\t" : : + "r" (mxcc_control), "r" (MXCC_CREG), + "i" (ASI_M_MXCC)); + srmmu_set_mmureg(mreg); + mreg |= VIKING_TCENABLE; } else { - if(psr_vers) { - srmmu_modtype = Viking_2x; - hwbug_bitmask |= HWBUG_PC_BADFAULT_ADDR; /* see above */ - } else { - if(mod_rev == 1) { - srmmu_modtype = Viking_30; - hwbug_bitmask |= HWBUG_PACINIT_BITROT; - - /* At boot time the physical cache - * has cherry bombs in it, so you - * have to scrape it by hand before - * enabling it. Nice CAD tools guys. - */ - } else { - if(mod_rev < 8) - srmmu_modtype = Viking_35; - else - srmmu_modtype = Viking_new; - } + unsigned long bpreg; + + mreg &= ~(VIKING_TCENABLE); + if(smp_catch++) { + /* Must disable mixed-cmd mode here for + * other cpu's. + */ + bpreg = viking_get_bpreg(); + bpreg &= ~(VIKING_ACTION_MIX); + viking_set_bpreg(bpreg); + + /* Just in case PROM does something funny. */ + msi_set_sync(); } } - /* XXX Dave, play with the MXCC you pinhead XXX */ + + viking_unlock_icache(); viking_flush_icache(); +#if 0 + viking_unlock_dcache(); viking_flush_dcache(); - mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE | - VIKING_TCENABLE | VIKING_DPENABLE); +#endif + mreg |= VIKING_SPENABLE; + mreg |= (VIKING_ICENABLE | VIKING_DCENABLE); + mreg |= VIKING_SBENABLE; + mreg &= ~(VIKING_ACENABLE); +#if CONFIG_AP1000 + mreg &= ~(VIKING_SBENABLE); +#endif +#ifdef __SMP__ + mreg &= ~(VIKING_SBENABLE); +#endif srmmu_set_mmureg(mreg); - invalidate_all = viking_invalidate_all; - invalidate_mm = viking_invalidate_mm; - invalidate_page = viking_invalidate_page; - invalidate_range = viking_invalidate_range; +} + +void init_viking(void) +{ + unsigned long mreg = srmmu_get_mmureg(); + + /* Ahhh, the viking. SRMMU VLSI abortion number two... */ + + if(mreg & VIKING_MMODE) { + unsigned long bpreg; + + srmmu_name = "TI Viking"; + viking_mxcc_present = 0; + can_cache_ptables = 0; + + bpreg = viking_get_bpreg(); + bpreg &= ~(VIKING_ACTION_MIX); + viking_set_bpreg(bpreg); + + msi_set_sync(); + + flush_cache_page_to_uncache = viking_no_mxcc_flush_page; + } else { + srmmu_name = "TI Viking/MXCC"; + viking_mxcc_present = 1; + can_cache_ptables = 1; + flush_cache_page_to_uncache = viking_mxcc_flush_page; + } + + flush_cache_all = viking_flush_cache_all; + flush_cache_mm = viking_flush_cache_mm; + flush_cache_page = viking_flush_cache_page; + flush_cache_range = viking_flush_cache_range; + + flush_tlb_all = viking_flush_tlb_all; + flush_tlb_mm = viking_flush_tlb_mm; + flush_tlb_page = viking_flush_tlb_page; + flush_tlb_range = viking_flush_tlb_range; + + flush_page_to_ram = viking_flush_page_to_ram; + flush_page_for_dma = viking_flush_page_for_dma; + flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit; + + poke_srmmu = poke_viking; } /* Probe for the srmmu chip version. */ @@ -1418,13 +2389,13 @@ if(psr_typ == 4 && ((psr_vers == 0) || ((psr_vers == 1) && (mod_typ == 0) && (mod_rev == 0)))) { - init_viking(psr_vers, mod_rev); + init_viking(); return; } /* Finally the Tsunami. */ if(psr_typ == 4 && psr_vers == 1 && (mod_typ || mod_rev)) { - init_tsunami(mreg); + init_tsunami(); return; } @@ -1438,6 +2409,10 @@ extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk, tsetup_srmmu_stackchk, srmmu_rett_stackchk; +#ifdef __SMP__ +extern unsigned long rirq_mmu_patchme, srmmu_reti_stackchk; +#endif + extern unsigned long srmmu_fault; #define PATCH_BRANCH(insn, dest) do { \ @@ -1454,15 +2429,35 @@ PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk); PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk); PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk); +#ifdef __SMP__ + PATCH_BRANCH(rirq_mmu_patchme, srmmu_reti_stackchk); +#endif PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault); PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault); + PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault); +} + +#ifdef __SMP__ +/* Local cross-calls. */ +static void smp_flush_page_for_dma(unsigned long page) +{ + xc1((smpfunc_t) local_flush_page_for_dma, page); +} + +static void smp_flush_cache_page_to_uncache(unsigned long page) +{ + xc1((smpfunc_t) local_flush_cache_page_to_uncache, page); +} + +static void smp_flush_tlb_page_for_cbit(unsigned long page) +{ + xc1((smpfunc_t) local_flush_tlb_page_for_cbit, page); } +#endif /* Load up routines and constants for sun4m mmu */ void ld_mmu_srmmu(void) { - prom_printf("Loading srmmu MMU routines\n"); - /* First the constants */ pmd_shift = SRMMU_PMD_SHIFT; pmd_size = SRMMU_PMD_SIZE; @@ -1497,23 +2492,17 @@ pte_none = srmmu_pte_none; pte_present = srmmu_pte_present; - pte_inuse = srmmu_pte_inuse; pte_clear = srmmu_pte_clear; - pte_reuse = srmmu_pte_reuse; pmd_none = srmmu_pmd_none; pmd_bad = srmmu_pmd_bad; pmd_present = srmmu_pmd_present; - pmd_inuse = srmmu_pmd_inuse; pmd_clear = srmmu_pmd_clear; - pmd_reuse = srmmu_pmd_reuse; pgd_none = srmmu_pgd_none; pgd_bad = srmmu_pgd_bad; pgd_present = srmmu_pgd_present; - pgd_inuse = srmmu_pgd_inuse; pgd_clear = srmmu_pgd_clear; - pgd_reuse = srmmu_pgd_reuse; mk_pte = srmmu_mk_pte; pgd_set = srmmu_pgd_set; @@ -1547,9 +2536,15 @@ mmu_flush_hook = srmmu_flush_hook; mmu_lockarea = srmmu_lockarea; mmu_unlockarea = srmmu_unlockarea; - mmu_get_scsi_buffer = srmmu_get_scsi_buffer; - mmu_release_scsi_buffer = srmmu_release_scsi_buffer; + + mmu_get_scsi_one = srmmu_get_scsi_one; + mmu_get_scsi_sgl = srmmu_get_scsi_sgl; + mmu_release_scsi_one = srmmu_release_scsi_one; + mmu_release_scsi_sgl = srmmu_release_scsi_sgl; + mmu_info = srmmu_mmu_info; + mmu_v2p = srmmu_v2p; + mmu_p2v = srmmu_p2v; /* Task struct and kernel stack allocating/freeing. */ alloc_kernel_stack = srmmu_alloc_kernel_stack; @@ -1559,13 +2554,40 @@ quick_kernel_fault = srmmu_quick_kernel_fault; + /* SRMMU specific. */ + ctxd_set = srmmu_ctxd_set; + pmd_set = srmmu_pmd_set; + get_srmmu_type(); - if(!(srmmu_get_mmureg() & 0x800)) { - srmmu_read_physical = msparc_read_physical; - srmmu_write_physical = msparc_write_physical; - } else { - srmmu_read_physical = gensrmmu_read_physical; - srmmu_write_physical = gensrmmu_write_physical; - } patch_window_trap_handlers(); + +#ifdef __SMP__ + /* El switcheroo... */ + + local_flush_cache_all = flush_cache_all; + local_flush_cache_mm = flush_cache_mm; + local_flush_cache_range = flush_cache_range; + local_flush_cache_page = flush_cache_page; + local_flush_tlb_all = flush_tlb_all; + local_flush_tlb_mm = flush_tlb_mm; + local_flush_tlb_range = flush_tlb_range; + local_flush_tlb_page = flush_tlb_page; + local_flush_page_to_ram = flush_page_to_ram; + local_flush_page_for_dma = flush_page_for_dma; + local_flush_cache_page_to_uncache = flush_cache_page_to_uncache; + local_flush_tlb_page_for_cbit = flush_tlb_page_for_cbit; + + flush_cache_all = smp_flush_cache_all; + flush_cache_mm = smp_flush_cache_mm; + flush_cache_range = smp_flush_cache_range; + flush_cache_page = smp_flush_cache_page; + flush_tlb_all = smp_flush_tlb_all; + flush_tlb_mm = smp_flush_tlb_mm; + flush_tlb_range = smp_flush_tlb_range; + flush_tlb_page = smp_flush_tlb_page; + flush_page_to_ram = smp_flush_page_to_ram; + flush_page_for_dma = smp_flush_page_for_dma; + flush_cache_page_to_uncache = smp_flush_cache_page_to_uncache; + flush_tlb_page_for_cbit = smp_flush_tlb_page_for_cbit; +#endif } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/srmmu_mp.S linux/arch/sparc/mm/srmmu_mp.S --- v1.3.92/linux/arch/sparc/mm/srmmu_mp.S Thu Jan 1 02:00:00 1970 +++ linux/arch/sparc/mm/srmmu_mp.S Sun Apr 21 12:30:31 1996 @@ -0,0 +1,52 @@ +/* srmmu_mp.S: Low level invalidates for MP SRMMU modules. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ +#include +#include + + /* Protocol is: + * + * %l0 --> %l3 NO TOUCH + * %l7 NO TOUCH + * %l6 return address - 0x8 + * %l4, %l5 what we can use + */ + + .globl C_LABEL(hyper_invalidate_low) +C_LABEL(hyper_invalidate_low): + /* First the on-chip cache. */ + set C_LABEL(hyper_cache_size), %l5 + ld [%l5], %l5 +1: + subcc %l5, 32, %l5 + bne 1b + sta %g0, [%l5] ASI_M_FLUSH_CTX + + /* Now the on-chip ICACHE. */ + sta %g0, [%g0] ASI_M_FLUSH_IWHOLE + + /* Flush the TLB and return. */ + mov 0x400, %l4 + sta %g0, [%l4] ASI_M_FLUSH_PROBE + + jmpl %l6 + 0x8, %g0 + nop + + .globl C_LABEL(viking_invalidate_low) +C_LABEL(viking_invalidate_low): + /* Flash clear the I/D caches. */ + sta %g0, [%g0] ASI_M_IC_FLCLEAR + sta %g0, [%g0] ASI_M_DC_FLCLEAR + + /* Flush the TLB and return. */ + mov 0x400, %l4 + sta %g0, [%l4] ASI_M_FLUSH_PROBE + + jmpl %l6 + 0x8, %g0 + nop + + /* XXX Write the Cypress when I get access to + * XXX some modules, poke mossip real hard until + * XXX he takes care of the Nubis upgrade. + */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/srmmuinv.c linux/arch/sparc/mm/srmmuinv.c --- v1.3.92/linux/arch/sparc/mm/srmmuinv.c Sat Nov 25 02:59:37 1995 +++ linux/arch/sparc/mm/srmmuinv.c Thu Jan 1 02:00:00 1970 @@ -1,169 +0,0 @@ -/* $Id: srmmuinv.c,v 1.2 1995/11/25 00:59:36 davem Exp $ - * srmmuinv.c: Invalidate routines for the various different - * SRMMU implementations. - * - * Copyright (C) 1995 David S. Miller - */ - -/* HyperSparc */ -hyper_invalidate(void) -{ - volatile unsigned int sfsr_clear; - - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - /* Flush ICACHE */ - flush_whole_icache(); - sfsr_clear = srmmu_get_fstatus(); - return; -} - -hyper_invalidate_mp(void) -{ - volatile unsigned int sfsr_clear; - - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - /* Flush ICACHE */ - flush_whole_icache(); - - sfsr_clear = srmmu_get_fstatus(); - - /* Tell other CPUS to each call the Uniprocessor - * invalidate routine. - */ - - return; -} - -/* Cypress */ -void -cypress_invalidate(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -void -cypress_invalidate_mp(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - /* Tell other CPUS to call the UP version */ - - return; -} - -void -cypress_invalidate_asibad(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache w/o using ASIs */ - - return; -} - -void -cypress_invalidate_asibad_mp(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache w/o using ASIs */ - - /* Tell other CPUS to call the UP version */ - - return; -} - -/* Swift */ -void -swift_invalidate(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -void -swift_invalidate_poke_kernel_pageperms(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -void -swift_invalidate_poke_kernel_pte_cbits(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -void -swift_invalidate_poke_everything(void) -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -/* Tsunami */ -tsunami_invalidate() -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Flush Virtual Address Cache */ - - return; -} - -/* Viking */ -viking_invalidate() -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - return; -} - -viking_invalidate_mp() -{ - /* Flush TLB */ - srmmu_flush_whole_tlb(); - - /* Make other CPUS call UP routine. */ - - return; -} - -/* That should be it */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c --- v1.3.92/linux/arch/sparc/mm/sun4c.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/mm/sun4c.c Sun Apr 21 12:30:32 1996 @@ -20,6 +20,19 @@ struct sun4c_vac_props sun4c_vacinfo; static int ctxflushes, segflushes, pageflushes; +/* convert a virtual address to a physical address and vice + versa. Easy on the 4c */ +static unsigned long sun4c_v2p(unsigned long vaddr) +{ + return(vaddr - PAGE_OFFSET); +} + +static unsigned long sun4c_p2v(unsigned long vaddr) +{ + return(vaddr + PAGE_OFFSET); +} + + /* Invalidate every sun4c cache line tag. */ void sun4c_flush_all(void) { @@ -40,7 +53,7 @@ } /* Blow the entire current context out of the virtual cache. */ -/* static */ inline void sun4c_flush_context(void) +static inline void sun4c_flush_context(void) { unsigned long vaddr; @@ -482,7 +495,7 @@ } /* Using this method to free up mmu entries eliminates a lot of - * potential races since we have a kernel that incurs tlb + * potention races since we have a kernel that incurs tlb * replacement faults. There may be performance penalties. */ static inline struct sun4c_mmu_entry *sun4c_user_strategy(void) @@ -567,8 +580,8 @@ /* READ THIS: If you put any diagnostic printing code in any of the kernel * fault handling code you will lose badly. This is the most * delicate piece of code in the entire kernel, atomicity of - * kernel tlb replacement must be guaranteed. This is why we - * have separate user and kernel allocation rings to alleviate + * kernel tlb replacement must be guarenteed. This is why we + * have seperate user and kernel allocation rings to alleviate * as many bad interactions as possible. * * XXX Someday make this into a fast in-window trap handler to avoid @@ -626,8 +639,7 @@ struct task_bucket { struct task_struct task; char _unused1[PAGE_SIZE - sizeof(struct task_struct)]; - char _unused2[PAGE_SIZE]; - char kstack[(PAGE_SIZE<<1)]; + char kstack[(PAGE_SIZE*3)]; }; struct task_bucket *sun4c_bucket[NR_TASKS]; @@ -717,7 +729,7 @@ static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk) { unsigned long saddr = (unsigned long) tsk; - unsigned long page[2]; + unsigned long page[3]; if(!saddr) return 0; @@ -729,24 +741,33 @@ free_page(page[0]); return 0; } - saddr += (PAGE_SIZE << 1); - sun4c_put_pte(saddr - PAGE_SIZE, 0); + page[2] = get_free_page(GFP_KERNEL); + if(!page[2]) { + free_page(page[0]); + free_page(page[1]); + return 0; + } + saddr += PAGE_SIZE; sun4c_put_pte(saddr, BUCKET_PTE(page[0])); sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1])); + sun4c_put_pte(saddr + (PAGE_SIZE<<1), BUCKET_PTE(page[2])); return saddr; } static void sun4c_free_kernel_stack(unsigned long stack) { - unsigned long page[2]; + unsigned long page[3]; page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack)); page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE)); + page[2] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+(PAGE_SIZE<<1))); sun4c_flush_segment(stack & SUN4C_REAL_PGDIR_MASK); sun4c_put_pte(stack, 0); sun4c_put_pte(stack + PAGE_SIZE, 0); + sun4c_put_pte(stack + (PAGE_SIZE<<1), 0); free_page(page[0]); free_page(page[1]); + free_page(page[2]); } static void sun4c_free_task_struct(struct task_struct *tsk) @@ -779,32 +800,69 @@ static unsigned long *sun4c_iobuffer_map; static int iobuffer_map_size; -static char *sun4c_lockpage(char *vaddr, unsigned long _unused) +/* + * Alias our pages so they do not cause a trap. + * Also one page may be aliased into several I/O areas and we may + * finish these I/O separately. + */ +static char *sun4c_lockarea(char *vaddr, unsigned long size) { - unsigned long vpage, voffset, search, pte; - unsigned long npage; + unsigned long base, scan; + unsigned long npages; + unsigned long vpage; + unsigned long pte; + unsigned long apage; + + npages = (((unsigned long)vaddr & ~PAGE_MASK) + + size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + + scan = 0; + for (;;) { + scan = find_next_zero_bit(sun4c_iobuffer_map, + iobuffer_map_size, scan); + if ((base = scan) + npages > iobuffer_map_size) goto abend; + for (;;) { + if (scan >= base + npages) goto found; + if (test_bit(scan, sun4c_iobuffer_map)) break; + scan++; + } + } +found: vpage = ((unsigned long) vaddr) & PAGE_MASK; - voffset = ((unsigned long) vaddr) & ~PAGE_MASK; - pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL); - pte |= _SUN4C_PAGE_NOCACHE; - search = find_first_zero_bit(sun4c_iobuffer_map, iobuffer_map_size); - set_bit(search, sun4c_iobuffer_map); - npage = (search << PAGE_SHIFT) + sun4c_iobuffer_start; - sun4c_flush_page(vpage); - sun4c_put_pte(npage, pte); - return (char *) (npage + voffset); -} - -static void sun4c_unlockpage(char *vaddr, unsigned long _unused) -{ - unsigned long vpage, nr; - - vpage = (unsigned long) vaddr; - vpage &= PAGE_MASK; - nr = (vpage - sun4c_iobuffer_start) >> PAGE_SHIFT; - sun4c_put_pte(vpage, 0); - clear_bit(nr, sun4c_iobuffer_map); + for (scan = base; scan < base+npages; scan++) { + pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT); + pte |= pgprot_val(SUN4C_PAGE_KERNEL); + pte |= _SUN4C_PAGE_NOCACHE; + set_bit(scan, sun4c_iobuffer_map); + apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start; + sun4c_flush_page(vpage); + sun4c_put_pte(apage, pte); + vpage += PAGE_SIZE; + } + return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start + + (((unsigned long) vaddr) & ~PAGE_MASK)); + +abend: + printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size); + panic("Out of iobuffer table"); + return 0; +} + +static void sun4c_unlockarea(char *vaddr, unsigned long size) +{ + unsigned long vpage, npages; + + vpage = (unsigned long)vaddr & PAGE_MASK; + npages = (((unsigned long)vaddr & ~PAGE_MASK) + + size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + while (npages != 0) { + --npages; + sun4c_put_pte(vpage, 0); + clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT, + sun4c_iobuffer_map); + vpage += PAGE_SIZE; + } } /* Note the scsi code at init time passes to here buffers @@ -812,32 +870,43 @@ * by implication and fool the page locking code above * if passed to by mistake. */ -static char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus) +static char *sun4c_get_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) { - unsigned long page1, page2; + unsigned long page; - page1 = ((unsigned long) bufptr) & PAGE_MASK; - page2 = (((unsigned long) bufptr) + len - 1) & PAGE_MASK; - if(page1 != page2) { - printk("Problem, trying to lock multipage scsi buffer.\n"); - printk("page1<%08lx> page2<%08lx>\n", page1, page2); - panic("Scsi buffer too big."); - } - if(page1 > high_memory) + page = ((unsigned long) bufptr) & PAGE_MASK; + if(page > high_memory) return bufptr; /* already locked */ - return sun4c_lockpage(bufptr, PAGE_SIZE); + return sun4c_lockarea(bufptr, len); } -static void sun4c_release_scsi_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus) +static void sun4c_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + while(sz >= 0) { + sg[sz].alt_addr = sun4c_lockarea(sg[sz].addr, sg[sz].len); + sz--; + } +} + +static void sun4c_release_scsi_one(char *bufptr, unsigned long len, struct linux_sbus *sbus) { unsigned long page = (unsigned long) bufptr; if(page < sun4c_iobuffer_start) return; /* On kernel stack or similar, see above */ - sun4c_unlockpage(bufptr, PAGE_SIZE); + sun4c_unlockarea(bufptr, len); +} + +static void sun4c_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + while(sz >= 0) { + sun4c_unlockarea(sg[sz].alt_addr, sg[sz].len); + sg[sz].alt_addr = 0; + sz--; + } } -#define TASK_ENTRY_SIZE (3 * PAGE_SIZE) +#define TASK_ENTRY_SIZE BUCKET_SIZE /* see above */ #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) struct vm_area_struct sun4c_kstack_vma; @@ -858,7 +927,7 @@ } sun4c_iobuffer_start = SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end); - sun4c_iobuffer_end = sun4c_iobuffer_start + SUN4C_REAL_PGDIR_SIZE; + sun4c_iobuffer_end = SUN4C_LOCK_END; bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT; bitmap_size = (bitmap_size + 7) >> 3; bitmap_size = LONG_ALIGN(bitmap_size); @@ -878,33 +947,181 @@ return start_mem; } -static void sun4c_invalidate_all(void) +/* Cache flushing on the sun4c. */ +static void sun4c_flush_cache_all(void) +{ + unsigned long start, end; + + /* Clear all tags in the sun4c cache. + * The cache is write through so this is safe. + */ + start = AC_CACHETAGS; + end = start + sun4c_vacinfo.num_bytes; + flush_user_windows(); + while(start < end) { + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (start), "i" (ASI_CONTROL)); + start += sun4c_vacinfo.linesize; + } +} + +static void sun4c_flush_cache_mm(struct mm_struct *mm) +{ + unsigned long flags; + int octx; + +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = sun4c_get_context(); + save_flags(flags); cli(); + flush_user_windows(); + sun4c_set_context(mm->context); + sun4c_flush_context(); + sun4c_set_context(octx); + restore_flags(flags); +#ifndef __SMP__ + } +#endif +} + +static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end) +{ + unsigned long flags; + int size, octx; + +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + size = start - end; + + flush_user_windows(); + + if(size >= sun4c_vacinfo.num_bytes) + goto flush_it_all; + + save_flags(flags); cli(); + octx = sun4c_get_context(); + sun4c_set_context(mm->context); + + if(size <= (PAGE_SIZE << 1)) { + start &= PAGE_MASK; + while(start < end) { + sun4c_flush_page(start); + start += PAGE_SIZE; + }; + } else { + start &= SUN4C_REAL_PGDIR_MASK; + while(start < end) { + sun4c_flush_segment(start); + start += SUN4C_REAL_PGDIR_SIZE; + } + } + sun4c_set_context(octx); + restore_flags(flags); +#ifndef __SMP__ + } +#endif + return; + +flush_it_all: + /* Cache size bounded flushing, thank you. */ + sun4c_flush_cache_all(); +} + +static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ + unsigned long flags; + int octx; + struct mm_struct *mm = vma->vm_mm; + + /* Sun4c has no seperate I/D caches so cannot optimize for non + * text page flushes. + */ +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + octx = sun4c_get_context(); + save_flags(flags); cli(); + flush_user_windows(); + sun4c_set_context(mm->context); + sun4c_flush_page(page); + sun4c_set_context(octx); + restore_flags(flags); +#ifndef __SMP__ + } +#endif +} + +/* Sun4c cache is write-through, so no need to validate main memory + * during a page copy in kernel space. + */ +static void sun4c_flush_page_to_ram(unsigned long page) +{ +} + +/* TLB flushing on the sun4c. These routines count on the cache + * flushing code to flush the user register windows so that we need + * not do so when we get here. + */ + +static void sun4c_flush_tlb_all(void) { struct sun4c_mmu_entry *this_entry, *next_entry; + unsigned long flags; + int savectx, ctx; + save_flags(flags); cli(); this_entry = sun4c_kernel_ring.ringhd.next; + savectx = sun4c_get_context(); while(sun4c_kernel_ring.num_entries) { next_entry = this_entry->next; - sun4c_kernel_unmap(this_entry); + for(ctx = 0; ctx < num_contexts; ctx++) { + sun4c_set_context(ctx); + sun4c_put_segmap(this_entry->vaddr, invalid_segment); + } free_kernel_entry(this_entry, &sun4c_kernel_ring); this_entry = next_entry; } + sun4c_set_context(savectx); + restore_flags(flags); } -static void sun4c_invalidate_mm(struct mm_struct *mm) +static void sun4c_flush_tlb_mm(struct mm_struct *mm) { - if(mm->context == NO_CONTEXT) - return; - sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context); + struct sun4c_mmu_entry *this_entry, *next_entry; + struct sun4c_mmu_ring *crp; + int savectx, ctx; + +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + crp = &sun4c_context_ring[mm->context]; + savectx = sun4c_get_context(); + ctx = mm->context; + this_entry = crp->ringhd.next; + sun4c_set_context(mm->context); + while(crp->num_entries) { + next_entry = this_entry->next; + sun4c_user_unmap(this_entry); + free_user_entry(ctx, this_entry); + this_entry = next_entry; + } + sun4c_set_context(savectx); +#ifndef __SMP__ + } +#endif } -static void sun4c_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end) +static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { struct sun4c_mmu_entry *this_entry; unsigned char pseg, savectx; +#ifndef __SMP__ if(mm->context == NO_CONTEXT) return; +#endif flush_user_windows(); savectx = sun4c_get_context(); sun4c_set_context(mm->context); @@ -914,7 +1131,7 @@ if(pseg == invalid_segment) goto next_one; this_entry = &mmu_entry_pool[pseg]; - sun4c_user_unmap(this_entry); + sun4c_put_segmap(this_entry->vaddr, invalid_segment); free_user_entry(mm->context, this_entry); next_one: start += SUN4C_REAL_PGDIR_SIZE; @@ -922,22 +1139,23 @@ sun4c_set_context(savectx); } -static void sun4c_invalidate_page(struct vm_area_struct *vma, unsigned long page) +static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) { struct mm_struct *mm = vma->vm_mm; - unsigned char savectx; + int savectx; - if(mm->context == NO_CONTEXT) - return; - flush_user_windows(); - savectx = sun4c_get_context(); - sun4c_set_context(mm->context); - page &= PAGE_MASK; - if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID) { - sun4c_flush_page(page); - sun4c_put_pte(page, 0); +#ifndef __SMP__ + if(mm->context != NO_CONTEXT) { +#endif + savectx = sun4c_get_context(); + sun4c_set_context(mm->context); + page &= PAGE_MASK; + if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID) + sun4c_put_pte(page, 0); + sun4c_set_context(savectx); +#ifndef __SMP__ } - sun4c_set_context(savectx); +#endif } /* Sun4c mmu hardware doesn't update the dirty bit in the pte's @@ -1045,18 +1263,6 @@ } } -void sun4c_test_wp(void) -{ - wp_works_ok = -1; - - /* Let it rip... */ - sun4c_put_pte((unsigned long) 0x0, (_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV)); - __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory"); - sun4c_put_pte((unsigned long) 0x0, 0x0); - if (wp_works_ok < 0) - wp_works_ok = 0; -} - static char s4cinfo[512]; static char *sun4c_mmu_info(void) @@ -1067,7 +1273,7 @@ for(i=0; i < num_contexts; i++) used_user_entries += sun4c_context_ring[i].num_entries; - sprintf(s4cinfo, "vacsize: %d bytes\n" + sprintf(s4cinfo, "vacsize\t\t: %d bytes\n" "vachwflush\t: %s\n" "vaclinesize\t: %d bytes\n" "mmuctxs\t\t: %d\n" @@ -1114,13 +1320,7 @@ static int sun4c_pte_none(pte_t pte) { return !pte_val(pte); } static int sun4c_pte_present(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; } -static int sun4c_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; } static void sun4c_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } -static void sun4c_pte_reuse(pte_t *ptep) -{ - if(!mem_map[MAP_NR(ptep)].reserved) - mem_map[MAP_NR(ptep)].count++; -} static int sun4c_pmd_none(pmd_t pmd) { return !pmd_val(pmd); } static int sun4c_pmd_bad(pmd_t pmd) @@ -1129,14 +1329,11 @@ } static int sun4c_pmd_present(pmd_t pmd) { return pmd_val(pmd) & PGD_PRESENT; } -static int sun4c_pmd_inuse(pmd_t *pmdp) { return 0; } static void sun4c_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; } -static void sun4c_pmd_reuse(pmd_t * pmdp) { } static int sun4c_pgd_none(pgd_t pgd) { return 0; } static int sun4c_pgd_bad(pgd_t pgd) { return 0; } static int sun4c_pgd_present(pgd_t pgd) { return 1; } -static int sun4c_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; } static void sun4c_pgd_clear(pgd_t * pgdp) { } /* @@ -1163,7 +1360,7 @@ return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); } -static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot) +static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) { return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); } @@ -1212,7 +1409,6 @@ */ static void sun4c_pte_free_kernel(pte_t *pte) { - mem_map[MAP_NR(pte)].reserved = 0; free_page((unsigned long) pte); } @@ -1224,7 +1420,6 @@ if (sun4c_pmd_none(*pmd)) { if (page) { pmd_val(*pmd) = PGD_TABLE | (unsigned long) page; - mem_map[MAP_NR(page)].reserved = 1; return page + address; } pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE; @@ -1376,10 +1571,40 @@ | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY; /* Functions */ - invalidate_all = sun4c_invalidate_all; - invalidate_mm = sun4c_invalidate_mm; - invalidate_range = sun4c_invalidate_range; - invalidate_page = sun4c_invalidate_page; +#ifndef __SMP__ + flush_cache_all = sun4c_flush_cache_all; + flush_cache_mm = sun4c_flush_cache_mm; + flush_cache_range = sun4c_flush_cache_range; + flush_cache_page = sun4c_flush_cache_page; + + flush_tlb_all = sun4c_flush_tlb_all; + flush_tlb_mm = sun4c_flush_tlb_mm; + flush_tlb_range = sun4c_flush_tlb_range; + flush_tlb_page = sun4c_flush_tlb_page; +#else + local_flush_cache_all = sun4c_flush_cache_all; + local_flush_cache_mm = sun4c_flush_cache_mm; + local_flush_cache_range = sun4c_flush_cache_range; + local_flush_cache_page = sun4c_flush_cache_page; + + local_flush_tlb_all = sun4c_flush_tlb_all; + local_flush_tlb_mm = sun4c_flush_tlb_mm; + local_flush_tlb_range = sun4c_flush_tlb_range; + local_flush_tlb_page = sun4c_flush_tlb_page; + + flush_cache_all = smp_flush_cache_all; + flush_cache_mm = smp_flush_cache_mm; + flush_cache_range = smp_flush_cache_range; + flush_cache_page = smp_flush_cache_page; + + flush_tlb_all = smp_flush_tlb_all; + flush_tlb_mm = smp_flush_tlb_mm; + flush_tlb_range = smp_flush_tlb_range; + flush_tlb_page = smp_flush_tlb_page; +#endif + + flush_page_to_ram = sun4c_flush_page_to_ram; + set_pte = sun4c_set_pte; switch_to_context = sun4c_switch_to_context; pmd_align = sun4c_pmd_align; @@ -1393,21 +1618,16 @@ pte_none = sun4c_pte_none; pte_present = sun4c_pte_present; - pte_inuse = sun4c_pte_inuse; pte_clear = sun4c_pte_clear; - pte_reuse = sun4c_pte_reuse; pmd_none = sun4c_pmd_none; pmd_bad = sun4c_pmd_bad; pmd_present = sun4c_pmd_present; - pmd_inuse = sun4c_pmd_inuse; pmd_clear = sun4c_pmd_clear; - pmd_reuse = sun4c_pmd_reuse; pgd_none = sun4c_pgd_none; pgd_bad = sun4c_pgd_bad; pgd_present = sun4c_pgd_present; - pgd_inuse = sun4c_pgd_inuse; pgd_clear = sun4c_pgd_clear; mk_pte = sun4c_mk_pte; @@ -1439,10 +1659,16 @@ update_mmu_cache = sun4c_update_mmu_cache; mmu_exit_hook = sun4c_exit_hook; mmu_flush_hook = sun4c_flush_hook; - mmu_lockarea = sun4c_lockpage; - mmu_unlockarea = sun4c_unlockpage; - mmu_get_scsi_buffer = sun4c_get_scsi_buffer; - mmu_release_scsi_buffer = sun4c_release_scsi_buffer; + mmu_lockarea = sun4c_lockarea; + mmu_unlockarea = sun4c_unlockarea; + + mmu_get_scsi_one = sun4c_get_scsi_one; + mmu_get_scsi_sgl = sun4c_get_scsi_sgl; + mmu_release_scsi_one = sun4c_release_scsi_one; + mmu_release_scsi_sgl = sun4c_release_scsi_sgl; + + mmu_v2p = sun4c_v2p; + mmu_p2v = sun4c_p2v; /* Task struct and kernel stack allocating/freeing. */ alloc_kernel_stack = sun4c_alloc_kernel_stack; @@ -1455,6 +1681,5 @@ /* These should _never_ get called with two level tables. */ pgd_set = 0; - pgd_reuse = 0; pgd_page = 0; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/bootstr.c linux/arch/sparc/prom/bootstr.c --- v1.3.92/linux/arch/sparc/prom/bootstr.c Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/prom/bootstr.c Sun Apr 21 12:30:32 1996 @@ -1,9 +1,10 @@ -/* $Id: bootstr.c,v 1.4 1996/02/08 07:06:43 zaitcev Exp $ +/* $Id: bootstr.c,v 1.5 1996/04/04 16:30:53 tridge Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include static char barg_buf[256]; @@ -33,6 +34,14 @@ cp += strlen(cp); *cp = 0; break; + case PROM_AP1000: + /* + * Get message from host boot process. + */ +#if CONFIG_AP1000 + ap_getbootargs(barg_buf); +#endif + break; default: barg_buf[0] = 0; break; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/console.c linux/arch/sparc/prom/console.c --- v1.3.92/linux/arch/sparc/prom/console.c Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/prom/console.c Sun Apr 21 12:30:32 1996 @@ -1,10 +1,11 @@ -/* $Id: console.c,v 1.6 1996/01/01 02:46:27 davem Exp $ +/* $Id: console.c,v 1.8 1996/04/05 07:44:35 tridge Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include #include @@ -28,6 +29,9 @@ return inc; return -1; break; + case PROM_AP1000: + return -1; + break; }; return 0; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -52,6 +56,15 @@ return 0; return -1; break; + case PROM_AP1000: +#if CONFIG_AP1000 + { + extern void ap_putchar(char ); + ap_putchar(c); + return 0; + } +#endif + break; }; return 0; /* Ugh, we could spin forever on unsupported proms ;( */ } @@ -110,6 +123,8 @@ return PROMDEV_ITTYB; } return PROMDEV_I_UNK; + case PROM_AP1000: + return PROMDEV_I_UNK; }; } @@ -162,6 +177,8 @@ }; } break; + case PROM_AP1000: + return PROMDEV_I_UNK; }; return PROMDEV_O_UNK; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/devops.c linux/arch/sparc/prom/devops.c --- v1.3.92/linux/arch/sparc/prom/devops.c Sat Nov 25 03:00:00 1995 +++ linux/arch/sparc/prom/devops.c Sun Apr 21 12:30:32 1996 @@ -1,4 +1,4 @@ -/* $Id: devops.c,v 1.3 1995/11/25 00:59:59 davem Exp $ +/* $Id: devops.c,v 1.4 1996/04/04 16:30:58 tridge Exp $ * devops.c: Device operations using the PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -27,6 +27,8 @@ handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr); return handle; break; + case PROM_AP1000: + break; }; return -1; @@ -45,6 +47,8 @@ case PROM_P1275: (*(romvec->pv_v2devops.v2_dev_close))(dhandle); return; + case PROM_AP1000: + return; }; return; } @@ -63,6 +67,8 @@ case PROM_V3: case PROM_P1275: (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo); + break; + case PROM_AP1000: break; }; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/devtree.c linux/arch/sparc/prom/devtree.c --- v1.3.92/linux/arch/sparc/prom/devtree.c Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/prom/devtree.c Thu Jan 1 02:00:00 1970 @@ -1,114 +0,0 @@ -/* devtree.c: Build a copy of the prom device tree in kernel - * memory for easier access and cleaner interface. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include - -/* Add more as appropriate. */ -enum bus_t { - OBIO_BUS, - SBUS_BUS, - PCI_BUS, - PMEM_BUS, - CPU_BUS, -}; - -struct sdevmapping { - unsigned long physpage; - int mapsz; - enum bus_t where; -}; - -/* limitation of sparc arch. */ -#define NUM_SPARC_IRQS 15 - -struct sdev_irqs { - int level; - int vector; /* For vme/sbus irq sharing methinks. */ -}; - -struct sparcdev { - struct sparcdev *next; - struct sparcdev *prev; - int node; - char *name; - int num_mappings; - struct sdevmapping *maps; - int num_irqs; - struct sdev_irqs irqinfo[NUM_SPARC_IRQS]; -}; - -struct sparcbus { - struct sparcbus *next; - enum bus_t type; - struct sparcdev *device_list; -}; - -/* Add more as appropriate. */ -struct sparcbus obiobus_info = { 0, OBIO_BUS, { 0, 0}, }; -struct sparcbus sbusbus_info = { 0, SBUS_BUS, { 0, 0}, }; -struct sparcbus pcibus_info = { 0, PCI_BUS, { 0, 0}, }; -struct sparcbus pmembus_info = { 0, PMEM_BUS, { 0, 0}, }; -struct sparcbus cpubus_info = { 0, CPU_BUS, { 0, 0}, }; - -struct sparcbus *sparcbus_list = 0; - -/* This is called at boot time to build the prom device tree. */ -int prom_build_devtree(unsigned long start_mem, unsigned long end_mem) -{ -} - -/* Search the bus device list for a device which matches one of the - * names in NAME_VECTOR which is an array or NUM_NAMES strings, given - * the passed BUSTYPE. Return ptr to the matching sparcdev structure - * or NULL if no matches found. - */ -struct sparcdev *prom_find_dev_on_bus(bus_t bustype, char **name_vector, int num_names) -{ - struct sparcdev *sdp; - struct sparcbus *thebus; - int niter; - - if(!num_names) - return 0; - - if(!sparcbus_list) { - prom_printf("prom_find_dev_on_bus: Device list not initted yet!\n"); - prom_halt(); - } - - while(thebus = sparcbus_list; thebus; thebus = thebus->next) - if(thebus->type == bustype) - break; - if(!thebus || !thebus->device_list) - return 0; - - for(sdp = thebus->device_list; sdp; sdp = sdp->next) { - for(niter = 0; niter < num_names; niter++) - if(!strcmp(sdp->name, name_vector[niter])) - break; - } - return sdp; -} - -/* Continue searching on a device list, starting at START_DEV for the next - * instance whose name matches one of the elements of NAME_VECTOR which is - * of length NUM_NAMES. - */ -struct sparcdev *prom_find_next_dev(struct sparcdev *start_dev, char **name_vector, int num_names) -{ - struct sparcdev *sdp; - int niter; - - if(!start_dev->next || !num_names) - return 0; - for(sdp = start_dev->next; sdp; sdp = sdp->next) { - for(niter = 0; niter < num_names; niter++) - if(!strcmp(sdp->name, name_vector[niter])) - break; - } - return sdp; -} diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c --- v1.3.92/linux/arch/sparc/prom/init.c Sat Nov 25 03:00:02 1995 +++ linux/arch/sparc/prom/init.c Sun Apr 21 12:30:32 1996 @@ -1,10 +1,11 @@ -/* $Id: init.c,v 1.6 1995/11/25 01:00:01 davem Exp $ +/* $Id: init.c,v 1.7 1996/04/04 16:31:00 tridge Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include @@ -33,6 +34,12 @@ { romvec = rp; +#if CONFIG_AP1000 + prom_vers = PROM_AP1000; + prom_meminit(); + prom_ranges_init(); + return; +#endif switch(romvec->pv_romvers) { case 0: prom_vers = PROM_V0; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c --- v1.3.92/linux/arch/sparc/prom/memory.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/prom/memory.c Sun Apr 21 12:30:32 1996 @@ -1,19 +1,21 @@ -/* $Id: memory.c,v 1.4 1995/11/25 01:00:02 davem Exp $ +/* $Id: memory.c,v 1.6 1996/04/08 09:02:27 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include + #include #include -/* This routine, for consistency, returns the ram parameters in the - * V0 prom memory descriptor format. I choose this format because I +/* This routine, for consistancy, returns the ram parameters in the + * V0 prom memory descriptor format. I choose this format becuase I * think it was the easiest to work with. I feel the religious * arguments now... ;) Also, I return the linked lists sorted to - * prevent paging_init() upset stomach as I have not yet written - * the pepto-bismol kernel module yet. + * prevent paging_init() upset stomache as I have not yet written + * the pepto-bismal kernel module yet. */ struct linux_prom_registers prom_reg_memlist[64]; @@ -173,7 +175,24 @@ /* Sort the other two lists. */ prom_sortmemlist(prom_phys_total); prom_sortmemlist(prom_phys_avail); + break; + case PROM_AP1000: + /* really simple memory map */ + prom_phys_total[0].start_adr = 0x00000000; + prom_phys_total[0].num_bytes = 0x01000000; /* 16MB */ + prom_phys_total[0].theres_more = 0x0; + prom_prom_taken[0].start_adr = 0x00000000; + prom_prom_taken[0].num_bytes = 0x00000000; + prom_prom_taken[0].theres_more = 0x0; + prom_phys_avail[0].start_adr = 0x00000000; + prom_phys_avail[0].num_bytes = 0x01000000; /* 16MB */ + prom_phys_avail[0].theres_more = 0x0; + prom_sortmemlist(prom_phys_total); + prom_sortmemlist(prom_prom_taken); + prom_sortmemlist(prom_phys_avail); + printk("Initialised AP1000 memory lists (forced 16MB)\n"); + break; }; /* Link all the lists into the top-level descriptor. */ diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/misc.c linux/arch/sparc/prom/misc.c --- v1.3.92/linux/arch/sparc/prom/misc.c Mon Mar 4 08:49:58 1996 +++ linux/arch/sparc/prom/misc.c Sun Apr 21 12:30:32 1996 @@ -1,10 +1,11 @@ -/* $Id: misc.c,v 1.5 1996/02/02 03:37:44 davem Exp $ +/* $Id: misc.c,v 1.8 1996/04/17 23:03:23 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include @@ -30,8 +31,11 @@ } /* We want to do this more nicely some day. */ +#if CONFIG_SUN_CONSOLE extern void console_restore_palette(void); extern void set_palette(void); +extern int serial_console; +#endif /* Drop into the prom, with the chance to continue with the 'go' * prom command. @@ -39,9 +43,22 @@ void prom_halt(void) { - console_restore_palette (); + extern void kernel_enter_debugger(void); + extern void install_obp_ticker(void); + extern void install_linux_ticker(void); + + kernel_enter_debugger(); +#if CONFIG_SUN_CONSOLE + if(!serial_console) + console_restore_palette (); +#endif + install_obp_ticker(); (*(romvec->pv_abort))(); - set_palette (); + install_linux_ticker(); +#if CONFIG_SUN_CONSOLE + if(!serial_console) + set_palette (); +#endif return; } @@ -62,6 +79,10 @@ void prom_setsync(sfunc_t funcp) { +#if CONFIG_AP1000 + printk("not doing setsync\n"); + return; +#endif if(!funcp) return; *romvec->pv_synchook = funcp; return; diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/mp.c linux/arch/sparc/prom/mp.c --- v1.3.92/linux/arch/sparc/prom/mp.c Sat Nov 25 03:00:08 1995 +++ linux/arch/sparc/prom/mp.c Sun Apr 21 12:30:32 1996 @@ -1,4 +1,4 @@ -/* $Id: mp.c,v 1.4 1995/11/25 01:00:06 davem Exp $ +/* $Id: mp.c,v 1.5 1996/04/04 16:31:06 tridge Exp $ * mp.c: OpenBoot Prom Multiprocessor support routines. Don't call * these on a UP or else you will halt and catch fire. ;) * @@ -19,6 +19,7 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: + case PROM_AP1000: break; case PROM_V3: case PROM_P1275: @@ -38,6 +39,7 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: + case PROM_AP1000: break; case PROM_V3: case PROM_P1275: @@ -57,6 +59,7 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: + case PROM_AP1000: break; case PROM_V3: case PROM_P1275: @@ -76,6 +79,7 @@ switch(prom_vers) { case PROM_V0: case PROM_V2: + case PROM_AP1000: break; case PROM_V3: case PROM_P1275: diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/palloc.c linux/arch/sparc/prom/palloc.c --- v1.3.92/linux/arch/sparc/prom/palloc.c Fri Apr 12 15:51:49 1996 +++ linux/arch/sparc/prom/palloc.c Sun Apr 21 12:30:32 1996 @@ -18,7 +18,7 @@ /* Allocate a chunk of memory of size 'num_bytes' giving a suggestion * of virtual_hint as the preferred virtual base address of this chunk. - * There are no guarantees that you will get the allocation, or that + * There are no guarentees that you will get the allocation, or that * the prom will abide by your "hint". So check your return value. */ char * diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/printf.c linux/arch/sparc/prom/printf.c --- v1.3.92/linux/arch/sparc/prom/printf.c Sat Nov 25 03:00:12 1995 +++ linux/arch/sparc/prom/printf.c Sun Apr 21 12:30:32 1996 @@ -1,4 +1,4 @@ -/* $Id: printf.c,v 1.4 1995/11/25 01:00:10 davem Exp $ +/* $Id: printf.c,v 1.5 1996/04/04 16:31:07 tridge Exp $ * printf.c: Internal prom library printf facility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,7 @@ * about or use it! It's simple and smelly anyway.... */ +#include #include #include @@ -27,13 +28,16 @@ bptr = ppbuf; +#if CONFIG_AP1000 + ap_write(1,bptr,strlen(bptr)); +#else while((ch = *(bptr++)) != 0) { if(ch == '\n') prom_putchar('\r'); prom_putchar(ch); } - +#endif va_end(args); return; } diff -u --recursive --new-file v1.3.92/linux/arch/sparc/prom/tree.c linux/arch/sparc/prom/tree.c --- v1.3.92/linux/arch/sparc/prom/tree.c Mon Mar 4 08:49:59 1996 +++ linux/arch/sparc/prom/tree.c Sun Apr 21 12:30:32 1996 @@ -1,10 +1,11 @@ -/* $Id: tree.c,v 1.7 1996/01/01 02:46:24 davem Exp $ +/* $Id: tree.c,v 1.8 1996/04/04 16:31:09 tridge Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ +#include #include #include @@ -20,6 +21,10 @@ { int cnode; +#if CONFIG_AP1000 + printk("prom_getchild -> 0\n"); + return 0; +#endif if(node == -1) return 0; cnode = prom_nodeops->no_child(node); if((cnode == 0) || (cnode == -1)) return 0; @@ -34,6 +39,10 @@ { int sibnode; +#if CONFIG_AP1000 + printk("prom_getsibling -> 0\n"); + return 0; +#endif if(node == -1) return 0; sibnode = prom_nodeops->no_nextnode(node); if((sibnode == 0) || (sibnode == -1)) return 0; @@ -46,6 +55,10 @@ int prom_getproplen(int node, char *prop) { +#if CONFIG_AP1000 + printk("prom_getproplen(%s) -> -1\n",prop); + return -1; +#endif if((!node) || (!prop)) return -1; return prom_nodeops->no_proplen(node, prop); } @@ -59,6 +72,10 @@ { int plen; +#if CONFIG_AP1000 + printk("prom_getproperty(%s) -> -1\n",prop); + return -1; +#endif plen = prom_getproplen(node, prop); if((plen > bufsize) || (plen == 0) || (plen == -1)) return -1; @@ -74,6 +91,10 @@ { static int intprop; +#if CONFIG_AP1000 + printk("prom_getint(%s) -> -1\n",prop); + return -1; +#endif if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) return intprop; @@ -89,6 +110,10 @@ { int retval; +#if CONFIG_AP1000 + printk("prom_getintdefault(%s) -> 0\n",property); + return 0; +#endif retval = prom_getint(node, property); if(retval == -1) return deflt; @@ -101,6 +126,10 @@ { int retval; +#if CONFIG_AP1000 + printk("prom_getbool(%s) -> 0\n",prop); + return 0; +#endif retval = prom_getproplen(node, prop); if(retval == -1) return 0; return 1; @@ -115,6 +144,10 @@ { int len; +#if CONFIG_AP1000 + printk("prom_getstring(%s) -> .\n",prop); + return; +#endif len = prom_getproperty(node, prop, user_buf, ubuf_size); if(len != -1) return; user_buf[0] = 0; diff -u --recursive --new-file v1.3.92/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.3.92/linux/drivers/block/floppy.c Sun Apr 21 12:39:00 1996 +++ linux/drivers/block/floppy.c Sun Apr 21 17:40:52 1996 @@ -1232,6 +1232,15 @@ break; case 1: dtr = 300; + if (FDCS->version >= FDC_82078) { + /* chose the default rate table, not the one + * where 1 = 2 Mbps */ + output_byte(FD_DRIVESPEC); + if(need_more_output() == MORE_OUTPUT) { + output_byte(UNIT(current_drive)); + output_byte(0xc0); + } + } break; case 2: dtr = 250; @@ -3007,7 +3016,15 @@ ptr->next = 0; ptr->buffer_length = 0; param += sizeof(struct floppy_raw_cmd); - if (ptr->cmd_count > 16) + if (ptr->cmd_count > 33) + /* the command may now also take up the space + * initially intended for the reply & the + * reply count. Needed for long 82078 commands + * such as RESTORE, which takes ... 17 command + * bytes. Murphy's law #137: When you reserve + * 16 bytes for a structure, you'll one day + * discover that you really need 17... + */ return -EINVAL; } @@ -3817,9 +3834,9 @@ printk(KERN_INFO "FDC %d is a National Semiconductor PC87306\n", fdc); return FDC_87306; default: - printk(KERN_INFO "FDC %d init: 82077 variant with PARTID=%d.\n", + printk(KERN_INFO "FDC %d init: 82078 variant with unknown PARTID=%d.\n", fdc, reply_buffer[0] >> 5); - return FDC_82077_UNKN; + return FDC_82078_UNKN; } } /* get_fdc_version */ diff -u --recursive --new-file v1.3.92/linux/drivers/block/linear.c linux/drivers/block/linear.c --- v1.3.92/linux/drivers/block/linear.c Fri Apr 12 15:51:50 1996 +++ linux/drivers/block/linear.c Sun Apr 21 11:03:53 1996 @@ -27,8 +27,6 @@ #define MD_DRIVER #define MD_PERSONALITY -#include - static int linear_run (int minor, struct md_dev *mddev) { int cur=0, i, size, dev0_size, nb_zone; @@ -105,76 +103,38 @@ } -static int linear_map (int minor, struct md_dev *mddev, struct request *req) +static int linear_map (struct md_dev *mddev, kdev_t *rdev, + unsigned long *rsector, unsigned long size) { struct linear_data *data=(struct linear_data *) mddev->private; struct linear_hash *hash; struct real_dev *tmp_dev; - long block, rblock; - struct buffer_head *bh, *bh2; - int queue, nblk; - static struct request pending[MAX_REAL]={{0, }, }; + long block; - while (req->nr_sectors) + block=*rsector >> 1; + hash=data->hash_table+(block/data->smallest->size); + + if (block >= (hash->dev0->size + hash->dev0->offset)) { - block=req->sector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - if (block >= (hash->dev0->size + hash->dev0->offset)) - { - if (!hash->dev1) - printk ("linear_map : hash->dev1==NULL for block %ld\n", block); - tmp_dev=hash->dev1; - } - else - tmp_dev=hash->dev0; - - if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) - printk ("Block %ld out of bounds on dev %04x size %d offset %d\n", block, tmp_dev->dev, tmp_dev->size, tmp_dev->offset); - - rblock=(block-(tmp_dev->offset)); - - if (req->sem) /* This is a paging request */ + if (!hash->dev1) { - req->rq_dev=tmp_dev->dev; - req->sector=rblock << 1; - add_request (blk_dev+MAJOR (tmp_dev->dev), req); - - return REDIRECTED_REQ; + printk ("linear_map : hash->dev1==NULL for block %ld\n", block); + return (-1); } - - queue=tmp_dev - devices[minor]; - - for (nblk=0, bh=bh2=req->bh; - bh && rblock + nblk + (bh->b_size >> 10) <= tmp_dev->size; - nblk+=bh->b_size >> 10, bh2=bh, bh=bh->b_reqnext) - { - if (!buffer_locked(bh)) - printk("md%d: block %ld not locked\n", minor, bh->b_blocknr); - - bh->b_rdev=tmp_dev->dev; - } - - pending[queue].rq_dev=tmp_dev->dev; - pending[queue].cmd=req->cmd; - pending[queue].sector=rblock << 1; - pending[queue].nr_sectors=nblk << 1; - pending[queue].current_nr_sectors=req->bh->b_size >> 9; - pending[queue].bh=req->bh; - pending[queue].bhtail=bh2; - bh2->b_reqnext=NULL; - req->bh=bh; - req->sector+=nblk << 1; - req->nr_sectors-=nblk << 1; + tmp_dev=hash->dev1; } + else + tmp_dev=hash->dev0; + + if (block >= (tmp_dev->size + tmp_dev->offset) || block < tmp_dev->offset) + printk ("Block %ld out of bounds on dev %04x size %d offset %d\n", block, tmp_dev->dev, tmp_dev->size, tmp_dev->offset); + + *rdev=tmp_dev->dev; + *rsector=(block-(tmp_dev->offset)) << 1; - req->rq_status=RQ_INACTIVE; - wake_up (&wait_for_request); - make_md_request (pending, mddev->nb_dev); - return REDIRECTED_REQ; + return (0); } - static int linear_status (char *page, int minor, struct md_dev *mddev) { diff -u --recursive --new-file v1.3.92/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.3.92/linux/drivers/block/ll_rw_blk.c Wed Apr 17 09:06:31 1996 +++ linux/drivers/block/ll_rw_blk.c Sun Apr 21 11:03:53 1996 @@ -226,14 +226,11 @@ * which is important for drive_stat_acct() above. */ -struct semaphore request_lock = MUTEX; - void add_request(struct blk_dev_struct * dev, struct request * req) { struct request * tmp; short disk_index; - down (&request_lock); switch (MAJOR(req->rq_dev)) { case SCSI_DISK_MAJOR: disk_index = (MINOR(req->rq_dev) & 0x0070) >> 4; @@ -254,11 +251,10 @@ req->next = NULL; cli(); - if (req->bh && req->bh->b_dev==req->bh->b_rdev) + if (req->bh) mark_buffer_clean(req->bh); if (!(tmp = dev->current_request)) { dev->current_request = req; - up (&request_lock); (dev->request_fn)(); sti(); return; @@ -272,9 +268,8 @@ req->next = tmp->next; tmp->next = req; - up (&request_lock); /* for SCSI devices, call request_fn unconditionally */ - if (scsi_major(MAJOR(req->rq_dev)) && MAJOR(req->rq_dev)!=MD_MAJOR) + if (scsi_major(MAJOR(req->rq_dev))) (dev->request_fn)(); sti(); @@ -287,13 +282,13 @@ int rw_ahead, max_req; count = bh->b_size >> 9; - sector = bh->b_blocknr * count; + sector = bh->b_rsector; if (blk_size[major]) - if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) { + if (blk_size[major][MINOR(bh->b_rdev)] < (sector + count)>>1) { bh->b_state = 0; printk("attempt to access beyond end of device\n"); - printk("%s: rw=%d, want=%d, limit=%d\n", kdevname(bh->b_dev), - rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_dev)]); + printk("%s: rw=%d, want=%d, limit=%d\n", kdevname(bh->b_rdev), + rw, (sector + count)>>1, blk_size[major][MINOR(bh->b_rdev)]); return; } /* Uhhuh.. Nasty dead-lock possible here.. */ @@ -313,7 +308,7 @@ return; } kstat.pgpgin++; - max_req = (major == MD_MAJOR) ? NR_REQUEST/2 : NR_REQUEST; /* reads take precedence */ + max_req = NR_REQUEST; /* reads take precedence */ break; case WRITEA: rw_ahead = 1; @@ -329,7 +324,7 @@ * requests are only for reads. */ kstat.pgpgout++; - max_req = (major == MD_MAJOR) ? NR_REQUEST/3 : (NR_REQUEST * 2) / 3; + max_req = (NR_REQUEST * 2) / 3; break; default: printk("make_request: bad block dev cmd, must be R/W/RA/WA\n"); @@ -338,7 +333,6 @@ } /* look for a free request. */ - down (&request_lock); /* * Try to coalesce the new request with old requests @@ -371,7 +365,6 @@ case SCSI_DISK_MAJOR: case SCSI_CDROM_MAJOR: - case MD_MAJOR: do { if (req->sem) @@ -380,7 +373,7 @@ continue; if (req->nr_sectors >= 244) continue; - if (req->rq_dev != bh->b_dev) + if (req->rq_dev != bh->b_rdev) continue; /* Can we add it to the end of this request? */ if (req->sector + req->nr_sectors == sector) { @@ -398,16 +391,13 @@ req->nr_sectors += count; mark_buffer_clean(bh); - up (&request_lock); sti(); return; } while ((req = req->next) != NULL); } - up (&request_lock); - /* find an unused request. */ - req = get_request(max_req, bh->b_dev); + req = get_request(max_req, bh->b_rdev); sti(); /* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */ @@ -416,7 +406,7 @@ unlock_buffer(bh); return; } - req = __get_request_wait(max_req, bh->b_dev); + req = __get_request_wait(max_req, bh->b_rdev); } /* fill up the request-info, and add it to the queue */ @@ -433,15 +423,6 @@ add_request(major+blk_dev,req); } -#ifdef CONFIG_BLK_DEV_MD - -struct request *get_md_request (int max_req, kdev_t dev) -{ - return (get_request_wait (max_req, dev)); -} - -#endif - /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ @@ -487,6 +468,16 @@ correct_size, bh[i]->b_size); goto sorry; } + + /* Md remaps blocks now */ + bh[i]->b_rdev = bh[i]->b_dev; + bh[i]->b_rsector=bh[i]->b_blocknr*(bh[i]->b_size >> 9); +#ifdef CONFIG_BLK_DEV_MD + if (major==MD_MAJOR && + md_map (MINOR(bh[i]->b_dev), &bh[i]->b_rdev, + &bh[i]->b_rsector, bh[i]->b_size >> 9)) + goto sorry; +#endif } if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { @@ -499,10 +490,7 @@ if (bh[i]) { set_bit(BH_Req, &bh[i]->b_state); - /* Md needs this for error recovery */ - bh[i]->b_rdev = bh[i]->b_dev; - - make_request(major, rw, bh[i]); + make_request(MAJOR(bh[i]->b_rdev), rw, bh[i]); } } return; @@ -521,6 +509,8 @@ { int i, j; int buffersize; + unsigned long rsector; + kdev_t rdev; struct request * req[8]; unsigned int major = MAJOR(dev); struct semaphore sem = MUTEX_LOCKED; @@ -548,25 +538,36 @@ { for (; j < 8 && i < nb; j++, i++, buf += buffersize) { + rdev = dev; + rsector = (b[i] * buffersize) >> 9; +#ifdef CONFIG_BLK_DEV_MD + if (major==MD_MAJOR && + md_map (MINOR(dev), &rdev, + &rsector, buffersize >> 9)) { + printk ("Bad md_map in ll_rw_page_size\n"); + return; + } +#endif + if (j == 0) { - req[j] = get_request_wait(NR_REQUEST, dev); + req[j] = get_request_wait(NR_REQUEST, rdev); } else { cli(); - req[j] = get_request(NR_REQUEST, dev); + req[j] = get_request(NR_REQUEST, rdev); sti(); if (req[j] == NULL) break; } req[j]->cmd = rw; req[j]->errors = 0; - req[j]->sector = (b[i] * buffersize) >> 9; + req[j]->sector = rsector; req[j]->nr_sectors = buffersize >> 9; req[j]->current_nr_sectors = buffersize >> 9; req[j]->buffer = buf; req[j]->sem = &sem; req[j]->bh = NULL; req[j]->next = NULL; - add_request(major+blk_dev,req[j]); + add_request(MAJOR(rdev)+blk_dev,req[j]); } run_task_queue(&tq_disk); while (j > 0) { diff -u --recursive --new-file v1.3.92/linux/drivers/block/md.c linux/drivers/block/md.c --- v1.3.92/linux/drivers/block/md.c Fri Apr 19 10:07:58 1996 +++ linux/drivers/block/md.c Sun Apr 21 11:03:53 1996 @@ -41,16 +41,6 @@ #include -#ifdef CONFIG_MD_SUPPORT_RAID5 -int support_for_raid5; /* So raid-5 module won't be inserted if support - was not set in the kernel */ -#endif - -#ifdef CONFIG_MD_SUPPORT_RAID1 -int support_for_raid1; /* So raid-1 module won't be inserted if support - was not set in the kernel */ -#endif - static struct hd_struct md_hd_struct[MAX_MD_DEV]; static int md_blocksizes[MAX_MD_DEV]; @@ -374,195 +364,29 @@ block_fsync }; - -static inline int remap_request (int minor, struct request *req) +int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size) { + if ((unsigned int) minor >= MAX_MD_DEV) + { + printk ("Bad md device %d\n", minor); + return (-1); + } + if (!md_dev[minor].pers) { printk ("Oops ! md%d not running, giving up !\n", minor); - return -1; + return (-1); } - return (md_dev[minor].pers->map(minor, md_dev+minor, req)); + return (md_dev[minor].pers->map(md_dev+minor, rdev, rsector, size)); } + static void do_md_request (void) { - int minor; - long flags; - struct request *req; - - while (1) - { -#ifdef MD_COUNT_SIZE - int reqsize, chunksize; -#endif - - save_flags (flags); - cli (); - req = blk_dev[MD_MAJOR].current_request; - if (!req || (req->rq_status == RQ_INACTIVE)) - { - restore_flags (flags); - return; - } - -#ifdef MD_COUNT_SIZE - reqsize=req->nr_sectors>>1; - chunksize=1 << FACTOR_SHIFT(FACTOR(md_dev+MINOR(req->rq_dev))); - if (reqsize==chunksize) (md_dev+MINOR(req->rq_dev))->equal_count++; - if (reqsizerq_dev))->smallest_count++; - if (reqsize>chunksize) (md_dev+MINOR(req->rq_dev))->biggest_count++; -#endif - - blk_dev[MD_MAJOR].current_request = req->next; - restore_flags (flags); - - minor = MINOR(req->rq_dev); - if ((MAJOR(req->rq_dev) != MD_MAJOR) || (minor >= MAX_REAL)) - { - printk("md: bad device: %s\n", kdevname(req->rq_dev)); - end_request(0, req); - continue; - } - - switch (remap_request (minor, req)) - { - case REDIRECTED_BHREQ: /* All right, redirection was successful */ - req->rq_status=RQ_INACTIVE; - wake_up (&wait_for_request); - break; - - case REDIRECTED_REQ: - break; /* Redirected whole request (for swapping) */ - - case REDIRECT_FAILED: /* Swap redirection failed in RAID-[15] */ - end_request (0, req); - break; - - default: - printk ("remap_request returned strange value !\n"); - } - } -} - -extern struct semaphore request_lock; - -void make_md_request (struct request *pending, int n) -{ - int i, j, max_req, major=0, rw, found; - kdev_t dev; - struct buffer_head *bh; - struct request *req; - long flags; - - down (&request_lock); - save_flags (flags); - cli(); - - for (i=0; i - * (He reads my own code better than I do... ;-) - */ - if (major != SCSI_DISK_MAJOR) - req = req->next; - - while (req && !found) - { - if (req->rq_status!=RQ_ACTIVE && &blk_dev[major].plug!=req) - printk ("Saw bad status request !\n"); - - if (req->rq_dev == dev && - !req->sem && - req->cmd == rw && - req->sector + req->nr_sectors == pending[i].sector && - (req->nr_sectors + pending[i].nr_sectors) < 245) - { - req->bhtail->b_reqnext = bh; - req->bhtail = pending[i].bhtail; - req->nr_sectors += pending[i].nr_sectors; - found=1; - continue; - } - - if (!found && - req->rq_dev == dev && - !req->sem && - req->cmd == rw && - req->sector - pending[i].nr_sectors == pending[i].sector && - (req->nr_sectors + pending[i].nr_sectors) < 245) - { - req->nr_sectors += pending[i].nr_sectors; - pending[i].bhtail->b_reqnext = req->bh; - req->buffer = bh->b_data; - req->current_nr_sectors = bh->b_size >> 9; - req->sector = pending[i].sector; - req->bh = bh; - found=1; - continue; - } - - req = req->next; - } - } - - if (found) - continue; - - up (&request_lock); - sti (); - req=get_md_request (max_req, dev); - - /* Build it up... */ - req->cmd = rw; - req->errors = 0; -#if defined (CONFIG_MD_SUPPORT_RAID1) - req->shared_count = 0; -#endif - req->sector = pending[i].sector; - req->nr_sectors = pending[i].nr_sectors; - req->current_nr_sectors = bh->b_size >> 9; - req->buffer = bh->b_data; - req->sem = NULL; - req->bh = bh; - req->bhtail = pending[i].bhtail; - req->next = NULL; - - add_request (blk_dev + MAJOR(dev), req); - down (&request_lock); - cli (); - } - - up (&request_lock); - restore_flags (flags); - for (j=0; j>PERSONALITY_SHIFT)]) { sz+=sprintf (page+sz, " %dk chunks", 1<status (page+sz, i, md_dev+i); @@ -679,90 +486,6 @@ return (sz); } -#if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5) - -int md_valid_device (int minor, kdev_t dev, int mode) -{ - int i; - - for (i=0; imd_dev[minor].nb_dev) - { - printk ("Oops, dev %04x not found in md_valid_device\n", dev); - return -EINVAL; - } - - switch (mode) - { - case VALID: - /* Don't consider INVALID_NEXT as a real invalidation. - Maybe that's not the good way to treat such a thing, - we'll see. */ - if (devices[minor][i].invalid==INVALID_ALWAYS) - { - devices[minor][i].fault_count=0; /* reset fault count */ - if (md_dev[minor].invalid_dev_count) - md_dev[minor].invalid_dev_count--; - } - break; - - case INVALID: - if (devices[minor][i].invalid != VALID ) - return 0; /* Don't invalidate twice */ - - if (++devices[minor][i].fault_count > MAX_FAULT(md_dev+minor) && - MAX_FAULT(md_dev+minor)!=0xFF) - { - /* We cannot tolerate this fault. - So sing a song, and say GoodBye to this device... */ - - mode=INVALID_ALWAYS; - md_dev[minor].invalid_dev_count++; - } - else - /* FIXME : - If we reached the max_invalid_dev count, doing one - more invalidation will kill the md_dev. So we choose - not to invalid the physical dev in such a case. But - next access will probably fail... */ - if (md_dev[minor].invalid_dev_count<=md_dev[minor].pers->max_invalid_dev) - mode=INVALID_NEXT; - else - mode=VALID; - break; - - case INVALID_ALWAYS: /* Only used via MD_INVALID ioctl */ - md_dev[minor].invalid_dev_count++; - } - - devices[minor][i].invalid=mode; - return 0; -} - - -int md_can_reemit (int minor) -{ - /* FIXME : - If the device is raid-1 (md_dev[minor].pers->max_invalid_dev=-1), - always pretend that we can reemit the request. - Problem : if the 2 devices in the pair are dead, will loop - forever. Maybe having a per-personality can_reemit function would - help. */ - - if (!md_dev[minor].pers) - return (0); - - return(md_dev[minor].pers->max_invalid_dev && - ((md_dev[minor].pers->max_invalid_dev==-1) ? - 1 : - md_dev[minor].invalid_dev_count<=md_dev[minor].pers->max_invalid_dev)); -} - -#endif - int register_md_personality (int p_num, struct md_personality *p) { int i=(p_num >> PERSONALITY_SHIFT); @@ -817,12 +540,6 @@ #endif #ifdef CONFIG_MD_STRIPED raid0_init (); -#endif -#ifdef CONFIG_MD_RAID1 - raid1_init (); -#endif -#ifdef CONFIG_MD_RAID5 - raid5_init (); #endif return (0); diff -u --recursive --new-file v1.3.92/linux/drivers/block/raid0.c linux/drivers/block/raid0.c --- v1.3.92/linux/drivers/block/raid0.c Fri Apr 12 15:51:50 1996 +++ linux/drivers/block/raid0.c Sun Apr 21 11:03:53 1996 @@ -17,7 +17,6 @@ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include @@ -27,8 +26,6 @@ #define MD_DRIVER #define MD_PERSONALITY -#include - static void create_strip_zones (int minor, struct md_dev *mddev) { int i, j, c=0; @@ -179,92 +176,54 @@ * Of course, those facts may not be valid anymore (and surely won't...) * Hey guys, there's some work out there ;-) */ -static int raid0_map (int minor, struct md_dev *mddev, struct request *req) +static int raid0_map (struct md_dev *mddev, kdev_t *rdev, + unsigned long *rsector, unsigned long size) { struct raid0_data *data=(struct raid0_data *) mddev->private; static struct raid0_hash *hash; struct strip_zone *zone; struct real_dev *tmp_dev; - int i, queue, blk_in_chunk, factor, chunk; + int blk_in_chunk, factor, chunk, chunk_size; long block, rblock; - struct buffer_head *bh; - static struct request pending[MAX_REAL]={{0, }, }; factor=FACTOR(mddev); + chunk_size=(1UL << FACTOR_SHIFT(factor)); + block=*rsector >> 1; + hash=data->hash_table+(block/data->smallest->size); - while (req->bh || req->sem) + /* Sanity check */ + if ((chunk_size*2)<(*rsector % (chunk_size*2))+size) { - block=req->sector >> 1; - hash=data->hash_table+(block/data->smallest->size); - - if (block >= (hash->zone0->size + - hash->zone0->zone_offset)) - { - if (!hash->zone1) - printk ("raid0_map : hash->zone1==NULL for block %ld\n", block); - zone=hash->zone1; - } - else - zone=hash->zone0; - - blk_in_chunk=block & ((1UL << FACTOR_SHIFT(factor)) - 1); - chunk=(block - zone->zone_offset) / (zone->nb_dev<dev[(block >> FACTOR_SHIFT(factor)) % zone->nb_dev]; - rblock=(chunk << FACTOR_SHIFT(factor)) + blk_in_chunk + zone->dev_offset; - - if (req->sem) /* This is a paging request */ + printk ("raid0_convert : can't convert block across chunks or bigger than %dk %ld %ld\n", chunk_size, *rsector, size); + return (-1); + } + + if (block >= (hash->zone0->size + + hash->zone0->zone_offset)) + { + if (!hash->zone1) { - req->rq_dev=tmp_dev->dev; - req->sector=rblock << 1; - add_request (blk_dev+MAJOR (tmp_dev->dev), req); - - return REDIRECTED_REQ; + printk ("raid0_convert : hash->zone1==NULL for block %ld\n", block); + return (-1); } - - queue=tmp_dev - devices[minor]; - /* This is a buffer request */ - for (i=blk_in_chunk; - i<(1UL << FACTOR_SHIFT(factor)) && req->bh; - i+=bh->b_size >> 10) - { - bh=req->bh; - if (!buffer_locked(bh)) - printk("md%d: block %ld not locked\n", minor, bh->b_blocknr); - - bh->b_rdev=tmp_dev->dev; -#if defined (CONFIG_MD_SUPPORT_RAID1) - bh->b_reqshared=NULL; - bh->b_sister_req=NULL; -#endif - - if (!pending[queue].bh) - { - pending[queue].rq_dev=tmp_dev->dev; - pending[queue].bhtail=pending[queue].bh=bh; - pending[queue].sector=rblock << 1; - pending[queue].cmd=req->cmd; - pending[queue].current_nr_sectors= - pending[queue].nr_sectors=bh->b_size >> 9; - } - else - { - pending[queue].bhtail->b_reqnext=bh; - pending[queue].bhtail=bh; - pending[queue].nr_sectors+=bh->b_size >> 9; - } - - end_redirect (req); /* Separate bh from the request */ - } + zone=hash->zone1; } + else + zone=hash->zone0; + + blk_in_chunk=block & (chunk_size -1); + chunk=(block - zone->zone_offset) / (zone->nb_dev<dev[(block >> FACTOR_SHIFT(factor)) % zone->nb_dev]; + rblock=(chunk << FACTOR_SHIFT(factor)) + blk_in_chunk + zone->dev_offset; - req->rq_status=RQ_INACTIVE; - wake_up (&wait_for_request); - make_md_request (pending, mddev->nb_dev); - return REDIRECTED_REQ; /* Since we already set the request free */ -} + *rdev=tmp_dev->dev; + *rsector=rblock<<1; + return (0); +} + static int raid0_status (char *page, int minor, struct md_dev *mddev) { int sz=0; diff -u --recursive --new-file v1.3.92/linux/drivers/char/README.cyclomY linux/drivers/char/README.cyclomY --- v1.3.92/linux/drivers/char/README.cyclomY Sun Apr 21 12:39:00 1996 +++ linux/drivers/char/README.cyclomY Sun Apr 21 10:28:44 1996 @@ -1,6 +1,6 @@ -NOTE: Earlier versions of the driver mapped ttyS0 to minor -number 32, but this is changed in this distribution. Port ttyS0 +NOTE: Earlier versions of the driver mapped ttyC0 to minor +number 32, but this is changed in this distribution. Port ttyC0 now maps to minor number 0.) The following patch should be applied to /dev/MAKEDEV and the script should then be re-run to create new entries for the ports. diff -u --recursive --new-file v1.3.92/linux/drivers/char/suncons.c linux/drivers/char/suncons.c --- v1.3.92/linux/drivers/char/suncons.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/suncons.c Sun Apr 21 17:32:01 1996 @@ -0,0 +1,1874 @@ +/* suncons.c: Sun SparcStation console support. + * + * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su) + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx) + * Added render_screen and faster scrolling Nov/27, miguel + * Added console palette code for cg6 Dec/13/95, miguel + * Added generic frame buffer support Dec/14/95, miguel + * Added cgsix and bwtwo drivers Jan/96, miguel + * Added 4m, and cg3 driver Feb/96, miguel + * Fixed the cursor on color displays Feb/96, miguel. + * + * Cleaned up the detection code, generic 8bit depth display + * code, Mar/96 miguel + * + * This file contains the frame buffer device drivers. + * Each driver is kept together in case we would like to + * split this file. + * + * Much of this driver is derived from the DEC TGA driver by + * Jay Estabrook who has done a nice job with the console + * driver abstraction btw. + * + * We try to make everything a power of two if possible to + * speed up the bit blit. Doing multiplies, divides, and + * remainer routines end up calling software library routines + * since not all Sparcs have the hardware to do it. + * + * TODO: + * do not use minor to index into instances of the frame buffer, + * since the numbers assigned to us are not consecutive. + * + * do not blank the screen when frame buffer is mapped. + * + * Change the detection loop to use more than one video card. + */ + + +/* Define thie one if you are debugging something in X, it will not disable the console output */ +/* #define DEBUGGING_X */ +/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */ + +#define GRAPHDEV_MAJOR 29 + +#define FRAME_BUFFERS 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for the sun4c_nocache */ + +#include "kbd_kern.h" +#include "vt_kern.h" +#include "consolemap.h" +#include "selection.h" +#include "console_struct.h" + +#define cmapsz 8192 + +extern void register_console(void (*proc)(const char *)); +extern void console_print(const char *); +extern unsigned char vga_font[]; +extern int graphics_on; +extern int serial_console; + +/* Based upon what the PROM tells us, we can figure out where + * the console is currently located. The situation can be either + * of the following two scenerios: + * + * 1) Console i/o is done over the serial line, ttya or ttyb + * 2) Console output on frame buffer (video card) and input + * coming from the keyboard/mouse which each use a zilog8530 + * serial channel a piece. + */ + +/* The following variables describe a Sparc console. */ + +/* From the PROM */ +static char con_name[40]; + +/* Screen dimensions and color depth. */ +static int con_depth, con_width, con_height, con_type; + +static int con_linebytes; + +/* Base address of first line. */ +static unsigned char *con_fb_base; + +/* Screen parameters: we compute those at startup to make the code faster */ +static int chars_per_line; /* number of bytes per line */ +static int ints_per_line; /* number of ints per line */ +static int skip_bytes; /* number of bytes we skip for the y margin */ +static int x_margin, y_margin; /* the x and y margins */ +static int bytes_per_row; /* bytes used by one screen line (of 16 scan lines) */ + +/* Functions used by the SPARC dependant console code + * to perform the restore_palette function. + */ +static void (*restore_palette)(void); +void set_palette (void); + + + /* Our screen looks like at 1152 X 900: + * + * 0,0 + * ------------------------------------------------------------------ + * | ^^^^^^^^^^^ | + * | 18 y-pixels | + * | ^^^^^^^^^^^ | + * 13 | <-64 pixels->| <-- 128 8x16 characters --> | <-64 pixels-> | + * .... + * 54 chars from top to bottom + * .... + * 888 | <-64 pixels->| <-- 128 8x16 characters --> | <-64 pixels-> | + * | ^^^^^^^^^^^ | + * | 18 y-pixels | + * | ^^^^^^^^^^^ | + * ------------------------------------------------------------------ + */ +/* First for MONO displays. */ +#define SCREEN_WIDTH 1152 /* Screen width in pixels */ +#define SCREEN_HEIGHT 900 /* Screen height in pixels */ +#define CHARS_PER_LINE 144 /* Make this imperical for speed */ +#define NICE_Y_MARGIN 18 /* We skip 18 y-pixels at top/bottom */ +#define NICE_X_MARGIN 8 /* We skip 64 x-pixels at left/right */ +#define FBUF_TOP_SKIP 2592 /* Imperical, (CHARS_PER_LINE * NICE_Y_MARGIN) */ +#define CHAR_HEIGHT 16 +#define ONE_ROW 2304 /* CHARS_PER_LINE * CHAR_HEIGHT */ + +/* Now we have this, to compute the base frame buffer position + * for a new character to be rendered. 1 and 8 bit depth. + */ +#define FBUF_OFFSET(cindex) \ + (((FBUF_TOP_SKIP) + (((cindex)>>7) * ONE_ROW)) + \ + ((NICE_X_MARGIN) + (((cindex)&127)))) + + +#define COLOR_FBUF_OFFSET(cindex) \ + (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \ + ((x_margin) + (((cindex)&127) << 3))) + +void +__set_origin(unsigned short offset) +{ + /* + * should not be called, but if so, do nothing... + */ +} + +/* For the cursor, we just invert the 8x16 block at the cursor + * location. Easy enough... + * + * Hide the cursor from view, during blanking, usually... + */ +static int cursor_pos = -1; +void +hide_cursor(void) +{ + unsigned long flags; + int j; + + save_flags(flags); cli(); + + if(cursor_pos == -1) { + restore_flags (flags); + return; + } + /* We just zero out the area for now. Certain graphics + * cards like the cg6 have a hardware cursor that we could + * use, but this is an optimization for some time later. + */ + switch (con_depth){ + case 1: { + unsigned char *dst; + dst = (unsigned char *)((unsigned long)con_fb_base + + FBUF_OFFSET(cursor_pos)); + for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE) + *dst = ~(0); + break; + } + case 8: { + unsigned long *dst; + const int ipl = ints_per_line; + + dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos)); + for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) { + *dst = ~(0UL); + *(dst + 1) = ~(0UL); + } + break; + } + default: + break; + } + restore_flags(flags); +} + +/* The idea is the following: + * we only use the colors in the range 0..15, and we only + * setup the palette on that range, so we better keep the + * pixel inverion using those colors, that's why we have + * those constants below. + */ +inline static void +cursor_reverse (long *dst, int height, const int ints_on_line) +{ + int j; + + for (j = 0; j < height; j++){ + *dst = ~(*dst) & 0x0f0f0f0f; + *(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f; + dst += ints_on_line; + } +} + +void +set_cursor(int currcons) +{ + int j, idx, oldpos; + unsigned long flags; + + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) + return; + + if (__real_origin != __origin) + __set_origin(__real_origin); + + save_flags(flags); cli(); + + idx = (pos - video_mem_base) >> 1; + oldpos = cursor_pos; + cursor_pos = idx; + if (!deccm) { + hide_cursor (); + restore_flags (flags); + return; + } + switch (con_depth){ + case 1: { + unsigned char *dst, *opos; + + dst = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(idx)); + opos = (unsigned char *)((unsigned long)con_fb_base + FBUF_OFFSET(oldpos)); + if(oldpos != -1) { + /* Restore what was at the old position */ + for(j=0; j < CHAR_HEIGHT; j++, opos += CHARS_PER_LINE) { + *opos = ~*opos; + } + } + for(j=0; j < 16; j++, dst+=CHARS_PER_LINE) { + *dst = ~*dst; + } + break; + } + case 8: { + unsigned long *dst, *opos; + dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx)); + opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos)); + + if(oldpos != -1) + cursor_reverse(opos, CHAR_HEIGHT, ints_per_line); + cursor_reverse (dst, CHAR_HEIGHT, ints_per_line); + break; + } + default: + } + restore_flags(flags); +} + +/* + * Render the current screen + * Only used at startup to avoid the caching that is being done in selection.h + */ +static void +render_screen(void) +{ + int count; + unsigned short *contents; + + count = video_num_columns * video_num_lines; + contents = (unsigned short *) video_mem_base; + + for (;count--; contents++) + sun_blitc (*contents, (unsigned long) contents); +} + +unsigned long +con_type_init(unsigned long kmem_start, const char **display_desc) +{ + can_do_color = (con_type != FBTYPE_SUN2BW); + + video_type = VIDEO_TYPE_SUN; + *display_desc = "SUN"; + + if (!serial_console) { + /* If we fall back to PROM than our output have to remain readable. */ + prom_putchar('\033'); prom_putchar('['); prom_putchar('H'); + + /* + * fake the screen memory with some CPU memory + */ + video_mem_base = kmem_start; + kmem_start += video_screen_size; + video_mem_term = kmem_start; + + render_screen(); + } + return kmem_start; +} + +/* + * NOTE: get_scrmem() and set_scrmem() are here only because + * the VGA version of set_scrmem() has some direct VGA references. + */ +void +get_scrmem(int currcons) +{ + memcpyw((unsigned short *)vc_scrbuf[currcons], + (unsigned short *)origin, video_screen_size); + origin = video_mem_start = (unsigned long)vc_scrbuf[currcons]; + scr_end = video_mem_end = video_mem_start + video_screen_size; + pos = origin + y*video_size_row + (x<<1); +} + +void +set_scrmem(int currcons, long offset) +{ + if (video_mem_term - video_mem_base < offset + video_screen_size) + offset = 0; + memcpyw((unsigned short *)(video_mem_base + offset), + (unsigned short *) origin, video_screen_size); + video_mem_start = video_mem_base; + video_mem_end = video_mem_term; + origin = video_mem_base + offset; + scr_end = origin + video_screen_size; + pos = origin + y*video_size_row + (x<<1); +} + +/* + * PIO_FONT support. + */ +int +set_get_font(char * arg, int set, int ch512) +{ + int error, i, line; + + if (!arg) + return -EINVAL; + error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg, + ch512 ? 2* cmapsz : cmapsz); + if (error) + return error; + + /* download the current font */ + if (!set){ + memset (arg, 0, cmapsz); + for (i = 0; i < 256; i++) + for (line = 0; line < CHAR_HEIGHT; line++) + put_user (vga_font [i], arg+(i*32+line)); + return 0; + } + + /* set the font */ + for (i = 0; i < 256; i++) + for (line = 0; line < CHAR_HEIGHT; line++){ + vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line))); + if (con_depth == 1) + vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line]; + } + return 0; +} + +/* + * Adjust the screen to fit a font of a certain height + * + * Returns < 0 for error, 0 if nothing changed, and the number + * of lines on the adjusted console if changed. + * + * for now, we only support the built-in font... + */ +int +con_adjust_height(unsigned long fontheight) +{ + return -EINVAL; +} + +int +set_get_cmap(unsigned char * arg, int set) +{ + int i; + + i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3); + if (i) + return i; + + for (i=0; i<16; i++) { + if (set) { + default_red[i] = get_user(arg++) ; + default_grn[i] = get_user(arg++) ; + default_blu[i] = get_user(arg++) ; + } else { + put_user (default_red[i], arg++) ; + put_user (default_grn[i], arg++) ; + put_user (default_blu[i], arg++) ; + } + } + if (set) { + for (i=0; ivc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + } + set_palette(); + } + + return 0; +} + + +void +sun_clear_screen(void) +{ + memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)), + (con_depth * con_height * con_width) / 8); + /* also clear out the "shadow" screen memory */ + memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base)); +} + +/* + * dummy routines for the VESA blanking code, which is VGA only, + * so we don't have to carry that stuff around for the Sparc... + */ +void vesa_blank(void) +{ +} +void vesa_unblank(void) +{ +} +void set_vesa_blanking(const unsigned long arg) +{ +} + +void vesa_powerdown(void) +{ +} + +#undef color +/* cg6 cursor status, kernel tracked copy */ +struct cg6_cursor { + short enable; /* cursor is enabled */ + struct fbcurpos cpos; /* position */ + struct fbcurpos chot; /* hot-spot */ + struct fbcurpos size; /* size of mask & image fields */ + int bits[2][32]; /* space for mask & image bits */ + char color [6]; /* cursor colors */ +}; + +struct cg6_info { + struct bt_regs *bt; /* color control */ + void *fbc; + struct cg6_fhc *fhc; + struct cg6_tec *tec; + struct cg6_thc *thc; + struct cg6_cursor cursor; /* cursor control */ + void *dhc; +}; + +struct bwtwo_info { + struct bwtwo_regs *regs; +}; + +struct cg3_info { + struct bt_regs *bt; /* brooktree (color) registers */ +}; + +/* Array holding the information for the frame buffers */ +typedef struct { + union { + struct bwtwo_info bwtwo; + struct cg3_info cg3; + struct cg6_info cg6; + } info; /* per frame information */ + int space; /* I/O space this card resides in */ + int blanked; /* true if video blanked */ + int open; /* is this fb open? */ + int mmaped; /* has this fb been mmapped? */ + int vtconsole; /* virtual console where it is opened */ + long base; /* frame buffer base */ + struct fbtype type; /* frame buffer type */ + int (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *); + void (*loadcmap)(void *this, int index, int count); + void (*blank)(void *this); + void (*unblank)(void *this); + int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *); +} fbinfo_t; + +static fbinfo_t fbinfo [FRAME_BUFFERS]; + +/* We need to keep a copy of the color map to answer ioctl requests */ +static union { + unsigned char map[256][3]; /* reasonable way to access */ + unsigned int raw[256*3/4]; /* hardware wants it like this */ +} color_map; + +#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED) + +static int +fb_open (struct inode * inode, struct file * file) +{ + int minor = MINOR (inode->i_rdev); + + if (minor >= FRAME_BUFFERS) + return -EBADF; + if (fbinfo [minor].open) + return -EBUSY; + fbinfo [minor].open = 1; + fbinfo [minor].mmaped = 0; + return 0; +} + +static int +fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int minor = MINOR (inode->i_rdev); + fbinfo_t *fb; + struct fbcmap *cmap; + int i; + + if (minor >= FRAME_BUFFERS) + return -EBADF; + fb = &fbinfo [minor]; + + switch (cmd){ + case FBIOGTYPE: /* return frame buffer type */ + i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype)); + if (i) return i; + *(struct fbtype *)arg = (fb->type); + break; + case FBIOGATTR:{ + struct fbgattr *fba = (struct fbgattr *) arg; + + i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr)); + if (i) return i; + fba->real_type = fb->type.fb_type; + fba->owner = 0; + fba->fbtype = fb->type; + fba->sattr.flags = 0; + fba->sattr.emu_type = fb->type.fb_type; + fba->sattr.dev_specific [0] = -1; + fba->emu_types [0] = fb->type.fb_type; + fba->emu_types [1] = -1; + break; + } + case FBIOSVIDEO: + i = verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if (i) return i; + + if (*(int *)arg){ + if (!fb->blanked || !fb->unblank) + break; + (*fb->unblank)(fb); + fb->blanked = 0; + } else { + if (fb->blanked || !fb->blank) + break; + (*fb->blank)(fb); + fb->blanked = 1; + } + break; + case FBIOGVIDEO: + i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)); + if (i) return i; + *(int *) arg = fb->blanked; + break; + case FBIOPUTCMAP: { /* load color map entries */ + char *rp, *gp, *bp; + int end, count;; + + if (!fb->loadcmap) + return -EINVAL; + i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap)); + if (i) return i; + cmap = (struct fbcmap *) arg; + count = cmap->count; + if ((cmap->index < 0) || (cmap->index > 255)) + return -EINVAL; + if (cmap->index + count > 256) + count = 256 - cmap->index; + i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count); + if (i) return i; + i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count); + if (i) return i; + i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count); + if (i) return i; + + end = cmap->index + count; + for (i = cmap->index; i < end; i++){ + color_map.map [i][0] = *rp++; + color_map.map [i][1] = *gp++; + color_map.map [i][2] = *bp++; + } + (*fb->loadcmap)(fb, cmap->index, count); + break; + } + + default: + if (fb->ioctl){ + i = fb->ioctl (inode, file, cmd, arg, fb); + if (i == -EINVAL) + printk ("[[FBIO: %8.8x]]\n", cmd); + return i; + } + printk ("[[FBIO: %8.8x]]\n", cmd); + return -EINVAL; + } + return 0; +} + +static void +fb_close (struct inode * inode, struct file *filp) +{ + int minor = MINOR(inode->i_rdev); + struct fbcursor cursor; + + if (minor >= FRAME_BUFFERS) + return; + if (fbinfo [minor].open) + fbinfo [minor].open = 0; + vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT; + + /* Leaving graphics mode, turn off the cursor */ + graphics_on = 0; + if (fbinfo [minor].mmaped) + sun_clear_screen (); + cursor.set = FB_CUR_SETCUR; + cursor.enable = 0; + fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor); + set_palette (); + render_screen (); + return; +} + +static int +fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma) +{ + int minor = MINOR (inode->i_rdev); + fbinfo_t *fb; + + if (minor >= FRAME_BUFFERS) + return -ENXIO; + /* FIXME: the fg_console below should actually be the + * console on which the invoking process is running + */ + if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS) + return -ENXIO; + fbinfo [minor].vtconsole = fg_console; + fb = &fbinfo [minor]; + + if (fb->mmap){ + int v; + + v = (*fb->mmap)(inode, file, vma, fb->base, fb); + if (v) return v; + fbinfo [minor].mmaped = 1; + vt_cons [fg_console]->vc_mode = KD_GRAPHICS; + graphics_on = 1; + return 0; + } else + return -ENXIO; +} + +static struct file_operations graphdev_fops = +{ + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + fb_ioctl, + fb_mmap, + fb_open, /* open */ + fb_close, /* close */ +}; + +/* Call the frame buffer routine for setting the palette */ +void +set_palette (void) +{ + if (console_blanked || vt_cons [fg_console]->vc_mode == KD_GRAPHICS) + return; + + if (fbinfo [0].loadcmap){ + int i, j; + + /* First keep color_map with the palette colors */ + for (i = 0; i < 16; i++){ + j = color_table [i]; + color_map.map [i][0] = default_red [j]; + color_map.map [i][1] = default_grn [j]; + color_map.map [i][2] = default_blu [j]; + } + (*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16); + } +} + +/* Called when returning to prom */ +void +console_restore_palette (void) +{ + if (restore_palette) + (*restore_palette) (); +} + +/* This routine should be moved to srmmu.c */ +static __inline__ unsigned int +srmmu_get_pte (unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlda [%1] %2,%0\n\t" : + "=r" (entry): + "r" ((addr & 0xfffff000) | 0x400), "i" (ASI_M_FLUSH_PROBE)); + return entry; +} + +unsigned int +get_phys (unsigned int addr) +{ + switch (sparc_cpu_model){ + case sun4c: + return sun4c_get_pte (addr) << PAGE_SHIFT; + case sun4m: + return ((srmmu_get_pte (addr) & 0xffffff00) << 4); + default: + panic ("get_phys called for unsupported cpu model\n"); + return 0; + } +} + +/* CG6 support code */ + +/* Offset of interesting structures in the OBIO space */ +/* + * Brooktree is the video dac and is funny to program on the cg6. + * (it's even funnier on the cg3) + * The FBC could be the the frame buffer control + * The FHC could be the frame buffer hardware control. + */ +#define CG6_ROM_OFFSET 0x0 +#define CG6_BROOKTREE_OFFSET 0x200000 +#define CG6_DHC_OFFSET 0x240000 +#define CG6_ALT_OFFSET 0x280000 +#define CG6_FHC_OFFSET 0x300000 +#define CG6_THC_OFFSET 0x301000 +#define CG6_FBC_OFFSET 0x700000 +#define CG6_TEC_OFFSET 0x701000 +#define CG6_RAM_OFFSET 0x800000 + +struct bt_regs { + unsigned int addr; /* address register */ + unsigned int color_map; /* color map */ + unsigned int control; /* control register */ + unsigned int cursor; /* cursor map register */ +}; + +/* The contents are unknown */ +struct cg6_tec { + int tec_matrix; + int tec_clip; + int tec_vdc; +}; + +struct cg6_thc { + unsigned int thc_xxx0[512]; /* ??? */ + unsigned int thc_hsync1; /* hsync timing */ + unsigned int thc_hsync2; + unsigned int thc_hsync3; + unsigned int thc_vsync1; /* vsync timing */ + unsigned int thc_vsync2; + unsigned int thc_refresh; + unsigned int thc_misc; + unsigned int thc_xxx1[56]; + unsigned int thc_cursxy; /* cursor x,y position (16 bits each) */ + unsigned int thc_cursmask[32]; /* cursor mask bits */ + unsigned int thc_cursbits[32]; /* what to show where mask enabled */ +}; + +static void +cg6_restore_palette (void) +{ + volatile struct bt_regs *bt; + + bt = fbinfo [0].info.cg6.bt; + bt->addr = 0; + bt->color_map = 0xffffffff; + bt->color_map = 0xffffffff; + bt->color_map = 0xffffffff; +} + +/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */ +/* So, we just mmap the things that are being asked for */ +static int +cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx) +{ + unsigned int size, page, r, map_size; + unsigned int map_offset = 0; + fbinfo_t *fb = (fbinfo_t *) xx; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + /* To stop the swapper from even considering these pages */ + vma->vm_flags |= FB_MMAP_VM_FLAGS; + + /* Each page, see which map applies */ + for (page = 0; page < size; ){ + switch (vma->vm_offset+page){ + case CG6_TEC: + map_size = PAGE_SIZE; + map_offset = get_phys ((uint)fb->info.cg6.tec); + break; + case CG6_FBC: + map_size = PAGE_SIZE; + map_offset = get_phys ((uint)fb->info.cg6.fbc); + break; + case CG6_FHC: + map_size = PAGE_SIZE; + map_offset = get_phys ((uint)fb->info.cg6.fhc); + break; + case CG6_THC: + map_size = PAGE_SIZE; + map_offset = get_phys ((uint)fb->info.cg6.thc); + break; + case CG6_BTREGS: + map_size = PAGE_SIZE; + map_offset = get_phys ((uint)fb->info.cg6.bt); + break; + + case CG6_DHC: + map_size = PAGE_SIZE * 40; + map_offset = get_phys ((uint)fb->info.cg6.dhc); + break; + + case CG6_ROM: + map_size = 0; + break; + + case CG6_RAM: + map_size = size-page; + map_offset = get_phys ((uint) con_fb_base); + if (map_size < fb->type.fb_size) + map_size = fb->type.fb_size; + break; + default: + map_size = 0; + break; + } + if (!map_size){ + page += PAGE_SIZE; + continue; + } + r = io_remap_page_range (vma->vm_start+page, + map_offset, + map_size, vma->vm_page_prot, + fb->space); + if (r) return -EAGAIN; + page += map_size; + } + vma->vm_inode = inode; + inode->i_count++; + return 0; +} + +#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2)) /* (x / 4) * 3 */ +#define BT_D4M4(x) ((x) & ~3) /* (x / 4) * 4 */ + +static void +cg6_loadcmap (void *fbinfo, int index, int count) +{ + fbinfo_t *fb = (fbinfo_t *) fbinfo; + struct bt_regs *bt = fb->info.cg6.bt; + int i; + + bt->addr = index << 24; + for (i = index; count--; i++){ + bt->color_map = color_map.map [i][0] << 24; + bt->color_map = color_map.map [i][1] << 24; + bt->color_map = color_map.map [i][2] << 24; + } +} + +/* Load cursor information */ +static void +cg6_setcursor (struct cg6_info *info) +{ + unsigned int v; + struct cg6_cursor *c = &info->cursor; + + if (c->enable){ + v = ((c->cpos.fbx - c->chot.fbx) << 16) + |((c->cpos.fby - c->chot.fby) & 0xffff); + } else { + /* Magic constant to turn off the cursor */ + v = ((65536-32) << 16) | (65536-32); + } + info->thc->thc_cursxy = v; +} + +#undef pos +static int +cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb) +{ + int op = cursor->set; + volatile struct cg6_thc *thc = fb->info.cg6.thc; + struct cg6_cursor *cursor_info = &fb->info.cg6.cursor; + int i, bytes = 0; + + if (op & FB_CUR_SETSHAPE){ + if ((unsigned int) cursor->size.fbx > 32) + return -EINVAL; + if ((unsigned int) cursor->size.fby > 32) + return -EINVAL; + bytes = (cursor->size.fby * 32)/8; + i = verify_area (VERIFY_READ, cursor->image, bytes); + if (i) return i; + i = verify_area (VERIFY_READ, cursor->mask, bytes); + if (i) return i; + } + if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){ + if (op & FB_CUR_SETCUR) + cursor_info->enable = cursor->enable; + if (op & FB_CUR_SETPOS) + cursor_info->cpos = cursor->pos; + if (op & FB_CUR_SETHOT) + cursor_info->chot = cursor->hot; + cg6_setcursor (&fb->info.cg6); + } + if (op & FB_CUR_SETSHAPE){ + unsigned int u; + + cursor_info->size = cursor->size; + memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size)); + memcpy (cursor_info->bits [0], cursor->mask, bytes); + memcpy (cursor_info->bits [1], cursor->image, bytes); + u = ~0; + if (cursor_info->size.fbx < 32) + u = ~(u >> cursor_info->size.fbx); + for (i = 0; i < 32; i++){ + int m = cursor_info->bits [0][i] & u; + thc->thc_cursmask [i] = m; + thc->thc_cursbits [i] = m & cursor_info->bits [1][i]; + } + } + return 0; +} + +/* Handle cg6-specific ioctls */ +static int +cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb) +{ + int i; + + switch (cmd){ + case FBIOGCURMAX: + i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos)); + if (i) return i; + ((struct fbcurpos *) arg)->fbx = 32; + ((struct fbcurpos *) arg)->fby = 32; + break; + + case FBIOSVIDEO: + /* vesa_blank and vesa_unblank could do the job on fb [0] */ + break; + + case FBIOSCURSOR: + return cg6_scursor ((struct fbcursor *) arg, fb); + + case FBIOSCURPOS: + /* + i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos)); + if (i) return i; + */ + fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg; + cg6_setcursor (&fb->info.cg6); + break; + default: + return -EINVAL; + } + return 0; +} + +static void +cg6_setup (int slot, unsigned int cg6, int cg6_io) +{ + struct cg6_info *cg6info; + + printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6); + + /* Fill in parameters we left out */ + fbinfo [slot].type.fb_cmsize = 256; + fbinfo [slot].mmap = cg6_mmap; + fbinfo [slot].loadcmap = cg6_loadcmap; + fbinfo [slot].ioctl = (void *) cg6_ioctl; + fbinfo [slot].blank = 0; + fbinfo [slot].unblank = 0; + + cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6; + + /* Map the hardware registers */ + cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0, + sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0); + cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0, + sizeof (int), "cgsix_fhc", cg6_io, 0); + cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0, + sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0); + cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0, + sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0); + cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0, + 0x40000, "cgsix_dhc", cg6_io, 0); + cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0, + 0x1000, "cgsix_fbc", cg6_io, 0); + if (!con_fb_base){ + con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0, + fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0); + } + if (!slot) + restore_palette = cg6_restore_palette; +} + +/* The cg3 driver, obio space addresses for mapping the cg3 stuff */ +#define CG3_REGS 0x400000 +#define CG3_RAM 0x800000 +#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */ +#define D4M4(x) ((x)&~0x3) /* (x/4)*4 */ + +/* The cg3 palette is loaded with 4 color values at each time */ +/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */ +static void +cg3_loadcmap (void *fbinfo, int index, int count) +{ + fbinfo_t *fb = (fbinfo_t *) fbinfo; + struct bt_regs *bt = fb->info.cg3.bt; + int *i, steps; + + i = &color_map.raw [D4M3(index)]; + steps = D4M3(index+count-1) - D4M3(index)+3; + bt->addr = D4M4(index); + while (steps--) + bt->color_map = *i++; +} + +/* The cg3 is pressumed to emulate a cg4, I guess older programs will want that */ +/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation */ +static int +cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx) +{ + unsigned int size, page, r, map_size; + unsigned int map_offset = 0; + fbinfo_t *fb = (fbinfo_t *) xx; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + /* To stop the swapper from even considering these pages */ + vma->vm_flags |= FB_MMAP_VM_FLAGS; + + /* Each page, see which map applies */ + for (page = 0; page < size; ){ + switch (vma->vm_offset+page){ + case CG3_MMAP_OFFSET: + map_size = size-page; + map_offset = get_phys ((uint) con_fb_base); + if (map_size > fb->type.fb_size) + map_size = fb->type.fb_size; + break; + default: + map_size = 0; + break; + } + if (!map_size){ + page += PAGE_SIZE; + continue; + } + r = io_remap_page_range (vma->vm_start+page, + map_offset, + map_size, vma->vm_page_prot, + fb->space); + if (r) return -EAGAIN; + page += map_size; + } + vma->vm_inode = inode; + inode->i_count++; + return 0; +} + +static void +cg3_setup (int slot, unsigned int cg3, int cg3_io) +{ + struct cg3_info *cg3info; + + printk ("cgthree%d at 0x%8.8x\n", slot, cg3); + + /* Fill in parameters we left out */ + fbinfo [slot].type.fb_cmsize = 256; + fbinfo [slot].mmap = cg3_mmap; + fbinfo [slot].loadcmap = cg3_loadcmap; + fbinfo [slot].ioctl = 0; /* no special ioctls */ + + cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3; + + /* Map the card registers */ + cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0, + sizeof (struct bt_regs),"cg3_bt", cg3_io, 0); + + if (!con_fb_base){ + con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0, + fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0); + } +} + +/* OBio addresses for the bwtwo registers */ +#define BWTWO_REGISTER_OFFSET 0x400000 + +struct bwtwo_regs { + char unknown [16]; +#define BWTWO_ENABLE_VIDEO 0x40 + unsigned char control; + char unknown2 [15]; +}; + +static int +bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx) +{ + unsigned int size, map_offset, r; + fbinfo_t *fb = (fbinfo_t *) xx; + int map_size; + + map_size = size = vma->vm_end - vma->vm_start; + + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + /* To stop the swapper from even considering these pages */ + vma->vm_flags |= FB_MMAP_VM_FLAGS; + printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n", + (unsigned int) base, + (unsigned int) vma->vm_start, size, + (unsigned int) vma->vm_offset); + + /* This routine should also map the register if asked for, but we don't do that yet */ + map_offset = get_phys ((uint) con_fb_base); + r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot, + fb->space); + if (r) return -EAGAIN; + vma->vm_inode = inode; + inode->i_count++; + return 0; +} + +static void +bwtwo_blank (void *xx) +{ + fbinfo_t *fb = (fbinfo_t *) xx; + + fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO; +} + +static void +bwtwo_unblank (void *xx) +{ + fbinfo_t *fb = (fbinfo_t *) xx; + fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO; +} + +static void +bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io) +{ + printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo); + fbinfo [slot].type.fb_cmsize = 2; + fbinfo [slot].mmap = bwtwo_mmap; + fbinfo [slot].loadcmap = 0; + fbinfo [slot].ioctl = 0; + fbinfo [slot].blank = bwtwo_blank; + fbinfo [slot].unblank = bwtwo_unblank; + fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET, + 0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0); +} + +static char *known_cards [] = { + "cgsix", "cgthree", "bwtwo", "SUNW,tcx", 0 +}; + +static int +known_card (char *name) +{ + int i; + + for (i = 0; known_cards [i]; i++) + if (strcmp (name, known_cards [i]) == 0) + return 1; + return 0; +} + +static struct { + int depth; + int resx, resy; + int x_margin, y_margin; +} scr_def [] = { + { 1, 1152, 900, 8, 18 }, + { 8, 1152, 900, 64, 18 }, + { 8, 1280, 1024, 96, 80 }, + { 8, 1024, 768, 0, 0 }, + { 0 }, +}; + +static int +sparc_console_probe(void) +{ + int propl, con_node, i; + struct linux_sbus_device *sbdp; + unsigned int fbbase = 0xb001b001; + int fbiospace = 0; + + /* XXX The detection code needs to support multiple video cards in one system */ + con_node = 0; + switch(prom_vers) { + case PROM_V0: + /* V0 proms are at sun4c only. Can skip many checks. */ + con_type = FBTYPE_NOTYPE; + if(SBus_chain == 0) { + prom_printf("SBUS chain is NULL, bailing out...\n"); + prom_halt(); + } + for_each_sbusdev(sbdp, SBus_chain) { + con_node = sbdp->prom_node; + + /* If no "address" than it is not the PROM console. */ + if(sbdp->num_vaddrs) { + if(!strncmp(sbdp->prom_name, "cgsix", 5)) { + con_type = FBTYPE_SUNFAST_COLOR; + fbbase = (uint) sbdp->reg_addrs [0].phys_addr; + fbiospace = sbdp->reg_addrs[0].which_io; + break; + } else if(!strncmp(sbdp->prom_name, "cgthree", 7)) { + con_type = FBTYPE_SUN3COLOR; + fbbase = (uint) sbdp->reg_addrs [0].phys_addr; + fbiospace = sbdp->reg_addrs[0].which_io; + break; + } else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) { + con_type = FBTYPE_SUN2BW; + fbbase = (uint) sbdp->reg_addrs [0].phys_addr; + fbiospace = sbdp->reg_addrs[0].which_io; + break; + } + } + } + if(con_type == FBTYPE_NOTYPE) return -1; + con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0]; + strncpy(con_name, sbdp->prom_name, sizeof (con_name)); + break; + case PROM_V2: + case PROM_V3: + case PROM_P1275: + for_each_sbusdev(sbdp, SBus_chain) { + if (known_card (sbdp->prom_name)) + break; + } + if (!sbdp){ + prom_printf ("Could not find a know video card on this machine\n"); + prom_halt (); + } + prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers); + fbbase = (long) sbdp->reg_addrs [0].phys_addr; + fbiospace = sbdp->reg_addrs[0].which_io; + con_node = (*romvec->pv_v2devops.v2_inst2pkg) + (*romvec->pv_v2bootargs.fd_stdout); + /* + * Determine the type of hardware accelerator. + */ + propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name)); + if (propl < 0 || propl >= sizeof (con_name)) { + /* Early cg3s had no "emulation". */ + propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name)); + if (propl < 0) { + prom_printf("console: no device name!!\n"); + return -1; + } + } + if(!strncmp(con_name, "cgsix", sizeof (con_name))) { + con_type = FBTYPE_SUNFAST_COLOR; + } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) { + con_type = FBTYPE_SUN3COLOR; + } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) { + con_type = FBTYPE_MDICOLOR; + } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) { + con_type = FBTYPE_SUN2BW; + } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){ + con_type = FBTYPE_SUN3COLOR; + } else { + prom_printf("console: \"%s\" is unsupported\n", con_name); + return -1; + } + propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4); + if (propl != 4) { + con_fb_base = 0; + } + break; + default: + return -1; + }; + + /* Get the device geometry */ + con_linebytes = prom_getintdefault(con_node, "linebytes", 1152); + con_width = prom_getintdefault(con_node, "width", 1152); + con_height = prom_getintdefault(con_node, "height", 900); + + /* Currently we just support 1-bit and 8-bit depth displays */ + if (con_type == FBTYPE_SUN2BW) { + con_depth = 1; + } else { + con_depth = 8; + } + for (i = 0; scr_def [i].depth; i++){ + if (scr_def [i].resx != con_width || scr_def [i].resy != con_height) + continue; + if (scr_def [i].depth != con_depth) + continue; + x_margin = scr_def [i].x_margin; + y_margin = scr_def [i].y_margin; + chars_per_line = (con_width * con_depth) / 8; + skip_bytes = chars_per_line * y_margin; + ints_per_line = chars_per_line / 4; + bytes_per_row = CHAR_HEIGHT * chars_per_line; + break; + } + if (!scr_def [i].depth){ + x_margin = y_margin = 0; + prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height); + prom_halt (); + } + /* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */ + if ((con_linebytes*8) / con_depth != con_width) { + prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n", + con_linebytes, con_width, con_depth); + return -1; + } + + /* Negate the font table on 1 bit depth cards so we have white on black */ + if (con_depth == 1) + for(i=0; i<(16 * 256); i++) + vga_font[i] = ~vga_font[i]; + + /* Fill in common fb information */ + fbinfo [0].type.fb_type = con_type; + fbinfo [0].type.fb_height = con_height; + fbinfo [0].type.fb_width = con_width; + fbinfo [0].type.fb_depth = con_depth; + fbinfo [0].type.fb_size = PAGE_ALIGN((con_linebytes) * (con_height)); + fbinfo [0].space = fbiospace; + fbinfo [0].blanked = 0; + + /* Should be filled in for supported video cards */ + fbinfo [0].mmap = 0; + fbinfo [0].loadcmap = 0; + fbinfo [0].ioctl = 0; + fbinfo [0].blank = 0; + fbinfo [0].unblank = 0; + + if (fbbase == 0xb001b001){ + printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name); + } + + /* Per card setup */ + switch (con_type){ + case FBTYPE_SUN3COLOR: + cg3_setup (0, fbbase, fbiospace); + break; + case FBTYPE_SUNFAST_COLOR: + cg6_setup (0, fbbase, fbiospace); + break; + case FBTYPE_SUN2BW: + bwtwo_setup (0, fbbase, fbiospace); + break; + default: + break; + } + if (!con_fb_base){ + prom_printf ("PROM does not have an 'address' property for this\n" + "frame buffer and the Linux drivers do not know how\n" + "to map the video of this device\n"); + prom_halt (); + } + fbinfo [0].base = (long) con_fb_base; + + /* Register the frame buffer device */ + if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){ + printk ("Could not register graphics device\n"); + return -EIO; + } + return 0; /* success */ +} + +/* video init code, called from withing the SBUS bus scanner at + * boot time. + */ +void +sun_console_init(void) +{ + if(serial_console) + return; + + if(sparc_console_probe()) { + prom_printf("Could not probe console, bailing out...\n"); + prom_halt(); + } + sun_clear_screen(); +} + +/* + * sun_blitc + * + * Displays an ASCII character at a specified character cell + * position. + * + * Called from scr_writew() when the destination is + * the "shadow" screen + */ +static unsigned int +fontmask_bits[16] = { + 0x00000000, + 0x000000ff, + 0x0000ff00, + 0x0000ffff, + 0x00ff0000, + 0x00ff00ff, + 0x00ffff00, + 0x00ffffff, + 0xff000000, + 0xff0000ff, + 0xff00ff00, + 0xff00ffff, + 0xffff0000, + 0xffff00ff, + 0xffffff00, + 0xffffffff +}; + +int +sun_blitc(unsigned int charattr, unsigned long addr) +{ + int j, idx; + unsigned char *font_row; + +#ifndef DEBUGGING_X + if (graphics_on) + return 0; +#endif + idx = (addr - video_mem_base) >> 1; + + /* Invalidate the cursor position if necessary. */ + if(idx == cursor_pos) + cursor_pos = -1; + font_row = &vga_font[(charattr & 0xff) << 4]; + + switch (con_depth){ + case 1: { + register unsigned char *dst; + + dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx)); + for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE) + *dst = *font_row; + break; + } + case 8: { + register unsigned long *dst; + unsigned long fgmask, bgmask, data, rowbits, attrib; + const int ipl = ints_per_line; + + dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx)); + attrib = (charattr >> 8) & 0x0ff; + fgmask = attrib & 0x0f; + bgmask = (attrib >> 4) & 0x0f; + fgmask = fgmask << 8 | fgmask; + fgmask |= fgmask << 16; + bgmask = bgmask << 8 | bgmask; + bgmask |= bgmask << 16; + + for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) { + rowbits = *font_row; + data = fontmask_bits[(rowbits>>4)&0xf]; + data = (data & fgmask) | (~data & bgmask); + *dst = data; + data = fontmask_bits[rowbits&0xf]; + data = (data & fgmask) | (~data & bgmask); + *(dst+1) = data; + } + break; + } /* case */ + } /* switch */ + return (0); +} + +unsigned char vga_font[cmapsz] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, +0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, +0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, +0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, +0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, +0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, +0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, +0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, +0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, +0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, +0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, +0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, +0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, +0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, +0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, +0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, +0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, +0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, +0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, +0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, +0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, +0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, +0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, +0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, +0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, +0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, +0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, +0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, +0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, +0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, +0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, +0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, +0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, +0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, +0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, +0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, +0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, +0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, +0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, +0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, +0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, +0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, +0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, +0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, +0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, +0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, +0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, +0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, +0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, +0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, +0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, +0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, +0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, +0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, +0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, +0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, +0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, +0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, +0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, +0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, +0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, +0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, +0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, +0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, +0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, +0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, +0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, +0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, +0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, +0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, +0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, +0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, +0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, +0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, +0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, +0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, +0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, +0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, +0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, +0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, +0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, +0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, +0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, +0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, +0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, +0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, +0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, +0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, +0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, +0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, +0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, +0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, +0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, +0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, +0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, +0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, +0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, +0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, +0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, +0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff -u --recursive --new-file v1.3.92/linux/drivers/char/sunmouse.c linux/drivers/char/sunmouse.c --- v1.3.92/linux/drivers/char/sunmouse.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/char/sunmouse.c Sun Apr 21 17:32:01 1996 @@ -0,0 +1,420 @@ +/* sunmouse.c: Sun mouse driver for the Sparc + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * + * Parts based on the psaux.c driver written by: + * Johan Myreen. + * + * Dec/19/95 Added SunOS mouse ioctls - miguel. + * Jan/5/96 Added VUID support, sigio supprot - miguel. + * Mar/5/96 Added proper mouse stream support - miguel. + */ + +/* The mouse is run off of one of the Zilog serial ports. On + * that port is the mouse and the keyboard, each gets a zs channel. + * The mouse itself is mouse-systems in nature. So the protocol is: + * + * Byte 1) Button state which is bit-encoded as + * 0x4 == left-button down, else up + * 0x2 == middle-button down, else up + * 0x1 == right-button down, else up + * + * Byte 2) Delta-x + * Byte 3) Delta-y + * Byte 4) Delta-x again + * Byte 5) Delta-y again + * + * One day this driver will have to support more than one mouse in the system. + * + * This driver has two modes of operation: the default VUID_NATIVE is + * set when the device is opened and allows the application to see the + * mouse character stream as we get it from the serial (for gpm for + * example). The second method, VUID_FIRM_EVENT will provide cooked + * events in Firm_event records. + * */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* The following keeps track of software state for the Sun + * mouse. + */ +#define STREAM_SIZE 2048 +#define EV_SIZE (STREAM_SIZE/sizeof (Firm_event)) +#define BUTTON_LEFT 4 +#define BUTTON_MIDDLE 2 +#define BUTTON_RIGHT 1 + +struct sun_mouse { + unsigned char transaction[5]; /* Each protocol transaction */ + unsigned char byte; /* Counter, starts at 0 */ + unsigned char button_state; /* Current button state */ + unsigned char prev_state; /* Previous button state */ + int delta_x; /* Current delta-x */ + int delta_y; /* Current delta-y */ + int present; + int ready; /* set if there if data is available */ + int active; /* set if device is open */ + int vuid_mode; /* VUID_NATIVE or VUID_FIRM_EVENT */ + struct wait_queue *proc_list; + struct fasync_struct *fasync; + + /* The event/stream queue */ + unsigned int head; + unsigned int tail; + union { + char stream [STREAM_SIZE]; + Firm_event ev [0]; + } queue; +}; + +static struct sun_mouse sunmouse; +#define gen_events (sunmouse.vuid_mode != VUID_NATIVE) +#define bstate sunmouse.button_state +#define pstate sunmouse.prev_state + +extern void mouse_put_char(char ch); + +/* #define SMOUSE_DEBUG */ + +static void +push_event (Firm_event *ev) +{ + int next = (sunmouse.head + 1) % EV_SIZE; + + if (next != sunmouse.tail){ + sunmouse.queue.ev [sunmouse.head] = *ev; + sunmouse.head = next; + } +} + +static int +queue_empty (void) +{ + return sunmouse.head == sunmouse.tail; +} + +static Firm_event * +get_from_queue (void) +{ + Firm_event *result; + + result = &sunmouse.queue.ev [sunmouse.tail]; + sunmouse.tail = (sunmouse.tail + 1) % EV_SIZE; + return result; +} + +static void +push_char (char c) +{ + int next = (sunmouse.head + 1) % STREAM_SIZE; + + if (next != sunmouse.tail){ + sunmouse.queue.stream [sunmouse.head] = c; + sunmouse.head = next; + } + sunmouse.ready = 1; + if (sunmouse.fasync) + kill_fasync (sunmouse.fasync, SIGIO); + wake_up_interruptible (&sunmouse.proc_list); +} + +/* The following is called from the zs driver when bytes are received on + * the Mouse zs8530 channel. + */ +void +sun_mouse_inbyte(unsigned char byte, unsigned char status) +{ + signed char mvalue; + int d; + Firm_event ev; + + add_mouse_randomness (byte); + if(!sunmouse.active) + return; + + if (!gen_events){ + push_char (byte); + return; + } + /* Check for framing errors and parity errors */ + /* XXX TODO XXX */ + + /* If the mouse sends us a byte from 0x80 to 0x87 + * we are starting at byte zero in the transaction + * protocol. + */ + if(byte >= 0x80 && byte <= 0x87) + sunmouse.byte = 0; + + mvalue = (signed char) byte; + switch(sunmouse.byte) { + case 0: + /* Button state */ + sunmouse.button_state = (~byte) & 0x7; +#ifdef SMOUSE_DEBUG + printk("B", + ((sunmouse.button_state & 0x4) ? "DOWN" : "UP"), + ((sunmouse.button_state & 0x2) ? "DOWN" : "UP"), + ((sunmouse.button_state & 0x1) ? "DOWN" : "UP")); +#endif + sunmouse.byte++; + return; + case 1: + /* Delta-x 1 */ +#ifdef SMOUSE_DEBUG + printk("DX1<%d>", mvalue); +#endif + sunmouse.delta_x = mvalue; + sunmouse.byte++; + return; + case 2: + /* Delta-y 1 */ +#ifdef SMOUSE_DEBUG + printk("DY1<%d>", mvalue); +#endif + sunmouse.delta_y = mvalue; + sunmouse.byte++; + return; + case 3: + /* Delta-x 2 */ +#ifdef SMOUSE_DEBUG + printk("DX2<%d>", mvalue); +#endif + sunmouse.delta_x += mvalue; + sunmouse.byte++; + return; + case 4: + /* Last byte, Delta-y 2 */ +#ifdef SMOUSE_DEBUG + printk("DY2<%d>", mvalue); +#endif + sunmouse.delta_y += mvalue; + sunmouse.byte = 69; /* Some rediculious value */ + break; + case 69: + /* Until we get the (0x80 -> 0x87) value we aren't + * in the middle of a real transaction, so just + * return. + */ + return; + default: + printk("sunmouse: bogon transaction state\n"); + sunmouse.byte = 69; /* What could cause this? */ + return; + }; + d = bstate ^ pstate; + pstate = bstate; + if (d){ + if (d & BUTTON_LEFT){ + ev.id = MS_LEFT; + ev.value = bstate & BUTTON_LEFT; + } + if (d & BUTTON_RIGHT){ + ev.id = MS_RIGHT; + ev.value = bstate & BUTTON_RIGHT; + } + if (d & BUTTON_MIDDLE){ + ev.id = MS_MIDDLE; + ev.value = bstate & BUTTON_MIDDLE; + } + ev.time = xtime; + ev.value = ev.value ? VKEY_DOWN : VKEY_UP; + push_event (&ev); + } + if (sunmouse.delta_x){ + ev.id = LOC_X_DELTA; + ev.time = xtime; + ev.value = sunmouse.delta_x; + push_event (&ev); + sunmouse.delta_x = 0; + } + if (sunmouse.delta_y){ + ev.id = LOC_Y_DELTA; + ev.time = xtime; + ev.value = sunmouse.delta_y; + push_event (&ev); + } + + /* We just completed a transaction, wake up whoever is awaiting + * this event. + */ + sunmouse.ready = 1; + if (sunmouse.fasync) + kill_fasync (sunmouse.fasync, SIGIO); + wake_up_interruptible(&sunmouse.proc_list); + return; +} + +static int +sun_mouse_open(struct inode * inode, struct file * file) +{ + if(!sunmouse.present) + return -EINVAL; + if(sunmouse.active) + return -EBUSY; + sunmouse.active = 1; + sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0; + sunmouse.button_state = 0x80; + sunmouse.vuid_mode = VUID_NATIVE; + return 0; +} + +static int +sun_mouse_fasync (struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper (inode, filp, on, &sunmouse.fasync); + if (retval < 0) + return retval; + return 0; +} + +static void +sun_mouse_close(struct inode *inode, struct file *file) +{ + sunmouse.active = sunmouse.ready = 0; + sun_mouse_fasync (inode, file, 0); +} + +static int +sun_mouse_write(struct inode *inode, struct file *file, const char *buffer, + int count) +{ + return -EINVAL; /* foo on you */ +} + +static int +sun_mouse_read(struct inode *inode, struct file *file, char *buffer, + int count) +{ + struct wait_queue wait = { current, NULL }; + + if (queue_empty ()){ + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + add_wait_queue (&sunmouse.proc_list, &wait); + while (queue_empty () && !(current->signal & ~current->blocked)){ + current->state = TASK_INTERRUPTIBLE; + schedule (); + } + current->state = TASK_RUNNING; + remove_wait_queue (&sunmouse.proc_list, &wait); + } + if (gen_events){ + char *p = buffer, *end = buffer+count; + + while (p < end && !queue_empty ()){ + *(Firm_event *)p = *get_from_queue (); + p += sizeof (Firm_event); + } + sunmouse.ready = !queue_empty (); + inode->i_atime = CURRENT_TIME; + return p-buffer; + } else { + int c; + + for (c = count; !queue_empty () && c; c--){ + *buffer++ = sunmouse.queue.stream [sunmouse.tail]; + sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE; + } + sunmouse.ready = !queue_empty (); + inode->i_atime = CURRENT_TIME; + return count-c; + } + /* Only called if nothing was sent */ + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; +} + +static int +sun_mouse_select(struct inode *inode, struct file *file, int sel_type, + select_table *wait) +{ + if(sel_type != SEL_IN) + return 0; + if(sunmouse.ready) + return 1; + select_wait(&sunmouse.proc_list, wait); + return 0; +} +int +sun_mouse_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int i; + + switch (cmd){ + /* VUIDGFORMAT - Get input device byte stream format */ + case _IOR('v', 2, int): + i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int)); + if (i) return i; + *(int *)arg = sunmouse.vuid_mode; + break; + + /* VUIDSFORMAT - Set input device byte stream format*/ + case _IOW('v', 1, int): + i = verify_area (VERIFY_READ, (void *)arg, sizeof (int)); + if (i) return i; + i = *(int *) arg; + if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){ + sunmouse.vuid_mode = *(int *)arg; + sunmouse.head = sunmouse.tail = 0; + } else + return -EINVAL; + break; + + default: + printk ("[MOUSE-ioctl: %8.8x]\n", cmd); + return -1; + } + return 0; +} + +struct file_operations sun_mouse_fops = { + NULL, + sun_mouse_read, + sun_mouse_write, + NULL, + sun_mouse_select, + sun_mouse_ioctl, + NULL, + sun_mouse_open, + sun_mouse_close, + NULL, + sun_mouse_fasync, +}; + +static struct miscdevice sun_mouse_mouse = { + SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops +}; + +int +sun_mouse_init(void) +{ + printk("Sun Mouse-Systems mouse driver version 1.00\n"); + sunmouse.present = 1; + sunmouse.ready = sunmouse.active = 0; + misc_register (&sun_mouse_mouse); + sunmouse.delta_x = sunmouse.delta_y = 0; + sunmouse.button_state = 0x80; + sunmouse.proc_list = NULL; + return 0; +} + +void +sun_mouse_zsinit(void) +{ + sunmouse.ready = 1; +} diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in --- v1.3.92/linux/drivers/isdn/Config.in Mon Feb 26 11:58:04 1996 +++ linux/drivers/isdn/Config.in Sun Apr 21 11:56:14 1996 @@ -10,3 +10,4 @@ fi dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN dep_tristate 'ICN B1 and B2 support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN +dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/Makefile linux/drivers/isdn/Makefile --- v1.3.92/linux/drivers/isdn/Makefile Mon Feb 26 11:58:04 1996 +++ linux/drivers/isdn/Makefile Sun Apr 21 11:56:14 1996 @@ -1,6 +1,6 @@ SUB_DIRS := MOD_SUB_DIRS := -ALL_SUB_DIRS := icn teles +ALL_SUB_DIRS := icn teles pcbit L_OBJS := LX_OBJS := @@ -47,6 +47,16 @@ else ifeq ($(CONFIG_ISDN_DRV_ICN),m) MOD_SUB_DIRS += icn + endif +endif + +ifeq ($(CONFIG_ISDN_DRV_PCBIT),y) + L_OBJS += pcbit/pcbit.o + SUB_DIRS += pcbit + MOD_SUB_DIRS += pcbit +else + ifeq ($(CONFIG_ISDN_DRV_PCBIT),m) + MOD_SUB_DIRS += pcbit endif endif diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/icn/icn.c linux/drivers/isdn/icn/icn.c --- v1.3.92/linux/drivers/isdn/icn/icn.c Sat Apr 13 18:22:06 1996 +++ linux/drivers/isdn/icn/icn.c Sun Apr 21 11:56:14 1996 @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.18 1996/04/20 16:50:26 fritz + * Fixed status-buffer overrun. + * Misc. typos + * * Revision 1.17 1996/02/11 02:39:04 fritz * Increased Buffer for status-messages. * Removed conditionals for HDLC-firmware. @@ -100,7 +104,7 @@ #undef LOADEXTERN static char -*revision = "$Revision: 1.17 $"; +*revision = "$Revision: 1.18 $"; static void icn_pollcard(unsigned long dummy); @@ -466,7 +470,10 @@ save_flags(flags); cli(); *dev->msg_buf_write++ = (c == 0xff) ? '\n' : c; - /* No checks for buffer overflow for raw-status-device */ + if (dev->msg_buf_write == dev->msg_buf_read) { + if (++dev->msg_buf_read > dev->msg_buf_end) + dev->msg_buf_read = dev->msg_buf; + } if (dev->msg_buf_write > dev->msg_buf_end) dev->msg_buf_write = dev->msg_buf; restore_flags(flags); @@ -795,7 +802,7 @@ } restore_flags(flags); OUTB_P(0, ICN_RUN); /* Reset Controller */ - OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ + OUTB_P(0, ICN_MAPRAM); /* Disable RAM */ icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */ icn_shiftout(ICN_CFG, (unsigned long) dev->shmem, 23, 10); /* Set RAM-Addr. */ #ifdef BOOT_DEBUG @@ -947,6 +954,8 @@ u_char *p; for (p = buf, count = 0; count < len; p++, count++) { + if (dev->msg_buf_read == dev->msg_buf_write) + return count; if (user) put_fs_byte(*dev->msg_buf_read++, p); else diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/icn/icn.h linux/drivers/isdn/icn/icn.h --- v1.3.92/linux/drivers/isdn/icn/icn.h Fri Apr 12 15:51:53 1996 +++ linux/drivers/isdn/icn/icn.h Sun Apr 21 12:53:19 1996 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.12 1996/01/22 05:01:22 fritz Exp fritz $ +/* $Id: icn.h,v 1.13 1996/04/20 16:51:41 fritz Exp $ * * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.13 1996/04/20 16:51:41 fritz + * Increased status buffer. + * Misc. typos + * * Revision 1.12 1996/01/22 05:01:22 fritz * Revert to GPL. * @@ -184,7 +188,7 @@ } pqueue; typedef struct { - unsigned short port; /* Base-port-address */ + unsigned short port; /* Base-port-address */ icn_shmem *shmem; /* Pointer to memory-mapped-buffers */ int myid; /* Driver-Nr. assigned by linklevel */ int rvalid; /* IO-portregion has been requested */ @@ -194,7 +198,7 @@ unsigned short flags; /* Statusflags */ int doubleS0; /* Flag: Double-S0-Card */ int secondhalf; /* Flag: Second half of a doubleS0 */ - int ptype; /* Protocol type (1TR6 or Euro) */ + int ptype; /* Protocol type (1TR6 or Euro) */ struct timer_list st_timer; /* Timer for Status-Polls */ struct timer_list rb_timer; /* Timer for B-Channel-Polls */ int channel; /* Currently mapped Channel */ diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_cards.c linux/drivers/isdn/isdn_cards.c --- v1.3.92/linux/drivers/isdn/isdn_cards.c Mon Feb 26 11:58:04 1996 +++ linux/drivers/isdn/isdn_cards.c Sun Apr 21 11:56:14 1996 @@ -1,3 +1,28 @@ +/* $Id: isdn_cards.c,v 1.1 1996/04/20 16:04:36 fritz Exp $ + * + * Linux ISDN subsystem, initialization for non-modularized drivers. + * + * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: isdn_cards.c,v $ + * Revision 1.1 1996/04/20 16:04:36 fritz + * Initial revision + * + */ #include @@ -9,6 +34,10 @@ extern void teles_init(void); #endif +#ifdef CONFIG_ISDN_DRV_PCBIT +extern void pcbit_init(void); +#endif + void isdn_cards_init(void) { #if CONFIG_ISDN_DRV_ICN @@ -16,6 +45,9 @@ #endif #if CONFIG_ISDN_DRV_TELES teles_init(); +#endif +#if CONFIG_ISDN_DRV_PCBIT + pcbit_init(); #endif } diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_cards.h linux/drivers/isdn/isdn_cards.h --- v1.3.92/linux/drivers/isdn/isdn_cards.h Mon Feb 26 11:58:04 1996 +++ linux/drivers/isdn/isdn_cards.h Sun Apr 21 11:56:14 1996 @@ -1,3 +1,28 @@ +/* $Id: isdn_cards.h,v 1.1 1996/04/20 16:04:03 fritz Exp $ + * + * Linux ISDN subsystem, initialization for non-modularized drivers. + * + * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log: isdn_cards.h,v $ + * Revision 1.1 1996/04/20 16:04:03 fritz + * Initial revision + * + */ extern void isdn_cards_init(void); diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_common.c linux/drivers/isdn/isdn_common.c --- v1.3.92/linux/drivers/isdn/isdn_common.c Mon Feb 26 11:58:05 1996 +++ linux/drivers/isdn/isdn_common.c Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.4 1996/02/11 02:33:26 fritz Exp fritz $ +/* $Id: isdn_common.c,v 1.5 1996/04/20 16:19:07 fritz Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.5 1996/04/20 16:19:07 fritz + * Changed slow timer handlers to increase accuracy. + * Added statistic information for usage by xisdnload. + * Fixed behaviour of isdnctrl-device on non-blocked io. + * Fixed all io to go through generic writebuf-function without + * bypassing. Same for incoming data. + * Fixed bug: Last channel had been unusable. + * Fixed kfree of tty xmit_buf on ppp initialization failure. + * * Revision 1.4 1996/02/11 02:33:26 fritz * Fixed bug in main timer-dispatcher. * Bugfix: Lot of tty-callbacks got called regardless of the events already @@ -61,7 +70,7 @@ isdn_dev *dev = (isdn_dev *) 0; static int has_exported = 0; -static char *isdn_revision = "$Revision: 1.4 $"; +static char *isdn_revision = "$Revision: 1.5 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -159,12 +168,12 @@ isdn_tty_modem_xmit(); } if (tf & ISDN_TIMER_SLOW) { - if (++isdn_timer_cnt1 > ISDN_TIMER_02SEC) { + if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) { isdn_timer_cnt1 = 0; if (tf & ISDN_TIMER_NETDIAL) isdn_net_dial(); } - if (++isdn_timer_cnt2 > ISDN_TIMER_1SEC) { + if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { isdn_timer_cnt2 = 0; if (tf & ISDN_TIMER_NETHANGUP) isdn_net_autohup(); @@ -233,6 +242,8 @@ return; if ((i = isdn_dc2minor(di,channel))==-1) return; + /* Update statistics */ + dev->ibytes[i] += len; /* First, try to deliver data to network-device */ if (isdn_net_receive_callback(i, buf, len)) return; @@ -375,14 +386,17 @@ break; case 2: /* For calling back, first reject incoming call ... */ case 3: /* Interface found, but down, reject call actively */ + printk(KERN_INFO "isdn: Rejecting Call\n"); cmd.driver = di; cmd.arg = c->arg; cmd.command = ISDN_CMD_HANGUP; dev->drv[di]->interface->command(&cmd); - if (r == 2) - /* ... then start dialing. */ - isdn_net_dial(); - break; + if (r == 3) + break; + /* Fall through */ + case 4: + /* ... then start callback. */ + isdn_net_dial(); } return 0; break; @@ -730,8 +744,11 @@ if (minor == ISDN_MINOR_STATUS) { char *p; - if (!file->private_data) + if (!file->private_data) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; interruptible_sleep_on(&(dev->info_waitq)); + } save_flags(flags); p = isdn_statstr(); restore_flags(flags); @@ -760,8 +777,11 @@ drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) return -ENODEV; - if (!dev->drv[drvidx]->stavail) + if (!dev->drv[drvidx]->stavail) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); + } if (dev->drv[drvidx]->interface->readstat) len = dev->drv[drvidx]->interface-> readstat(buf, MIN(count, dev->drv[drvidx]->stavail), 1); @@ -769,7 +789,10 @@ len = 0; save_flags(flags); cli(); - dev->drv[drvidx]->stavail -= len; + if (len) + dev->drv[drvidx]->stavail -= len; + else + dev->drv[drvidx]->stavail = 0; restore_flags(flags); file->f_pos += len; return len; @@ -803,7 +826,8 @@ if (!dev->drv[drvidx]->running) return -ENODEV; chidx = isdn_minor2chan(minor); - while (dev->drv[drvidx]->interface->writebuf(drvidx, chidx, buf, count, 1) != count) + dev->obytes[minor] += count; + while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count) interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); return count; } @@ -1008,8 +1032,27 @@ isdn_net_ioctl_phone phone; isdn_net_ioctl_cfg cfg; - if (minor == ISDN_MINOR_STATUS) - return -EPERM; + if (minor == ISDN_MINOR_STATUS) { + switch (cmd) { + case IIOCGETCPS: + if (arg) { + ulong *p = (ulong *)arg; + int i; + if ((ret = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(ulong)*ISDN_MAX_CHANNELS*2))) + return ret; + for (i = 0;iibytes[i],p++); + put_fs_long(dev->obytes[i],p++); + } + return 0; + } else + return -EINVAL; + break; + default: + return -EINVAL; + } + } if (!dev->drivers) return -ENODEV; if (minor < ISDN_MINOR_CTRL) { @@ -1367,7 +1410,6 @@ if (minor == ISDN_MINOR_STATUS) { infostruct *p; - if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { MOD_INC_USE_COUNT; p->next = (char *) dev->infochain; @@ -1423,12 +1465,10 @@ int drvidx; isdn_ctrl c; - if (!dev->channels) - return; - MOD_DEC_USE_COUNT; if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; + MOD_DEC_USE_COUNT; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) @@ -1441,7 +1481,11 @@ p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); + return; } + if (!dev->channels) + return; + MOD_DEC_USE_COUNT; if (minor < ISDN_MINOR_CTRL) { drvidx = isdn_minor2drv(minor); if (drvidx < 0) @@ -1463,9 +1507,8 @@ return; } #ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { + if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); - } #endif } @@ -1559,6 +1602,8 @@ (dev->chanmap[i] == ch)) { dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE); strcpy(dev->num[i], "???"); + dev->ibytes[i] = 0; + dev->obytes[i] = 0; isdn_info_update(); restore_flags(flags); return; @@ -1593,17 +1638,20 @@ void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb) { - int i; + int i, len; if (dev->global_flags & ISDN_GLOBAL_STOPPED) return; if ((i = isdn_dc2minor(drvidx,chan))==-1) return; + len = skb->len; if (isdn_net_rcv_skb(i, skb) == 0) { isdn_receive_callback(drvidx, chan, skb->data, skb->len); skb->free = 1; kfree_skb(skb, FREE_READ); - } + } else + /* Update statistics */ + dev->ibytes[i] += len; } /* @@ -1613,28 +1661,55 @@ int isdn_writebuf_stub(int drvidx, int chan, const u_char *buf, int len, int user) { - struct sk_buff * skb; - - skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC); - if (skb == NULL) - return 0; + if (dev->drv[drvidx]->interface->writebuf) + return dev->drv[drvidx]->interface->writebuf(drvidx, chan, buf, + len, user); + else { + struct sk_buff * skb; + + skb = alloc_skb(dev->drv[drvidx]->interface->hl_hdrlen + len, GFP_ATOMIC); + if (skb == NULL) + return 0; + + skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); + skb->free = 1; + + if (user) + memcpy_fromfs(skb_put(skb, len), buf, len); + else + memcpy(skb_put(skb, len), buf, len); + + return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb); + } +} - skb_reserve(skb, dev->drv[drvidx]->interface->hl_hdrlen); - skb->free = 1; +/* + * writebuf_skb replacement for NON SKB_ABLE drivers + * If lowlevel-device does not support supports skbufs, use + * standard send-routine, else sind directly. + * + * Return: length of data on success, -ERRcode on failure. + */ - if (user) - memcpy_fromfs(skb_put(skb, len), buf, len); - else - memcpy(skb_put(skb, len), buf, len); +int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb) +{ + int ret; - return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb); + if (dev->drv[drvidx]->interface->writebuf_skb) + ret = dev->drv[drvidx]->interface-> + writebuf_skb(drvidx, chan, skb); + else { + if ((ret = dev->drv[drvidx]->interface-> + writebuf(drvidx,chan,skb->data,skb->len,0))==skb->len) + dev_kfree_skb(skb, FREE_WRITE); + } + return ret; } - + /* * Low-level-driver registration */ - int register_isdn(isdn_if * i) { driver *d; @@ -1648,11 +1723,15 @@ return 0; } n = i->channels; - if (dev->channels + n >= ISDN_MAX_CHANNELS) { + if (dev->channels + n > ISDN_MAX_CHANNELS) { printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", ISDN_MAX_CHANNELS); return 0; } + if ((!i->writebuf_skb) && (!i->writebuf)) { + printk(KERN_WARNING "register_isdn: No write routine given.\n"); + return 0; + } if (!(d = (driver *) kmalloc(sizeof(driver), GFP_KERNEL))) { printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); return 0; @@ -1712,9 +1791,6 @@ if (!dev->drv[drvidx]) break; i->channels = drvidx; - - if (i->writebuf_skb && (!i->writebuf)) - i->writebuf = isdn_writebuf_stub; i->rcvcallb_skb = isdn_receive_skb_callback; i->rcvcallb = isdn_receive_callback; @@ -1790,7 +1866,7 @@ return -EIO; } memset((char *) dev, 0, sizeof(isdn_dev)); - for (i = 0; i < ISDN_MAX_DRIVERS; i++) + for (i = 0; i < ISDN_MAX_CHANNELS; i++) dev->drvmap[i] = -1; for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->chanmap[i] = -1; @@ -1818,7 +1894,7 @@ tty_unregister_driver(&dev->mdm.tty_modem); tty_unregister_driver(&dev->mdm.cua_modem); for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(dev->mdm.info[i].xmit_buf); + kfree(dev->mdm.info[i].xmit_buf - 4); unregister_chrdev(ISDN_MAJOR, "isdn"); kfree(dev); return -EIO; diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_common.h linux/drivers/isdn/isdn_common.h --- v1.3.92/linux/drivers/isdn/isdn_common.h Fri Apr 12 15:51:53 1996 +++ linux/drivers/isdn/isdn_common.h Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.h,v 1.1 1996/01/10 21:37:19 fritz Exp fritz $ +/* $Id: isdn_common.h,v 1.2 1996/04/20 16:20:40 fritz Exp $ * * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.h,v $ + * Revision 1.2 1996/04/20 16:20:40 fritz + * Misc. typos. + * * Revision 1.1 1996/01/10 21:37:19 fritz * Initial revision * @@ -49,10 +52,10 @@ extern void isdn_timer_ctrl(int tf, int onoff); extern void isdn_unexclusive_channel(int di, int ch); extern int isdn_getnum(char **); -extern int isdn_readbchan (int di, int channel, u_char *buf, - u_char *fp, int len, int user); -extern int isdn_get_free_channel(int usage, int l2_proto, int l3_proto, - int pre_dev, int pre_chan); +extern int isdn_readbchan (int, int, u_char *, u_char *, int, int); +extern int isdn_get_free_channel(int, int, int, int, int); +extern int isdn_writebuf_stub(int, int, const u_char *, int, int); +extern int isdn_writebuf_skb_stub(int, int, struct sk_buff *); #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) extern void isdn_dumppkt(char *, u_char *, int, int); #endif diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_net.c linux/drivers/isdn/isdn_net.c --- v1.3.92/linux/drivers/isdn/isdn_net.c Fri Apr 12 15:51:53 1996 +++ linux/drivers/isdn/isdn_net.c Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.4 1996/02/19 15:23:38 fritz Exp fritz $ +/* $Id: isdn_net.c,v 1.5 1996/04/20 16:28:38 fritz Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.5 1996/04/20 16:28:38 fritz + * Made more parameters of the dial statemachine user-configurable and + * added hangup after dial for more reliability using callback. + * Changed all io going through generic routines in isdn_common.c + * Added missing call to dev_free_skb on failed dialing. + * Added uihdlc encapsulation. + * Fixed isdn_net_setcfg not to destroy interface-flags anymore. + * Misc. typos. + * * Revision 1.4 1996/02/19 15:23:38 fritz * Bugfix: Sync-PPP packets got compressed twice, when resent due to * send-queue-full reject. @@ -70,7 +79,7 @@ static int isdn_net_start_xmit(struct sk_buff *, struct device *); static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.4 $"; +char *isdn_net_revision = "$Revision: 1.5 $"; /* * Code for raw-networking over ISDN @@ -208,10 +217,15 @@ return 1; case ISDN_STAT_DCONN: /* D-Channel is up */ - if (lp->dialstate == 4 || lp->dialstate == 7 - || lp->dialstate == 8) { - lp->dialstate++; - return 1; + switch (lp->dialstate) { + case 4: + case 7: + case 8: + lp->dialstate++; + return 1; + case 12: + lp->dialstate = 5; + return 1; } break; case ISDN_STAT_DHUP: @@ -236,25 +250,32 @@ break; case ISDN_STAT_BCONN: /* B-Channel is up */ - if (lp->dialstate >= 5 && lp->dialstate <= 10) { - if (lp->dialstate <= 6) { - dev->usage[idx] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } else - dev->rx_netdev[idx] = p; - lp->dialstate = 0; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,1); - printk(KERN_INFO "isdn_net: %s connected\n", lp->name); - /* If first Chargeinfo comes before B-Channel connect, - * we correct the timestamp here. - */ - lp->chargetime = jiffies; - /* Immediately send first skb to speed up arp */ - if (lp->first_skb) { - if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb))) - lp->first_skb = NULL; - } - return 1; + switch (lp->dialstate) { + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 12: + if (lp->dialstate <= 6) { + dev->usage[idx] |= ISDN_USAGE_OUTGOING; + isdn_info_update(); + } else + dev->rx_netdev[idx] = p; + lp->dialstate = 0; + isdn_timer_ctrl(ISDN_TIMER_NETHANGUP,1); + printk(KERN_INFO "isdn_net: %s connected\n", lp->name); + /* If first Chargeinfo comes before B-Channel connect, + * we correct the timestamp here. + */ + lp->chargetime = jiffies; + /* Immediately send first skb to speed up arp */ + if (lp->first_skb) { + if (!(isdn_net_xmit(&p->dev,lp,lp->first_skb))) + lp->first_skb = NULL; + } + return 1; } break; case ISDN_STAT_NODCH: @@ -316,6 +337,10 @@ isdn_ctrl cmd; while (p) { +#ifdef ISDN_DEBUG_NET_DIAL + if (p->local.dialstate) + printk(KERN_DEBUG "%s: dialstate=%d\n", p->local.name,p->local.dialstate); +#endif switch (p->local.dialstate) { case 0: /* Nothing to do for this interface */ @@ -359,6 +384,7 @@ p->local.huptimer = 0; p->local.outgoing = 1; p->local.hupflags |= 1; + p->local.hupflags &= ~2; if (!strcmp(p->local.dial->num, "LEASED")) { p->local.dialstate = 4; printk(KERN_INFO "%s: Open leased line ...\n", p->local.name); @@ -388,18 +414,20 @@ dev->drv[p->local.isdn_device]->interface->command(&cmd); } anymore = 1; - p->local.dialstate++; + p->local.dialstate = + (p->local.cbdelay && + (p->local.flags & ISDN_NET_CBOUT))?12:4; break; case 4: - /* Wait for D-Channel-connect or incoming call, if passive - * callback configured. If timeout and max retries not + /* Wait for D-Channel-connect. + * If timeout and max retries not * reached, switch back to state 3. */ if (p->local.dtimer++ > ISDN_TIMER_DTIMEOUT10) if (p->local.dialretry < p->local.dialmax) { p->local.dialstate = 3; } else - isdn_net_hangup(&p->dev); + isdn_net_hangup(&p->dev); anymore = 1; break; case 5: @@ -456,7 +484,7 @@ p->local.dialstate++; break; case 8: - case 10: + case 10: /* Wait for B- or D-channel-connect */ #ifdef ISDN_DEBUG_NET_DIAL printk(KERN_DEBUG "dialtimer4: %d\n", p->local.dtimer); @@ -466,6 +494,28 @@ else anymore = 1; break; + case 11: + /* Callback Delay */ + if (p->local.dtimer++ > p->local.cbdelay) + p->local.dialstate = 1; + anymore = 1; + break; + case 12: + /* Remote does callback. Hangup after cbdelay, then wait for incoming + * call (in state 4). + */ + if (p->local.dtimer++ > p->local.cbdelay) { + printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->local.name); + p->local.dtimer = 0; + p->local.dialstate = 4; + cmd.driver = p->local.isdn_device; + cmd.command = ISDN_CMD_HANGUP; + cmd.arg = p->local.isdn_channel; + (void) dev->drv[cmd.driver]->interface->command(&cmd); + isdn_all_eaz(p->local.isdn_device, p->local.isdn_channel); + } + anymore = 1; + break; default: printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", p->local.dialstate, p->local.name); @@ -476,24 +526,6 @@ } /* - * Send-data-helpfunction for net-interfaces - */ -int -isdn_net_send(u_char * buf, int di, int ch, int len) -{ - int l; - - if ((l = dev->drv[di]->interface->writebuf(di, ch, buf, len, 0)) == len) - return 1; - /* Device driver queue full (or packet > 4000 bytes, should never - * happen) - */ - if (l == -EINVAL) - printk(KERN_ERR "isdn_net: Huh, sending pkt too big!\n"); - return 0; -} - -/* * Perform hangup for a net-interface. */ void @@ -505,6 +537,10 @@ save_flags(flags); cli(); + if (lp->first_skb) { + dev_kfree_skb(lp->first_skb,FREE_WRITE); + lp->first_skb = NULL; + } if (lp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); lp->dialstate = 0; @@ -560,9 +596,9 @@ len = 4; #ifdef CONFIG_ISDN_MPP if (lp->ppp_minor!=-1) { - if (ippp_table[lp->ppp_minor].mpppcfg & + if (ippp_table[lp->ppp_minor]->mpppcfg & SC_MP_PROT) { - if (ippp_table[lp->ppp_minor].mpppcfg & + if (ippp_table[lp->ppp_minor]->mpppcfg & SC_OUT_SHORT_SEQ) len = 7; else @@ -634,16 +670,8 @@ int ret; lp->transcount += skb->len; - if (dev->drv[lp->isdn_device]->interface->writebuf_skb) - ret = dev->drv[lp->isdn_device]->interface-> - writebuf_skb(lp->isdn_device, lp->isdn_channel, skb); - else { - if ((ret = isdn_net_send(skb->data, lp->isdn_device, - lp->isdn_channel, skb->len))) - dev_kfree_skb(skb, FREE_WRITE); - } - - if (ret) + ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb); + if (ret == skb->len) clear_bit(0, (void *)&(ndev->tbusy)); return (!ret); } @@ -790,6 +818,11 @@ /* remember first skb to speed up arp * when using encap ETHER */ + if (lp->first_skb) { + printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n"); + dev_kfree_skb(lp->first_skb,FREE_WRITE); + lp->first_skb = NULL; + } lp->first_skb = skb; /* Initiate dialing */ isdn_net_dial(); @@ -951,35 +984,39 @@ isdn_dumppkt("R:", skb->data, skb->len, 40); #endif switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - /* Ethernet over ISDN */ - skb->protocol = isdn_net_type_trans(skb,ndev); - break; - case ISDN_NET_ENCAP_RAWIP: - /* RAW-IP without MAC-Header */ - skb->protocol = htons(ETH_P_IP); - break; - case ISDN_NET_ENCAP_CISCOHDLC: - /* CISCO-HDLC IP with type field and fake I-frame-header */ - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_IPTYP: - /* IP with type field */ - skb->protocol = *(unsigned short *)&(skb->data[0]); - skb_pull(skb, 2); - if (*(unsigned short *)skb->data == 0xFFFF) - skb->protocol = htons(ETH_P_802_3); - break; + case ISDN_NET_ENCAP_ETHER: + /* Ethernet over ISDN */ + skb->protocol = isdn_net_type_trans(skb,ndev); + break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-frame (for ispa with -h1 option) */ + skb_pull(skb,2); + /* Fall through */ + case ISDN_NET_ENCAP_RAWIP: + /* RAW-IP without MAC-Header */ + skb->protocol = htons(ETH_P_IP); + break; + case ISDN_NET_ENCAP_CISCOHDLC: + /* CISCO-HDLC IP with type field and fake I-frame-header */ + skb_pull(skb, 2); + /* Fall through */ + case ISDN_NET_ENCAP_IPTYP: + /* IP with type field */ + skb->protocol = *(unsigned short *)&(skb->data[0]); + skb_pull(skb, 2); + if (*(unsigned short *)skb->data == 0xFFFF) + skb->protocol = htons(ETH_P_802_3); + break; #ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - isdn_ppp_receive(lp->netdev, olp, skb); - return; -#endif - default: - printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", - lp->name); - kfree_skb(skb,FREE_READ); - return; + case ISDN_NET_ENCAP_SYNCPPP: + isdn_ppp_receive(lp->netdev, olp, skb); + return; +#endif + default: + printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", + lp->name); + kfree_skb(skb,FREE_READ); + return; } netif_rx(skb); return; @@ -1100,6 +1137,11 @@ *((ushort*) skb_push(skb, 2)) = htons(type); len = 2; break; + case ISDN_NET_ENCAP_UIHDLC: + /* HDLC with UI-Frames (for ispa with -h1 option) */ + *((ushort*) skb_push(skb, 2)) = htons(0x0103); + len = 2; + break; case ISDN_NET_ENCAP_CISCOHDLC: skb_push(skb, 4); skb->data[0] = 0x0f; @@ -1113,9 +1155,9 @@ len = 4; #ifdef CONFIG_ISDN_MPP if (lp->ppp_minor!=-1) { - if (ippp_table[lp->ppp_minor].mpppcfg & + if (ippp_table[lp->ppp_minor]->mpppcfg & SC_MP_PROT) { - if (ippp_table[lp->ppp_minor].mpppcfg & + if (ippp_table[lp->ppp_minor]->mpppcfg & SC_OUT_SHORT_SEQ) len = 7; else @@ -1355,7 +1397,9 @@ * * Return-Value: 0 = No appropriate interface for this call. * 1 = Call accepted - * 2 = Do callback + * 2 = Reject call, wait cbdelay, then call back + * 3 = Reject call + * 4 = Wait cbdelay, then call back */ int isdn_net_find_icall(int di, int ch, int idx, char *num) @@ -1436,11 +1480,11 @@ printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", p->local.name, p->local.msn, p->local.flags, p->local.dialstate); #endif - if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */ - (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - (((p->local.dialstate == 4) && /* if dialing */ - (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */ + if ((!strcmp(isdn_map_eaz2msn(p->local.msn, di), eaz)) && /* EAZ is matching */ + (((!(p->local.flags & ISDN_NET_CONNECTED)) && /* but not connected */ + (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ + ((((p->local.dialstate == 4) || (p->local.dialstate == 12)) && /* if dialing */ + (!(p->local.flags & ISDN_NET_CALLBACK))) /* but no callback */ ))) { #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", @@ -1513,7 +1557,7 @@ continue; } } - } + } /* if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) */ #ifdef ISDN_DEBUG_NET_ICALL printk(KERN_DEBUG "n_fi: match2\n"); #endif @@ -1578,7 +1622,8 @@ return 0; } /* Setup dialstate. */ - lp->dialstate = 1; + lp->dtimer = 0; + lp->dialstate = 11; lp->flags |= ISDN_NET_CONNECTED; /* Connect interface with channel */ isdn_net_bind_channel(lp, chi); @@ -1592,9 +1637,9 @@ return 0; } #endif - /* Initiate dialing by returning 2 */ + /* Initiate dialing by returning 2 or 4 */ restore_flags(flags); - return 2; + return (lp->flags & ISDN_NET_CBHUP)?2:4; } else printk(KERN_WARNING "isdn_net: %s: No phone number\n", lp->name); restore_flags(flags); @@ -1613,7 +1658,7 @@ #endif /* if this interface is dialing, it does it probably on a different device, so free this device */ - if (p->local.dialstate == 4) + if ((p->local.dialstate == 4) || (p->local.dialstate == 12)) isdn_free_channel(p->local.isdn_device, p->local.isdn_channel, ISDN_USAGE_NET); dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; @@ -1630,6 +1675,7 @@ p->local.outgoing = 0; p->local.huptimer = 0; p->local.hupflags |= 1; + p->local.hupflags &= ~2; #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) if (isdn_ppp_bind(lp) < 0) { @@ -1732,7 +1778,7 @@ * Allocate a new network-interface and initialize it's data structures. */ char * - isdn_net_new(char *name, struct device *master) +isdn_net_new(char *name, struct device *master) { isdn_net_dev *netdev; @@ -1802,8 +1848,9 @@ netdev->local.hupflags = 8; /* Do hangup even on incoming calls */ netdev->local.onhtime = 10; /* Default hangup-time for saving costs of those who forget configuring this */ - /* The following should be configurable via ioctl */ netdev->local.dialmax = 1; + netdev->local.flags = ISDN_NET_CBHUP; /* Hangup before Callback */ + netdev->local.cbdelay = 25; /* Wait 5 secs before Callback */ /* Put into to netdev-chain */ netdev->next = (void *) dev->netdev; dev->netdev = netdev; @@ -1811,7 +1858,7 @@ } char * - isdn_net_newslave(char *parm) +isdn_net_newslave(char *parm) { char *p = strchr(parm, ','); isdn_net_dev *n; @@ -1860,9 +1907,7 @@ printk(KERN_WARNING "isdn_net: No driver with selected features\n"); return -ENODEV; } - if ((p->local.p_encap != cfg->p_encap) && - ((p->local.p_encap == ISDN_NET_ENCAP_RAWIP) || - (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) )) + if (p->local.p_encap != cfg->p_encap) if (p->dev.start) { printk(KERN_WARNING "%s: cannot change encap when if is up\n", @@ -1939,16 +1984,30 @@ p->local.charge = cfg->charge; p->local.l2_proto = cfg->l2_proto; p->local.l3_proto = cfg->l3_proto; + p->local.cbdelay = cfg->cbdelay; + p->local.dialmax = cfg->dialmax; p->local.slavedelay = cfg->slavedelay * HZ; - p->local.p_encap = cfg->p_encap; if (cfg->secure) p->local.flags |= ISDN_NET_SECURE; else p->local.flags &= ~ISDN_NET_SECURE; - if (cfg->callback) - p->local.flags |= ISDN_NET_CALLBACK; + if (cfg->cbhup) + p->local.flags |= ISDN_NET_CBHUP; else - p->local.flags &= ~ISDN_NET_CALLBACK; + p->local.flags &= ~ISDN_NET_CBHUP; + switch (cfg->callback) { + case 0: + p->local.flags &= ~(ISDN_NET_CALLBACK&ISDN_NET_CBOUT); + break; + case 1: + p->local.flags |= ISDN_NET_CALLBACK; + p->local.flags &= ~ISDN_NET_CBOUT; + break; + case 2: + p->local.flags |= ISDN_NET_CBOUT; + p->local.flags &= ~ISDN_NET_CALLBACK; + break; + } if (cfg->chargehup) p->local.hupflags |= 4; else @@ -1957,23 +2016,26 @@ p->local.hupflags |= 8; else p->local.hupflags &= ~8; - if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev.hard_header = NULL; - p->dev.header_cache_bind = NULL; - p->dev.header_cache_update = NULL; - p->dev.flags = IFF_NOARP; - } else { - p->dev.hard_header = isdn_net_header; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { - p->dev.header_cache_bind = p->local.org_hcb; - p->dev.header_cache_update = p->local.org_hcu; - p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; - } else { + if (cfg->p_encap != p->local.p_encap) { + if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { + p->dev.hard_header = NULL; p->dev.header_cache_bind = NULL; p->dev.header_cache_update = NULL; p->dev.flags = IFF_NOARP; + } else { + p->dev.hard_header = isdn_net_header; + if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) { + p->dev.header_cache_bind = p->local.org_hcb; + p->dev.header_cache_update = p->local.org_hcu; + p->dev.flags = IFF_BROADCAST | IFF_MULTICAST; + } else { + p->dev.header_cache_bind = NULL; + p->dev.header_cache_update = NULL; + p->dev.flags = IFF_NOARP; + } } } + p->local.p_encap = cfg->p_encap; return 0; } return -ENODEV; @@ -2001,8 +2063,12 @@ cfg->p_encap = p->local.p_encap; cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; cfg->callback = (p->local.flags & ISDN_NET_CALLBACK) ? 1 : 0; + cfg->callback = (p->local.flags & ISDN_NET_CBOUT) ? 2 : 0; + cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0; cfg->ihup = (p->local.hupflags & 8) ? 1 : 0; + cfg->cbdelay = p->local.cbdelay; + cfg->dialmax = p->local.dialmax; cfg->slavedelay = p->local.slavedelay / HZ; if (p->local.slave) strcpy(cfg->slave, ((isdn_net_local *) p->local.slave->priv)->name); @@ -2074,6 +2140,7 @@ n = n->next; more = 1; } + put_fs_byte(0,phones); restore_flags(flags); return count; } diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_net.h linux/drivers/isdn/isdn_net.h --- v1.3.92/linux/drivers/isdn/isdn_net.h Fri Apr 12 15:51:53 1996 +++ linux/drivers/isdn/isdn_net.h Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.1 1996/02/11 02:35:13 fritz Exp fritz $ +/* $Id: isdn_net.h,v 1.2 1996/04/20 16:29:43 fritz Exp $ * * header for Linux ISDN subsystem, network related functions (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.2 1996/04/20 16:29:43 fritz + * Misc. typos + * * Revision 1.1 1996/02/11 02:35:13 fritz * Initial revision * diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_ppp.c linux/drivers/isdn/isdn_ppp.c --- v1.3.92/linux/drivers/isdn/isdn_ppp.c Fri Apr 12 15:51:53 1996 +++ linux/drivers/isdn/isdn_ppp.c Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.4 1996/02/19 15:25:50 fritz Exp fritz $ +/* $Id: isdn_ppp.c,v 1.5 1996/04/20 16:32:32 fritz Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.5 1996/04/20 16:32:32 fritz + * Changed ippp_table to an array of pointers, allocating each part + * separately. + * * Revision 1.4 1996/02/19 15:25:50 fritz * Bugfix: Sync-PPP packets got compressed twice, when resent due to * send-queue-full reject. @@ -68,8 +72,8 @@ int BEbyte, int *sqno, int min_sqno); #endif -char *isdn_ppp_revision = "$Revision: 1.4 $"; -struct ippp_struct *ippp_table = (struct ippp_struct *) 0; +char *isdn_ppp_revision = "$Revision: 1.5 $"; +struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); @@ -103,9 +107,9 @@ isdn_ppp_hangup(lp->ppp_minor); #if 0 - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor].lp); + printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_minor, (long) lp,(long) ippp_table[lp->ppp_minor]->lp); #endif - ippp_table[lp->ppp_minor].lp = NULL; + ippp_table[lp->ppp_minor]->lp = NULL; return 0; } @@ -126,7 +130,7 @@ * search a free device */ for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i].state == IPPP_OPEN) { /* OPEN, but not connected! */ + if (ippp_table[i]->state == IPPP_OPEN) { /* OPEN, but not connected! */ #if 0 printk(KERN_DEBUG "find_minor, %d lp: %08lx\n", i, (long) lp); #endif @@ -140,21 +144,21 @@ return -1; } lp->ppp_minor = i; - ippp_table[lp->ppp_minor].lp = lp; + ippp_table[lp->ppp_minor]->lp = lp; name = lp->name; unit = isdn_ppp_if_get_unit(&name); /* get unit number from interface name .. ugly! */ - ippp_table[lp->ppp_minor].unit = unit; + ippp_table[lp->ppp_minor]->unit = unit; - ippp_table[lp->ppp_minor].state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; + ippp_table[lp->ppp_minor]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; restore_flags(flags); /* * kick the ipppd on the new device */ - if (ippp_table[lp->ppp_minor].wq) - wake_up_interruptible(&ippp_table[lp->ppp_minor].wq); + if (ippp_table[lp->ppp_minor]->wq) + wake_up_interruptible(&ippp_table[lp->ppp_minor]->wq); return lp->ppp_minor; } @@ -164,10 +168,10 @@ if (minor < 0 || minor >= ISDN_MAX_CHANNELS) return 0; - if (ippp_table[minor].state && ippp_table[minor].wq) - wake_up_interruptible(&ippp_table[minor].wq); + if (ippp_table[minor]->state && ippp_table[minor]->wq) + wake_up_interruptible(&ippp_table[minor]->wq); - ippp_table[minor].state = IPPP_CLOSEWAIT; + ippp_table[minor]->state = IPPP_CLOSEWAIT; return 1; } @@ -178,39 +182,39 @@ int isdn_ppp_open(int minor, struct file *file) { #if 0 - printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor].state); + printk(KERN_DEBUG "ippp, open, minor: %d state: %04x\n", minor,ippp_table[minor]->state); #endif - if (ippp_table[minor].state) + if (ippp_table[minor]->state) return -EBUSY; - ippp_table[minor].lp = 0; - ippp_table[minor].mp_seqno = 0; /* MP sequence number */ - ippp_table[minor].pppcfg = 0; /* ppp configuration */ - ippp_table[minor].mpppcfg = 0; /* mppp configuration */ - ippp_table[minor].range = 0x1000000; /* MP: 24 bit range */ - ippp_table[minor].last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - ippp_table[minor].unit = -1; /* set, when we have our interface */ - ippp_table[minor].mru = 1524; /* MRU, default 1524 */ - ippp_table[minor].maxcid = 16; /* VJ: maxcid */ - ippp_table[minor].tk = current; - ippp_table[minor].wq = NULL; /* read() wait queue */ - ippp_table[minor].wq1 = NULL; /* select() wait queue */ - ippp_table[minor].first = ippp_table[minor].rq + NUM_RCV_BUFFS - 1; /* receive queue */ - ippp_table[minor].last = ippp_table[minor].rq; + ippp_table[minor]->lp = 0; + ippp_table[minor]->mp_seqno = 0; /* MP sequence number */ + ippp_table[minor]->pppcfg = 0; /* ppp configuration */ + ippp_table[minor]->mpppcfg = 0; /* mppp configuration */ + ippp_table[minor]->range = 0x1000000; /* MP: 24 bit range */ + ippp_table[minor]->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ + ippp_table[minor]->unit = -1; /* set, when we have our interface */ + ippp_table[minor]->mru = 1524; /* MRU, default 1524 */ + ippp_table[minor]->maxcid = 16; /* VJ: maxcid */ + ippp_table[minor]->tk = current; + ippp_table[minor]->wq = NULL; /* read() wait queue */ + ippp_table[minor]->wq1 = NULL; /* select() wait queue */ + ippp_table[minor]->first = ippp_table[minor]->rq + NUM_RCV_BUFFS - 1; /* receive queue */ + ippp_table[minor]->last = ippp_table[minor]->rq; #ifdef CONFIG_ISDN_PPP_VJ /* * VJ header compression init */ - ippp_table[minor].cbuf = kmalloc(ippp_table[minor].mru + PPP_HARD_HDR_LEN + 2, GFP_KERNEL); + ippp_table[minor]->cbuf = kmalloc(ippp_table[minor]->mru + PPP_HARD_HDR_LEN + 2, GFP_KERNEL); - if (ippp_table[minor].cbuf == NULL) { + if (ippp_table[minor]->cbuf == NULL) { printk(KERN_DEBUG "ippp: Can't allocate memory buffer for VJ compression.\n"); return -ENOMEM; } - ippp_table[minor].slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ + ippp_table[minor]->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ #endif - ippp_table[minor].state = IPPP_OPEN; + ippp_table[minor]->state = IPPP_OPEN; return 0; } @@ -223,35 +227,35 @@ return; #if 0 - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor].lp); + printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", minor, (long) ippp_table[minor]->lp); #endif - if (ippp_table[minor].lp) { /* a lp address says: this link is still up */ + if (ippp_table[minor]->lp) { /* a lp address says: this link is still up */ isdn_net_dev *p = dev->netdev; while(p) { /* find interface for our lp; */ - if(&p->local == ippp_table[minor].lp) + if(&p->local == ippp_table[minor]->lp) break; p = p->next; } if(!p) { printk(KERN_ERR "isdn_ppp_release: Can't find device for net_local\n"); - p = ippp_table[minor].lp->netdev; + p = ippp_table[minor]->lp->netdev; } - ippp_table[minor].lp->ppp_minor = -1; + ippp_table[minor]->lp->ppp_minor = -1; isdn_net_hangup(&p->dev); /* lp->ppp_minor==-1 => no calling of isdn_ppp_hangup() */ - ippp_table[minor].lp = NULL; + ippp_table[minor]->lp = NULL; } for (i = 0; i < NUM_RCV_BUFFS; i++) { - if (ippp_table[minor].rq[i].buf) - kfree(ippp_table[minor].rq[i].buf); + if (ippp_table[minor]->rq[i].buf) + kfree(ippp_table[minor]->rq[i].buf); } #ifdef CONFIG_ISDN_PPP_VJ - slhc_free(ippp_table[minor].slcomp); - kfree(ippp_table[minor].cbuf); + slhc_free(ippp_table[minor]->slcomp); + kfree(ippp_table[minor]->cbuf); #endif - ippp_table[minor].state = 0; + ippp_table[minor]->state = 0; } static int get_arg(void *b, unsigned long *val) @@ -279,10 +283,10 @@ #if 0 printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x",minor,cmd); - printk(KERN_DEBUG " state: %x\n",ippp_table[minor].state); + printk(KERN_DEBUG " state: %x\n",ippp_table[minor]->state); #endif - if (!(ippp_table[minor].state & IPPP_OPEN)) + if (!(ippp_table[minor]->state & IPPP_OPEN)) return -EINVAL; switch (cmd) { @@ -296,38 +300,38 @@ if ((r = get_arg((void *) arg, &val))) return r; printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) minor, (int) ippp_table[minor].unit, (int) val); + (int) minor, (int) ippp_table[minor]->unit, (int) val); return isdn_ppp_bundle(minor, val); #else return -1; #endif break; case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg((void *) arg, ippp_table[minor].unit))) + if ((r = set_arg((void *) arg, ippp_table[minor]->unit))) return r; break; case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, ippp_table[minor].mpppcfg))) + if ((r = set_arg((void *) arg, ippp_table[minor]->mpppcfg))) return r; break; case PPPIOCSMPFLAGS: /* set configuration flags */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor].mpppcfg = val; + ippp_table[minor]->mpppcfg = val; break; case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg((void *) arg, ippp_table[minor].pppcfg))) + if ((r = set_arg((void *) arg, ippp_table[minor]->pppcfg))) return r; break; case PPPIOCSFLAGS: /* set configuration flags */ if ((r = get_arg((void *) arg, &val))) { return r; } - if (val & SC_ENABLE_IP && !(ippp_table[minor].pppcfg & SC_ENABLE_IP)) { - ippp_table[minor].lp->netdev->dev.tbusy = 0; + if (val & SC_ENABLE_IP && !(ippp_table[minor]->pppcfg & SC_ENABLE_IP)) { + ippp_table[minor]->lp->netdev->dev.tbusy = 0; mark_bh(NET_BH); /* OK .. we are ready to send the first buffer */ } - ippp_table[minor].pppcfg = val; + ippp_table[minor]->pppcfg = val; break; #if 0 case PPPIOCGSTAT: /* read PPP statistic information */ @@ -338,7 +342,7 @@ case PPPIOCSMRU: /* set receive unit size for PPP */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor].mru = val; + ippp_table[minor]->mru = val; break; case PPPIOCSMPMRU: break; @@ -347,7 +351,7 @@ case PPPIOCSMAXCID: /* set the maximum compression slot id */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor].maxcid = val; + ippp_table[minor]->maxcid = val; break; case PPPIOCGDEBUG: break; @@ -368,28 +372,28 @@ printk(KERN_DEBUG "isdn_ppp_select: minor: %d, type: %d \n",minor,type); #endif - if (!(ippp_table[minor].state & IPPP_OPEN)) + if (!(ippp_table[minor]->state & IPPP_OPEN)) return -EINVAL; switch (type) { case SEL_IN: save_flags(flags); cli(); - bl = ippp_table[minor].last; - bf = ippp_table[minor].first; - if (bf->next == bl && !(ippp_table[minor].state & IPPP_NOBLOCK)) { - select_wait(&ippp_table[minor].wq, st); + bl = ippp_table[minor]->last; + bf = ippp_table[minor]->first; + if (bf->next == bl && !(ippp_table[minor]->state & IPPP_NOBLOCK)) { + select_wait(&ippp_table[minor]->wq, st); restore_flags(flags); return 0; } - ippp_table[minor].state &= ~IPPP_NOBLOCK; + ippp_table[minor]->state &= ~IPPP_NOBLOCK; restore_flags(flags); return 1; case SEL_OUT: /* we're always ready to send .. */ return 1; case SEL_EX: - select_wait(&ippp_table[minor].wq1, st); + select_wait(&ippp_table[minor]->wq1, st); return 0; } return 1; @@ -408,21 +412,21 @@ printk(KERN_WARNING "ippp: illegal minor.\n"); return 0; } - if (!(ippp_table[minor].state & IPPP_CONNECT)) { + if (!(ippp_table[minor]->state & IPPP_CONNECT)) { printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } save_flags(flags); cli(); - bf = ippp_table[minor].first; - bl = ippp_table[minor].last; + bf = ippp_table[minor]->first; + bl = ippp_table[minor]->last; if (bf == bl) { printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); bf = bf->next; kfree(bf->buf); - ippp_table[minor].first = bf; + ippp_table[minor]->first = bf; } bl->buf = (char *) kmalloc(len, GFP_ATOMIC); if (!bl->buf) { @@ -434,11 +438,11 @@ memcpy(bl->buf, buf, len); - ippp_table[minor].last = bl->next; + ippp_table[minor]->last = bl->next; restore_flags(flags); - if (ippp_table[minor].wq) - wake_up_interruptible(&ippp_table[minor].wq); + if (ippp_table[minor]->wq) + wake_up_interruptible(&ippp_table[minor]->wq); return len; } @@ -450,12 +454,12 @@ int isdn_ppp_read(int minor, struct file *file, char *buf, int count) { - struct ippp_struct *c = &ippp_table[minor]; + struct ippp_struct *c = ippp_table[minor]; struct ippp_buf_queue *b; int r; unsigned long flags; - if (!(ippp_table[minor].state & IPPP_OPEN)) + if (!(ippp_table[minor]->state & IPPP_OPEN)) return 0; if ((r = verify_area(VERIFY_WRITE, (void *) buf, count))) @@ -488,10 +492,10 @@ { isdn_net_local *lp; - if (!(ippp_table[minor].state & IPPP_CONNECT)) + if (!(ippp_table[minor]->state & IPPP_CONNECT)) return 0; - lp = ippp_table[minor].lp; + lp = ippp_table[minor]->lp; /* -> push it directly to the lowlevel interface */ @@ -503,8 +507,8 @@ if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && (lp->flags & ISDN_NET_CONNECTED)) - dev->drv[lp->isdn_device]->interface->writebuf( - lp->isdn_device,lp->isdn_channel, buf, count, 1); + isdn_writebuf_stub(lp->isdn_device,lp->isdn_channel, + buf, count, 1); } return count; @@ -518,22 +522,24 @@ { int i, j; - if (!(ippp_table = (struct ippp_struct *) - kmalloc(sizeof(struct ippp_struct) * ISDN_MAX_CHANNELS, GFP_KERNEL))) { - printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - return -1; - } - memset((char *) ippp_table, 0, sizeof(struct ippp_struct) * ISDN_MAX_CHANNELS); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - ippp_table[i].state = 0; - ippp_table[i].first = ippp_table[i].rq + NUM_RCV_BUFFS - 1; - ippp_table[i].last = ippp_table[i].rq; + if (!(ippp_table[i] = (struct ippp_struct *) + kmalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { + printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); + for (j = 0; j < i; j++) + kfree(ippp_table[i]); + return -1; + } + memset((char *) ippp_table[i], 0, sizeof(struct ippp_struct)); + ippp_table[i]->state = 0; + ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; + ippp_table[i]->last = ippp_table[i]->rq; for (j = 0; j < NUM_RCV_BUFFS; j++) { - ippp_table[i].rq[j].buf = NULL; - ippp_table[i].rq[j].last = ippp_table[i].rq + + ippp_table[i]->rq[j].buf = NULL; + ippp_table[i]->rq[j].last = ippp_table[i]->rq + (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS; - ippp_table[i].rq[j].next = ippp_table[i].rq + (j + 1) % NUM_RCV_BUFFS; + ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS; } } return 0; @@ -541,7 +547,10 @@ void isdn_ppp_cleanup(void) { - kfree(ippp_table); + int i; + + for (i = 0; i < ISDN_MAX_CHANNELS; i++) + kfree(ippp_table[i]); } /* @@ -556,11 +565,11 @@ if(skb->data[0] == 0xff && skb->data[1] == 0x03) skb_pull(skb,2); - else if (ippp_table[lp->ppp_minor].pppcfg & SC_REJ_COMP_AC) + else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) return; /* discard it silently */ #ifdef CONFIG_ISDN_MPP - if (!(ippp_table[lp->ppp_minor].mpppcfg & SC_REJ_MP_PROT)) { + if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_REJ_MP_PROT)) { int proto; int sqno_end; if (skb->data[0] & 0x1) { @@ -579,7 +588,7 @@ (int) skb->len, (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); #endif - if (!(ippp_table[lp->ppp_minor].mpppcfg & SC_IN_SHORT_SEQ)) { + if (!(ippp_table[lp->ppp_minor]->mpppcfg & SC_IN_SHORT_SEQ)) { sqno = ((int) skb->data[1] << 16) + ((int) skb->data[2] << 8) + (int) skb->data[3]; skb_pull(skb,4); } else { @@ -587,26 +596,26 @@ skb_pull(skb,2); } - if ((tseq = ippp_table[lp->ppp_minor].last_link_seqno) >= sqno) { - int range = ippp_table[lp->ppp_minor].range; + if ((tseq = ippp_table[lp->ppp_minor]->last_link_seqno) >= sqno) { + int range = ippp_table[lp->ppp_minor]->range; if (tseq + 1024 < range + sqno) /* redundancy check .. not MP conform */ printk(KERN_WARNING "isdn_ppp_receive, MP, detected overflow with sqno: %d, last: %d !!!\n", sqno, tseq); else { sqno += range; - ippp_table[lp->ppp_minor].last_link_seqno = sqno; + ippp_table[lp->ppp_minor]->last_link_seqno = sqno; } } else - ippp_table[lp->ppp_minor].last_link_seqno = sqno; + ippp_table[lp->ppp_minor]->last_link_seqno = sqno; for (min_sqno = 0, lpq = net_dev->queue;;) { - if (ippp_table[lpq->ppp_minor].last_link_seqno > min_sqno) - min_sqno = ippp_table[lpq->ppp_minor].last_link_seqno; + if (ippp_table[lpq->ppp_minor]->last_link_seqno > min_sqno) + min_sqno = ippp_table[lpq->ppp_minor]->last_link_seqno; lpq = lpq->next; if (lpq == net_dev->queue) break; } - if (min_sqno >= ippp_table[lpq->ppp_minor].range) { /* OK, every link overflowed */ - int mask = ippp_table[lpq->ppp_minor].range - 1; /* range is a power of 2 */ + if (min_sqno >= ippp_table[lpq->ppp_minor]->range) { /* OK, every link overflowed */ + int mask = ippp_table[lpq->ppp_minor]->range - 1; /* range is a power of 2 */ isdn_ppp_cleanup_queue(net_dev, min_sqno); isdn_ppp_mask_queue(net_dev, mask); net_dev->ib.next_num &= mask; @@ -619,7 +628,7 @@ } min_sqno &= mask; for (lpq = net_dev->queue;;) { - ippp_table[lpq->ppp_minor].last_link_seqno &= mask; + ippp_table[lpq->ppp_minor]->last_link_seqno &= mask; lpq = lpq->next; if (lpq == net_dev->queue) break; @@ -729,7 +738,7 @@ break; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: - slhc_remember(ippp_table[net_dev->local.ppp_minor].slcomp, skb->data, skb->len); + slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len); #endif case PPP_IP: skb->dev = dev; @@ -752,7 +761,7 @@ skb_put(skb,skb_old->len + 40); memcpy(skb->data, skb_old->data, skb_old->len); skb->mac.raw = skb->data; - pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor].slcomp, + pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb_old->len); skb_trim(skb, pkt_len); dev_kfree_skb(skb_old,FREE_WRITE); @@ -792,8 +801,8 @@ isdn_net_dev *nd = ((isdn_net_local *) dev->priv)->netdev; isdn_net_local *lp = nd->queue; int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt = ippp_table + lp->ppp_minor; - struct ippp_struct *ipts = ippp_table + lp->netdev->local.ppp_minor; + struct ippp_struct *ipt = ippp_table[lp->ppp_minor]; + struct ippp_struct *ipts = ippp_table[lp->netdev->local.ppp_minor]; /* If packet is to be resent, it has already been processed and * therefore it's first bytes are already initialized. In this case @@ -911,7 +920,7 @@ save_flags(flags); cli(); - nlp = ippp_table[minor].lp; + nlp = ippp_table[minor]->lp; lp = p->queue; p->ib.bundled = 1; @@ -923,17 +932,17 @@ nlp->netdev = lp->netdev; - ippp_table[nlp->ppp_minor].unit = ippp_table[lp->ppp_minor].unit; + ippp_table[nlp->ppp_minor]->unit = ippp_table[lp->ppp_minor]->unit; /* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_minor].pppcfg |= ippp_table[lp->ppp_minor].pppcfg & + ippp_table[nlp->ppp_minor]->pppcfg |= ippp_table[lp->ppp_minor]->pppcfg & (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); - ippp_table[nlp->ppp_minor].mpppcfg |= ippp_table[lp->ppp_minor].mpppcfg & + ippp_table[nlp->ppp_minor]->mpppcfg |= ippp_table[lp->ppp_minor]->mpppcfg & (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); #if 0 - if (ippp_table[nlp->ppp_minor].mpppcfg != ippp_table[lp->ppp_minor].mpppcfg) { + if (ippp_table[nlp->ppp_minor]->mpppcfg != ippp_table[lp->ppp_minor]->mpppcfg) { printk(KERN_WARNING "isdn_ppp_bundle: different MP options %04x and %04x\n", - ippp_table[nlp->ppp_minor].mpppcfg, ippp_table[lp->ppp_minor].mpppcfg); + ippp_table[nlp->ppp_minor]->mpppcfg, ippp_table[lp->ppp_minor]->mpppcfg); } #endif diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_ppp.h linux/drivers/isdn/isdn_ppp.h --- v1.3.92/linux/drivers/isdn/isdn_ppp.h Mon Feb 26 11:58:05 1996 +++ linux/drivers/isdn/isdn_ppp.h Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.1 1996/01/10 21:39:10 fritz Exp fritz $ +/* $Id: isdn_ppp.h,v 1.2 1996/04/20 16:35:11 fritz Exp $ * * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.2 1996/04/20 16:35:11 fritz + * Changed isdn_ppp_receive to use sk_buff as parameter. + * Added definition of isdn_ppp_dial_slave and ippp_table. + * * Revision 1.1 1996/01/10 21:39:10 fritz * Initial revision * @@ -41,4 +45,4 @@ extern void isdn_ppp_release(int, struct file *); extern int isdn_ppp_dial_slave(char *); -extern struct ippp_struct *ippp_table; +extern struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c --- v1.3.92/linux/drivers/isdn/isdn_tty.c Fri Apr 12 15:51:54 1996 +++ linux/drivers/isdn/isdn_tty.c Sun Apr 21 11:56:14 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.3 1996/02/11 02:12:32 fritz Exp fritz $ +/* $Id: isdn_tty.c,v 1.4 1996/04/20 16:39:54 fritz Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.4 1996/04/20 16:39:54 fritz + * Changed all io to go through generic routines in isdn_common.c + * Fixed a real ugly bug in modem-emulator: 'ATA' had been accepted + * even when a call has been cancelled from the remote machine. + * * Revision 1.3 1996/02/11 02:12:32 fritz * Bugfixes according to similar fixes in standard serial.c of kernel. * @@ -49,7 +54,7 @@ static char *isdn_ttyname_ttyI = "ttyI"; static char *isdn_ttyname_cui = "cui"; -char *isdn_tty_revision = "$Revision: 1.3 $"; +char *isdn_tty_revision = "$Revision: 1.4 $"; int isdn_tty_try_read(int i, u_char * buf, int len) { @@ -194,8 +199,10 @@ { isdn_ctrl cmd; - dev->mdm.rcvsched[info->line] = 0; - dev->mdm.online[info->line] = 0; + if (!info) + return; + dev->mdm.rcvsched[info->line] = 0; + dev->mdm.online[info->line] = 0; if (info->isdn_driver >= 0) { cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_HANGUP; @@ -204,22 +211,24 @@ isdn_all_eaz(info->isdn_driver, info->isdn_channel); isdn_free_channel(info->isdn_driver, info->isdn_channel, ISDN_USAGE_MODEM); } - dev->m_idx[info->drv_index] = -1; info->isdn_driver = -1; info->isdn_channel = -1; - info->drv_index = -1; + if (info->drv_index >= 0) { + info->drv_index = -1; + dev->m_idx[info->drv_index] = -1; + } } static inline int isdn_tty_paranoia_check(modem_info * info, dev_t device, const char *routine) { #ifdef MODEM_PARANOIA_CHECK if (!info) { - printk(KERN_WARNING "isdn: null info_struct for (%d, %d) in %s\n", + printk(KERN_WARNING "isdn_tty: null info_struct for (%d, %d) in %s\n", MAJOR(device), MINOR(device), routine); return 1; } if (info->magic != ISDN_ASYNC_MAGIC) { - printk(KERN_WARNING "isdn: bad magic for modem struct (%d, %d) in %s\n", + printk(KERN_WARNING "isdn_tty: bad magic for modem struct (%d, %d) in %s\n", MAJOR(device), MINOR(device), routine); return 1; } @@ -253,13 +262,12 @@ } else { info->MCR &= ~UART_MCR_DTR; isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); - if (dev->mdm.online[info->line]) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in changespeed\n"); + printk(KERN_DEBUG "Mhup in changespeed\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info); + if (dev->mdm.online[info->line]) isdn_tty_modem_result(3, info); - } return; } /* byte size and parity */ @@ -338,12 +346,10 @@ if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); - if (dev->mdm.online[info->line]) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); + printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); #endif - isdn_tty_modem_hup(info); - } + isdn_tty_modem_hup(info); } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); @@ -414,8 +420,8 @@ isdn_dumppkt("T70pack2:", bufptr, buflen, 40); #endif } - if (dev->drv[info->isdn_driver]->interface-> - writebuf(info->isdn_driver, info->isdn_channel, bufptr, buflen, 0) > 0) { + if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, bufptr, + buflen, 0) > 0) { info->xmit_count = 0; info->xmit_size = dev->mdm.atmodem[i].mdmreg[16] * 16; #if FUTURE @@ -607,13 +613,12 @@ if (arg & TIOCM_DTR) { info->MCR &= ~UART_MCR_DTR; isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); - if (dev->mdm.online[info->line]) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); + printk(KERN_DEBUG "Mhup in TIOCMBIC\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info); + if (dev->mdm.online[info->line]) isdn_tty_modem_result(3, info); - } } break; case TIOCMSET: @@ -622,13 +627,12 @@ | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); if (!(info->MCR & UART_MCR_DTR)) { isdn_tty_modem_reset_regs(&dev->mdm.atmodem[info->line], 0); - if (dev->mdm.online[info->line]) { #ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); + printk(KERN_DEBUG "Mhup in TIOCMSET\n"); #endif - isdn_tty_modem_hup(info); + isdn_tty_modem_hup(info); + if (dev->mdm.online[info->line]) isdn_tty_modem_result(3, info); - } } break; default: @@ -780,7 +784,7 @@ */ if (tty_hung_up_p(filp) || (info->flags & ISDN_ASYNC_CLOSING)) { - if (info->flags & ISDN_ASYNC_CLOSING) + if (info->flags & ISDN_ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); #ifdef MODEM_DO_RESTART if (info->flags & ISDN_ASYNC_HUP_NOTIFY) @@ -1172,11 +1176,11 @@ m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT; if (tty_register_driver(&m->tty_modem)) { - printk(KERN_WARNING "isdn: Unable to register modem-device\n"); + printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n"); return -1; } if (tty_register_driver(&m->cua_modem)) { - printk(KERN_WARNING "Couldn't register modem-callout-device\n"); + printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n"); return -2; } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { @@ -1228,13 +1232,13 @@ if (num[0] == ',') { nr[0] = '0'; strncpy(&nr[1], num, 29); - printk(KERN_WARNING "isdn: Incoming call without OAD, assuming '0'\n"); + printk(KERN_WARNING "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else strncpy(nr, num, 30); s = strtok(nr, ","); s = strtok(NULL, ","); if (!s) { - printk(KERN_WARNING "isdn: Incoming callinfo garbled, ignored: %s\n", + printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n", num); restore_flags(flags); return -1; @@ -1242,7 +1246,7 @@ si1 = (int)simple_strtoul(s,NULL,10); s = strtok(NULL, ","); if (!s) { - printk(KERN_WARNING "isdn: Incoming callinfo garbled, ignored: %s\n", + printk(KERN_WARNING "isdn_tty: Incoming callinfo garbled, ignored: %s\n", num); restore_flags(flags); return -1; @@ -1250,7 +1254,7 @@ si2 = (int)simple_strtoul(s,NULL,10); eaz = strtok(NULL, ","); if (!eaz) { - printk(KERN_WARNING "isdn: Incoming call without CPN, assuming '0'\n"); + printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } #ifdef ISDN_DEBUG_MODEM_ICALL @@ -1318,7 +1322,7 @@ ulong flags; if (!msg) { - printk(KERN_WARNING "isdn: Null-Message in isdn_tty_at_cout\n"); + printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); return; } save_flags(flags); @@ -1567,7 +1571,7 @@ case 'A': /* A - Accept incoming call */ p++; - if (m->mdmreg[1]) { + if (dev->mdm.msr[info->line] & UART_MSR_RI) { #define FIDOBUG #ifdef FIDOBUG /* Variables fido... defined temporarily for finding a strange bug */ @@ -2019,8 +2023,8 @@ isdn_dumppkt("T70pack4:", bufptr, buflen, 40); #endif } - if (dev->drv[info->isdn_driver]->interface-> - writebuf(info->isdn_driver, info->isdn_channel, bufptr, buflen, 0) > 0) { + if (isdn_writebuf_stub(info->isdn_driver, info->isdn_channel, + bufptr, buflen, 0) > 0) { info->xmit_count = 0; info->xmit_size = dev->mdm.atmodem[midx].mdmreg[16] * 16; #if FUTURE diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/Makefile linux/drivers/isdn/pcbit/Makefile --- v1.3.92/linux/drivers/isdn/pcbit/Makefile Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/Makefile Sun Apr 21 11:56:14 1996 @@ -0,0 +1,15 @@ +L_OBJS := +M_OBJS := +O_OBJS := module.o edss1.o drv.o layer2.o capi.o callbacks.o + +O_TARGET := +ifeq ($(CONFIG_ISDN_DRV_PCBIT),y) + O_TARGET += pcbit.o +else + ifeq ($(CONFIG_ISDN_DRV_PCBIT),m) + O_TARGET += pcbit.o + M_OBJS += pcbit.o + endif +endif + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/callbacks.c linux/drivers/isdn/pcbit/callbacks.c --- v1.3.92/linux/drivers/isdn/pcbit/callbacks.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/callbacks.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,361 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * callbacks for the FSM + */ + +#define __NO_VERSION__ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include "pcbit.h" +#include "layer2.h" +#include "edss1.h" +#include "callbacks.h" +#include "capi.h" + +ushort last_ref_num = 1; + +/* + * send_conn_req + * + */ + +void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *cbdata) +{ + struct sk_buff *skb; + int len; + ushort refnum; + + +#ifdef DEBUG + printk(KERN_DEBUG "Called Party Number: %s\n", + cbdata->data.setup.CalledPN); +#endif + /* + * hdr - kmalloc in capi_conn_req + * - kfree when msg has been sent + */ + + if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb)) < 0) + { + printk("capi_conn_req failed\n"); + return; + } + + + refnum = last_ref_num++ & 0x7fffU; + + chan->callref = 0; + chan->layer2link = 0; + chan->snum = 0; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len); +} + +/* + * rcv CONNECT + * will go into ACTIVE state + * send CONN_ACTIVE_RESP + * send Select protocol request + */ + +void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + isdn_ctrl ictl; + struct sk_buff *skb; + int len; + ushort refnum; + + if ((len=capi_conn_active_resp(chan, &skb)) < 0) + { + printk("capi_conn_active_req failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len); + + + ictl.command = ISDN_STAT_DCONN; + ictl.driver=dev->id; + ictl.arg=chan->id; + dev->dev_if->statcallb(&ictl); + + /* ACTIVE D-channel */ + + /* Select protocol */ + + if ((len=capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) { + printk("capi_select_proto_req failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); +} + + +/* + * Disconnect received (actualy RELEASE COMPLETE) + * This means we where not hable to establish connection with remote + * Inform the big boss above + */ +void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + isdn_ctrl ictl; + + ictl.command = ISDN_STAT_DHUP; + ictl.driver=dev->id; + ictl.arg=chan->id; + dev->dev_if->statcallb(&ictl); +} + + +/* + * Incomming call received + * inform user + */ + +void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *cbdata) +{ + isdn_ctrl ictl; + unsigned short refnum; + struct sk_buff *skb; + int len; + + + ictl.command = ISDN_STAT_ICALL; + ictl.driver=dev->id; + ictl.arg=chan->id; + + /* + * ictl.num >= strlen() + strlen() + 5 + */ + + if (cbdata->data.setup.CalledPN) + sprintf(ictl.num, "%s,%d,%d,%s", + cbdata->data.setup.CallingPN, + 7, 0, + cbdata->data.setup.CalledPN); + + else + sprintf(ictl.num, "%s,%d,%d,%s", + cbdata->data.setup.CallingPN, + 7, 0, + "0"); + + +#ifdef DEBUG + printk(KERN_DEBUG "statstr: %s\n", ictl.num); +#endif + + dev->dev_if->statcallb(&ictl); + + + if ((len=capi_conn_resp(chan, &skb)) < 0) { + printk(KERN_DEBUG "capi_conn_resp failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len); +} + +/* + * user has replyed + * open the channel + * send CONNECT message CONNECT_ACTIVE_REQ in CAPI + */ + +void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + unsigned short refnum; + struct sk_buff *skb; + int len; + + if ((len = capi_conn_active_req(chan, &skb)) < 0) { + printk(KERN_DEBUG "capi_conn_active_req failed\n"); + return; + } + + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n"); + pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len); +} + +/* + * CONN_ACK arrived + * start b-proto selection + * + */ + +void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + unsigned short refnum; + struct sk_buff *skb; + int len; + + if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0) + { + printk("capi_select_proto_req failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len); + +} + + +/* + * Received disconnect ind on active state + * send disconnect resp + * send msg to user + */ +void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + struct sk_buff *skb; + int len; + ushort refnum; + isdn_ctrl ictl; + + if ((len = capi_disc_resp(chan, &skb)) < 0) { + printk("capi_disc_resp failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len); + + ictl.command = ISDN_STAT_BHUP; + ictl.driver=dev->id; + ictl.arg=chan->id; + dev->dev_if->statcallb(&ictl); +} + + +/* + * User HANGUP on active/call proceding state + * send disc.req + */ +void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + struct sk_buff *skb; + int len; + ushort refnum; + + if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0) + { + printk("capi_disc_req failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len); +} + +/* + * Disc confirm received send BHUP + * Problem: when the HL driver sends the disc req itself + * LL receives BHUP + */ +void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + isdn_ctrl ictl; + + ictl.command = ISDN_STAT_BHUP; + ictl.driver=dev->id; + ictl.arg=chan->id; + dev->dev_if->statcallb(&ictl); +} + +void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ +} + +/* + * send activate b-chan protocol + */ +void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + struct sk_buff *skb; + int len; + ushort refnum; + + if ((len = capi_activate_transp_req(chan, &skb)) < 0) + { + printk("capi_conn_activate_transp_req failed\n"); + return; + } + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len); +} + +/* + * Inform User that the B-channel is availiable + */ +void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data) +{ + isdn_ctrl ictl; + + ictl.command = ISDN_STAT_BCONN; + ictl.driver=dev->id; + ictl.arg=chan->id; + dev->dev_if->statcallb(&ictl); +} + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/callbacks.h linux/drivers/isdn/pcbit/callbacks.h --- v1.3.92/linux/drivers/isdn/pcbit/callbacks.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/callbacks.h Sun Apr 21 11:56:14 1996 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * Callbacks prototypes for FSM + * + */ + +#ifndef CALLBACKS_H +#define CALLBACKS_H + + +extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); +extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); +extern void cb_in_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_disc_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); +extern void cb_disc_2(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); +extern void cb_disc_3(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_notdone(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +extern void cb_selp_1(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); +extern void cb_open(struct pcbit_dev * dev, struct pcbit_chan* chan, + struct callb_data *data); + +#endif + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/capi.c linux/drivers/isdn/pcbit/capi.c --- v1.3.92/linux/drivers/isdn/pcbit/capi.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/capi.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,663 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * CAPI encoder/decoder for + * Portugal Telecom CAPI 2.0 + * + * Not compatible with the AVM Gmbh. CAPI 2.0 + */ + +/* + * Documentation: + * - "Common ISDN API - Perfil Português - Versão 2.1", + * Telecom Portugal, Fev 1992. + * - "Common ISDN API - Especificação de protocolos para + * acesso aos canais B", Inesc, Jan 1994. + */ + +/* + * TODO: better decoding of Information Elements + * for debug purposes mainly + * encode our number in CallerPN and ConnectedPN + */ + +#define __NO_VERSION__ + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "pcbit.h" +#include "edss1.h" +#include "capi.h" + + +/* + * Encoding of CAPI messages + * + */ + +int capi_conn_req(const char * calledPN, struct sk_buff **skb) +{ + ushort len; + + /* + * length + * AppInfoMask - 2 + * BC0 - 3 + * BC1 - 1 + * Chan - 2 + * Keypad - 1 + * CPN - 1 + * CPSA - 1 + * CalledPN - 2 + strlen + * CalledPSA - 1 + * rest... - 4 + * ---------------- + * Total 18 + strlen + */ + + len = 18 + strlen(calledPN); + + if ((*skb = dev_alloc_skb(len)) == NULL) { + + printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n"); + return -1; + } + + /* InfoElmMask */ + *((ushort*) skb_put(*skb, 2)) = AppInfoMask; + + + /* Bearer Capbility - Mandatory*/ + *(skb_put(*skb, 1)) = 2; /* BC0.Length */ + *(skb_put(*skb, 1)) = 0x88; /* BC0.Octect3 - Digital Information */ + *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 - */ + + /* Bearer Capbility - Optional*/ + *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */ + + *(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */ + *(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */ + + *(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */ + + + *(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */ + *(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */ + + /* Called Party Number */ + *(skb_put(*skb, 1)) = strlen(calledPN) + 1; + *(skb_put(*skb, 1)) = 0x81; + memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN)); + + /* '#' */ + + *(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */ + + /* LLC.Length = 0; */ + /* HLC0.Length = 0; */ + /* HLC1.Length = 0; */ + /* UTUS.Length = 0; */ + memset(skb_put(*skb, 4), 0, 4); + + return len; +} + +int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb) +{ + + if ((*skb = dev_alloc_skb(5)) == NULL) { + + printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + *(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */ + *(skb_put(*skb, 1)) = 0; + *(skb_put(*skb, 1)) = 0; + + return 5; +} + +int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb) +{ + /* + * 8 bytes + */ + + if ((*skb = dev_alloc_skb(8)) == NULL) { + + printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + +#ifdef DEBUG + printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); +#endif + + *(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */ + *(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */ + *(skb_put(*skb, 1)) = 0; /* PSA.Length */ + *(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */ + *(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */ + *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ + + return 8; +} + +int capi_conn_active_resp(struct pcbit_chan* chan, struct sk_buff **skb) +{ + /* + * 2 bytes + */ + + if ((*skb = dev_alloc_skb(2)) == NULL) { + + printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + + return 2; +} + + +int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb, + int outgoing) +{ + + /* + * 18 bytes + */ + + if ((*skb = dev_alloc_skb(18)) == NULL) { + + printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + + /* Layer2 protocol */ + + switch (chan->proto) { + case ISDN_PROTO_L2_X75I: + *(skb_put(*skb, 1)) = 0x05; /* LAPB */ + break; + case ISDN_PROTO_L2_HDLC: +#ifdef DEBUG + printk(KERN_DEBUG "HDLC\n"); /* HDLC */ +#endif + *(skb_put(*skb, 1)) = 0x02; + break; + default: +#ifdef DEBUG + printk(KERN_DEBUG "Transparent\n"); +#endif + *(skb_put(*skb, 1)) = 0x03; + break; + } + + *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */ + *(skb_put(*skb, 1)) = 0x00; + + *((ushort *) skb_put(*skb, 2)) = MRU; + + + *(skb_put(*skb, 1)) = 0x08; /* Modulo */ + *(skb_put(*skb, 1)) = 0x07; /* Max Window */ + + *(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */ + + /* + * 2 - layer3 MTU [10] + * - Modulo [12] + * - Window + * - layer1 proto [14] + * - bitrate + * - sub-channel [16] + * - layer1dataformat [17] + */ + + memset(skb_put(*skb, 8), 0, 8); + + return 18; +} + + +int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb) +{ + + if ((*skb = dev_alloc_skb(7)) == NULL) { + + printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + + + *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */ + *(skb_put(*skb, 1)) = 0x00; /* Transmit by default */ + + *((ushort *) skb_put(*skb, 2)) = MRU; + + *(skb_put(*skb, 1)) = 0x01; /* Enables reception*/ + + return 7; +} + +int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb) +{ + ushort data_len; + + + /* + * callref - 2 + * layer2link - 1 + * wBlockLength - 2 + * data - 4 + * sernum - 1 + */ + + data_len = skb->len; + + skb_push(skb, 10); + + *((u16 *) (skb->data)) = chan->callref; + skb->data[2] = chan->layer2link; + *((u16 *) (skb->data + 3)) = data_len; + + chan->s_refnum = (chan->s_refnum + 1) % 8; + *((u32 *) (skb->data + 5)) = chan->s_refnum; + + skb->data[9] = 0; /* HDLC frame number */ + + return 10; +} + +int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb) + +{ + if ((*skb = dev_alloc_skb(4)) == NULL) { + + printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = chan->callref; + + *(skb_put(*skb, 1)) = chan->layer2link; + *(skb_put(*skb, 1)) = chan->r_refnum; + + return (*skb)->len; +} + +int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause) +{ + + if ((*skb = dev_alloc_skb(6)) == NULL) { + + printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2) ) = callref; + + *(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */ + *(skb_put(*skb, 1)) = 0x80; + *(skb_put(*skb, 1)) = 0x80 | cause; + + /* + * Change it: we should send 'Sic transit gloria Mundi' here ;-) + */ + + *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */ + + return 6; +} + +int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb) +{ + if ((*skb = dev_alloc_skb(2)) == NULL) { + + printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n"); + return -1; + } + + (*skb)->free = 1; + + *((ushort*) skb_put(*skb, 2)) = chan->callref; + + return 2; +} + + +/* + * Decoding of CAPI messages + * + */ + +int capi_decode_conn_ind(struct pcbit_chan * chan, + struct sk_buff *skb, + struct callb_data *info) +{ + int CIlen, len; + + /* Call Reference [CAPI] */ + chan->callref = *((ushort*) skb->data); + skb_pull(skb, 2); + +#ifdef DEBUG + printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref); +#endif + + /* Channel Identification */ + + /* Expect + Len = 1 + Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ] + */ + + CIlen = skb->data[0]; +#ifdef DEBUG + if (CIlen == 1) { + + if ( ((skb->data[1]) & 0xFC) == 0x48 ) + printk(KERN_DEBUG "decode_conn_ind: chan ok\n"); + printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03); + } + else + printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen); +#endif + skb_pull(skb, CIlen + 1); + + /* Calling Party Number */ + /* An "aditional service" as far as Portugal Telecom is concerned */ + + len = skb->data[0]; + + if (len > 0) { + int count = 1; + +#ifdef DEBUG + printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]); +#endif + if ((skb->data[1] & 0x80) == 0) + count = 2; + + if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC))) + return -1; + + memcpy(info->data.setup.CallingPN, skb->data + count + 1, + len - count); + info->data.setup.CallingPN[len - count] = 0; + + } + else { + info->data.setup.CallingPN = NULL; + printk(KERN_DEBUG "NULL CallingPN\n"); + } + + skb_pull(skb, len + 1); + + /* Calling Party Subaddress */ + skb_pull(skb, skb->data[0] + 1); + + /* Called Party Number */ + + len = skb->data[0]; + + if (len > 0) { + int count = 1; + + if ((skb->data[1] & 0x80) == 0) + count = 2; + + if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC))) + return -1; + + memcpy(info->data.setup.CalledPN, skb->data + count + 1, + len - count); + info->data.setup.CalledPN[len - count] = 0; + + } + else { + info->data.setup.CalledPN = NULL; + printk(KERN_DEBUG "NULL CalledPN\n"); + } + + skb_pull(skb, len + 1); + + /* Called Party Subaddress */ + skb_pull(skb, skb->data[0] + 1); + + /* LLC */ + skb_pull(skb, skb->data[0] + 1); + + /* HLC */ + skb_pull(skb, skb->data[0] + 1); + + /* U2U */ + skb_pull(skb, skb->data[0] + 1); + + return 0; +} + +/* + * returns errcode + */ + +int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, + int *complete) +{ + int errcode; + + chan->callref = *((ushort *) skb->data); /* Update CallReference */ + skb_pull(skb, 2); + + errcode = *((ushort *) skb->data); /* read errcode */ + skb_pull(skb, 2); + + *complete = *(skb->data); + skb_pull(skb, 1); + + /* FIX ME */ + /* This is actualy a firmware bug */ + if (!*complete) + { + printk(KERN_DEBUG "complete=%02x\n", *complete); + *complete = 1; + } + + + /* Optional Bearer Capability */ + skb_pull(skb, *(skb->data) + 1); + + /* Channel Identification */ + skb_pull(skb, *(skb->data) + 1); + + /* High Layer Compatibility follows */ + skb_pull(skb, *(skb->data) + 1); + + return errcode; +} + +int capi_decode_conn_actv_ind(struct pcbit_chan * chan, struct sk_buff *skb) +{ + ushort len; +#ifdef DEBUG + char str[32]; +#endif + + /* Yet Another Bearer Capability */ + skb_pull(skb, *(skb->data) + 1); + + + /* Connected Party Number */ + len=*(skb->data); + +#ifdef DEBUG + if (len > 1 && len < 31) { + memcpy(str, skb->data + 2, len - 1); + str[len] = 0; + printk(KERN_DEBUG "Connected Party Number: %s\n", str); + } + else + printk(KERN_DEBUG "actv_ind CPN len = %d\n", len); +#endif + + skb_pull(skb, len + 1); + + /* Connected Subaddress */ + skb_pull(skb, *(skb->data) + 1); + + /* Low Layer Capability */ + skb_pull(skb, *(skb->data) + 1); + + /* High Layer Capability */ + skb_pull(skb, *(skb->data) + 1); + + return 0; +} + +int capi_decode_conn_actv_conf(struct pcbit_chan * chan, struct sk_buff *skb) +{ + ushort errcode; + + errcode = *((ushort*) skb->data); + skb_pull(skb, 2); + + /* Channel Identification + skb_pull(skb, skb->data[0] + 1); + */ + return errcode; +} + + +int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb) +{ + ushort errcode; + + chan->layer2link = *(skb->data); + skb_pull(skb, 1); + + errcode = *((ushort*) skb->data); + skb_pull(skb, 2); + + return errcode; +} + +int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb) +{ + ushort errcode; + + if (chan->layer2link != *(skb->data) ) + printk("capi_decode_actv_trans_conf: layer2link doesn't match\n"); + + skb_pull(skb, 1); + + errcode = *((ushort*) skb->data); + skb_pull(skb, 2); + + return errcode; +} + +int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb) +{ + ushort len; +#ifdef DEBUG + int i; +#endif + /* Cause */ + + len = *(skb->data); + skb_pull(skb, 1); + +#ifdef DEBUG + + for (i=0; idata + i)); +#endif + + skb_pull(skb, len); + + return 0; +} + +int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb) +{ + ushort errcode; + + errcode = *((ushort*) skb->data); + skb_pull(skb, 2); + + return errcode; +} + +#ifdef DEBUG +int capi_decode_debug_188(u_char *hdr, ushort hdrlen) +{ + char str[64]; + int len; + + len = hdr[0]; + + if (len < 64 && len == hdrlen - 1) { + memcpy(str, hdr + 1, hdrlen - 1); + str[hdrlen - 1] = 0; + printk("%s\n", str); + } + else + printk("debug message incorrect\n"); + + return 0; +} +#endif + + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/capi.h linux/drivers/isdn/pcbit/capi.h --- v1.3.92/linux/drivers/isdn/pcbit/capi.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/capi.h Sun Apr 21 11:56:14 1996 @@ -0,0 +1,90 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * CAPI encode/decode prototypes and defines + */ + +#ifndef CAPI_H +#define CAPI_H + + +#define REQ_CAUSE 0x01 +#define REQ_DISPLAY 0x04 +#define REQ_USER_TO_USER 0x08 + +#define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER + +/* Connection Setup */ +extern int capi_conn_req(const char * calledPN, struct sk_buff **buf); +extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, + int *complete); + +extern int capi_decode_conn_ind(struct pcbit_chan * chan, struct sk_buff *skb, + struct callb_data *info); +extern int capi_conn_resp(struct pcbit_chan* chan, struct sk_buff **skb); + +extern int capi_conn_active_req(struct pcbit_chan* chan, struct sk_buff **skb); +extern int capi_decode_conn_actv_conf(struct pcbit_chan * chan, + struct sk_buff *skb); + +extern int capi_decode_conn_actv_ind(struct pcbit_chan * chan, + struct sk_buff *skb); +extern int capi_conn_active_resp(struct pcbit_chan* chan, + struct sk_buff **skb); + +/* Data */ +extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb, + int outgoing); +extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan, + struct sk_buff *skb); + +extern int capi_activate_transp_req(struct pcbit_chan *chan, + struct sk_buff **skb); +extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan, + struct sk_buff *skb); + +extern int capi_tdata_req(struct pcbit_chan* chan, struct sk_buff *skb); +extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb); + +/* Connection Termination */ +extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause); +extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb); + +extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb); +extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb); + +#ifdef DEBUG +extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen); +#endif + +extern __inline__ +struct pcbit_chan * +capi_channel(struct pcbit_dev *dev, struct sk_buff *skb) +{ + ushort callref; + + callref = *((ushort*) skb->data); + skb_pull(skb, 2); + + if (dev->b1->callref == callref) + return dev->b1; + else if (dev->b2->callref == callref) + return dev->b2; + + return NULL; +} + +#endif + + + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/drv.c linux/drivers/isdn/pcbit/drv.c --- v1.3.92/linux/drivers/isdn/pcbit/drv.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/drv.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,1140 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * PCBIT-D interface with isdn4linux + */ + +#define __NO_VERSION__ + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pcbit.h" +#include "edss1.h" +#include "layer2.h" +#include "capi.h" + + +extern ushort last_ref_num; + +static int pcbit_ioctl(isdn_ctrl* ctl); + +static char* pcbit_devname[MAX_PCBIT_CARDS] = { + "pcbit0", + "pcbit1", + "pcbit2", + "pcbit3" +}; + +/* + * prototypes + */ + +int pcbit_command(isdn_ctrl* ctl); +int pcbit_stat(u_char* buf, int len, int user); +int pcbit_xmit(int driver, int chan, struct sk_buff *skb); +int pcbit_writecmd(const u_char*, int, int); + +static int set_protocol_running(struct pcbit_dev * dev); + +static void pcbit_clear_msn(struct pcbit_dev *dev); +static void pcbit_set_msn(struct pcbit_dev *dev, char *list); +static int pcbit_check_msn(struct pcbit_dev *dev, char *msn); + + +extern void pcbit_deliver(void * data); + +int pcbit_init_dev(int board, int mem_base, int irq) +{ + struct pcbit_dev *dev; + isdn_if *dev_if; + + if ((dev=kmalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL) + { + printk("pcbit_init: couldn't malloc pcbit_dev struct\n"); + return -ENOMEM; + } + + dev_pcbit[board] = dev; + memset(dev, 0, sizeof(struct pcbit_dev)); + + if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) + dev->sh_mem = (unsigned char*) mem_base; + else + { + printk("memory address invalid"); + kfree(dev); + dev_pcbit[board] = NULL; + return -EACCES; + } + + dev->b1 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL); + if (!dev->b1) { + printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); + kfree(dev); + return -ENOMEM; + } + + dev->b2 = kmalloc(sizeof(struct pcbit_chan), GFP_KERNEL); + if (!dev->b2) { + printk("pcbit_init: couldn't malloc pcbit_chan struct\n"); + kfree(dev->b1); + kfree(dev); + return -ENOMEM; + } + + memset(dev->b1, 0, sizeof(struct pcbit_chan)); + memset(dev->b2, 0, sizeof(struct pcbit_chan)); + dev->b2->id = 1; + + + dev->qdelivery.next = 0; + dev->qdelivery.sync = 0; + dev->qdelivery.routine = pcbit_deliver; + dev->qdelivery.data = dev; + + /* + * interrupts + */ + + if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0) + { + kfree(dev->b1); + kfree(dev->b2); + kfree(dev); + dev_pcbit[board] = NULL; + return -EIO; + } + + dev->irq = irq; + + /* next frame to be received */ + dev->rcv_seq = 0; + dev->send_seq = 0; + dev->unack_seq = 0; + + dev->hl_hdrlen = 10; + + dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL); + + if (!dev_if) { + free_irq(irq, dev); + kfree(dev->b1); + kfree(dev->b2); + kfree(dev); + dev_pcbit[board] = NULL; + return -EIO; + } + + dev->dev_if = dev_if; + + dev_if->channels = 2; + + + dev_if->features = ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_HDLC; + + dev_if->writebuf_skb = pcbit_xmit; + dev_if->writebuf = NULL; + dev_if->hl_hdrlen = 10; + + dev_if->maxbufsize = MAXBUFSIZE; + dev_if->command = pcbit_command; + + dev_if->writecmd = pcbit_writecmd; + dev_if->readstat = pcbit_stat; + + + strcpy(dev_if->id, pcbit_devname[board]); + + if (!register_isdn(dev_if)) { + free_irq(irq, dev); + kfree(dev->b1); + kfree(dev->b2); + kfree(dev); + dev_pcbit[board] = NULL; + return -EIO; + } + + dev->id = dev_if->channels; + + + dev->l2_state = L2_DOWN; + dev->free = 511; + + /* + * set_protocol_running(dev); + */ + + return 0; +} + +#ifdef MODULE +void pcbit_terminate(int board) +{ + struct pcbit_dev * dev; + + dev = dev_pcbit[board]; + + if (dev) { + /* unregister_isdn(dev->dev_if); */ + free_irq(dev->irq, dev); + pcbit_clear_msn(dev); + kfree(dev->dev_if); + if (dev->b1->fsm_timer.function) + del_timer(&dev->b1->fsm_timer); + if (dev->b2->fsm_timer.function) + del_timer(&dev->b2->fsm_timer); + kfree(dev->b1); + kfree(dev->b2); + kfree(dev); + } +} +#endif + +int pcbit_command(isdn_ctrl* ctl) +{ + struct pcbit_dev *dev; + struct pcbit_chan *chan; + struct callb_data info; + char *cp; + + dev = finddev(ctl->driver); + + if (!dev) + { + printk("pcbit_command: unknown device\n"); + return -1; + } + + chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1; + + + switch(ctl->command) { + case ISDN_CMD_IOCTL: + return pcbit_ioctl(ctl); + break; + case ISDN_CMD_DIAL: + info.type = EV_USR_SETUP_REQ; + info.data.setup.CalledPN = (char *) &ctl->num; + cp = strchr(info.data.setup.CalledPN, ','); + if (cp) + *cp = 0; + else { + printk(KERN_DEBUG "DIAL: error in CalledPN\n"); + return -1; + } + pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info); + break; + case ISDN_CMD_ACCEPTD: + pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL); + break; + case ISDN_CMD_ACCEPTB: + printk("ISDN_CMD_ACCEPTB - not realy needed\n"); + break; + case ISDN_CMD_HANGUP: + pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL); + break; + case ISDN_CMD_SETL2: + chan->proto = (ctl->arg >> 8); + break; + case ISDN_CMD_GETL2: + return chan->proto; + break; + case ISDN_CMD_LOCK: + MOD_INC_USE_COUNT; + break; + case ISDN_CMD_UNLOCK: + MOD_DEC_USE_COUNT; + break; + case ISDN_CMD_CLREAZ: + pcbit_clear_msn(dev); + break; + case ISDN_CMD_SETEAZ: + pcbit_set_msn(dev, ctl->num); + break; + case ISDN_CMD_SETL3: + if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS) + printk(KERN_DEBUG "L3 protocol unknown\n"); + break; + case ISDN_CMD_GETL3: + return ISDN_PROTO_L3_TRANS; + break; + case ISDN_CMD_GETEAZ: + case ISDN_CMD_SETSIL: + case ISDN_CMD_GETSIL: + printk(KERN_DEBUG "pcbit_command: code %d not implemented yet\n", ctl->command); + break; + default: + printk(KERN_DEBUG "pcbit_command: unknown command\n"); + break; + }; + + return 0; +} + +/* + * Another Hack :-( + * on some conditions the board stops sending TDATA_CONFs + * let's see if we can turn around the problem + */ + +#ifdef BLOCK_TIMER +static void pcbit_block_timer(unsigned long data) +{ + struct pcbit_chan *chan; + struct pcbit_dev * dev; + isdn_ctrl ictl; + + chan = (struct pcbit_chan *) data; + + dev = chan2dev(chan); + + if (dev == NULL) { + printk(KERN_DEBUG "pcbit: chan2dev failed\n"); + return; + } + + del_timer(&chan->block_timer); + chan->block_timer.function = NULL; + +#ifdef DEBUG + printk(KERN_DEBUG "pcbit_block_timer\n"); +#endif + chan->queued = 0; + ictl.driver = dev->id; + ictl.command = ISDN_STAT_BSENT; + ictl.arg = chan->id; + dev->dev_if->statcallb(&ictl); +} +#endif + +int pcbit_xmit(int driver, int chnum, struct sk_buff *skb) +{ + ushort hdrlen; + int refnum, len; + struct pcbit_chan * chan; + struct pcbit_dev *dev; + + dev = finddev(driver); + if (dev == NULL) + { + printk("finddev returned NULL"); + return -1; + } + + chan = chnum ? dev->b2 : dev->b1; + + + if (chan->fsm_state != ST_ACTIVE) + return -1; + + if (chan->queued >= MAX_QUEUED ) + { +#ifdef DEBUG_QUEUE + printk(KERN_DEBUG + "pcbit: %d packets allready in queue - write fails\n", + chan->queued); +#endif + /* + * packet stays on the head of the device queue + * since dev_start_xmit will fail + * see net/core/dev.c + */ +#ifdef BLOCK_TIMER + if (chan->block_timer.function == NULL) { + init_timer(&chan->block_timer); + chan->block_timer.function = &pcbit_block_timer; + chan->block_timer.data = (long) chan; + chan->block_timer.expires = jiffies + 1 * HZ; + add_timer(&chan->block_timer); + } +#endif + return 0; + } + + + chan->queued++; + + len = skb->len; + + hdrlen = capi_tdata_req(chan, skb); + + refnum = last_ref_num++ & 0x7fffU; + chan->s_refnum = refnum; + + pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen); + + return len; +} + + +int pcbit_writecmd(const u_char* buf, int len, int user) +{ + struct pcbit_dev * dev; + int board, i, j; + const u_char * loadbuf; + u_char * ptr = NULL; + + int errstat; + + /* we should have the driver id as input here too - let's say it's 0 */ + board = 0; + + dev = dev_pcbit[board]; + + if (!dev) + { + printk("pcbit_writecmd: couldn't find device"); + return -ENODEV; + } + + switch(dev->l2_state) { + case L2_LWMODE: + /* check (size <= rdp_size); write buf into board */ + if (len > BANK4 + 1) + { + printk("pcbit_writecmd: invalid length %d\n", len); + return -EFAULT; + } + + if (user) + { + u_char cbuf[1024]; + + memcpy_fromfs(cbuf, buf, len); + for (i=0; ish_mem + i); + } + else + memcpy_toio(dev->sh_mem, buf, len); + return len; + break; + case L2_FWMODE: + /* this is the hard part */ + /* dumb board */ + if (len < 0) + return -EINVAL; + + if (user) { + /* get it into kernel space */ + if ((ptr = kmalloc(len, GFP_KERNEL))==NULL) + return -ENOMEM; + memcpy_fromfs(ptr, buf, len); + loadbuf = ptr; + } + else + loadbuf = buf; + + errstat = 0; + + for (i=0; i < len; i++) + { + for(j=0; j < LOAD_RETRY; j++) + { + __volatile__ unsigned char * ptr; + + ptr = dev->sh_mem + dev->loadptr; + if (*ptr == 0) + break; + + } + + if (j == LOAD_RETRY) + { + errstat = -ETIME; + printk("TIMEOUT i=%d\n", i); + break; + } + writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1); + writeb(0x01, dev->sh_mem + dev->loadptr); + + dev->loadptr += 2; + if (dev->loadptr > LOAD_ZONE_END) + dev->loadptr = LOAD_ZONE_START; + } + + if (user) + kfree(ptr); + + return errstat ? errstat : len; + + break; + default: + return -EBUSY; + } + return 0; +} + +/* + * demultiplexing of messages + * + */ + +void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, + struct sk_buff * skb, + ushort hdr_len, ushort refnum) +{ + struct pcbit_chan *chan; + struct sk_buff *skb2; + unsigned short len; + struct callb_data cbdata; + int complete, err; + isdn_ctrl ictl; +#ifdef DEBUG + struct msg_fmt * fmsg; +#endif + + switch(msg) { + + case MSG_TDATA_IND: + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + chan->r_refnum = skb->data[7]; + skb_pull(skb, 8); + + dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb); + + if (capi_tdata_resp(chan, &skb2) > 0) + pcbit_l2_write(dev, MSG_TDATA_RESP, refnum, + skb2, skb2->len); + return; + break; + case MSG_TDATA_CONF: + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + +#ifdef DEBUG + if ( (*((ushort *) (skb->data + 2) )) != 0) { + printk(KERN_DEBUG "TDATA_CONF error\n"); + } +#endif +#ifdef BLOCK_TIMER + if (chan->queued == MAX_QUEUED) { + del_timer(&chan->block_timer); + chan->block_timer.function = NULL; + } + +#endif + chan->queued--; + + ictl.driver = dev->id; + ictl.command = ISDN_STAT_BSENT; + ictl.arg = chan->id; + dev->dev_if->statcallb(&ictl); + break; + + case MSG_CONN_IND: + /* + * channel: 1st not used will do + * if both are used we're in trouble + */ + + if (!dev->b1->fsm_state) + chan = dev->b1; + else if (!dev->b2->fsm_state) + chan = dev->b2; + else { + printk(KERN_INFO + "Incoming connection: no channels available"); + + if ((len = capi_disc_req(*(ushort*)(skb->data), &skb2, CAUSE_NOCHAN)) > 0) + pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len); + break; + } + + cbdata.data.setup.CalledPN = NULL; + cbdata.data.setup.CallingPN = NULL; + + capi_decode_conn_ind(chan, skb, &cbdata); + cbdata.type = EV_NET_SETUP; + + pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL); + + if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN)) + pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata); + else + pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL); + + if (cbdata.data.setup.CalledPN) + kfree(cbdata.data.setup.CalledPN); + if (cbdata.data.setup.CallingPN) + kfree(cbdata.data.setup.CallingPN); + break; + + case MSG_CONN_CONF: + /* + * We should be able to find the channel by the message + * reference number. The current version of the firmware + * doesn't sent the ref number correctly. + */ +#ifdef DEBUG + printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum, + dev->b1->s_refnum, + dev->b2->s_refnum); +#endif +#if 0 + if (dev->b1->s_refnum == refnum) + chan = dev->b1; + else { + + if (dev->b2->s_refnum == refnum) + chan = dev->b2; + else { + chan = NULL; + printk(KERN_WARNING "Connection Confirm - refnum doesn't match chan\n"); + break; + } + } +#else + /* We just try to find a channel in the right state */ + + if (dev->b1->fsm_state == ST_CALL_INIT) + chan = dev->b1; + else { + if (dev->b2->s_refnum == ST_CALL_INIT) + chan = dev->b2; + else { + chan = NULL; + printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n"); + break; + } + } +#endif + if (capi_decode_conn_conf(chan, skb, &complete)) { + printk(KERN_DEBUG "conn_conf indicates error\n"); + pcbit_fsm_event(dev, chan, EV_ERROR, NULL); + } + else + if (complete) + pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL); + else + pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL); + break; + case MSG_CONN_ACTV_IND: + + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (capi_decode_conn_actv_ind(chan, skb)) { + printk("error in capi_decode_conn_actv_ind\n"); + /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */ + break; + } + chan->r_refnum = refnum; + pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL); + break; + case MSG_CONN_ACTV_CONF: + + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (capi_decode_conn_actv_conf(chan, skb) == 0) + pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL); + + else + printk(KERN_DEBUG "decode_conn_actv_conf failed\n"); + break; + + case MSG_SELP_CONF: + + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (!(err = capi_decode_sel_proto_conf(chan, skb))) + pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL); + else { + /* Error */ + printk("error %d - capi_decode_sel_proto_conf\n", err); + } + break; + case MSG_ACT_TRANSP_CONF: + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (!capi_decode_actv_trans_conf(chan, skb)) + pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL); + break; + + case MSG_DISC_IND: + + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (!capi_decode_disc_ind(chan, skb)) + pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL); + else + printk(KERN_WARNING "capi_decode_disc_ind - error\n"); + break; + case MSG_DISC_CONF: + if (!(chan = capi_channel(dev, skb))) { + printk(KERN_WARNING + "CAPI header: unknown channel id\n"); + break; + } + + if (!capi_decode_disc_ind(chan, skb)) + pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL); + else + printk(KERN_WARNING "capi_decode_disc_conf - error\n"); + break; + case MSG_INFO_IND: +#ifdef DEBUG + printk(KERN_DEBUG "received Info Indication - discarded\n"); +#endif + break; +#ifdef DEBUG + case MSG_DEBUG_188: + capi_decode_debug_188(skb->data, skb->len); + break; + + default: + printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n", + msg); + fmsg = (struct msg_fmt *) &msg; + printk(KERN_DEBUG "cmd=%02x sub=%02x\n", + fmsg->cmd, fmsg->scmd); + break; +#endif + } + + skb->free = 1; + + kfree_skb(skb, FREE_READ); + +} + +/* + * Single statbuf + * should be a statbuf per device + */ + +static char statbuf[STATBUF_LEN]; +static int stat_st = 0; +static int stat_end = 0; + + +#define memcpy_to_COND(flag, d, s, len) \ +(flag ? memcpy_tofs(d, s, len) : memcpy(d, s, len)) + + +int pcbit_stat(u_char* buf, int len, int user) +{ + int stat_count; + stat_count = stat_end - stat_st; + + if (stat_count < 0) + stat_count = STATBUF_LEN - stat_st + stat_end; + + /* FIXME: should we sleep and wait for more cockies ? */ + if (len > stat_count) + len = stat_count; + + if (stat_st < stat_end) + { + memcpy_to_COND(user, buf, statbuf + stat_st, len); + stat_st += len; + } + else + { + if (len > STATBUF_LEN - stat_st) + { + memcpy_to_COND(user, buf, statbuf + stat_st, + STATBUF_LEN - stat_st); + memcpy_to_COND(user, buf, statbuf, + len - (STATBUF_LEN - stat_st)); + + stat_st = len - (STATBUF_LEN - stat_st); + } + else + { + memcpy_to_COND(user, buf, statbuf + stat_st, + len); + + stat_st += len; + + if (stat_st == STATBUF_LEN) + stat_st = 0; + } + } + + if (stat_st == stat_end) + stat_st = stat_end = 0; + + return len; +} + +static void pcbit_logstat(struct pcbit_dev *dev, char *str) +{ + int i; + isdn_ctrl ictl; + + for (i=stat_end; iid; + ictl.arg=strlen(str); + dev->dev_if->statcallb(&ictl); +} + +extern char * isdn_state_table[]; +extern char * strisdnevent(unsigned short); + + +void pcbit_state_change(struct pcbit_dev * dev, struct pcbit_chan * chan, + unsigned short i, unsigned short ev, unsigned short f) +{ + char buf[256]; + + sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n", + dev->id, chan->id, + isdn_state_table[i], strisdnevent(ev), isdn_state_table[f] + ); + +#ifdef DEBUG + printk("%s", buf); +#endif + + pcbit_logstat(dev, buf); +} + +static void set_running_timeout(unsigned long ptr) +{ + struct pcbit_dev * dev; + +#ifdef DEBUG + printk(KERN_DEBUG "set_running_timeout\n"); +#endif + dev = (struct pcbit_dev *) ptr; + + wake_up_interruptible(&dev->set_running_wq); +} + +static int set_protocol_running(struct pcbit_dev * dev) +{ + isdn_ctrl ctl; + + init_timer(&dev->set_running_timer); + + dev->set_running_timer.function = &set_running_timeout; + dev->set_running_timer.data = (ulong) dev; + dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT; + + /* kick it */ + + dev->l2_state = L2_STARTING; + + writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), + dev->sh_mem + BANK4); + + add_timer(&dev->set_running_timer); + + interruptible_sleep_on(&dev->set_running_wq); + + del_timer(&dev->set_running_timer); + + if (dev->l2_state == L2_RUNNING) + { + printk(KERN_DEBUG "pcbit: running\n"); + + dev->unack_seq = dev->send_seq; + + dev->writeptr = dev->sh_mem; + dev->readptr = dev->sh_mem + BANK2; + + /* tell the good news to the upper layer */ + ctl.driver = dev->id; + ctl.command = ISDN_STAT_RUN; + + dev->dev_if->statcallb(&ctl); + } + else + { + printk(KERN_DEBUG "pcbit: initialization failed\n"); + printk(KERN_DEBUG "pcbit: firmware not loaded\n"); + + dev->l2_state = L2_DOWN; + +#ifdef DEBUG + printk(KERN_DEBUG "Bank3 = %02x\n", + readb(dev->sh_mem + BANK3)); +#endif + *(dev->sh_mem + BANK4) = 0x40U; + + /* warn the upper layer */ + ctl.driver = dev->id; + ctl.command = ISDN_STAT_STOP; + + dev->dev_if->statcallb(&ctl); + + return -EL2HLT; /* Level 2 halted */ + } + + return 0; +} + +static int pcbit_ioctl(isdn_ctrl* ctl) +{ + struct pcbit_dev * dev; + struct pcbit_ioctl *cmd; + + dev = finddev(ctl->driver); + + if (!dev) + { + printk(KERN_DEBUG "pcbit_ioctl: unknown device\n"); + return -ENODEV; + } + + cmd = (struct pcbit_ioctl *) ctl->num; + + switch(ctl->arg) { + case PCBIT_IOCTL_GETSTAT: + cmd->info.l2_status = dev->l2_state; + break; + + case PCBIT_IOCTL_STRLOAD: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + + dev->unack_seq = dev->send_seq = dev->rcv_seq = 0; + + dev->writeptr = dev->sh_mem; + dev->readptr = dev->sh_mem + BANK2; + + dev->l2_state = L2_LOADING; + break; + + case PCBIT_IOCTL_LWMODE: + if (dev->l2_state != L2_LOADING) + return -EINVAL; + + dev->l2_state = L2_LWMODE; + break; + + case PCBIT_IOCTL_FWMODE: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + dev->loadptr = LOAD_ZONE_START; + dev->l2_state = L2_FWMODE; + + break; + case PCBIT_IOCTL_ENDLOAD: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + dev->l2_state = L2_DOWN; + break; + + case PCBIT_IOCTL_SETBYTE: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + + /* check addr */ + if (cmd->info.rdp_byte.addr > BANK4) + return -EFAULT; + + writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr); + break; + case PCBIT_IOCTL_GETBYTE: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + + /* check addr */ + + if (cmd->info.rdp_byte.addr > BANK4) + { + printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr); + return -EFAULT; + } + + cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr); + break; + case PCBIT_IOCTL_RUNNING: + if (dev->l2_state == L2_RUNNING) + return -EBUSY; + return set_protocol_running(dev); + break; + case PCBIT_IOCTL_WATCH188: + if (dev->l2_state != L2_LOADING) + return -EINVAL; + pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0); + break; + case PCBIT_IOCTL_PING188: + if (dev->l2_state != L2_LOADING) + return -EINVAL; + pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0); + break; + case PCBIT_IOCTL_APION: + if (dev->l2_state != L2_LOADING) + return -EINVAL; + pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0); + break; + case PCBIT_IOCTL_STOP: + dev->l2_state = L2_DOWN; + writeb(0x40, dev->sh_mem + BANK4); + dev->rcv_seq = 0; + dev->send_seq = 0; + dev->unack_seq = 0; + break; + default: + printk("error: unkown ioctl\n"); + break; + }; + return 0; +} + +/* + * MSN list handling + * + * if null reject all calls + * if first entry has null MSN accept all calls + */ + +static void pcbit_clear_msn(struct pcbit_dev *dev) +{ + struct msn_entry *ptr, *back; + + for (ptr=dev->msn_list; ptr; ) + { + back = ptr->next; + kfree(ptr); + ptr = back; + } + + dev->msn_list = NULL; +} + +static void pcbit_set_msn(struct pcbit_dev *dev, char *list) +{ + struct msn_entry *ptr, *back; + char *cp, *sp; + int len; + + if (strlen(list) == 0) { + ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC); + if (!ptr) { + printk(KERN_WARNING "kmalloc failed\n"); + return; + } + + ptr->msn = NULL; + + ptr->next = dev->msn_list; + dev->msn_list = ptr; + + return; + } + + for (back=dev->msn_list; back->next; back=back->next); + + sp = list; + + do { + cp=strchr(sp, ','); + if (cp) + len = cp - sp; + else + len = strlen(sp); + + ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC); + + if (!ptr) { + printk(KERN_WARNING "kmalloc failed\n"); + return; + } + ptr->next = NULL; + + ptr->msn = kmalloc(len, GFP_ATOMIC); + if (!ptr->msn) { + printk(KERN_WARNING "kmalloc failed\n"); + return; + } + + memcpy(ptr->msn, sp, len - 1); + ptr->msn[len] = 0; + +#ifdef DEBUG + printk(KERN_DEBUG "msn: %s\n", ptr->msn); +#endif + if (dev->msn_list == NULL) + dev->msn_list = ptr; + else + back->next = ptr; + back = ptr; + sp += len; + } while(cp); +} + +/* + * check if we do signal or reject an incoming call + */ +static int pcbit_check_msn(struct pcbit_dev *dev, char *msn) +{ + struct msn_entry *ptr; + + for (ptr=dev->msn_list; ptr; ptr=ptr->next) { + + if (ptr->msn == NULL) + return 1; + + if (strcmp(ptr->msn, msn) == 0) + return 1; + } + + return 0; +} + + + + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/edss1.c linux/drivers/isdn/pcbit/edss1.c --- v1.3.92/linux/drivers/isdn/pcbit/edss1.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/edss1.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,333 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * DSS.1 Finite State Machine + * base: ITU-T Rec Q.931 + */ + +/* + * TODO: complete the FSM + * move state/event descriptions to a user space logger + */ + +#define __NO_VERSION__ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "pcbit.h" +#include "edss1.h" +#include "layer2.h" +#include "callbacks.h" + + +extern void pcbit_state_change(struct pcbit_dev *, struct pcbit_chan *, + unsigned short i, unsigned short ev, + unsigned short f); + +extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS]; + +char * isdn_state_table[] = { + "Closed", + "Call initiated", + "Overlap sending", + "Outgoing call proceeding", + "NOT DEFINED", + "Call delivered", + "Call present", + "Call received", + "Connect request", + "Incoming call proceeding", + "Active", + "Disconnect request", + "Disconnect indication", + "NOT DEFINED", + "NOT DEFINED", + "Suspend request", + "NOT DEFINED", + "Resume request", + "NOT DEFINED", + "Release Request", + "NOT DEFINED", + "NOT DEFINED", + "NOT DEFINED", + "NOT DEFINED", + "NOT DEFINED", + "Overlap receiving", + "Select protocol on B-Channel", + "Activate B-channel protocol" +}; + +#ifdef DEBUG_ERRS +static +struct CauseValue { + byte nr; + char *descr; +} cvlist[]={ + {0x01,"Unallocated (unassigned) number"}, + {0x02,"No route to specified transit network"}, + {0x03,"No route to destination"}, + {0x04,"Send special information tone"}, + {0x05,"Misdialled trunk prefix"}, + {0x06,"Channel unacceptable"}, + {0x07,"Channel awarded and being delivered in an established channel"}, + {0x08,"Preemption"}, + {0x09,"Preemption - circuit reserved for reuse"}, + {0x10,"Normal call clearing"}, + {0x11,"User busy"}, + {0x12,"No user responding"}, + {0x13,"No answer from user (user alerted)"}, + {0x14,"Subscriber absent"}, + {0x15,"Call rejected"}, + {0x16,"Number changed"}, + {0x1a,"non-selected user clearing"}, + {0x1b,"Destination out of order"}, + {0x1c,"Invalid number format (address incomplete)"}, + {0x1d,"Facility rejected"}, + {0x1e,"Response to Status enuiry"}, + {0x1f,"Normal, unspecified"}, + {0x22,"No circuit/channel available"}, + {0x26,"Network out of order"}, + {0x27,"Permanent frame mode connection out-of-service"}, + {0x28,"Permanent frame mode connection operational"}, + {0x29,"Temporary failure"}, + {0x2a,"Switching equipment congestion"}, + {0x2b,"Access information discarded"}, + {0x2c,"Requested circuit/channel not available"}, + {0x2e,"Precedence call blocked"}, + {0x2f,"Resource unavailable, unspecified"}, + {0x31,"Quality of service unavailable"}, + {0x32,"Requested facility not subscribed"}, + {0x35,"Outgoing calls barred within CUG"}, + {0x37,"Incoming calls barred within CUG"}, + {0x39,"Bearer capability not auhorized"}, + {0x3a,"Bearer capability not presently available"}, + {0x3e,"Inconsistency in designated outgoing access information and subscriber class"}, + {0x3f,"Service or option not available, unspecified"}, + {0x41,"Bearer capability not implemented"}, + {0x42,"Channel type not implemented"}, + {0x43,"Requested facility not implemented"}, + {0x44,"Only restricted digital information bearer capability is available"}, + {0x4f,"Service or option not implemented"}, + {0x51,"Invalid call reference value"}, + {0x52,"Identified channel does not exist"}, + {0x53,"A suspended call exists, but this call identity does not"}, + {0x54,"Call identity in use"}, + {0x55,"No call suspended"}, + {0x56,"Call having the requested call identity has been cleared"}, + {0x57,"User not member of CUG"}, + {0x58,"Incompatible destination"}, + {0x5a,"Non-existent CUG"}, + {0x5b,"Invalid transit network selection"}, + {0x5f,"Invalid message, unspecified"}, + {0x60,"Mandatory information element is missing"}, + {0x61,"Message type non-existent or not implemented"}, + {0x62,"Message not compatible with call state or message type non-existent or not implemented"}, + {0x63,"Information element/parameter non-existent or not implemented"}, + {0x64,"Invalid information element contents"}, + {0x65,"Message not compatible with call state"}, + {0x66,"Recovery on timer expiry"}, + {0x67,"Parameter non-existent or not implemented - passed on"}, + {0x6e,"Message with unrecognized parameter discarded"}, + {0x6f,"Protocol error, unspecified"}, + {0x7f,"Interworking, unspecified"} +}; + +#endif + +static struct isdn_event_desc { + unsigned short ev; + char * desc; +} isdn_event_table [] = { + {EV_USR_SETUP_REQ, "CC->L3: Setup Request"}, + {EV_USR_SETUP_RESP, "CC->L3: Setup Response"}, + {EV_USR_PROCED_REQ, "CC->L3: Proceeding Request"}, + {EV_USR_RELEASE_REQ, "CC->L3: Release Request"}, + + {EV_NET_SETUP, "NET->TE: setup "}, + {EV_NET_CALL_PROC, "NET->TE: call proceding"}, + {EV_NET_SETUP_ACK, "NET->TE: setup acknowlegde (more info needed)"}, + {EV_NET_CONN, "NET->TE: connect"}, + {EV_NET_CONN_ACK, "NET->TE: connect aknowlegde"}, + {EV_NET_DISC, "NET->TE: disconnect indication"}, + {EV_NET_RELEASE, "NET->TE: release"}, + {EV_NET_RELEASE_COMP, "NET->TE: release complete"}, + {EV_NET_SELP_RESP, "Board: Select B-channel protocol ack"}, + {EV_NET_ACTV_RESP, "Board: Activate B-channel protocol ack"}, + {EV_TIMER, "Timeout"}, + {0, "NULL"} +}; + +char * strisdnevent(ushort ev) +{ + struct isdn_event_desc * entry; + + for (entry = isdn_event_table; entry->ev; entry++) + if (entry->ev == ev) + break; + + return entry->desc; +} + +/* + * Euro ISDN finite state machine + */ + +static struct fsm_timer_entry fsm_timers[] = { + {ST_CALL_PROC, 10}, + {ST_DISC_REQ, 2}, + {ST_ACTIVE_SELP, 5}, + {ST_ACTIVE_ACTV, 5}, + {ST_INCM_PROC, 10}, + {ST_CONN_REQ, 2}, + {0xff, 0} +}; + +static struct fsm_entry fsm_table[] = { +/* Connect Phase */ + /* Outgoing */ + {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1}, + + {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone}, + {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL}, + {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2}, + + {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2}, + {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1}, + {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + + /* Incomming */ + {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL}, + + {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1}, + {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + + {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2}, + {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + + {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3}, + + /* Active */ + {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1}, + {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3}, + + /* Disconnect */ + + {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1}, + {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3}, + + /* protocol selection */ + {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1}, + {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + + {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open}, + {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2}, + + /* Timers */ + {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2}, + {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3}, + {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2}, + {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2}, + {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2}, + {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2}, + + {0xff, 0, 0, NULL} +}; + + +static void pcbit_fsm_timer(unsigned long data) +{ + struct pcbit_dev *dev; + struct pcbit_chan *chan; + + chan = (struct pcbit_chan *) data; + + del_timer(&chan->fsm_timer); + chan->fsm_timer.function = NULL; + + dev = chan2dev(chan); + + if (dev == NULL) { + printk(KERN_WARNING "pcbit: timer for unkown device\n"); + return; + } + + pcbit_fsm_event(dev, chan, EV_TIMER, NULL); +} + + +void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan, + unsigned short event, struct callb_data *data) +{ + struct fsm_entry * action; + struct fsm_timer_entry *tentry; + unsigned long flags; + + save_flags(flags); + cli(); + + if (chan->fsm_timer.function) { + del_timer(&chan->fsm_timer); + chan->fsm_timer.function = NULL; + } + + for (action = fsm_table; action->init != 0xff; action++) + if (action->init == chan->fsm_state && action->event == event) + break; + + + if (action->init == 0xff) { + + printk(KERN_DEBUG "fsm error: event %x on state %x\n", + event, chan->fsm_state); + return; + } + + chan->fsm_state = action->final; + + pcbit_state_change(dev, chan, action->init, event, action->final); + + for (tentry = fsm_timers; tentry->init != 0xff; tentry++) + if (tentry->init == chan->fsm_state) + break; + + if (tentry->init != 0xff) { + init_timer(&chan->fsm_timer); + chan->fsm_timer.function = &pcbit_fsm_timer; + chan->fsm_timer.data = (ulong) chan; + chan->fsm_timer.expires = jiffies + tentry->timeout * HZ; + add_timer(&chan->fsm_timer); + } + + restore_flags(flags); + + if (action->callb) + action->callb(dev, chan, data); + +} + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/edss1.h linux/drivers/isdn/pcbit/edss1.h --- v1.3.92/linux/drivers/isdn/pcbit/edss1.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/edss1.h Sun Apr 21 11:56:14 1996 @@ -0,0 +1,101 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * DSS.1 module definitions + */ + +#ifndef EDSS1_H +#define EDSS1_H + +/* ISDN states */ + +#define ST_NULL 0 +#define ST_CALL_INIT 1 /* Call initiated */ +#define ST_OVER_SEND 2 /* Overlap sending - Requests More Info 4 call */ +#define ST_CALL_PROC 3 /* Call Procceding */ +#define ST_CALL_DELV 4 +#define ST_CALL_PRES 6 /* Call Present - Received CONN.IND */ +#define ST_CALL_RECV 7 /* Alerting sent */ +#define ST_CONN_REQ 8 /* Answered - wainting 4 CONN.CONF */ +#define ST_INCM_PROC 9 +#define ST_ACTIVE 10 +#define ST_DISC_REQ 11 +#define ST_DISC_IND 12 +#define ST_SUSP_REQ 15 +#define ST_RESM_REQ 17 +#define ST_RELS_REQ 19 +#define ST_OVER_RECV 25 + +#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */ +#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol */ + +#define MAX_STATE ST_ACTIVE_ACTV + +#define EV_NULL 0 +#define EV_USR_SETUP_REQ 1 +#define EV_USR_SETUP_RESP 2 +#define EV_USR_PROCED_REQ 3 +#define EV_USR_RELEASE_REQ 4 +#define EV_USR_REJECT_REQ 4 + +#define EV_NET_SETUP 16 +#define EV_NET_CALL_PROC 17 +#define EV_NET_SETUP_ACK 18 +#define EV_NET_CONN 19 +#define EV_NET_CONN_ACK 20 + +#define EV_NET_SELP_RESP 21 +#define EV_NET_ACTV_RESP 22 + +#define EV_NET_DISC 23 +#define EV_NET_RELEASE 24 +#define EV_NET_RELEASE_COMP 25 + +#define EV_TIMER 26 +#define EV_ERROR 32 + +/* + * Cause values + * only the ones we use + */ + +#define CAUSE_NORMAL 0x10U +#define CAUSE_NOCHAN 0x22U + +struct callb_data { + unsigned short type; + union { + struct ConnInfo { + char *CalledPN; + char *CallingPN; + } setup; + unsigned short cause; + } data; +}; + +struct fsm_entry { + unsigned short init; + unsigned short final; + unsigned short event; + void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*); +}; + +struct fsm_timer_entry { + unsigned short init; + unsigned long timeout; /* in seconds */ +}; + + +extern void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *, + unsigned short event, struct callb_data *); +#endif + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/layer2.c linux/drivers/isdn/pcbit/layer2.c --- v1.3.92/linux/drivers/isdn/pcbit/layer2.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/layer2.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,859 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * PCBIT-D low-layer interface + */ + +/* + * Based on documentation provided by Inesc: + * - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93 + */ + +/* + * TODO: better handling of errors + * re-write/remove debug printks + */ + +#define __NO_VERSION__ + + +#ifdef MODULE +#define INCLUDE_INLINE_FUNCS +#endif + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +#include "pcbit.h" +#include "layer2.h" +#include "edss1.h" + +#undef DEBUG_FRAG + + + +/* + * task queue struct + */ +struct tq_struct *tq_delivery=NULL; + +static void do_pcbit_bh(task_queue *list) +{ + run_task_queue(list); +} + +struct tq_struct run_delivery= { + 0, 0, (void *)(void *) do_pcbit_bh, &tq_delivery, +}; + + +/* + * Layer 3 packet demultiplexer + * drv.c + */ + +extern void pcbit_l3_receive(struct pcbit_dev * dev, ulong msg, + struct sk_buff * skb, + ushort hdr_len, ushort refnum); + +/* + * Prototypes + */ + +void pcbit_deliver(void * data); +static void pcbit_transmit(struct pcbit_dev * dev); + +static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); +static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq); + +static void pcbit_l2_error(struct pcbit_dev *dev); +static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); +static void pcbit_l2_err_recover(unsigned long data); + +static void pcbit_firmware_bug(struct pcbit_dev * dev); + +static void pcbit_sched_delivery(struct pcbit_dev *dev) +{ + queue_task_irq_off(&dev->qdelivery, &tq_delivery); + queue_task_irq_off(&run_delivery, &tq_immediate); + mark_bh(IMMEDIATE_BH); +} + + +/* + * Called from layer3 + */ + +int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, + struct sk_buff *skb, unsigned short hdr_len) + +{ + struct frame_buf * frame, * ptr; + unsigned long flags; + + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) { + dev_kfree_skb(skb, FREE_WRITE); + return -1; + } + + if ( (frame = (struct frame_buf *) kmalloc(sizeof(struct frame_buf), + GFP_ATOMIC)) == NULL ) { + printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n"); + dev_kfree_skb(skb, FREE_WRITE); + return -1; + } + + frame->msg = msg; + frame->refnum = refnum; + frame->copied = 0; + frame->hdr_len = hdr_len; + + if (skb) { + frame->dt_len = skb->len - hdr_len; + if (frame->dt_len == 0) + skb->lock++; + } + else + frame->dt_len = 0; + + frame->skb = skb; + + frame->next = NULL; + + save_flags(flags); + cli(); + + if (dev->write_queue == NULL) { + dev->write_queue = frame; + restore_flags(flags); + pcbit_transmit(dev); + } + else { + for(ptr=dev->write_queue; ptr->next; ptr=ptr->next); + ptr->next = frame; + + restore_flags(flags); + } + return 0; +} + +static __inline__ void pcbit_tx_update(struct pcbit_dev *dev, ushort len) +{ + u_char info; + + dev->send_seq = (dev->send_seq + 1) % 8; + + dev->fsize[dev->send_seq] = len; + info = 0; + info |= dev->rcv_seq << 3; + info |= dev->send_seq; + + writeb(info, dev->sh_mem + BANK4); + +} + +/* + * called by interrupt service routine or by write_2 + */ + +static void pcbit_transmit(struct pcbit_dev * dev) +{ + struct frame_buf * frame = NULL; + unsigned char unacked; + int flen; /* fragment frame length including all headers */ + int totlen; /* non-fragmented frame length */ + int free; + int count, cp_len; + unsigned long flags; + unsigned short tt; + + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) + return; + + unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; + + if (dev->free > 16 && dev->write_queue && unacked < 7) { + + save_flags(flags); + cli(); + + + if (!dev->w_busy) + dev->w_busy = 1; + else + { + restore_flags(flags); + return; + } + + restore_flags(flags); + + frame = dev->write_queue; + free = dev->free; + + if (frame->copied == 0) { + + /* Type 0 frame */ + + struct msg_fmt * msg; + + if (frame->skb) + totlen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len; + else + totlen = FRAME_HDR_LEN + PREHDR_LEN; + + flen = MIN(totlen, free); + + msg = (struct msg_fmt *) &(frame->msg); + + /* + * Board level 2 header + */ + + pcbit_writew(dev, flen - FRAME_HDR_LEN); + + pcbit_writeb(dev, msg->cpu); + + pcbit_writeb(dev, msg->proc); + + /* TH */ + pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); + + /* TD */ + pcbit_writew(dev, frame->dt_len); + + + /* + * Board level 3 fixed-header + */ + + /* LEN = TH */ + pcbit_writew(dev, frame->hdr_len + PREHDR_LEN); + + /* XX */ + pcbit_writew(dev, 0); + + /* C + S */ + pcbit_writeb(dev, msg->cmd); + pcbit_writeb(dev, msg->scmd); + + /* NUM */ + pcbit_writew(dev, frame->refnum); + + count = FRAME_HDR_LEN + PREHDR_LEN; + } + else { + /* Type 1 frame */ + + totlen = 2 + (frame->skb->len - frame->copied); + + flen = MIN(totlen, free); + + /* TT */ + tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */ + pcbit_writew(dev, tt); + + count = 2; + } + + if (frame->skb) { + cp_len = MIN(frame->skb->len - frame->copied, + flen - count); + + memcpy_topcbit(dev, frame->skb->data + frame->copied, + cp_len); + frame->copied += cp_len; + } + + /* bookeeping */ + dev->free -= flen; + pcbit_tx_update(dev, flen); + + save_flags(flags); + cli(); + + + if (frame->skb == NULL || frame->copied == frame->skb->len) { + + dev->write_queue = frame->next; + + if (frame->skb != NULL) { + /* free frame */ + dev_kfree_skb(frame->skb, FREE_WRITE); + } + + kfree(frame); + } + + dev->w_busy = 0; + restore_flags(flags); + } +#ifdef DEBUG + else + printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", + unacked, dev->free, dev->write_queue ? "not empty" : + "empty"); +#endif +} + + +/* + * deliver a queued frame to the upper layer + */ + +void pcbit_deliver(void * data) +{ + struct frame_buf *frame; + unsigned long flags; + struct msg_fmt msg; + struct pcbit_dev *dev = (struct pcbit_dev *) data; + + save_flags(flags); + cli(); + + /* get frame from queue */ + if (!(frame=dev->read_queue)) { + restore_flags(flags); + return; + } + + dev->read_queue = frame->next; + restore_flags(flags); + + msg.cpu = 0; + msg.proc = 0; + msg.cmd = frame->skb->data[2]; + msg.scmd = frame->skb->data[3]; + + frame->refnum = *((ushort*) frame->skb->data + 4); + frame->msg = *((ulong*) &msg); + + skb_pull(frame->skb, 6); + + pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, + frame->refnum); + + kfree(frame); +} + +/* + * Reads BANK 2 & Reassembles + */ + +static void pcbit_receive(struct pcbit_dev * dev) +{ + unsigned short tt; + u_char cpu, proc; + struct frame_buf * frame = NULL; + unsigned long flags; + u_char type1; + + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) + return; + + tt = pcbit_readw(dev); + + if ((tt & 0x7fffU) > 511) { + printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n", + tt); + pcbit_l2_error(dev); + return; + } + + if (!(tt & 0x8000U)) + { /* Type 0 */ + type1 = 0; + + if (dev->read_frame) { + printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n"); +#if 0 + pcbit_l2_error(dev); + return; +#else + /* discard previous queued frame */ + if (dev->read_frame->skb) { + dev->read_frame->skb->free = 1; + kfree_skb(dev->read_frame->skb, FREE_READ); + } + kfree(dev->read_frame); + dev->read_frame = NULL; +#endif + } + + frame = kmalloc(sizeof(struct frame_buf), GFP_ATOMIC); + + if (frame == NULL) { + printk(KERN_WARNING "kmalloc failed\n"); + return; + } + memset(frame, 0, sizeof(struct frame_buf)); + + cpu = pcbit_readb(dev); + proc = pcbit_readb(dev); + + + if (cpu != 0x06 && cpu != 0x02) + { + printk (KERN_DEBUG "pcbit: invalid cpu value\n"); + kfree(frame); + pcbit_l2_error(dev); + return; + } + + /* + * we discard cpu & proc on receiving + * but we read it to update the pointer + */ + + frame->hdr_len = pcbit_readw(dev); + frame->dt_len = pcbit_readw(dev); + + /* + * 0 sized packet + * I don't know if they are an error or not... + * But they are very frequent + * Not documented + */ + + if (frame->hdr_len == 0) { + kfree(frame); +#ifdef DEBUG + printk(KERN_DEBUG "0 sized frame\n"); +#endif + pcbit_firmware_bug(dev); + return; + } + + /* sanity check the length values */ + if (frame->hdr_len > 1024 || frame->dt_len > 2048) + { +#ifdef DEBUG + printk(KERN_DEBUG "length problem: "); + printk(KERN_DEBUG "TH=%04x TD=%04x\n", + frame->hdr_len, + frame->dt_len); +#endif + pcbit_l2_error(dev); + kfree(frame); + return; + } + + /* miminum frame read */ + + frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len + + ((frame->hdr_len + 15) & ~15)); + + if (!frame->skb) { + printk(KERN_DEBUG "pcbit_receive: out of memmory\n"); + kfree(frame); + return; + } + + /* 16 byte aligment for IP */ + if (frame->dt_len) + skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15); + + } + else { + /* Type 1 */ + type1 = 1; + tt &= 0x7fffU; + + if (!(frame = dev->read_frame)) { + printk("Type 1 frame and no frame queued\n"); +#if 1 + /* usualy after an error: toss frame */ + dev->readptr += tt; + if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN) + dev->readptr -= BANKLEN; +#else + pcbit_l2_error(dev); +#endif + return; + + } + } + + memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt); + + frame->copied += tt; + + if (frame->copied == frame->hdr_len + frame->dt_len) { + + save_flags(flags); + cli(); + + if (type1) { + dev->read_frame = NULL; + } + + if (dev->read_queue) { + struct frame_buf *ptr; + for(ptr=dev->read_queue;ptr->next;ptr=ptr->next); + ptr->next = frame; + } + else + dev->read_queue = frame; + + pcbit_sched_delivery(dev); + restore_flags(flags); + + } + else { + save_flags(flags); + cli(); + dev->read_frame = frame; + restore_flags(flags); + } +} + +/* + * The board sends 0 sized frames + * They are TDATA_CONFs that get messed up somehow + * gotta send a fake acknowledment to the upper layer somehow + */ + +static __inline__ void pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan * chan) +{ + isdn_ctrl ictl; + + if (chan->queued) { + chan->queued--; + + ictl.driver = dev->id; + ictl.command = ISDN_STAT_BSENT; + ictl.arg = chan->id; + dev->dev_if->statcallb(&ictl); + } +} + +static void pcbit_firmware_bug(struct pcbit_dev * dev) +{ + struct pcbit_chan *chan; + + chan = dev->b1; + + if (chan->fsm_state == ST_ACTIVE) { + pcbit_fake_conf(dev, chan); + } + + chan = dev->b2; + + if (chan->fsm_state == ST_ACTIVE) { + pcbit_fake_conf(dev, chan); + } + +} + +void pcbit_irq_handler(int interrupt, void * devptr, struct pt_regs *regs) +{ + struct pcbit_dev * dev; + u_char info, ack_seq, read_seq; + u_char ack_int = 1; + + dev = (struct pcbit_dev *) devptr; + + if (!dev) + { + printk(KERN_WARNING "pcbit_irq_handler: wrong device\n"); + return; + } + + if (dev->interrupt) { + printk(KERN_DEBUG "pcbit: reentering interrupt hander\n"); + return; + } + + dev->interrupt = 1; + + info = readb(dev->sh_mem + BANK3); + + if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) + { + pcbit_l2_active_conf(dev, info); + dev->interrupt = 0; + return; + } + + if (info & 0x40U) /* E bit set */ + { +#ifdef DEBUG + printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n"); +#endif + pcbit_l2_error(dev); + dev->interrupt = 0; + return; + } + + if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) + { + dev->interrupt = 0; + return; + } + + ack_seq = (info >> 3) & 0x07U; + read_seq = (info & 0x07U); + + dev->interrupt = 0; + sti(); + + /* + * Bottom Half + * Runs with ints enabled + */ + + if (read_seq != dev->rcv_seq) + { + pcbit_frame_read(dev, read_seq); + ack_int = 0; + } + + if (ack_seq != dev->unack_seq) + { + pcbit_recv_ack(dev, ack_seq); + ack_int = 0; + } + + if (ack_int) + { + info = 0; + info |= dev->rcv_seq << 3; + info |= dev->send_seq; + + writeb(info, dev->sh_mem + BANK4); + } +} + + +static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info) +{ + u_char state; + + state = dev->l2_state; + +#ifdef DEBUG + printk(KERN_DEBUG "layer2_active_confirm\n"); +#endif + + + if (info & 0x80U ) { + dev->rcv_seq = info & 0x07U; + dev->l2_state = L2_RUNNING; + } + else + dev->l2_state = L2_DOWN; + + if (state == L2_STARTING) + wake_up_interruptible(&dev->set_running_wq); + + if (state == L2_ERROR && dev->l2_state == L2_RUNNING) { + pcbit_transmit(dev); + } + +} + +static void pcbit_l2_err_recover(unsigned long data) +{ + + struct pcbit_dev * dev; + struct frame_buf *frame; + + dev = (struct pcbit_dev *) data; + + del_timer(&dev->error_recover_timer); + if (dev->w_busy || dev->r_busy) + { + init_timer(&dev->error_recover_timer); + dev->error_recover_timer.expires = jiffies + ERRTIME; + add_timer(&dev->error_recover_timer); + return; + } + + dev->w_busy = dev->r_busy = 1; + + if (dev->read_frame) { + if (dev->read_frame->skb) { + dev->read_frame->skb->free = 1; + kfree_skb(dev->read_frame->skb, FREE_READ); + } + kfree(dev->read_frame); + dev->read_frame = NULL; + } + + + if (dev->write_queue) { + frame = dev->write_queue; +#ifdef FREE_ON_ERROR + dev->write_queue = dev->write_queue->next; + + if (frame->skb) { + dev_kfree_skb(frame->skb, FREE_WRITE); + } + + kfree(frame); +#else + frame->copied = 0; +#endif + } + + dev->rcv_seq = dev->send_seq = dev->unack_seq = 0; + dev->free = 511; + dev->l2_state = L2_ERROR; + + /* this is an hack... */ + pcbit_firmware_bug(dev); + + dev->writeptr = dev->sh_mem; + dev->readptr = dev->sh_mem + BANK2; + + writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)), + dev->sh_mem + BANK4); + dev->w_busy = dev->r_busy = 0; + +} + +static void pcbit_l2_error(struct pcbit_dev *dev) +{ + if (dev->l2_state == L2_RUNNING) { + + printk(KERN_INFO "pcbit: layer 2 error\n"); + +#ifdef DEBUG + log_state(dev); +#endif + + dev->l2_state = L2_DOWN; + + init_timer(&dev->error_recover_timer); + dev->error_recover_timer.function = &pcbit_l2_err_recover; + dev->error_recover_timer.data = (ulong) dev; + dev->error_recover_timer.expires = jiffies + ERRTIME; + add_timer(&dev->error_recover_timer); + } +} + +/* + * Description: + * if board acks frames + * update dev->free + * call pcbit_transmit to write possible queued frames + */ + +static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack) +{ + int i, count; + int unacked; + + unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; + + /* dev->unack_seq < ack <= dev->send_seq; */ + + if (unacked) + { + + if (dev->send_seq > dev->unack_seq) + if (ack <= dev->unack_seq || ack > dev->send_seq) + { + printk("layer 2 ack unacceptable - dev %d", dev->id); + pcbit_l2_error(dev); + } + else + if (ack > dev->send_seq && ack <= dev->unack_seq) { + printk("layer 2 ack unacceptable - dev %d", dev->id); + pcbit_l2_error(dev); + } + + /* ack is acceptable */ + + + i = dev->unack_seq; + + do { + dev->unack_seq = i = (i + 1) % 8; + dev->free += dev->fsize[i]; + } while (i != ack); + + count = 0; + while (count < 7 && dev->write_queue) + { + u8 lsend_seq = dev->send_seq; + + pcbit_transmit(dev); + + if (dev->send_seq == lsend_seq) + break; + count++; + } + + if (!count) { + u_char info; + + info = 0; + info |= dev->rcv_seq << 3; + info |= dev->send_seq; + + writeb(info, dev->sh_mem + BANK4); + } + } + else + printk(KERN_DEBUG "recv_ack: unacked = 0\n"); +} + +static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq) +{ + unsigned long flags; + int busy; + u_char info; + + save_flags(flags); + cli(); + if (!(busy=dev->r_busy)) + dev->r_busy = 1; + restore_flags(flags); + + if (busy) + return; + + + while (read_seq != dev->rcv_seq) { + pcbit_receive(dev); + dev->rcv_seq = (dev->rcv_seq + 1) % 8; + } + + dev->r_busy = 0; + + info = 0; + info |= dev->rcv_seq << 3; + info |= dev->send_seq; + + writeb(info, dev->sh_mem + BANK4); +} + + + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/layer2.h linux/drivers/isdn/pcbit/layer2.h --- v1.3.92/linux/drivers/isdn/pcbit/layer2.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/layer2.h Sun Apr 21 11:56:14 1996 @@ -0,0 +1,287 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * PCBIT-D low-layer interface definitions + */ + +#ifndef LAYER2_H +#define LAYER2_H + +#include + +#define BANK1 0x0000U /* PC -> Board */ +#define BANK2 0x01ffU /* Board -> PC */ +#define BANK3 0x03feU /* Att Board */ +#define BANK4 0x03ffU /* Att PC */ + +#define BANKLEN 0x01FFU + +#define LOAD_ZONE_START 0x03f8U +#define LOAD_ZONE_END 0x03fdU + +#define LOAD_RETRY 18000000 + + + +/* TAM - XX - C - S - NUM */ +#define PREHDR_LEN 8 +/* TT - M - I - TH - TD */ +#define FRAME_HDR_LEN 8 + +#define MSG_CONN_REQ 0x08000100 +#define MSG_CONN_CONF 0x00000101 +#define MSG_CONN_IND 0x00000102 +#define MSG_CONN_RESP 0x08000103 + +#define MSG_CONN_ACTV_REQ 0x08000300 +#define MSG_CONN_ACTV_CONF 0x00000301 +#define MSG_CONN_ACTV_IND 0x00000302 +#define MSG_CONN_ACTV_RESP 0x08000303 + +#define MSG_DISC_REQ 0x08000400 +#define MSG_DISC_CONF 0x00000401 +#define MSG_DISC_IND 0x00000402 +#define MSG_DISC_RESP 0x08000403 + +#define MSG_TDATA_REQ 0x0908E200 +#define MSG_TDATA_CONF 0x0000E201 +#define MSG_TDATA_IND 0x0000E202 +#define MSG_TDATA_RESP 0x0908E203 + +#define MSG_SELP_REQ 0x09004000 +#define MSG_SELP_CONF 0x00004001 + +#define MSG_ACT_TRANSP_REQ 0x0908E000 +#define MSG_ACT_TRANSP_CONF 0x0000E001 + +#define MSG_STPROT_REQ 0x09004100 +#define MSG_STPROT_CONF 0x00004101 + +#define MSG_PING188_REQ 0x09030500 +#define MSG_PING188_CONF 0x000005bc + +#define MSG_WATCH188 0x09030400 + +#define MSG_API_ON 0x08020102 +#define MSG_POOL_PCBIT 0x08020400 +#define MSG_POOL_PCBIT_CONF 0x00000401 + +#define MSG_INFO_IND 0x00002602 +#define MSG_INFO_RESP 0x08002603 + +#define MSG_DEBUG_188 0x0000ff00 + +/* + + long 4 3 2 1 + Intel 1 2 3 4 +*/ + +struct msg_fmt { +#if __BYTE_ORDER == 1234 /* Little Endian */ + u_char scmd; + u_char cmd; + u_char proc; + u_char cpu; +#else +#error "Non-Intel CPU" + u_char cpu; + u_char proc; + u_char cmd; + u_char scmd; +#endif +}; + + +#define MAX_QUEUED 7 + +#define SCHED_READ 0x01 +#define SCHED_WRITE 0x02 + +#define SET_RUN_TIMEOUT 2*HZ /* 2 seconds */ + + +struct frame_buf { + ulong msg; + unsigned short refnum; + unsigned short dt_len; + unsigned short hdr_len; + struct sk_buff *skb; + unsigned short copied; + struct frame_buf * next; +}; + +#define MIN(a,b) ((awriteptr - dev->sh_mem)); + printk(KERN_DEBUG "readptr = %ld\n", + (ulong) (dev->readptr - (dev->sh_mem + BANK2))); + printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n", + dev->rcv_seq, dev->send_seq, dev->unack_seq); +} +#endif + +static __inline__ struct pcbit_dev * chan2dev(struct pcbit_chan * chan) +{ + struct pcbit_dev * dev; + int i; + + + for (i=0; ib1 == chan || dev->b2 == chan) + return dev; + return NULL; + +} + +static __inline__ struct pcbit_dev * finddev(int id) +{ + struct pcbit_dev * dev; + int i; + + for (i=0; iid == id) + return dev; + return NULL; +} + + +/* + * Support routines for reading and writing in the board + */ + +static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt) +{ + writeb(dt, dev->writeptr++); + if (dev->writeptr == dev->sh_mem + BANKLEN) + dev->writeptr = dev->sh_mem; +} + +static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt) +{ + int dist; + + dist = BANKLEN - (dev->writeptr - dev->sh_mem); + switch (dist) { + case 2: + writew(dt, dev->writeptr); + dev->writeptr = dev->sh_mem; + break; + case 1: + writeb((u_char) (dt & 0x00ffU), dev->writeptr); + dev->writeptr = dev->sh_mem; + writeb((u_char) (dt >> 8), dev->writeptr++); + break; + default: + writew(dt, dev->writeptr); + dev->writeptr += 2; + break; + }; +} + +static __inline__ void memcpy_topcbit(struct pcbit_dev * dev, u_char * data, + int len) +{ + int diff; + + diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem) ); + + if (diff > 0) + { + memcpy_toio(dev->writeptr, data, len - diff); + memcpy_toio(dev->sh_mem, data + (len - diff), diff); + dev->writeptr = dev->sh_mem + diff; + } + else + { + memcpy_toio(dev->writeptr, data, len); + + dev->writeptr += len; + if (diff == 0) + dev->writeptr = dev->sh_mem; + } +} + +static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev) +{ + unsigned char val; + + val = readb(dev->readptr++); + if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN) + dev->readptr = dev->sh_mem + BANK2; + + return val; +} + +static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev) +{ + int dist; + unsigned short val; + + dist = BANKLEN - ( dev->readptr - (dev->sh_mem + BANK2 ) ); + switch (dist) { + case 2: + val = readw(dev->readptr); + dev->readptr = dev->sh_mem + BANK2; + break; + case 1: + val = readb(dev->readptr); + dev->readptr = dev->sh_mem + BANK2; + val = (readb(dev->readptr++) << 8) | val; + break; + default: + val = readw(dev->readptr); + dev->readptr += 2; + break; + }; + return val; +} + +static __inline__ void memcpy_frompcbit(struct pcbit_dev * dev, u_char * data, int len) +{ + int diff; + + diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2) ) ); + if (diff > 0) + { + memcpy_fromio(data, dev->readptr, len - diff); + memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff); + dev->readptr = dev->sh_mem + BANK2 + diff; + } + else + { + memcpy_fromio(data, dev->readptr, len); + dev->readptr += len; + if (diff == 0) + dev->readptr = dev->sh_mem + BANK2; + } +} + + +#endif + + + + + + + diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c --- v1.3.92/linux/drivers/isdn/pcbit/module.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/isdn/pcbit/module.c Sun Apr 21 11:56:14 1996 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 1996 Universidade de Lisboa + * + * Writen by Pedro Roque Marques (roque@di.fc.ul.pt) + * + * This software may be used and distributed according to the terms of + * the GNU Public License, incorporated herein by reference. + */ + +/* + * PCBIT-D module support + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include "pcbit.h" + +int mem[MAX_PCBIT_CARDS] = {0, }; +int irq[MAX_PCBIT_CARDS] = {0, }; + +int num_boards; +struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0}; + +int init_module(void); +void cleanup_module(void); + +extern void pcbit_terminate(int board); +extern int pcbit_init_dev(int board, int mem_base, int irq); + +#ifdef MODULE +#define pcbit_init init_module +#endif + +int pcbit_init(void) +{ + int board; + + num_boards = 0; + + printk(KERN_INFO + "PCBIT-D device driver v 0.5 - " + "Copyright (C) 1996 Universidade de Lisboa\n"); + + if (mem[0] || irq[0]) + { + for (board=0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++) + { + if (!mem[board]) + mem[board] = 0xD0000; + if (!irq[board]) + irq[board] = 5; + + if (pcbit_init_dev(board, mem[board], irq[board]) == 0) + num_boards++; + + else + { + printk(KERN_WARNING + "pcbit_init failed for dev %d", + board + 1); + return -EIO; + } + } + } + + /* Hardcoded default settings detection */ + + if (!num_boards) + { + printk(KERN_INFO + "Trying to detect board using default settings\n"); + if (pcbit_init_dev(0, 0xD0000, 5) == 0) + num_boards++; + else + return -EIO; + } + + /* No symbols to export, hide all symbols */ + register_symtab(NULL); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + int board; + + if (MOD_IN_USE) { + printk(KERN_WARNING "pcbit: device busy, remove cancelled\n"); + return; + } + + for (board = 0; board < num_boards; board++) + pcbit_terminate(board); + printk(KERN_INFO + "PCBIT-D module unloaded\n"); +} + +#else +void pcbit_setup(char *str, int *ints) +{ + int i, j, argc; + + argc = ints[0]; + i = 0; + j = 1; + + while (argc && (i diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/callc.c linux/drivers/isdn/teles/callc.c --- v1.3.92/linux/drivers/isdn/teles/callc.c Mon Feb 26 11:58:05 1996 +++ linux/drivers/isdn/teles/callc.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,14 @@ +/* $Id: callc.c,v 1.2 1996/04/20 16:42:29 fritz Exp fritz $ + * + * $Log: callc.c,v $ + * Revision 1.2 1996/04/20 16:42:29 fritz + * Changed statemachine to allow reject of incoming calls. + * + * Revision 1.1 1996/04/13 10:20:59 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include "teles.h" @@ -59,6 +70,7 @@ ST_PRO_W, /* 13 call clear. (initiator), DISCONNECT req. sent */ ST_ANT_W, /* 14 call clear. (receiver), awaiting DISCONNECT ind. */ ST_DISC_BC_HANGUP, /* d channel gone, wait for b channel deactivation */ + ST_OUT_W_HANGUP, /* Outgoing waiting for D-Channel hangup received */ ST_D_ERR, /* d channel released while active */ }; @@ -81,6 +93,7 @@ "ST_PRO_W", "ST_ANT_W", "ST_DISC_BC_HANGUP", + "ST_OUT_W_HANGUP", "ST_D_ERR", }; @@ -267,6 +280,29 @@ ll_hangup(chanp, 0); } + +static void +r2_1(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL); + + FsmChangeState(fi, ST_OUT_W_HANGUP); +} + + +static void +r2_2(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + FsmChangeState(fi, ST_REL_W); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); + ll_hangup(chanp, 0); +} + + static void r3(struct FsmInst *fi, int event, void *arg) { @@ -276,9 +312,26 @@ FsmChangeState(fi, ST_REL_W); } + +static void +r3_1(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); + + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); + FsmChangeState(fi, ST_REL_W); + ll_hangup(chanp, 0); +} + + static void r4(struct FsmInst *fi, int event, void *arg) { + struct Channel *chanp=fi->userdata; + + chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); FsmChangeState(fi, ST_NULL); } @@ -313,16 +366,14 @@ struct Channel *chanp = fi->userdata; isdn_ctrl ic; - chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL); - - FsmChangeState(fi, ST_IN); - /* * Report incoming calls only once to linklevel, use octet 3 of * channel identification information element. (it's value * is copied to chanp->para.bchannel in l3s12(), file isdnl3.c) */ if (((chanp->chan & 1) + 1) & chanp->para.bchannel) { + chanp->is.l4.l4l3(&chanp->is, CC_ALERTING_REQ, NULL); + FsmChangeState(fi, ST_IN); if (chanp->debug & 1) stat_debug(chanp, "STAT_ICALL"); ic.driver = drid; @@ -335,6 +386,10 @@ sprintf(ic.num, "%s,%d,0,%s", chanp->para.calling, chanp->para.info, chanp->para.called); iif.statcallb(&ic); + } else { + chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE, NULL); + FsmChangeState(fi, ST_REL_W); } } @@ -454,6 +509,24 @@ FsmChangeState(fi, ST_ANT_W); } + +static void +r17_1(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + chanp->data_open = 0; + release_ds(chanp->chan); + + chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); + + FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); + + FsmChangeState(fi, ST_NULL); + + ll_hangup(chanp,!0); +} + static void r18(struct FsmInst *fi, int event, void *arg) { @@ -481,12 +554,17 @@ r20(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; + + chanp->is.l4.l4l3(&chanp->is,CC_DLRL,NULL); + + FsmEvent(&chanp->lc_d.lcfi,EV_LC_RELEASE,NULL); FsmChangeState(fi, ST_NULL); ll_hangup(chanp, 0); } + static void r21(struct FsmInst *fi, int event, void *arg) { @@ -523,6 +601,22 @@ } static void +r23_1(struct FsmInst *fi, int event, void *arg) +{ + struct Channel *chanp = fi->userdata; + + release_ds(chanp->chan); + + chanp->is.l4.l4l3(&chanp->is, CC_DLRL,NULL); + + FsmEvent(&chanp->lc_d.lcfi, EV_LC_RELEASE,NULL); + + FsmChangeState(fi, ST_NULL); + + ll_hangup(chanp,!0); +} + +static void r24(struct FsmInst *fi, int event, void *arg) { struct Channel *chanp = fi->userdata; @@ -562,32 +656,51 @@ static struct FsmNode fnlist[] = { - {ST_NULL, EV_DIAL, r1}, - {ST_OUT_W, EV_DLEST, r5}, - {ST_OUT_W, EV_DLRL, r20}, - {ST_OUT, EV_DISCONNECT_IND, r2}, - {ST_CLEAR, EV_RELEASE_CNF, r3}, - {ST_REL_W, EV_DLRL, r4}, - {ST_NULL, EV_SETUP_IND, r6}, - {ST_IN_W, EV_DLEST, r7}, - {ST_IN, EV_RELEASE_IND, r3}, - {ST_IN, EV_ACCEPTD, r8}, - {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9}, - {ST_OUT, EV_SETUP_CNF, r10}, - {ST_OUT_ESTB, EV_BC_EST, r12}, - {ST_OUT_ESTB, EV_BC_REL, r23}, - {ST_IN_DACT, EV_BC_EST, r12}, - {ST_ACTIVE, EV_HANGUP, r15}, - {ST_BC_HANGUP, EV_BC_REL, r16}, - {ST_BC_HANGUP, EV_DISCONNECT_IND, r21}, - {ST_ACTIVE, EV_BC_REL, r17}, - {ST_ACTIVE, EV_DISCONNECT_IND, r21}, - {ST_ACTIVE, EV_DLRL, r24}, - {ST_ACTIVE, EV_CINF, r26}, - {ST_PRO_W, EV_RELEASE_IND, r18}, - {ST_ANT_W, EV_DISCONNECT_IND, r19}, - {ST_DISC_BC_HANGUP, EV_BC_REL, r22}, - {ST_D_ERR, EV_BC_REL, r25}, + {ST_NULL, EV_DIAL, r1}, + {ST_OUT_W, EV_DLEST, r5}, + {ST_OUT_W, EV_DLRL, r20}, + {ST_OUT_W, EV_RELEASE_CNF, r2_2 }, + {ST_OUT, EV_DISCONNECT_IND, r2}, + {ST_OUT, EV_SETUP_CNF, r10}, + {ST_OUT, EV_HANGUP, r2_1}, + {ST_OUT, EV_RELEASE_IND, r20}, + {ST_OUT, EV_DLRL, r2_2}, + {ST_OUT_W_HANGUP, EV_RELEASE_IND, r2_2}, + {ST_OUT_W_HANGUP, EV_DLRL, r20}, + {ST_CLEAR, EV_RELEASE_CNF, r3}, + {ST_CLEAR, EV_DLRL, r20}, + {ST_REL_W, EV_DLRL, r4}, + {ST_NULL, EV_SETUP_IND, r6}, + {ST_IN_W, EV_DLEST, r7}, + {ST_IN_W, EV_DLRL, r3_1}, + {ST_IN, EV_DLRL, r3_1}, + {ST_IN, EV_HANGUP, r3_1}, + {ST_IN, EV_RELEASE_IND, r2_2}, + {ST_IN, EV_RELEASE_CNF, r2_2}, + {ST_IN, EV_ACCEPTD, r8}, + {ST_IN_SETUP, EV_HANGUP, r2_1}, + {ST_IN_SETUP, EV_SETUP_CMPL_IND, r9}, + {ST_IN_SETUP, EV_RELEASE_IND, r2_2}, + {ST_IN_SETUP, EV_DISCONNECT_IND, r2}, + {ST_IN_SETUP, EV_DLRL, r20}, + {ST_OUT_ESTB, EV_BC_EST, r12}, + {ST_OUT_ESTB, EV_BC_REL, r23}, + {ST_OUT_ESTB, EV_DLRL, r23_1}, + {ST_IN_DACT, EV_BC_EST, r12}, + {ST_IN_DACT, EV_BC_REL, r17}, + {ST_IN_DACT, EV_DLRL, r17_1}, + {ST_ACTIVE, EV_HANGUP, r15}, + {ST_ACTIVE, EV_BC_REL, r17}, + {ST_ACTIVE, EV_DISCONNECT_IND, r21}, + {ST_ACTIVE, EV_DLRL, r24}, + {ST_ACTIVE, EV_CINF, r26}, + {ST_ACTIVE, EV_RELEASE_IND, r17}, + {ST_BC_HANGUP, EV_BC_REL, r16}, + {ST_BC_HANGUP, EV_DISCONNECT_IND, r21}, + {ST_PRO_W, EV_RELEASE_IND, r18}, + {ST_ANT_W, EV_DISCONNECT_IND, r19}, + {ST_DISC_BC_HANGUP, EV_BC_REL, r22}, + {ST_D_ERR, EV_BC_REL, r25}, }; #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode)) @@ -664,15 +777,15 @@ static struct FsmNode LcFnList[] = { - {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1}, - {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6}, - {ST_LC_DELAY, EV_LC_TIMER, lc_r2}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3}, - {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4}, - {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5}, - {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5}, - {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5}, - {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5}, + {ST_LC_NULL, EV_LC_ESTABLISH, lc_r1}, + {ST_LC_ACTIVATE_WAIT, EV_LC_PH_ACTIVATE, lc_r6}, + {ST_LC_DELAY, EV_LC_TIMER, lc_r2}, + {ST_LC_ESTABLISH_WAIT, EV_LC_DL_ESTABLISH, lc_r3}, + {ST_LC_CONNECTED, EV_LC_RELEASE, lc_r4}, + {ST_LC_CONNECTED, EV_LC_DL_RELEASE, lc_r5}, + {ST_LC_RELEASE_WAIT, EV_LC_DL_RELEASE, lc_r5}, + {ST_LC_ACTIVATE_WAIT, EV_LC_TIMER, lc_r5}, + {ST_LC_ESTABLISH_WAIT, EV_LC_DL_RELEASE, lc_r5}, }; #define LC_FN_COUNT (sizeof(LcFnList)/sizeof(struct FsmNode)) @@ -1275,15 +1388,16 @@ if (err) return (0); - if (count > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) { - printk(KERN_WARNING "teles_writebuf: packet too large!\n"); - return (-EINVAL); - } ptr = DATAPTR(ibh); if (chanp->lc_b.l2_establish) i = st->l2.ihsize; else i = 0; + + if ((count+i) > BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS)) { + printk(KERN_WARNING "teles_writebuf: packet too large!\n"); + return (-EINVAL); + } ptr += i; diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/card.c linux/drivers/isdn/teles/card.c --- v1.3.92/linux/drivers/isdn/teles/card.c Sat Mar 2 12:37:45 1996 +++ linux/drivers/isdn/teles/card.c Sun Apr 21 11:56:15 1996 @@ -1,14 +1,16 @@ -/* +/* $Id: card.c,v 1.1 1996/04/13 10:22:42 fritz Exp $ + * * card.c low level stuff for the Teles S0 isdn card * * Author Jan den Ouden * - * - * - * Changelog: - * * Beat Doebeli log all D channel traffic * + * $Log: card.c,v $ + * Revision 1.1 1996/04/13 10:22:42 fritz + * Initial revision + * + * */ #define __NO_VERSION__ diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/config.c linux/drivers/isdn/teles/config.c --- v1.3.92/linux/drivers/isdn/teles/config.c Mon Feb 26 11:58:05 1996 +++ linux/drivers/isdn/teles/config.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: config.c,v 1.1 1996/04/13 10:23:11 fritz Exp $ + * + * $Log: config.c,v $ + * Revision 1.1 1996/04/13 10:23:11 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include #include diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/fsm.c linux/drivers/isdn/teles/fsm.c --- v1.3.92/linux/drivers/isdn/teles/fsm.c Mon Feb 26 11:58:05 1996 +++ linux/drivers/isdn/teles/fsm.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: fsm.c,v 1.1 1996/04/13 10:23:41 fritz Exp $ + * + * $Log: fsm.c,v $ + * Revision 1.1 1996/04/13 10:23:41 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include "teles.h" diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/isdnl2.c linux/drivers/isdn/teles/isdnl2.c --- v1.3.92/linux/drivers/isdn/teles/isdnl2.c Mon Feb 26 11:58:06 1996 +++ linux/drivers/isdn/teles/isdnl2.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: isdnl2.c,v 1.1 1996/04/13 10:24:16 fritz Exp $ + * + * $Log: isdnl2.c,v $ + * Revision 1.1 1996/04/13 10:24:16 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include "teles.h" diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/isdnl3.c linux/drivers/isdn/teles/isdnl3.c --- v1.3.92/linux/drivers/isdn/teles/isdnl3.c Fri Apr 12 15:51:54 1996 +++ linux/drivers/isdn/teles/isdnl3.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,16 @@ +/* $Id: isdnl3.c,v 1.2 1996/04/20 16:45:05 fritz Exp $ + * + * $Log: isdnl3.c,v $ + * Revision 1.2 1996/04/20 16:45:05 fritz + * Changed to report all incoming calls to Linklevel, not just those + * with Service 7. + * Misc. typos + * + * Revision 1.1 1996/04/13 10:24:45 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #define P_1TR6 #include "teles.h" @@ -61,6 +74,17 @@ } static void +l3s4_1(struct PStack *st, byte pr, void *arg) +{ + struct BufHeader *ibh = arg; + + BufPoolRelease(ibh); + newl3state(st, 19); + l3_message(st, MT_RELEASE); + st->l3.l3l4(st, CC_RELEASE_CNF, NULL); +} + +static void l3s5(struct PStack *st, byte pr, void *arg) { @@ -188,6 +212,7 @@ l3s12(struct PStack *st, byte pr, void *arg) { byte *p; + int bcfound = 0; struct BufHeader *ibh = arg; p = DATAPTR(ibh); @@ -202,6 +227,7 @@ if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x18, 0))) { st->pa->bchannel = p[2] & 0x3; + bcfound++ ; } else printk(KERN_WARNING "l3s12: Channel ident not found\n"); @@ -265,14 +291,15 @@ strcpy(st->pa->calling, ""); BufPoolRelease(ibh); - if (st->pa->info == 7) { - newl3state(st, 6); - st->l3.l3l4(st, CC_SETUP_IND, NULL); - } else { - printk(KERN_WARNING "non-digital call: %s -> %s\n", - st->pa->calling, - st->pa->called); - } + if (bcfound) { + if (st->pa->info != 7) { + printk(KERN_WARNING "non-dgital call: %s -> %s\n", + st->pa->calling, + st->pa->called); + } + newl3state(st, 6); + st->l3.l3l4(st, CC_SETUP_IND, NULL); + } } static void @@ -366,13 +393,32 @@ static struct stateentry downstatelist[] = { - {0, CC_SETUP_REQ, l3s5}, - {6, CC_REJECT_REQ, l3s13}, - {6, CC_SETUP_RSP, l3s16}, - {6, CC_ALERTING_REQ, l3s20}, - {7, CC_SETUP_RSP, l3s16}, - {10, CC_DISCONNECT_REQ, l3s18}, - {12, CC_RELEASE_REQ, l3s3}, + {0,CC_SETUP_REQ,l3s5}, + {1,CC_DISCONNECT_REQ,l3s18}, + {1,CC_RELEASE_REQ,l3s3}, + {1,CC_DLRL,l3s13}, + {3,CC_DISCONNECT_REQ,l3s18}, + {3,CC_RELEASE_REQ,l3s3}, + {3,CC_DLRL,l3s13}, + {4,CC_RELEASE_REQ,l3s3}, + {4,CC_DISCONNECT_REQ,l3s18}, + {4,CC_DLRL,l3s13}, + {6,CC_RELEASE_REQ,l3s3}, + {6,CC_DISCONNECT_REQ,l3s18}, + {6,CC_ALERTING_REQ,l3s20}, + {6,CC_DLRL,l3s13}, + {7,CC_RELEASE_REQ,l3s3}, + {7,CC_SETUP_RSP,l3s16}, + {7,CC_DLRL,l3s13}, + {8,CC_RELEASE_REQ,l3s3}, + {8,CC_DISCONNECT_REQ,l3s18}, + {8,CC_DLRL,l3s13}, + {10,CC_DISCONNECT_REQ,l3s18}, + {10,CC_RELEASE_REQ,l3s3}, + {10,CC_DLRL,l3s13}, + {11,CC_RELEASE_REQ,l3s3}, + {12,CC_RELEASE_REQ,l3s3}, + {19,CC_DLRL,l3s13}, }; static int downsllen = sizeof(downstatelist) / @@ -380,20 +426,34 @@ static struct stateentry datastatelist[] = { - {0, MT_SETUP, l3s12}, - {1, MT_CALL_PROCEEDING, l3s6}, - {1, MT_RELEASE_COMPLETE, l3s7}, - {3, MT_DISCONNECT, l3s7}, - {3, MT_CONNECT, l3s8}, - {3, MT_ALERTING, l3s11}, - {4, MT_CONNECT, l3s8}, - {4, MT_DISCONNECT, l3s7}, - {4, MT_RELEASE, l3s19}, - {7, MT_RELEASE, l3s19}, - {8, MT_CONNECT_ACKNOWLEDGE, l3s17}, - {10, MT_DISCONNECT, l3s7}, - {11, MT_RELEASE, l3s19}, - {19, MT_RELEASE_COMPLETE, l3s4}, + {0,MT_SETUP,l3s12}, + {1,MT_CALL_PROCEEDING,l3s6}, + {1,MT_RELEASE_COMPLETE,l3s4}, + {1,MT_RELEASE,l3s19}, + {1,MT_DISCONNECT,l3s7}, + {3,MT_DISCONNECT,l3s7}, + {3,MT_CONNECT,l3s8}, + {3,MT_ALERTING,l3s11}, + {3,MT_RELEASE,l3s19}, + {3,MT_RELEASE_COMPLETE,l3s4}, + {4,MT_CONNECT,l3s8}, + {4,MT_DISCONNECT,l3s7}, + {4,MT_RELEASE,l3s19}, + {4,MT_RELEASE_COMPLETE,l3s4}, + {6,MT_SETUP,l3s12}, + {7,MT_RELEASE,l3s19}, + {7,MT_RELEASE_COMPLETE,l3s4_1}, + {7,MT_DISCONNECT,l3s7}, + {8,MT_RELEASE,l3s19}, + {8,MT_CONNECT_ACKNOWLEDGE,l3s17}, + {8,MT_DISCONNECT,l3s7}, + {8,MT_RELEASE_COMPLETE,l3s4_1}, + {10,MT_DISCONNECT,l3s7}, + {10,MT_RELEASE,l3s19}, + {10,MT_RELEASE_COMPLETE,l3s4_1}, + {11,MT_RELEASE,l3s19}, + {11,MT_RELEASE_COMPLETE,l3s4}, + {19,MT_RELEASE_COMPLETE,l3s4}, }; static int datasllen = sizeof(datastatelist) / diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/l3_1TR6.c linux/drivers/isdn/teles/l3_1TR6.c --- v1.3.92/linux/drivers/isdn/teles/l3_1TR6.c Fri Apr 12 15:51:54 1996 +++ linux/drivers/isdn/teles/l3_1TR6.c Sun Apr 21 11:56:15 1996 @@ -1,4 +1,16 @@ -#define DEBUG_1TR6 0 +/* $Id: l3_1TR6.c,v 1.2 1996/04/20 16:47:23 fritz Exp $ + * + * $Log: l3_1TR6.c,v $ + * Revision 1.2 1996/04/20 16:47:23 fritz + * Changed statemachine to allow reject of an incoming call. + * Report all incoming calls, not just those with Service = 7. + * Misc. typos + * + * Revision 1.1 1996/04/13 10:25:16 fritz + * Initial revision + * + * + */ char * mt_trans(int pd, int mt) @@ -101,15 +113,15 @@ byte *p; struct BufHeader *ibh = arg; -#if DEBUG_1TR6 - printk(KERN_INFO "1tr6: TU_SETUP\n"); -#endif - p = DATAPTR(ibh); p += st->l2.uihsize; st->pa->callref = getcallref(p); st->l3.callref = 0x80 + st->pa->callref; +#if DEBUG_1TR6 + printk(KERN_INFO "1tr6: TU_SETUP cr=%d\n",st->l3.callref); +#endif + /* * Channel Identification */ @@ -144,10 +156,14 @@ BufPoolRelease(ibh); - if (st->pa->info == 7) { - newl3state(st, 6); - st->l3.l3l4(st, CC_SETUP_IND, NULL); + /* Signal all services, linklevel takes care of Service-Indicator */ + if (st->pa->info != 7) { + printk(KERN_INFO "non-digital call: %s -> %s\n", + st->pa->calling, + st->pa->called); } + newl3state(st, 6); + st->l3.l3l4(st, CC_SETUP_IND, NULL); } static void @@ -413,13 +429,14 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg) { struct BufHeader *dibh; - byte *p; + byte *p; + byte rejflg; #if DEBUG_1TR6 printk(KERN_INFO "1tr6: send DISCON\n"); #endif - BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20); + BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21); p = DATAPTR(dibh); p += st->l2.ihsize; @@ -428,14 +445,25 @@ *p++ = st->l3.callref; *p++ = MT_N1_DISC; - *p++ = WE0_cause; - *p++ = 0x0; /* Laenge = 0 normales Ausloesen */ + if (st->l3.state == 7) { + rejflg = 1; + *p++ = WE0_cause; /* Anruf abweisen */ + *p++ = 0x01; /* Laenge = 1 */ + *p++ = CAUSE_CallRejected; + } else { + rejflg = 0; + *p++ = WE0_cause; + *p++ = 0x0; /* Laenge = 0 normales Ausloesen */ + } dibh->datasize = p - DATAPTR(dibh); i_down(st, dibh); - newl3state(st, 11); + if (rejflg) + newl3state(st, 0); + else + newl3state(st, 11); } static void @@ -450,11 +478,13 @@ static struct stateentry downstatelist_1tr6t[] = { {0, CC_SETUP_REQ, l3_1tr6_setup}, + {4, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, {6, CC_REJECT_REQ, l3_1tr6_ignore}, {6, CC_SETUP_RSP, l3_1tr6_conn}, {6, CC_ALERTING_REQ, l3_1tr6_alert}, {7, CC_SETUP_RSP, l3_1tr6_conn}, {7, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, + {7, CC_DLRL, l3_1tr6_disconn_req}, {8, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, {10, CC_DISCONNECT_REQ, l3_1tr6_disconn_req}, {12, CC_RELEASE_REQ, l3_1tr6_rel_req} diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/l3_1TR6.h linux/drivers/isdn/teles/l3_1TR6.h --- v1.3.92/linux/drivers/isdn/teles/l3_1TR6.h Mon Feb 26 11:58:07 1996 +++ linux/drivers/isdn/teles/l3_1TR6.h Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: l3_1TR6.h,v 1.1 1996/04/13 10:25:42 fritz Exp $ + * + * $Log: l3_1TR6.h,v $ + * Revision 1.1 1996/04/13 10:25:42 fritz + * Initial revision + * + * + */ #ifndef l3_1TR6 #define l3_1TR6 diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/llglue.c linux/drivers/isdn/teles/llglue.c --- v1.3.92/linux/drivers/isdn/teles/llglue.c Mon Feb 26 11:58:07 1996 +++ linux/drivers/isdn/teles/llglue.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: llglue.c,v 1.1 1996/04/13 10:26:29 fritz Exp $ + * + * $Log: llglue.c,v $ + * Revision 1.1 1996/04/13 10:26:29 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include "teles.h" #include diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/mod.c linux/drivers/isdn/teles/mod.c --- v1.3.92/linux/drivers/isdn/teles/mod.c Mon Feb 26 11:58:07 1996 +++ linux/drivers/isdn/teles/mod.c Sun Apr 21 11:56:15 1996 @@ -1,6 +1,12 @@ +/* $Id: mod.c,v 1.1 1996/04/13 10:27:02 fritz Exp $ + * + * $Log: mod.c,v $ + * Revision 1.1 1996/04/13 10:27:02 fritz + * Initial revision + * + * + */ #include "teles.h" - - extern struct IsdnCard cards[]; extern char *teles_id; diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/q931.c linux/drivers/isdn/teles/q931.c --- v1.3.92/linux/drivers/isdn/teles/q931.c Fri Apr 12 15:51:54 1996 +++ linux/drivers/isdn/teles/q931.c Sun Apr 21 11:56:15 1996 @@ -1,4 +1,5 @@ -/* +/* $Id: q931.c,v 1.2 1996/04/20 16:48:19 fritz Exp $ + * * q931.c code to decode ITU Q.931 call control messages * * Author Jan den Ouden @@ -9,6 +10,14 @@ * * Beat Doebeli cause texts, display information element * + * $Log: q931.c,v $ + * Revision 1.2 1996/04/20 16:48:19 fritz + * Misc. typos + * + * Revision 1.1 1996/04/13 10:27:49 fritz + * Initial revision + * + * */ diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/tei.c linux/drivers/isdn/teles/tei.c --- v1.3.92/linux/drivers/isdn/teles/tei.c Mon Feb 26 11:58:07 1996 +++ linux/drivers/isdn/teles/tei.c Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: tei.c,v 1.1 1996/04/13 10:28:25 fritz Exp $ + * + * $Log: tei.c,v $ + * Revision 1.1 1996/04/13 10:28:25 fritz + * Initial revision + * + * + */ #define __NO_VERSION__ #include "teles.h" diff -u --recursive --new-file v1.3.92/linux/drivers/isdn/teles/teles.h linux/drivers/isdn/teles/teles.h --- v1.3.92/linux/drivers/isdn/teles/teles.h Mon Feb 26 12:29:43 1996 +++ linux/drivers/isdn/teles/teles.h Sun Apr 21 11:56:15 1996 @@ -1,3 +1,11 @@ +/* $Id: teles.h,v 1.1 1996/04/13 10:29:00 fritz Exp $ + * + * $Log: teles.h,v $ + * Revision 1.1 1996/04/13 10:29:00 fritz + * Initial revision + * + * + */ #include #include #include diff -u --recursive --new-file v1.3.92/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.92/linux/drivers/net/3c509.c Fri Apr 5 13:35:28 1996 +++ linux/drivers/net/3c509.c Sun Apr 21 11:13:48 1996 @@ -221,6 +221,7 @@ lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; } + current_tag = dev->name[3]-'0'; /* For the first probe, clear all board's tag registers. */ if (current_tag == 0) outb(0xd0, id_port); @@ -265,6 +266,10 @@ /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); + + if( check_region(ioaddr, EL3_IO_EXTENT) ) + return -ENODEV; + found: dev->base_addr = ioaddr; dev->irq = irq; diff -u --recursive --new-file v1.3.92/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.3.92/linux/drivers/net/Makefile Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/Makefile Sun Apr 21 17:32:01 1996 @@ -242,6 +242,10 @@ endif endif +ifeq ($(CONFIG_SUNLANCE),y) +L_OBJS += sunlance.o +endif + ifeq ($(CONFIG_AT1700),y) L_OBJS += at1700.o else diff -u --recursive --new-file v1.3.92/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.3.92/linux/drivers/net/Space.c Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/Space.c Sun Apr 21 17:32:01 1996 @@ -73,6 +73,7 @@ extern int tc59x_probe(struct device *); extern int dgrs_probe(struct device *); extern int smc_init( struct device * ); +extern int sparc_lance_probe(struct device *); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -190,6 +191,9 @@ #ifdef CONFIG_NI52 && ni52_probe(dev) #endif +#ifdef CONFIG_SUNLANCE + && sparc_lance_probe(dev) +#endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ } @@ -205,7 +209,7 @@ #endif /* This must be AFTER the various FRADs so it initializes FIRST! */ - + #ifdef CONFIG_DLCI extern int dlci_init(struct device *); static struct device dlci_dev = { "dlci", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, dlci_init, }; @@ -294,7 +298,7 @@ #undef NEXT_DEV #define NEXT_DEV (&strip_bootstrap) #endif /* STRIP */ - + #if defined(CONFIG_PPP) extern int ppp_init(struct device *); static struct device ppp_bootstrap = { @@ -399,6 +403,21 @@ #endif #endif +#ifdef CONFIG_AP1000 + extern int apfddi_init(struct device *dev); + static struct device fddi_dev = { + "fddi", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, apfddi_init }; +# undef NEXT_DEV +# define NEXT_DEV (&fddi_dev) + + extern int bif_init(struct device *dev); + static struct device bif_dev = { + "bif", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NEXT_DEV, bif_init }; +# undef NEXT_DEV +# define NEXT_DEV (&bif_dev) + +#endif + extern int loopback_init(struct device *dev); struct device loopback_dev = { "lo", /* Software Loopback interface */ diff -u --recursive --new-file v1.3.92/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v1.3.92/linux/drivers/net/arcnet.c Fri Apr 12 15:51:55 1996 +++ linux/drivers/net/arcnet.c Sun Apr 21 10:48:46 1996 @@ -17,6 +17,10 @@ ********************** + v2.52 (96/04/20) + - Replaced more decimal node ID's with hex, for consistency. + - Changed a couple of printk debug levels. + v2.51 (96/02/29) - Inserted a rather important missing "volatile" in autoprobe. - arc0e and arc0s are now options in drivers/net/Config.in. @@ -138,6 +142,7 @@ TO DO: (semi-prioritized) + - Smarter recovery from RECON-during-transmit conditions. - Make arcnetE_send_packet use arcnet_prepare_tx for loading the packet into ARCnet memory. - Probe for multiple devices in one shot (trying to decide whether @@ -175,7 +180,7 @@ */ static const char *version = - "arcnet.c: v2.51 96/02/29 Avery Pennarun \n"; + "arcnet.c: v2.52 96/04/20 Avery Pennarun \n"; @@ -340,7 +345,8 @@ #define BUGLVL(x) if ((ARCNET_DEBUG_MAX)&arcnet_debug&(x)) #define BUGMSG2(x,msg,args...) BUGLVL(x) printk(msg, ## args) #define BUGMSG(x,msg,args...) BUGMSG2(x,"%s%6s: " msg, \ - x==D_NORMAL ? "" : x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \ + x==D_NORMAL ? KERN_WARNING : \ + x<=D_INIT_REASONS ? KERN_INFO : KERN_DEBUG , \ dev->name , ## args) /* Some useful multiprotocol macros. The idea here is that GCC will @@ -836,7 +842,7 @@ if (!numports) { - BUGMSG(D_INIT,"Stage 1: failed. No ARCnet cards found.\n"); + BUGMSG(D_NORMAL,"Stage 1: No ARCnet cards found.\n"); return -ENODEV; } @@ -918,7 +924,7 @@ if (!numshmems) { - BUGMSG(D_INIT,"Stage 3: failed. No ARCnet cards found.\n"); + BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n"); return -ENODEV; } @@ -1038,6 +1044,7 @@ } else { + /* just one shmem and port, assume they match */ *(u_char *)(shmems[0]) = TESTvalue; } #else @@ -1091,7 +1098,8 @@ */ for (shmem = &shmems[0]; shmem-shmemsstationid = first_mirror[1]; if (lp->stationid==0) - BUGMSG(D_NORMAL,"WARNING! Station address 0 is reserved " + BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved " "for broadcasts!\n"); else if (lp->stationid==255) BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse " @@ -1499,13 +1507,13 @@ if (status&TXFREEflag) /* transmit _DID_ finish */ { - BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%d)\n", + BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n", status,tickssofar,lp->intmask,lp->lasttrans_dest); lp->stats.tx_errors++; } else { - BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%d)\n", + BUGMSG(D_EXTRA,"tx timed out (status=%Xh, tickssofar=%d, intmask=%Xh, dest=%02Xh)\n", status,tickssofar,lp->intmask,lp->lasttrans_dest); lp->stats.tx_errors++; lp->stats.tx_aborted_errors++; @@ -1990,14 +1998,14 @@ { if (lp->lasttrans_dest != 0) { - BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%d)\n", + BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n", status,lp->lasttrans_dest); lp->stats.tx_errors++; lp->stats.tx_carrier_errors++; } else { - BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n", + BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n", status, lp->lasttrans_dest); } diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs.c linux/drivers/net/dgrs.c --- v1.3.92/linux/drivers/net/dgrs.c Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs.c Sun Apr 21 11:40:09 1996 @@ -1259,7 +1259,7 @@ #ifdef MODULE /* - * Variables that can be overriden from command line + * Variables that can be overridden from command line */ static int debug = -1; static int dma = -1; diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs_driver.c linux/drivers/net/dgrs_driver.c --- v1.3.92/linux/drivers/net/dgrs_driver.c Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs_driver.c Sun Apr 21 11:40:09 1996 @@ -1259,7 +1259,7 @@ #ifdef MODULE /* - * Variables that can be overriden from command line + * Variables that can be overridden from command line */ static int debug = -1; static int dma = -1; diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs_es4h.h linux/drivers/net/dgrs_es4h.h --- v1.3.92/linux/drivers/net/dgrs_es4h.h Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs_es4h.h Sun Apr 21 11:40:09 1996 @@ -170,7 +170,7 @@ /* * Because there are differences between the SE-4 and the SE-6, * we assume that the following globals will be set up at init - * time in main.c to containt the appropriate constants from above + * time in main.c to contain the appropriate constants from above */ extern ushort Gpp; /* Softcopy of GPP register */ extern ushort EEck; /* Clock bit */ diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs_ether.h linux/drivers/net/dgrs_ether.h --- v1.3.92/linux/drivers/net/dgrs_ether.h Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs_ether.h Sun Apr 21 11:40:09 1996 @@ -114,7 +114,7 @@ extern int Nports; /* Number of genuine ethernet controllers */ extern int Nchan; /* ... plus one for host interface */ -extern int FirstChan; /* 0 or 1, depedning on whether host is used */ +extern int FirstChan; /* 0 or 1, depending on whether host is used */ extern int NumChan; /* 4 or 5 */ /* diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs_i82596.h linux/drivers/net/dgrs_i82596.h --- v1.3.92/linux/drivers/net/dgrs_i82596.h Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs_i82596.h Sun Apr 21 11:40:09 1996 @@ -381,7 +381,7 @@ /* cmd halfword values */ #define I596_SCB_ACK 0xF000 /* ACKNOWLEDGMENTS */ #define I596_SCB_ACK_CX 0x8000 /* Ack command completion */ -#define I596_SCB_ACK_FR 0x4000 /* Ack recieved frame */ +#define I596_SCB_ACK_FR 0x4000 /* Ack received frame */ #define I596_SCB_ACK_CNA 0x2000 /* Ack command unit not active */ #define I596_SCB_ACK_RNR 0x1000 /* Ack rcv unit not ready */ #define I596_SCB_ACK_ALL 0xF000 /* Ack everything */ @@ -407,7 +407,7 @@ /* status halfword values */ #define I596_SCB_STAT 0xF000 /* STATUS */ #define I596_SCB_CX 0x8000 /* command completion */ -#define I596_SCB_FR 0x4000 /* recieved frame */ +#define I596_SCB_FR 0x4000 /* received frame */ #define I596_SCB_CNA 0x2000 /* command unit not active */ #define I596_SCB_RNR 0x1000 /* rcv unit not ready */ diff -u --recursive --new-file v1.3.92/linux/drivers/net/dgrs_plx9060.h linux/drivers/net/dgrs_plx9060.h --- v1.3.92/linux/drivers/net/dgrs_plx9060.h Sun Apr 21 12:39:01 1996 +++ linux/drivers/net/dgrs_plx9060.h Sun Apr 21 11:40:09 1996 @@ -18,7 +18,7 @@ #define PCI_INT_LINE 0x3C /* - * Registers accessable directly from PCI and local side. + * Registers accessible directly from PCI and local side. * Offset is from PCI side. Add PLX_LCL_OFFSET for local address. */ #define PLX_LCL_OFFSET 0x80 /* Offset of regs from local side */ diff -u --recursive --new-file v1.3.92/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c --- v1.3.92/linux/drivers/net/sunlance.c Fri Apr 12 15:51:57 1996 +++ linux/drivers/net/sunlance.c Sun Apr 21 12:41:57 1996 @@ -11,12 +11,18 @@ 1.4: Added support to run with a ledma on the Sun4m +1.5: + Added multiple card detection. + + 4/17/97: Burst sizes and tpe selection on sun4m by Christian Dost + (ecd@pool.informatik.rwth-aachen.de) */ #undef DEBUG_DRIVER static char *version = - "sunlance.c:v1.4 17/Feb/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; + "sunlance.c:v1.6 19/Apr/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n"; static char *lancestr = "LANCE"; +static char *lancedma = "LANCE DMA"; #include #include @@ -48,9 +54,9 @@ #include #include -/* Define: 2^2 Tx buffers and 2^4 Rx buffers */ +/* Define: 2^4 Tx buffers and 2^4 Rx buffers */ #ifndef LANCE_LOG_TX_BUFFERS -#define LANCE_LOG_TX_BUFFERS 2 +#define LANCE_LOG_TX_BUFFERS 4 #define LANCE_LOG_RX_BUFFERS 4 #endif @@ -95,10 +101,12 @@ #define LE_T1_OWN 0x80 /* Lance owns the packet */ #define LE_T1_ERR 0x40 /* Error summary */ +#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ #define LE_T1_EONE 0x08 /* Error: one retry needed */ #define LE_T1_EDEF 0x04 /* Error: deferred */ #define LE_T1_SOP 0x02 /* Start of packet */ #define LE_T1_EOP 0x01 /* End of packet */ +#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ #define LE_T3_BUF 0x8000 /* Buffer error */ #define LE_T3_UFL 0x4000 /* Error underflow */ @@ -120,52 +128,57 @@ #define TX_BUFF_SIZE PKT_BUF_SZ struct lance_rx_desc { - unsigned short rmd0; /* low address of packet */ - unsigned char rmd1_bits; /* descriptor bits */ - unsigned char rmd1_hadr; /* high address of packet */ - short length; /* This length is 2s complement (negative)! Buffer length */ - unsigned short mblength; /* This is the actual number of bytes received */ + unsigned short rmd0; /* low address of packet */ + unsigned char rmd1_bits; /* descriptor bits */ + unsigned char rmd1_hadr; /* high address of packet */ + short length; /* This length is 2s complement (negative)! + * Buffer length + */ + unsigned short mblength; /* This is the actual number of bytes received */ }; struct lance_tx_desc { - unsigned short tmd0; /* low address of packet */ - unsigned char tmd1_bits; /* descriptor bits */ - unsigned char tmd1_hadr; /* high address of packet */ - short length; /* Length is 2s complement (negative)! */ - unsigned short misc; + unsigned short tmd0; /* low address of packet */ + unsigned char tmd1_bits; /* descriptor bits */ + unsigned char tmd1_hadr; /* high address of packet */ + short length; /* Length is 2s complement (negative)! */ + unsigned short misc; }; /* The LANCE initialization block, described in databook. */ /* On the Sparc, this block should be on a DMA region */ struct lance_init_block { - unsigned short mode; /* Pre-set mode (reg. 15) */ - unsigned char phys_addr[6]; /* Physical ethernet address */ - unsigned filter[2]; /* Multicast filter. */ - - /* Receive and transmit ring base, along with extra bits. */ - unsigned short rx_ptr; /* receive descriptor addr */ - unsigned short rx_len; /* receive len and high addr */ - unsigned short tx_ptr; /* transmit descriptor addr */ - unsigned short tx_len; /* transmit len and high addr */ - - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ - struct lance_rx_desc brx_ring[RX_RING_SIZE]; - struct lance_tx_desc btx_ring[TX_RING_SIZE]; + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter. */ + + /* Receive and transmit ring base, along with extra bits. */ + unsigned short rx_ptr; /* receive descriptor addr */ + unsigned short rx_len; /* receive len and high addr */ + unsigned short tx_ptr; /* transmit descriptor addr */ + unsigned short tx_len; /* transmit len and high addr */ + + /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ + struct lance_rx_desc brx_ring[RX_RING_SIZE]; + struct lance_tx_desc btx_ring[TX_RING_SIZE]; - char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; - char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; + char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE]; + char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE]; }; struct lance_private { - char *name; - volatile struct lance_regs *ll; - volatile struct lance_init_block *init_block; + char *name; + volatile struct lance_regs *ll; + volatile struct lance_init_block *init_block; - int rx_new, tx_new; - int rx_old, tx_old; + int rx_new, tx_new; + int rx_old, tx_old; - struct enet_statistics stats; - struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ + struct enet_statistics stats; + struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ + + int tpe; /* cable-selection is TPE */ + int burst_sizes; /* ledma SBus burst sizes */ }; #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\ @@ -174,8 +187,8 @@ /* On the sparc, the lance control ports are memory mapped */ struct lance_regs { - unsigned short rdp; /* register data port */ - unsigned short rap; /* register address port */ + unsigned short rdp; /* register data port */ + unsigned short rap; /* register address port */ }; int sparc_lance_debug = 2; @@ -188,616 +201,720 @@ /* Load the CSR registers */ static void load_csrs (struct lance_private *lp) { - volatile struct lance_regs *ll = lp->ll; - volatile struct lance_init_block *ib = lp->init_block; - int leptr; - - leptr = LANCE_ADDR (ib); - ll->rap = LE_CSR1; - ll->rdp = (leptr & 0xFFFF); - ll->rap = LE_CSR2; - ll->rdp = leptr >> 16; - ll->rap = LE_CSR3; - ll->rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib = lp->init_block; + int leptr; + + leptr = LANCE_ADDR (ib); + ll->rap = LE_CSR1; + ll->rdp = (leptr & 0xFFFF); + ll->rap = LE_CSR2; + ll->rdp = leptr >> 16; + ll->rap = LE_CSR3; + ll->rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; - /* Point back to csr0 */ - ll->rap = LE_CSR0; + /* Point back to csr0 */ + ll->rap = LE_CSR0; } #define ZERO 0 /* Setup the Lance Rx and Tx rings */ /* Sets dev->tbusy */ -static void -lance_init_ring (struct device *dev) +static void lance_init_ring (struct device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; - volatile struct lance_init_block *ib = lp->init_block; - int leptr; - int i; - - /* Lock out other processes while setting up hardware */ - dev->tbusy = 1; - lp->rx_new = lp->tx_new = 0; - lp->rx_old = lp->tx_old = 0; - - ib->mode = 0; - - /* Copy the ethernet address to the lance init block - * Note that on the sparc you need to swap the ethernet address. - */ - ib->phys_addr [0] = dev->dev_addr [1]; - ib->phys_addr [1] = dev->dev_addr [0]; - ib->phys_addr [2] = dev->dev_addr [3]; - ib->phys_addr [3] = dev->dev_addr [2]; - ib->phys_addr [4] = dev->dev_addr [5]; - ib->phys_addr [5] = dev->dev_addr [4]; - - if (ZERO) - printk ("TX rings:\n"); - - /* Setup the Tx ring entries */ - for (i = 0; i <= TX_RING_SIZE; i++){ - leptr = LANCE_ADDR(&ib->tx_buf[i][0]); - ib->btx_ring [i].tmd0 = leptr; - ib->btx_ring [i].tmd1_hadr = leptr >> 16; - ib->btx_ring [i].tmd1_bits = 0; - ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */ - ib->btx_ring [i].misc = 0; - if (i < 3) - if (ZERO) printk ("%d: 0x%8.8x\n", i, leptr); - } - - /* Setup the Rx ring entries */ - if (ZERO) printk ("RX rings:\n"); - for (i = 0; i < RX_RING_SIZE; i++){ - leptr = LANCE_ADDR(&ib->rx_buf[i][0]); - - ib->brx_ring [i].rmd0 = leptr; - ib->brx_ring [i].rmd1_hadr = leptr >> 16; - ib->brx_ring [i].rmd1_bits = LE_R1_OWN; - ib->brx_ring [i].length = -RX_BUFF_SIZE | 0xf000; - ib->brx_ring [i].mblength = 0; - if (i < 3) - if (ZERO) printk ("%d: 0x%8.8x\n", i, leptr); - } - - /* Setup the initialization block */ - - /* Setup rx descriptor pointer */ - leptr = LANCE_ADDR(&ib->brx_ring); - ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); - ib->rx_ptr = leptr; - if (ZERO) printk ("RX ptr: %8.8x\n", leptr); - - /* Setup tx descriptor pointer */ - leptr = LANCE_ADDR(&ib->btx_ring); - ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); - ib->tx_ptr = leptr; - if (ZERO) printk ("TX ptr: %8.8x\n", leptr); - - /* Clear the multicast filter */ - ib->filter [0] = 0; - ib->filter [1] = 0; -} - -static int -init_restart_lance (struct lance_private *lp) -{ - volatile struct lance_regs *ll = lp->ll; - int i; - - ll->rap = LE_CSR0; - ll->rdp = LE_C0_INIT; - - /* Wait for the lance to complete initialization */ - for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++) - ; - if ((i == 100) || (ll->rdp & LE_C0_ERR)){ - printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); - if (lp->ledma) - printk ("dcsr=%8.8x\n", (unsigned int) lp->ledma->regs->cond_reg); - return -1; - } + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + int leptr; + int i; + + /* Lock out other processes while setting up hardware */ + dev->tbusy = 1; + lp->rx_new = lp->tx_new = 0; + lp->rx_old = lp->tx_old = 0; + + ib->mode = 0; + + /* Copy the ethernet address to the lance init block + * Note that on the sparc you need to swap the ethernet address. + */ + ib->phys_addr [0] = dev->dev_addr [1]; + ib->phys_addr [1] = dev->dev_addr [0]; + ib->phys_addr [2] = dev->dev_addr [3]; + ib->phys_addr [3] = dev->dev_addr [2]; + ib->phys_addr [4] = dev->dev_addr [5]; + ib->phys_addr [5] = dev->dev_addr [4]; + + if (ZERO) + printk ("TX rings:\n"); + + /* Setup the Tx ring entries */ + for (i = 0; i <= TX_RING_SIZE; i++) { + leptr = LANCE_ADDR(&ib->tx_buf[i][0]); + ib->btx_ring [i].tmd0 = leptr; + ib->btx_ring [i].tmd1_hadr = leptr >> 16; + ib->btx_ring [i].tmd1_bits = 0; + ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */ + ib->btx_ring [i].misc = 0; + if (i < 3) + if (ZERO) printk ("%d: 0x%8.8x\n", i, leptr); + } - /* Clear IDON by writing a "1", enable interrupts and start lance */ - ll->rdp = LE_C0_IDON; - ll->rdp = LE_C0_INEA | LE_C0_STRT; + /* Setup the Rx ring entries */ + if (ZERO) + printk ("RX rings:\n"); + for (i = 0; i < RX_RING_SIZE; i++) { + leptr = LANCE_ADDR(&ib->rx_buf[i][0]); + + ib->brx_ring [i].rmd0 = leptr; + ib->brx_ring [i].rmd1_hadr = leptr >> 16; + ib->brx_ring [i].rmd1_bits = LE_R1_OWN; + ib->brx_ring [i].length = -RX_BUFF_SIZE | 0xf000; + ib->brx_ring [i].mblength = 0; + if (i < 3 && ZERO) + printk ("%d: 0x%8.8x\n", i, leptr); + } - /* On the 4m, enable dma interrupts */ - if (lp->ledma) - lp->ledma->regs->cond_reg |= DMA_INT_ENAB; + /* Setup the initialization block */ + + /* Setup rx descriptor pointer */ + leptr = LANCE_ADDR(&ib->brx_ring); + ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16); + ib->rx_ptr = leptr; + if (ZERO) + printk ("RX ptr: %8.8x\n", leptr); + + /* Setup tx descriptor pointer */ + leptr = LANCE_ADDR(&ib->btx_ring); + ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16); + ib->tx_ptr = leptr; + if (ZERO) + printk ("TX ptr: %8.8x\n", leptr); + + /* Clear the multicast filter */ + ib->filter [0] = 0; + ib->filter [1] = 0; +} + +static int init_restart_lance (struct lance_private *lp) +{ + volatile struct lance_regs *ll = lp->ll; + int i; - return 0; + if (lp->ledma) { + struct sparc_dma_registers *dregs = lp->ledma->regs; + unsigned long creg; + + while (dregs->cond_reg & DMA_FIFO_ISDRAIN) /* E-Cache draining */ + barrier(); + + creg = dregs->cond_reg; + if (lp->burst_sizes & DMA_BURST32) + creg |= DMA_E_BURST8; + else + creg &= ~DMA_E_BURST8; + + creg |= (DMA_DSBL_RD_DRN | DMA_DSBL_WR_INV | DMA_FIFO_INV); + + if (lp->tpe) + creg |= DMA_EN_ENETAUI; + else + creg &= ~DMA_EN_ENETAUI; + udelay(20); + dregs->cond_reg = creg; + udelay(200); + } + + ll->rap = LE_CSR0; + ll->rdp = LE_C0_INIT; + + /* Wait for the lance to complete initialization */ + for (i = 0; (i < 100) && !(ll->rdp & (LE_C0_ERR | LE_C0_IDON)); i++) + barrier(); + if ((i == 100) || (ll->rdp & LE_C0_ERR)) { + printk ("LANCE unopened after %d ticks, csr0=%4.4x.\n", i, ll->rdp); + if (lp->ledma) + printk ("dcsr=%8.8x\n", + (unsigned int) lp->ledma->regs->cond_reg); + return -1; + } + + /* Clear IDON by writing a "1", enable interrupts and start lance */ + ll->rdp = LE_C0_IDON; + ll->rdp = LE_C0_INEA | LE_C0_STRT; + + if (lp->ledma) + lp->ledma->regs->cond_reg |= DMA_INT_ENAB; + + return 0; } -static int -lance_rx (struct device *dev) +static int lance_rx (struct device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_regs *ll = lp->ll; - volatile struct lance_rx_desc *rd; - unsigned char bits; + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_rx_desc *rd; + unsigned char bits; #ifdef TEST_HITS - printk ("["); - for (i = 0; i < RX_RING_SIZE; i++){ - if (i == lp->rx_new) - printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X"); - else - printk ("%s", ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1"); - } - printk ("]"); + printk ("["); + for (i = 0; i < RX_RING_SIZE; i++) { + if (i == lp->rx_new) + printk ("%s", + ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "_" : "X"); + else + printk ("%s", + ib->brx_ring [i].rmd1_bits & LE_R1_OWN ? "." : "1"); + } + printk ("]"); #endif - ll->rdp = LE_C0_RINT|LE_C0_INEA; - for (rd = &ib->brx_ring [lp->rx_new]; - !((bits = rd->rmd1_bits) & LE_R1_OWN); - rd = &ib->brx_ring [lp->rx_new]){ - int pkt_len; - struct sk_buff *skb; - char *buf; - - /* We got an incomplete frame? */ - if ((bits & LE_R1_POK) != LE_R1_POK){ - lp->stats.rx_over_errors++; - lp->stats.rx_errors++; - continue; - } else if (bits & LE_R1_ERR){ - /* Count only the end frame as a tx error, not the beginning */ - if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; - if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; - if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; - if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; - if (bits & LE_R1_EOP) lp->stats.rx_errors++; - } else { - pkt_len = rd->mblength; - skb = dev_alloc_skb (pkt_len+2); - if (skb == NULL){ - printk ("%s: Memory squeeze, deferring packet.\n", dev->name); - lp->stats.rx_dropped++; + ll->rdp = LE_C0_RINT|LE_C0_INEA; + for (rd = &ib->brx_ring [lp->rx_new]; + !((bits = rd->rmd1_bits) & LE_R1_OWN); + rd = &ib->brx_ring [lp->rx_new]) { + int pkt_len; + struct sk_buff *skb; + + /* We got an incomplete frame? */ + if ((bits & LE_R1_POK) != LE_R1_POK) { + lp->stats.rx_over_errors++; + lp->stats.rx_errors++; + continue; + } else if (bits & LE_R1_ERR) { + /* Count only the end frame as a tx error, not the beginning */ + if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++; + if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++; + if (bits & LE_R1_OFL) lp->stats.rx_over_errors++; + if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++; + if (bits & LE_R1_EOP) lp->stats.rx_errors++; + } else { + pkt_len = rd->mblength; + skb = dev_alloc_skb (pkt_len+2); + if (skb == NULL) { + printk ("%s: Memory squeeze, deferring packet.\n", + dev->name); + lp->stats.rx_dropped++; + rd->mblength = 0; + rd->rmd1_bits = LE_R1_OWN; + lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; + return 0; + } + + skb->dev = dev; + skb_reserve (skb, 2); /* 16 byte align */ + skb_put (skb, pkt_len); /* make room */ + eth_copy_and_sum(skb, + (unsigned char *)&(ib->rx_buf [lp->rx_new][0]), + pkt_len, 0); + skb->protocol = eth_type_trans (skb,dev); + netif_rx (skb); + lp->stats.rx_packets++; + } + + /* Return the packet to the pool */ + rd->mblength = 0; rd->rmd1_bits = LE_R1_OWN; lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; - return 0; - } - - skb->dev = dev; - skb_reserve (skb, 2); /* 16 byte align */ - buf = skb_put (skb, pkt_len); /* make room */ - memcpy (buf, (char *) &(ib->rx_buf [lp->rx_new][0]), pkt_len); - skb->protocol = eth_type_trans (skb,dev); - netif_rx (skb); - lp->stats.rx_packets++; - } - - /* Return the packet to the pool */ - rd->rmd1_bits = LE_R1_OWN; - lp->rx_new = (lp->rx_new + 1) & RX_RING_MOD_MASK; - } - return 0; -} - -static int -lance_tx (struct device *dev) -{ - struct lance_private *lp = (struct lance_private *) dev->priv; - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_regs *ll = lp->ll; - volatile struct lance_tx_desc *td; - int i, j; - int status; - - /* csr0 is 2f3 */ - ll->rdp = LE_C0_TINT | LE_C0_INEA; - /* csr0 is 73 */ - j = lp->tx_old; - for (i = 0; i < TX_RING_SIZE; i++){ - td = &ib->btx_ring [j]; + } + return 0; +} + +static int lance_tx (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_tx_desc *td; + int i, j; + int status; + + /* csr0 is 2f3 */ + ll->rdp = LE_C0_TINT | LE_C0_INEA; + /* csr0 is 73 */ + j = lp->tx_old; + for (i = 0; i < TX_RING_SIZE; i++) { + td = &ib->btx_ring [j]; - if (td->tmd1_bits & LE_T1_ERR){ - status = td->misc; + if (td->tmd1_bits & LE_T1_ERR) { + status = td->misc; - if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; - if (status & LE_T3_CLOS) lp->stats.tx_carrier_errors++; - if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; - - /* buffer errors and underflows turn off the transmitter */ - /* Restart the adapter */ - if (status & (LE_T3_BUF|LE_T3_UFL)){ - lp->stats.tx_fifo_errors++; - - printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", dev->name); - /* Stop the lance */ - ll->rdp = LE_CSR0; - ll->rap = LE_C0_STOP; - lance_init_ring (dev); - load_csrs (lp); - init_restart_lance (lp); - return 0; - } - } else - lp->stats.tx_packets++; + lp->stats.tx_errors++; + if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++; + if (status & LE_T3_CLOS) lp->stats.tx_carrier_errors++; + if (status & LE_T3_LCOL) lp->stats.tx_window_errors++; + + /* buffer errors and underflows turn off the transmitter */ + /* Restart the adapter */ + if (status & (LE_T3_BUF|LE_T3_UFL)) { + lp->stats.tx_fifo_errors++; + + printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n", + dev->name); + /* Stop the lance */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + lance_init_ring (dev); + load_csrs (lp); + init_restart_lance (lp); + return 0; + } + } else if ((td->tmd1_bits & LE_T1_POK) == LE_T1_POK) { + /* + * So we don't count the packet more than once. + */ + td->tmd1_bits &= ~(LE_T1_POK); + + /* One collision before packet was sent. */ + if (td->tmd1_bits & LE_T1_EONE) + lp->stats.collisions++; + + /* More than one collision, be optimistic. */ + if (td->tmd1_bits & LE_T1_EMORE) + lp->stats.collisions += 2; + + /* What to set here? */ + if (td->tmd1_bits & LE_T1_EDEF) + /* EMPTY */ ; + + lp->stats.tx_packets++; + } - j = (j + 1) & TX_RING_MOD_MASK; - } - lp->tx_old = (lp->tx_old+1) & TX_RING_MOD_MASK; + j = (j + 1) & TX_RING_MOD_MASK; + } + lp->tx_old = (lp->tx_old+1) & TX_RING_MOD_MASK; - ll->rdp = LE_C0_TINT | LE_C0_INEA; - return 0; + ll->rdp = LE_C0_TINT | LE_C0_INEA; + return 0; } -static void -lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) +static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) { - struct device *dev = (struct device *) (irq2dev_map [irq]); - struct lance_private *lp; - volatile struct lance_regs *ll; - int csr0; + struct device *dev; + struct lance_private *lp; + volatile struct lance_regs *ll; + int csr0; - lp = (struct lance_private *) dev->priv; - ll = lp->ll; +#ifdef OLD_STYLE_IRQ + dev = (struct device *) (irq2dev_map [irq]); +#else + dev = (struct device *) dev_id; +#endif - if (lp->ledma) - if (lp->ledma->regs->cond_reg & DMA_HNDL_ERROR){ - printk ("%s: should reset my ledma (dmacsr=%8.8x, csr=%4.4x\n", dev->name, - (unsigned int) lp->ledma->regs->cond_reg, ll->rdp); - printk ("send mail to miguel@nuclecu.unam.mx\n"); + lp = (struct lance_private *) dev->priv; + ll = lp->ll; + + if (lp->ledma) { + if (lp->ledma->regs->cond_reg & DMA_HNDL_ERROR) { + printk ("%s: should reset my ledma (dmacsr=%8.8x, csr=%4.4x\n", + dev->name, (unsigned int) lp->ledma->regs->cond_reg, + ll->rdp); + printk ("send mail to miguel@nuclecu.unam.mx\n"); + } } - if (dev->interrupt) - printk ("%s: again", dev->name); + if (dev->interrupt) + printk ("%s: again", dev->name); - dev->interrupt = 1; + dev->interrupt = 1; - csr0 = ll->rdp; + csr0 = ll->rdp; - /* Acknowledge all the interrupt sources ASAP */ - ll->rdp = csr0 & 0x004f; + /* Acknowledge all the interrupt sources ASAP */ + ll->rdp = csr0 & 0x004f; - if ((csr0 & LE_C0_ERR)){ - /* Clear the error condition */ - ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA; - } + if ((csr0 & LE_C0_ERR)) { + /* Clear the error condition */ + ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA; + } - if (csr0 & LE_C0_RINT){ - lance_rx (dev); - } + if (csr0 & LE_C0_RINT) + lance_rx (dev); - if (csr0 & LE_C0_TINT){ - lance_tx (dev); - } + if (csr0 & LE_C0_TINT) + lance_tx (dev); - if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy){ - dev->tbusy = 0; - mark_bh (NET_BH); - } - ll->rap = 0; - ll->rdp = 0x7940; + if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { + dev->tbusy = 0; + mark_bh (NET_BH); + } + ll->rap = LE_CSR0; + ll->rdp = 0x7940; - dev->interrupt = 0; + dev->interrupt = 0; } struct device *last_dev = 0; -static int -lance_open (struct device *dev) +static int lance_open (struct device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; - volatile struct lance_regs *ll = lp->ll; - int status = 0; - - last_dev = dev; - - if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, NULL)){ - printk ("Lance: Can't get irq %d\n", dev->irq); - return -EAGAIN; - } - /* Stop the Lance */ - ll->rap = LE_CSR0; - ll->rdp = LE_C0_STOP; - - irq2dev_map [dev->irq] = dev; - - /* On the 4m, setup the ledma to provide the upper bits for buffers */ - if (lp->ledma) - lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000; - - lance_init_ring (dev); - load_csrs (lp); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - status = init_restart_lance (lp); - if (lp->ledma) - lp->ledma->regs->cond_reg |= DMA_INT_ENAB; + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status = 0; + + last_dev = dev; + + if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, (void *) dev)) { + printk ("Lance: Can't get irq %d\n", dev->irq); + return -EAGAIN; + } + + /* Stop the Lance */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + +#ifdef OLD_STYLE_IRQ + irq2dev_map [dev->irq] = dev; +#endif + + /* On the 4m, setup the ledma to provide the upper bits for buffers */ + if (lp->ledma) + lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000; + + lance_init_ring (dev); + load_csrs (lp); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + status = init_restart_lance (lp); #if 0 - /* To emulate SunOS, we add a route to the local network */ - rt_add (RTF_UP, - dev->pa_addr & ip_get_mask (dev->pa_addr), - ip_get_mask (dev->pa_addr), - 0, dev, dev->mtu, 0, 0); + /* To emulate SunOS, we add a route to the local network */ + rt_add (RTF_UP, + dev->pa_addr & ip_get_mask (dev->pa_addr), + ip_get_mask (dev->pa_addr), + 0, dev, dev->mtu, 0, 0); #endif - return status; + return status; } -static int -lance_close (struct device *dev) +static int lance_close (struct device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; - volatile struct lance_regs *ll = lp->ll; + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_regs *ll = lp->ll; - dev->start = 0; - dev->tbusy = 1; - - /* Stop the card */ - ll->rap = LE_CSR0; - ll->rdp = LE_C0_STOP; - - free_irq (dev->irq, NULL); - irq2dev_map [dev->irq] = NULL; - - return 0; -} - -inline static int -lance_reset (struct device *dev) -{ - struct lance_private *lp = (struct lance_private *)dev->priv; - volatile struct lance_regs *ll = lp->ll; - int status; - - /* Stop the lance */ - ll->rdp = LE_CSR0; - ll->rap = LE_C0_STOP; - - /* On the 4m, reset the dma too */ - if (lp->ledma){ - printk ("resetting ledma\n"); - lp->ledma->regs->cond_reg |= DMA_RST_ENET; - udelay (200); - lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; - lp->ledma->regs->cond_reg |= DMA_INT_ENAB; - } - lance_init_ring (dev); - load_csrs (lp); - dev->trans_start = jiffies; - dev->interrupt = 0; - dev->start = 1; - dev->tbusy = 0; - status = init_restart_lance (lp); + dev->start = 0; + dev->tbusy = 1; + + /* Stop the card */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + + free_irq (dev->irq, NULL); +#ifdef OLD_STYLE_IRQ + irq2dev_map [dev->irq] = NULL; +#endif + + return 0; +} + +static inline int lance_reset (struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + int status; + + /* Stop the lance */ + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + + /* On the 4m, reset the dma too */ + if (lp->ledma) { + printk ("resetting ledma\n"); + lp->ledma->regs->cond_reg |= DMA_RST_ENET; + udelay (200); + lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; + lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000; + } + lance_init_ring (dev); + load_csrs (lp); + dev->trans_start = jiffies; + dev->interrupt = 0; + dev->start = 1; + dev->tbusy = 0; + status = init_restart_lance (lp); #ifdef DEBUG_DRIVER - printk ("Lance restart=%d\n", status); + printk ("Lance restart=%d\n", status); #endif - return status; + return status; } -static int -lance_start_xmit (struct sk_buff *skb, struct device *dev) +static int lance_start_xmit (struct sk_buff *skb, struct device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; - volatile struct lance_regs *ll = lp->ll; - volatile struct lance_init_block *ib = lp->init_block; - int entry, skblen, len; - int status = 0; - static int outs; - - /* Transmitter timeout, serious problems */ - if (dev->tbusy){ - int tickssofar = jiffies - dev->trans_start; + struct lance_private *lp = (struct lance_private *)dev->priv; + volatile struct lance_regs *ll = lp->ll; + volatile struct lance_init_block *ib = lp->init_block; + volatile unsigned long flush; + int entry, skblen, len; + int status = 0; + static int outs; + + /* Transmitter timeout, serious problems */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 100) - status = -1; - else { - printk ("%s: transmit timed out, status %04x, resetting\n", - dev->name, ll->rdp); - lance_reset (dev); - } - return status; - } - - if (skb == NULL){ - dev_tint (dev); - printk ("skb is NULL\n"); - return 0; - } + if (tickssofar < 100) { + status = -1; + } else { + printk ("%s: transmit timed out, status %04x, resetting\n", + dev->name, ll->rdp); + lance_reset (dev); + } + return status; + } - if (skb->len <= 0){ - printk ("skb len is %ld\n", skb->len); - return 0; - } - /* Block a timer-based transmit from overlapping. */ + if (skb == NULL) { + dev_tint (dev); + printk ("skb is NULL\n"); + return 0; + } + + if (skb->len <= 0) { + printk ("skb len is %ld\n", skb->len); + return 0; + } + /* Block a timer-based transmit from overlapping. */ #ifdef OLD_METHOD - dev->tbusy = 1; + dev->tbusy = 1; #else - if (set_bit (0, (void *) &dev->tbusy) != 0){ - printk ("Transmitter access conflict.\n"); - return -1; - } + if (set_bit (0, (void *) &dev->tbusy) != 0) { + printk ("Transmitter access conflict.\n"); + return -1; + } #endif - skblen = skb->len; + skblen = skb->len; - if (!TX_BUFFS_AVAIL){ - return -1; - } + if (!TX_BUFFS_AVAIL) + return -1; #ifdef DEBUG_DRIVER - /* dump the packet */ - { - int i; + /* dump the packet */ + { + int i; - for (i = 0; i < 64; i++){ - if ((i % 16) == 0) printk ("\n"); - printk ("%2.2x ", skb->data [i]); + for (i = 0; i < 64; i++) { + if ((i % 16) == 0) + printk ("\n"); + printk ("%2.2x ", skb->data [i]); + } } - } #endif - len = (skblen < ETH_ZLEN) ? ETH_ZLEN : skblen; - entry = lp->tx_new & TX_RING_MOD_MASK; - ib->btx_ring [entry].length = (-len) | 0xf000; - ib->btx_ring [entry].misc = 0; - - memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); - - /* Clear the slack of the packet, do I need this? */ - if (len != skblen){ - memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); - } - - - /* Now, give the packet to the lance */ - ib->btx_ring [entry].tmd1_bits = (LE_T1_SOP|LE_T1_EOP|LE_T1_OWN); - lp->tx_new = (lp->tx_new+1) & TX_RING_MOD_MASK; - - outs++; - /* Kick the lance: transmit now */ - ll->rdp = LE_C0_INEA | LE_C0_TDMD; - dev->trans_start = jiffies; - dev_kfree_skb (skb, FREE_WRITE); + len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen; + entry = lp->tx_new & TX_RING_MOD_MASK; + ib->btx_ring [entry].length = (-len) | 0xf000; + ib->btx_ring [entry].misc = 0; + + memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen); + + /* Clear the slack of the packet, do I need this? */ + if (len != skblen) + memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); + + /* Now, give the packet to the lance */ + ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); + lp->tx_new = (lp->tx_new+1) & TX_RING_MOD_MASK; + + outs++; + /* Kick the lance: transmit now */ + ll->rdp = LE_C0_INEA | LE_C0_TDMD; + dev->trans_start = jiffies; + dev_kfree_skb (skb, FREE_WRITE); - if (TX_BUFFS_AVAIL) - dev->tbusy = 0; + if (TX_BUFFS_AVAIL) + dev->tbusy = 0; - return status; + /* Read back CSR to invalidate the E-Cache. + * This is needed, because DMA_DSBL_WR_INV is set. */ + if (lp->ledma) + flush = ll->rdp; + + return status; } -static struct enet_statistics * -lance_get_stats (struct device *dev) +static struct enet_statistics *lance_get_stats (struct device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = (struct lance_private *) dev->priv; - return &lp->stats; + return &lp->stats; } -static void -lance_set_multicast (struct device *dev, int num_addrs, void *addrs) +static void lance_set_multicast (struct device *dev) { #ifdef NOT_YET - struct lance_private *lp = (struct lance_private *) dev->priv; - volatile struct lance_init_block *ib = lp->init_block; - volatile struct lance_regs *ll = lp->ll; - - ll->rdp = LE_CSR0; - ll->rap = LE_C0_STOP; - lance_init_ring (dev); - if (num_addrs >= 0){ - printk ("Ignoring set_multicast\n"); - } else { + struct lance_private *lp = (struct lance_private *) dev->priv; + volatile struct lance_init_block *ib = lp->init_block; + volatile struct lance_regs *ll = lp->ll; + + ll->rap = LE_CSR0; + ll->rdp = LE_C0_STOP; + lance_init_ring (dev); ib->mode |= LE_MO_PROM; - } - lance_init_ring (dev); - load_csrs (lp); - init_restart_lance (lp); - dev->tbusy = 0; + lance_init_ring (dev); + load_csrs (lp); + init_restart_lance (lp); + dev->tbusy = 0; #endif } +int sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev, + struct Linux_SBus_DMA *ledma, + struct linux_sbus_device *lebuffer) +{ + static unsigned version_printed = 0; + int i; + struct lance_private *lp; + volatile struct lance_regs *ll; + + if (dev == NULL) { + dev = init_etherdev (0, sizeof (struct lance_private)); + } else { + dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + } + if (sparc_lance_debug && version_printed++ == 0) + printk (version); + + printk ("%s: LANCE ", dev->name); + /* Fill the dev fields */ + dev->base_addr = (long) sdev; + + /* Copy the IDPROM ethernet address to the device structure, later we + * will copy the address in the device structure to the lance initialization + * block + */ + for (i = 0; i < 6; i++) + printk ("%2.2x%c", + dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':'); + printk("\n"); + + /* Get the IO region */ + prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers); + ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, + sizeof (struct lance_regs), lancestr, + sdev->reg_addrs[0].which_io, 0x0); + + /* Make certain the data structures used by the LANCE are aligned. */ + dev->priv = (void *)(((int)dev->priv + 7) & ~7); + lp = (struct lance_private *) dev->priv; + memset ((char *)dev->priv, 0, sizeof (struct lance_private)); + + if (lebuffer){ + prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers); + lp->init_block = (void *) + sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0, + sizeof (struct lance_init_block), "lebuffer", + lebuffer->reg_addrs [0].which_io, 0); + } else { + lp->init_block = (void *) + sparc_dvma_malloc (sizeof (struct lance_init_block), + lancedma); + } + + lp->ll = ll; + lp->name = lancestr; + lp->ledma = ledma; + + lp->burst_sizes = 0; + if (lp->ledma) { + char cable_prop[4]; + unsigned int sbmask; + + /* Find burst-size property for ledma */ + lp->burst_sizes = prom_getintdefault(ledma->SBus_dev->prom_node, + "burst-sizes", 0); + + /* ledma may be capable of fast bursts, but sbus may not. */ + sbmask = prom_getintdefault(ledma->SBus_dev->my_bus->prom_node, + "burst-sizes", DMA_BURSTBITS); + lp->burst_sizes &= sbmask; + + /* Get the cable-selection property */ + prom_getstring(ledma->SBus_dev->prom_node, "cable-selection", + cable_prop, sizeof(cable_prop)); + if (!strcmp(cable_prop, "aui")) + lp->tpe = 0; + else + lp->tpe = 1; + + /* Reset ledma */ + lp->ledma->regs->cond_reg |= DMA_RST_ENET; + udelay (200); + lp->ledma->regs->cond_reg &= ~DMA_RST_ENET; + } + + /* This should never happen. */ + if ((int)(lp->init_block->brx_ring) & 0x07) { + printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n"); + return ENODEV; + } + + dev->open = &lance_open; + dev->stop = &lance_close; + dev->hard_start_xmit = &lance_start_xmit; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &lance_set_multicast; + + dev->irq = (unsigned char) sdev->irqs [0].pri; + dev->dma = 0; + ether_setup (dev); + + return 0; +} + /* On 4m, find the associated dma for the lance chip */ static struct Linux_SBus_DMA * find_ledma (struct linux_sbus_device *dev) { - struct Linux_SBus_DMA *p; + struct Linux_SBus_DMA *p; - for (p = dma_chain; p; p = p->next) - if (p->SBus_dev == dev) - return p; - return 0; + for (p = dma_chain; p; p = p->next) + if (p->SBus_dev == dev) + return p; + return 0; } -/* FIXME: the probe code should be able to detect */ +/* Find all the lance cards on the system and initialize them */ int sparc_lance_probe (struct device *dev) { - static unsigned version_printed = 0; - int i; - int found = 0; - struct linux_sbus *bus; - struct linux_sbus_device *sdev = 0; - struct Linux_SBus_DMA *ledma = 0; - struct lance_private *lp; - volatile struct lance_regs *ll; - -#ifdef DEBUG_DRIVER - printk ("Lance probe...0x%p\n", SBus_chain); -#endif - for_each_sbus (bus){ - for_each_sbusdev (sdev, bus){ - if (strcmp (sdev->prom_name, "le") == 0){ - found = 1; - break; - } - if (strcmp (sdev->prom_name, "ledma") == 0){ - ledma = find_ledma (sdev); - found = 1; - sdev = sdev->child; - break; - } - } - } - if (!found) - return ENODEV; - - if (dev == NULL){ - printk ("LANCE buffer @0x0. You don't really want this\n"); - dev = init_etherdev (0, sizeof (struct lance_private)); - } else { - dev->priv = kmalloc (sizeof (struct lance_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - } - if (sparc_lance_debug && version_printed++ == 0) - printk (version); - - printk ("%s: LANCE ", dev->name); - /* Fill the dev fields */ - dev->base_addr = (long) sdev; - - /* Copy the IDPROM ethernet address to the device structure, later we - * will copy the address in the device structure to the lance initialization - * block - */ - for (i = 0; i < 6; i++){ - printk ("%2.2x%c", dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':'); - } - /* Get the IO region */ - prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers); - ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0, - sizeof (struct lance_regs), lancestr, - sdev->reg_addrs[0].which_io, 0x0); - - /* Make certain the data structures used by the LANCE are aligned. */ - dev->priv = (void *)(((int)dev->priv + 7) & ~7); - lp = (struct lance_private *) dev->priv; - memset ((char *)dev->priv, 0, sizeof (struct lance_private)); - - lp->init_block = (void *) - sparc_dvma_malloc (sizeof (struct lance_init_block), lancestr); - - lp->ll = ll; - lp->name = lancestr; - lp->ledma = ledma; - - /* This should never happen. */ - if ((int)(lp->init_block->brx_ring) & 0x07) { - printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n"); - return ENODEV; - } - - dev->open = &lance_open; - dev->stop = &lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; - dev->set_multicast_list = &lance_set_multicast; - - dev->irq = (unsigned char) sdev->irqs [0].pri; - dev->dma = 0; - ether_setup (dev); - - return 0; + struct linux_sbus *bus; + struct linux_sbus_device *sdev = 0; + struct Linux_SBus_DMA *ledma = 0; + int cards = 0, v; + + for_each_sbus (bus) { + for_each_sbusdev (sdev, bus) { + if (cards) dev = NULL; + if (strcmp (sdev->prom_name, "le") == 0) { + cards++; + if ((v = sparc_lance_init(dev, sdev, ledma,0))) + return v; + } + if (strcmp (sdev->prom_name, "ledma") == 0) { + cards++; + ledma = find_ledma (sdev); + sdev = sdev->child; + if ((v = sparc_lance_init(dev, sdev, ledma,0))) + return v; + break; + } + if (strcmp (sdev->prom_name, "lebuffer") == 0){ + struct linux_sbus_device *le = sdev->child; + cards++; + if ((v = sparc_lance_init(dev, le, ledma,sdev))) + return v; + break; + } + } /* for each sbusdev */ + } /* for each sbus */ + if (!cards) + return ENODEV; + return 0; } + /* * Local variables: - * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I../../..//net/tcp -c lance.c" * version-control: t * kept-new-versions: 5 * End: diff -u --recursive --new-file v1.3.92/linux/drivers/sbus/Makefile linux/drivers/sbus/Makefile --- v1.3.92/linux/drivers/sbus/Makefile Thu Jan 1 02:00:00 1970 +++ linux/drivers/sbus/Makefile Sun Apr 21 17:32:02 1996 @@ -0,0 +1,13 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +L_OBJS := sbus.o dvma.o +L_TARGET := sbus.a + +include $(TOPDIR)/Rules.make diff -u --recursive --new-file v1.3.92/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c --- v1.3.92/linux/drivers/sbus/dvma.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sbus/dvma.c Sun Apr 21 17:32:02 1996 @@ -0,0 +1,117 @@ +/* dvma.c: Routines that are used to access DMA on the Sparc SBus. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct Linux_SBus_DMA *dma_chain; + +/* Print out the current values in the DMA control registers */ +void +dump_dma_regs(struct sparc_dma_registers *dregs) +{ + printk("DMA CONTROL<%08lx> ADDR<%08lx> CNT<%08lx> TEST<%08lx>\n", + dregs->cond_reg, + (unsigned long) dregs->st_addr, + (unsigned long) dregs->cnt, + (unsigned long) dregs->dma_test); + return; +} + + +/* Probe this SBus DMA module(s) */ +unsigned long +dvma_init(struct linux_sbus *sbus, unsigned long memory_start) +{ + struct linux_sbus_device *this_dev; + struct Linux_SBus_DMA *dma; + struct Linux_SBus_DMA *dchain; + static int num_dma=0; + + for_each_sbusdev(this_dev, sbus) { + if(strcmp(this_dev->prom_name, "dma") && + strcmp(this_dev->prom_name, "ledma") && + strcmp(this_dev->prom_name, "espdma")) + continue; + + /* Found one... */ + dma = (struct Linux_SBus_DMA *) memory_start; + memory_start += sizeof(struct Linux_SBus_DMA); + + dma->SBus_dev = this_dev; + + /* Put at end of dma chain */ + dchain = dma_chain; + if(dchain) { + while(dchain->next) dchain=dchain->next; + dchain->next=dma; + } else { + /* We're the first in line */ + dma_chain=dma; + } + dma->next = 0; + + printk("dma%d: ", num_dma); + num_dma++; + + /* The constant PAGE_SIZE that is passed to sparc_alloc_io makes the + * routine only alloc 1 page, that was what the original code did + */ + prom_apply_sbus_ranges(dma->SBus_dev->reg_addrs, 0x1); + dma->regs = (struct sparc_dma_registers *) + sparc_alloc_io (dma->SBus_dev->reg_addrs[0].phys_addr, 0, + PAGE_SIZE, "dma", + dma->SBus_dev->reg_addrs[0].which_io, 0x0); + + dma->node = dma->SBus_dev->prom_node; + dma->running=0; /* No tranfers going on as of yet */ + dma->allocated=0; /* No one has allocated us yet */ + switch((dma->regs->cond_reg)&DMA_DEVICE_ID) { + case DMA_VERS0: + dma->revision=dvmarev0; + printk("Revision 0 "); + break; + case DMA_ESCV1: + dma->revision=dvmaesc1; + printk("ESC Revision 1 "); + break; + case DMA_VERS1: + dma->revision=dvmarev1; + printk("Revision 1 "); + break; + case DMA_VERS2: + dma->revision=dvmarev2; + printk("Revision 2 "); + break; + case DMA_VERSPLUS: + dma->revision=dvmarevplus; + printk("Revision 1 PLUS "); + break; + default: + printk("unknown dma version"); + dma->allocated = 1; + break; + } + printk("\n"); +#if 0 /* Clutters up the screen */ + dump_dma_regs(dma->regs); +#endif + }; /* while(this_dev) */ + + return memory_start; +} + diff -u --recursive --new-file v1.3.92/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c --- v1.3.92/linux/drivers/sbus/sbus.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/sbus/sbus.c Sun Apr 21 17:32:02 1996 @@ -0,0 +1,256 @@ +/* sbus.c: SBus support routines. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include + +#include +#include +#include +#include + +/* This file has been written to be more dynamic and a bit cleaner, + * but it still needs some spring cleaning. + */ + +struct linux_sbus *SBus_chain; + +static char lbuf[128]; + +/* Perhaps when I figure out more about the iommu we'll put a + * device registration routine here that probe_sbus() calls to + * setup the iommu for each Sbus. + */ + +/* We call this for each SBus device, and fill the structure based + * upon the prom device tree. We return the start of memory after + * the things we have allocated. + */ + +/* #define DEBUG_FILL */ +void +fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev) +{ + int grrr, len; + unsigned long dev_base_addr, base; + + sbus_dev->prom_node = nd; + prom_getstring(nd, "name", lbuf, sizeof(lbuf)); + strcpy(sbus_dev->prom_name, lbuf); + + dev_base_addr = prom_getint(nd, "address"); + if(dev_base_addr != -1) + sbus_dev->sbus_addr = dev_base_addr; + + len = prom_getproperty(nd, "reg", (void *) sbus_dev->reg_addrs, + sizeof(sbus_dev->reg_addrs)); + if(len%sizeof(struct linux_prom_registers)) { + prom_printf("WHOOPS: proplen for %s was %d, need multiple of %d\n", + sbus_dev->prom_name, len, + (int) sizeof(struct linux_prom_registers)); + panic("fill_sbus_device"); + } + sbus_dev->num_registers = (len/sizeof(struct linux_prom_registers)); + + base = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; + if(base>=SUN_SBUS_BVADDR || sparc_cpu_model == sun4m) { + /* Ahh, we can determine the slot and offset */ + sbus_dev->slot = sbus_dev_slot(base); + sbus_dev->offset = sbus_dev_offset(base); + } else { /* Grrr, gotta do calculations to fix things up */ + sbus_dev->slot = sbus_dev->reg_addrs[0].which_io; + sbus_dev->offset = base; + sbus_dev->reg_addrs[0].phys_addr = + (char *) sbus_devaddr(sbus_dev->slot, base); + for(grrr=1; grrrnum_registers; grrr++) { + base = (unsigned long) sbus_dev->reg_addrs[grrr].phys_addr; + sbus_dev->reg_addrs[grrr].phys_addr = (char *) + sbus_devaddr(sbus_dev->slot, base); + } + /* That surely sucked */ + } + sbus_dev->sbus_addr = (unsigned long) sbus_dev->reg_addrs[0].phys_addr; + + if(len>(sizeof(struct linux_prom_registers)*PROMREG_MAX)) { + prom_printf("WHOOPS: I got too many register addresses for %s len=%d\n", + sbus_dev->prom_name, len); + panic("sbus device register overflow"); + } + + len = prom_getproperty(nd, "address", (void *) sbus_dev->sbus_vaddrs, + sizeof(sbus_dev->sbus_vaddrs)); + if(len == -1) len=0; + if(len&3) { + prom_printf("Grrr, I didn't get a multiple of 4 proplen " + "for device %s got %d\n", sbus_dev->prom_name, len); + len=0; + } + sbus_dev->num_vaddrs = (len/4); + + len = prom_getproperty(nd, "intr", (void *)sbus_dev->irqs, + sizeof(sbus_dev->irqs)); + if (len == -1) len=0; + if (len&7) { + prom_printf("Grrr, I didn't get a multiple of 8 proplen for " + "device %s got %d\n", sbus_dev->prom_name, len); + len=0; + } + sbus_dev->num_irqs=(len/8); +#if OLD_STYLE_IRQ + /* Grrr, V3 prom tries to be efficient */ + for(len=0; lennum_irqs; len++) { + sbus_dev->irqs[len].pri &= 0xf; + } +#endif + if(sbus_dev->num_irqs == 0) sbus_dev->irqs[0].pri=0; + +#ifdef DEBUG_FILL + prom_printf("Found %s at SBUS slot %x offset %08lx irq-level %d\n", + sbus_dev->prom_name, sbus_dev->slot, sbus_dev->offset, + sbus_dev->irqs[0].pri); + prom_printf("Base address %08lx\n", sbus_dev->sbus_addr); + prom_printf("REGISTERS: Probed %d register(s)\n", sbus_dev->num_registers); + for(len=0; lennum_registers; len++) + prom_printf("Regs<%d> at address<%08lx> IO-space<%d> size<%d " + "bytes, %d words>\n", (int) len, + (unsigned long) sbus_dev->reg_addrs[len].phys_addr, + sbus_dev->reg_addrs[len].which_io, + sbus_dev->reg_addrs[len].reg_size, + (sbus_dev->reg_addrs[len].reg_size/4)); +#endif + + return; +} + +/* This routine gets called from whoever needs the sbus first, to scan + * the SBus device tree. Currently it just prints out the devices + * found on the bus and builds trees of SBUS structs and attached + * devices. + */ + +extern void sun_console_init(void); +extern unsigned long iommu_init(int iommu_node, unsigned long memstart, + unsigned long memend, struct linux_sbus *sbus); + +unsigned long +sbus_init(unsigned long memory_start, unsigned long memory_end) +{ + register int nd, this_sbus, sbus_devs, topnd, iommund; + unsigned int sbus_clock; + struct linux_sbus *sbus; + struct linux_sbus_device *this_dev; + int num_sbus = 0; /* How many did we find? */ + + memory_start = ((memory_start + 7) & (~7)); + + topnd = prom_getchild(prom_root_node); + + /* Finding the first sbus is a special case... */ + iommund = 0; + if((nd = prom_searchsiblings(topnd, "sbus")) == 0) { + if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 || + (nd = prom_getchild(iommund)) == 0 || + (nd = prom_searchsiblings(nd, "sbus")) == 0) { + /* No reason to run further - the data access trap will occur. */ + panic("sbus not found"); + } + } + + /* Ok, we've found the first one, allocate first SBus struct + * and place in chain. + */ + sbus = SBus_chain = (struct linux_sbus *) memory_start; + memory_start += sizeof(struct linux_sbus); + sbus->next = 0; + this_sbus=nd; + + /* Have IOMMU will travel. XXX grrr - this should be per sbus... */ + if(iommund) + memory_start = iommu_init(iommund, memory_start, memory_end, sbus); + + /* Loop until we find no more SBUS's */ + while(this_sbus) { + printk("sbus%d: ", num_sbus); + sbus_clock = prom_getint(this_sbus, "clock-frequency"); + if(sbus_clock==-1) sbus_clock = (25*1000*1000); + printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000), + (int) (((sbus_clock/1000)%1000 != 0) ? + (((sbus_clock/1000)%1000) + 1000) : 0)); + + prom_getstring(this_sbus, "name", lbuf, sizeof(lbuf)); + sbus->prom_node = this_sbus; + strcpy(sbus->prom_name, lbuf); + sbus->clock_freq = sbus_clock; + + sbus_devs = prom_getchild(this_sbus); + + sbus->devices = (struct linux_sbus_device *) memory_start; + memory_start += sizeof(struct linux_sbus_device); + + this_dev = sbus->devices; + this_dev->next = 0; + + fill_sbus_device(sbus_devs, this_dev); + this_dev->my_bus = sbus; + + /* Should we traverse for children? */ + if(strcmp(this_dev->prom_name, "espdma")==0 || + strcmp(this_dev->prom_name, "ledma")==0) { + /* Allocate device node */ + this_dev->child = (struct linux_sbus_device *) memory_start; + memory_start += sizeof(struct linux_sbus_device); + /* Fill it */ + fill_sbus_device(prom_getchild(sbus_devs), this_dev->child); + this_dev->child->my_bus = sbus; + } else { + this_dev->child = 0; + } + + while((sbus_devs = prom_getsibling(sbus_devs)) != 0) { + /* Allocate device node */ + this_dev->next = (struct linux_sbus_device *) memory_start; + memory_start += sizeof(struct linux_sbus_device); + this_dev=this_dev->next; + this_dev->next=0; + + /* Fill it */ + fill_sbus_device(sbus_devs, this_dev); + this_dev->my_bus = sbus; + + /* Is there a child node hanging off of us? */ + if(strcmp(this_dev->prom_name, "espdma")==0 || + strcmp(this_dev->prom_name, "ledma")==0) { + /* Get new device struct */ + this_dev->child = + (struct linux_sbus_device *) memory_start; + memory_start += sizeof(struct linux_sbus_device); + + /* Fill it */ + fill_sbus_device(prom_getchild(sbus_devs), + this_dev->child); + this_dev->child->my_bus = sbus; + } else { + this_dev->child = 0; + } + } + + memory_start = dvma_init(sbus, memory_start); + + num_sbus++; + this_sbus = prom_getsibling(this_sbus); + if(!this_sbus) break; + this_sbus = prom_searchsiblings(this_sbus, "sbus"); + if(this_sbus) { + sbus->next = (struct linux_sbus *) memory_start; + memory_start += sizeof(struct linux_sbus); + sbus = sbus->next; + sbus->next = 0; + } else { + break; + } + } /* while(this_sbus) */ + sun_console_init(); /* whee... */ + return memory_start; +} diff -u --recursive --new-file v1.3.92/linux/drivers/scsi/aic7xxx.c linux/drivers/scsi/aic7xxx.c --- v1.3.92/linux/drivers/scsi/aic7xxx.c Sun Apr 21 12:39:01 1996 +++ linux/drivers/scsi/aic7xxx.c Sun Apr 21 11:40:09 1996 @@ -700,7 +700,7 @@ scsi_conf = inb(SCSICONF + p->base); /* - * Scale the Data FIFO Threshhold and the Bus Release Time; they are + * Scale the Data FIFO Threshold and the Bus Release Time; they are * stored in formats compatible for writing to sequencer registers. */ dfthresh = p->bus_speed >> 6; @@ -3726,7 +3726,7 @@ /* * Set the QCNT (queue count) mask to deal with broken aic7850s that - * sporatically get garbage in the upper bits of their QCNT registers. + * sporadically get garbage in the upper bits of their QCNT registers. */ outb(config->qcntmask, QCNTMASK + base); diff -u --recursive --new-file v1.3.92/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c --- v1.3.92/linux/drivers/scsi/esp.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/esp.c Sun Apr 21 12:42:05 1996 @@ -0,0 +1,1128 @@ +/* esp.c: EnhancedScsiProcessor Sun SCSI driver code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "scsi.h" +#include "hosts.h" +#include "esp.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_ESP +/* #define DEBUG_ESP_SG */ + +#if defined(DEBUG_ESP) +#define ESPLOG(foo) printk foo +#else +#define ESPLOG(foo) +#endif /* (DEBUG_ESP) */ + +#define INTERNAL_ESP_ERROR \ + (panic ("Internal ESP driver error in file %s, line %d\n", \ + __FILE__, __LINE__)) + +#define INTERNAL_ESP_ERROR_NOPANIC \ + (printk ("Internal ESP driver error in file %s, line %d\n", \ + __FILE__, __LINE__)) + +/* This enum will be expanded when we have sync code written. */ +enum { + not_issued = 0x01, /* Still in the issue_SC queue. */ + in_selection = 0x02, /* ESP is arbitrating, awaiting IRQ */ + in_datain = 0x04, /* Data is transferring over the bus */ + in_dataout = 0x08, /* Data is transferring over the bus */ + in_status = 0x10, /* Awaiting status/msg bytes from target */ + in_finale = 0x11, /* Sent Msg ack, awaiting disconnect */ +}; + +struct proc_dir_entry proc_scsi_esp = { + PROC_SCSI_ESP, 3, "esp", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +struct Sparc_ESP *espchain; + +static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs); +static void esp_done(struct Sparc_ESP *esp, int error); + +/* Debugging routines */ +struct esp_cmdstrings { + unchar cmdchar; + char *text; +} esp_cmd_strings[] = { + /* Miscellaneous */ + { ESP_CMD_NULL, "ESP_NOP", }, + { ESP_CMD_FLUSH, "FIFO_FLUSH", }, + { ESP_CMD_RC, "RSTESP", }, + { ESP_CMD_RS, "RSTSCSI", }, + /* Disconnected State Group */ + { ESP_CMD_RSEL, "RESLCTSEQ", }, + { ESP_CMD_SEL, "SLCTNATN", }, + { ESP_CMD_SELA, "SLCTATN", }, + { ESP_CMD_SELAS, "SLCTATNSTOP", }, + { ESP_CMD_ESEL, "ENSLCTRESEL", }, + { ESP_CMD_DSEL, "DISSELRESEL", }, + { ESP_CMD_SA3, "SLCTATN3", }, + { ESP_CMD_RSEL3, "RESLCTSEQ", }, + /* Target State Group */ + { ESP_CMD_SMSG, "SNDMSG", }, + { ESP_CMD_SSTAT, "SNDSTATUS", }, + { ESP_CMD_SDATA, "SNDDATA", }, + { ESP_CMD_DSEQ, "DISCSEQ", }, + { ESP_CMD_TSEQ, "TERMSEQ", }, + { ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", }, + { ESP_CMD_DCNCT, "DISC", }, + { ESP_CMD_RMSG, "RCVMSG", }, + { ESP_CMD_RCMD, "RCVCMD", }, + { ESP_CMD_RDATA, "RCVDATA", }, + { ESP_CMD_RCSEQ, "RCVCMDSEQ", }, + /* Initiator State Group */ + { ESP_CMD_TI, "TRANSINFO", }, + { ESP_CMD_ICCSEQ, "INICMDSEQCOMP", }, + { ESP_CMD_MOK, "MSGACCEPTED", }, + { ESP_CMD_TPAD, "TPAD", }, + { ESP_CMD_SATN, "SATN", }, + { ESP_CMD_RATN, "RATN", }, +}; +#define NUM_ESP_COMMANDS ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings))) + +/* Print textual representation of an ESP command */ +static inline void esp_print_cmd(unchar espcmd) +{ + unchar dma_bit = espcmd & ESP_CMD_DMA; + int i; + + espcmd &= ~dma_bit; + for(i=0; i"); +} + +/* Print the interrupt register's value */ +static inline void esp_print_ireg(unchar intreg) +{ + printk("INTREG< "); + if(intreg & ESP_INTR_S) + printk("SLCT_NATN "); + if(intreg & ESP_INTR_SATN) + printk("SLCT_ATN "); + if(intreg & ESP_INTR_RSEL) + printk("RSLCT "); + if(intreg & ESP_INTR_FDONE) + printk("FDONE "); + if(intreg & ESP_INTR_BSERV) + printk("BSERV "); + if(intreg & ESP_INTR_DC) + printk("DISCNCT "); + if(intreg & ESP_INTR_IC) + printk("ILL_CMD "); + if(intreg & ESP_INTR_SR) + printk("SCSI_BUS_RESET "); + printk(">"); +} + +/* Print the sequence step registers contents */ +static inline void esp_print_seqreg(unchar stepreg) +{ + stepreg &= ESP_STEP_VBITS; + printk("STEP<%s>", + (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" : + (stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" : + (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" : + (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" : + (stepreg == ESP_STEP_FINI ? "CMD_SENT_OK" : + "UNKNOWN")))))); +} + +/* Manipulation of the ESP command queues. Thanks to the aha152x driver + * and its author, Juergen E. Fischer, for the methods used here. + * Note that these are per-ESP queues, not global queues like + * the aha152x driver uses. + */ +static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + Scsi_Cmnd *end; + unsigned long flags; + + save_flags(flags); cli(); + new_SC->host_scribble = (unsigned char *) NULL; + if(!*SC) + *SC = new_SC; + else { + for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } + restore_flags(flags); +} + +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) +{ + Scsi_Cmnd *ptr; + unsigned long flags; + + save_flags(flags); cli(); + ptr = *SC; + if(ptr) + *SC = (Scsi_Cmnd *) (*SC)->host_scribble; + restore_flags(flags); + return ptr; +} + +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun) +{ + Scsi_Cmnd *ptr, *prev; + unsigned long flags; + + save_flags(flags); cli(); + for(ptr = *SC, prev = NULL; + ptr && ((ptr->target != target) || (ptr->lun != lun)); + prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble) + ; + if(ptr) { + if(prev) + prev->host_scribble=ptr->host_scribble; + else + *SC=(Scsi_Cmnd *)ptr->host_scribble; + } + restore_flags(flags); + return ptr; +} + +static inline void do_pause(unsigned amount) +{ + unsigned long the_time = jiffies + amount; + + while(jiffies < the_time) + barrier(); /* Not really needed, but... */ +} + +/* This places the ESP into a known state at boot time. */ +static inline void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) +{ + struct sparc_dma_registers *dregs = esp->dregs; + volatile unchar trash; + + /* Punt the DVMA into a known state. */ + dregs->cond_reg |= DMA_RST_SCSI; + do_pause(100); + dregs->cond_reg &= ~(DMA_RST_SCSI); + if(esp->dma->revision == dvmarev2) + if(esp->erev != esp100) + dregs->cond_reg |= DMA_3CLKS; + else if(esp->dma->revision == dvmarev3) + if(esp->erev == fas236 || esp->erev == fas100a) { + dregs->cond_reg &= ~(DMA_3CLKS); + dregs->cond_reg |= DMA_2CLKS; + } + else if(esp->dma->revision == dvmaesc1) + dregs->cond_reg |= DMA_ADD_ENABLE; + DMA_INTSON(dregs); + + /* Now reset the ESP chip */ + eregs->esp_cmd = ESP_CMD_RC; + eregs->esp_cmd = (ESP_CMD_NULL | ESP_CMD_DMA); + eregs->esp_cmd = (ESP_CMD_NULL | ESP_CMD_DMA); /* borken hardware... */ + + /* Reload the configuration registers */ + eregs->esp_cfg1 = esp->config1; + eregs->esp_cfact = esp->cfact; + eregs->esp_stp = 0; + eregs->esp_soff = 0; + eregs->esp_timeo = esp->sync_defp; + if(esp->erev == esp100a || esp->erev == esp236) + eregs->esp_cfg2 = esp->config2; + if(esp->erev == esp236) + eregs->esp_cfg3 = esp->config3[0]; + /* Eat any bitrot in the chip */ + trash = eregs->esp_intrpt; + + /* Reset the SCSI bus, but tell ESP not to generate an irq */ + eregs->esp_cfg1 |= ESP_CONFIG1_SRRDISAB; + eregs->esp_cmd = ESP_CMD_RS; + do_pause(200); + eregs->esp_cfg1 = esp->config1; + + /* Eat any bitrot in the chip and we are done... */ + trash = eregs->esp_intrpt; +} + +/* Detecting ESP chips on the machine. This is the simple and easy + * version. + */ +int esp_detect(Scsi_Host_Template *tpnt) +{ + struct Sparc_ESP *esp, *elink; + struct Scsi_Host *esp_host; + struct linux_sbus *sbus; + struct linux_sbus_device *esp_dev, *sbdev_iter; + struct Sparc_ESP_regs *eregs; + struct sparc_dma_registers *dregs; + struct Linux_SBus_DMA *dma, *dlink; + unsigned int fmhz; + unchar ccf, bsizes, bsizes_more; + int nesps = 0; + int esp_node; + + espchain = 0; + if(!SBus_chain) + panic("No SBUS in esp_detect()"); + for_each_sbus(sbus) { + for_each_sbusdev(sbdev_iter, sbus) { + /* Is it an esp sbus device? */ + esp_dev = sbdev_iter; + if(strcmp(esp_dev->prom_name, "esp") && + strcmp(esp_dev->prom_name, "SUNW,esp")) { + if(!esp_dev->child || + strcmp(esp_dev->prom_name, "espdma")) + continue; /* nope... */ + esp_dev = esp_dev->child; + if(strcmp(esp_dev->prom_name, "esp") && + strcmp(esp_dev->prom_name, "SUNW,esp")) + continue; /* how can this happen? */ + } + esp_host = scsi_register(tpnt, sizeof(struct Sparc_ESP)); + if(!esp_host) + panic("Cannot register ESP SCSI host"); + esp = (struct Sparc_ESP *) esp_host->hostdata; + if(!esp) + panic("No esp in hostdata"); + esp->ehost = esp_host; + esp->edev = esp_dev; + /* Put into the chain of esp chips detected */ + if(espchain) { + elink = espchain; + while(elink->next) elink = elink->next; + elink->next = esp; + } else { + espchain = esp; + } + esp->next = 0; + + /* Get misc. prom information */ +#define ESP_IS_MY_DVMA(esp, dma) \ + ((esp->edev->my_bus == dma->SBus_dev->my_bus) && \ + (esp->edev->slot == dma->SBus_dev->slot) && \ + (!strcmp(dma->SBus_dev->prom_name, "dma") || \ + !strcmp(dma->SBus_dev->prom_name, "espdma"))) + + esp_node = esp_dev->prom_node; + prom_getstring(esp_node, "name", esp->prom_name, + sizeof(esp->prom_name)); + esp->prom_node = esp_node; + for_each_dvma(dlink) { + if(ESP_IS_MY_DVMA(esp, dlink) && !dlink->allocated) + break; + } +#undef ESP_IS_MY_DVMA + /* If we don't know how to handle the dvma, do not use this device */ + if(!dlink){ + printk ("Cannot find dvma for ESP SCSI\n"); + scsi_unregister (esp_host); + continue; + } + if (dlink->allocated){ + printk ("esp: can't use my espdma\n"); + scsi_unregister (esp_host); + continue; + } + dlink->allocated = 1; + dma = dlink; + esp->dma = dma; + esp->dregs = dregs = dma->regs; + + /* Map in the ESP registers from I/O space */ + prom_apply_sbus_ranges(esp->edev->reg_addrs, 1); + esp->eregs = eregs = (struct Sparc_ESP_regs *) + sparc_alloc_io(esp->edev->reg_addrs[0].phys_addr, 0, + PAGE_SIZE, "ESP Registers", + esp->edev->reg_addrs[0].which_io, 0x0); + if(!eregs) + panic("ESP registers unmappable"); + esp->esp_command = + sparc_dvma_malloc(16, "ESP DVMA Cmd Block"); + if(!esp->esp_command) + panic("ESP DVMA transport area unmappable"); + + /* Set up the irq's etc. */ + esp->ehost->base = (unsigned char *) esp->eregs; + esp->ehost->io_port = (unsigned int) esp->eregs; + esp->ehost->n_io_port = (unsigned char) + esp->edev->reg_addrs[0].reg_size; + /* XXX The following may be different on sun4ms XXX */ + esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri; + + /* Allocate the irq only if necessary */ + for_each_esp(elink) { + if((elink != esp) && (esp->irq == elink->irq)) { + goto esp_irq_acquired; /* BASIC rulez */ + } + } + /* XXX We have shared interrupts per level now, maybe + * XXX use them, maybe not... + */ + if(request_irq(esp->ehost->irq, esp_intr, SA_INTERRUPT, + "Sparc ESP SCSI", NULL)) + panic("Cannot acquire ESP irq line"); +esp_irq_acquired: + printk("esp%d: IRQ %d ", nesps, esp->ehost->irq); + /* Figure out our scsi ID on the bus */ + esp->scsi_id = prom_getintdefault(esp->prom_node, + "initiator-id", -1); + if(esp->scsi_id == -1) + esp->scsi_id = prom_getintdefault(esp->prom_node, + "scsi-initiator-id", -1); + if(esp->scsi_id == -1) + esp->scsi_id = + prom_getintdefault(esp->edev->my_bus->prom_node, + "scsi-initiator-id", 7); + esp->ehost->this_id = esp->scsi_id; + esp->scsi_id_mask = (1 << esp->scsi_id); + /* Check for differential bus */ + esp->diff = prom_getintdefault(esp->prom_node, "differential", -1); + esp->diff = (esp->diff == -1) ? 0 : 1; + /* Check out the clock properties of the chip */ + fmhz = prom_getintdefault(esp->prom_node, "clock-frequency", -1); + if(fmhz==-1) + fmhz = prom_getintdefault(esp->edev->my_bus->prom_node, + "clock-frequency", -1); + if(fmhz <= (5000)) + ccf = 0; + else + ccf = (((5000 - 1) + (fmhz))/(5000)); + if(!ccf || ccf > 8) { + ccf = ESP_CCF_F4; + fmhz = (5000 * 4); + } + if(ccf==(ESP_CCF_F7+1)) + esp->cfact = ESP_CCF_F0; + else if(ccf == ESP_CCF_NEVER) + esp->cfact = ESP_CCF_F2; + else + esp->cfact = ccf; + esp->cfreq = fmhz; + esp->ccycle = ((1000000000) / ((fmhz)/1000)); + esp->ctick = ((7682 * esp->cfact * esp->ccycle)/1000); + esp->sync_defp = ((7682 + esp->ctick - 1) / esp->ctick); + + /* XXX HACK HACK HACK XXX */ + if (esp->sync_defp < 153) + esp->sync_defp = 153; + + printk("SCSI ID %d Clock %d MHz Period %2x ", esp->scsi_id, + (fmhz / 1000), esp->sync_defp); + + /* Find the burst sizes this dma supports. */ + bsizes = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff); + bsizes_more = prom_getintdefault(esp->edev->my_bus->prom_node, + "burst-sizes", 0xff); + if(bsizes_more != 0xff) bsizes &= bsizes_more; + if(bsizes == 0xff || (bsizes & DMA_BURST16)==0 || + (bsizes & DMA_BURST32)==0) + bsizes = (DMA_BURST32 - 1); + esp->bursts = bsizes; + + /* Probe the revision of this esp */ + esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); + esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); + esp->config3[0] = ESP_CONFIG3_TENB; + eregs->esp_cfg2 = esp->config2; + if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) != + (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { + printk("NCR53C90(esp100) detected\n"); + esp->erev = esp100; + } else { + eregs->esp_cfg2 = esp->config2 = 0; + eregs->esp_cfg3 = 0; + eregs->esp_cfg3 = esp->config3[0] = 5; + if(eregs->esp_cfg3 != 5) { + printk("NCR53C90A(esp100a) detected\n"); + esp->erev = esp100a; + } else { + int target; + + for(target=0; target<8; target++) + esp->config3[target] = 0; + eregs->esp_cfg3 = 0; + if(esp->cfact > ESP_CCF_F5) { + printk("NCR53C9XF(espfast) detected\n"); + esp->erev = fast; + esp->config2 |= ESP_CONFIG2_FENAB; + eregs->esp_cfg2 = esp->config2; + } else { + printk("NCR53C9x(esp236) detected\n"); + esp->erev = esp236; + eregs->esp_cfg2 = esp->config2 = 0; + } + } + } + + /* Initialize the command queues */ + esp->current_SC = 0; + esp->disconnected_SC = 0; + esp->issue_SC = 0; + + /* Reset the thing before we try anything... */ + esp_bootup_reset(esp, eregs); + + nesps++; +#ifdef THREADED_ESP_DRIVER + kernel_thread(esp_kernel_thread, esp, 0); +#endif + } /* for each sbusdev */ + } /* for each sbus */ + return nesps; +} + +/* + * The info function will return whatever useful + * information the developer sees fit. If not provided, then + * the name field will be used instead. + */ +const char *esp_info(struct Scsi_Host *host) +{ + struct Sparc_ESP *esp; + + esp = (struct Sparc_ESP *) host->hostdata; + switch(esp->erev) { + case esp100: + return "Sparc ESP100 (NCR53C90)"; + case esp100a: + return "Sparc ESP100A (NCR53C90A)"; + case esp236: + return "Sparc ESP236"; + case fast: + return "Sparc ESP-FAST (236 or 100A)"; + case fas236: + return "Sparc ESP236-FAST"; + case fas100a: + return "Sparc ESP100A-FAST"; + default: + panic("Bogon ESP revision"); + }; +} + +/* Execute a SCSI command when the bus is free. All callers + * turn off all interrupts, so we don't need to explicitly do + * it here. + */ +static inline void esp_exec_cmd(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs; + struct Sparc_ESP_regs *eregs; + Scsi_Cmnd *SCptr; + int i; + + eregs = esp->eregs; + dregs = esp->dregs; + + /* Grab first member of the issue queue. */ + SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC); + if(!SCptr) + goto bad; + SCptr->SCp.phase = in_selection; + + /* NCR docs say: + * 1) Load select/reselect Bus ID register with target ID + * 2) Load select/reselect Timeout Reg with desired value + * 3) Load Synchronous offset register with zero (for + * asynchronous transfers). + * 4) Load Synchronous Transfer Period register (if + * synchronous) + * 5) Load FIFO with 6, 10, or 12 byte SCSI command + * 6) Issue SELECTION_WITHOUT_ATTENTION command + * + * They also mention that a DMA NOP command must be issued + * to the SCSI chip under many circumstances, plus it's + * also a good idea to flush out the fifo just in case. + */ + + /* Load zeros into COUNTER via 2 DMA NOP chip commands + * due to flaky implementations of the 53C9x which don't + * get the idea the first time around. + */ + dregs->cond_reg = (DMA_INT_ENAB | DMA_FIFO_INV); + + eregs->esp_tclow = 0; + eregs->esp_tcmed = 0; + eregs->esp_cmd = (ESP_CMD_NULL | ESP_CMD_DMA); + + /* Flush the fifo of excess garbage. */ + eregs->esp_cmd = ESP_CMD_FLUSH; + + /* Load bus-id and timeout values. */ + eregs->esp_busid = (SCptr->target & 7); + eregs->esp_timeo = esp->sync_defp; + + eregs->esp_soff = 0; /* This means async transfer... */ + eregs->esp_stp = 0; + + /* Load FIFO with the actual SCSI command. */ + for(i=0; i < SCptr->cmd_len; i++) + eregs->esp_fdata = SCptr->cmnd[i]; + + /* Make sure the dvma forwards the ESP interrupt. */ + dregs->cond_reg = DMA_INT_ENAB; + + /* Tell ESP to SELECT without asserting ATN. */ + eregs->esp_cmd = ESP_CMD_SEL; + return; + +bad: + panic("esp: daaarrrkk starrr crashesss...."); +} + +/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */ +int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ + struct Sparc_ESP *esp; + unsigned long flags; + + save_flags(flags); cli(); + + /* Set up func ptr and initial driver cmd-phase. */ + SCpnt->scsi_done = done; + SCpnt->SCp.phase = not_issued; + + esp = (struct Sparc_ESP *) SCpnt->host->hostdata; + + /* We use the scratch area. */ + if(!SCpnt->use_sg) { + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = + (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.buffers_residual = 0; + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + SCpnt->SCp.ptr = mmu_get_scsi_one((char *)SCpnt->SCp.buffer, + SCpnt->SCp.this_residual, + esp->edev->my_bus); + } else { +#ifdef DEBUG_ESP_SG + printk("esp: sglist at %p with %d buffers\n", + SCpnt->buffer, SCpnt->use_sg); +#endif + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer, + SCpnt->SCp.buffers_residual, + esp->edev->my_bus); + SCpnt->SCp.ptr = (char *) SCpnt->SCp.buffer->alt_address; + } + + /* Place into our queue. */ + append_SC(&esp->issue_SC, SCpnt); + + /* Run it now if we can */ + if(!esp->current_SC) + esp_exec_cmd(esp); + + restore_flags(flags); + return 0; +} + +/* Only queuing supported in this ESP driver. */ +int esp_command(Scsi_Cmnd *SCpnt) +{ + ESPLOG(("esp: esp_command() called...\n")); + return -1; +} + +/* Abort a command. Those that are on the bus force a SCSI bus + * reset. + */ +int esp_abort(Scsi_Cmnd *SCpnt) +{ + ESPLOG(("esp_abort: Not implemented yet\n")); + return SCSI_ABORT_ERROR; +} + +/* Reset ESP chip, reset hanging bus, then kill active and + * disconnected commands for targets without soft reset. + */ +int esp_reset(Scsi_Cmnd *SCptr, unsigned int how) +{ + ESPLOG(("esp_reset: Not implemented yet\n")); + return SCSI_RESET_ERROR; +} + +/* Internal ESP done function. */ +static inline void esp_done(struct Sparc_ESP *esp, int error) +{ + unsigned long flags; + Scsi_Cmnd *done_SC; + + if(esp->current_SC) { + /* Critical section... */ + save_flags(flags); cli(); + done_SC = esp->current_SC; + esp->current_SC = NULL; + /* Free dvma entry. */ + if(!done_SC->use_sg) { + mmu_release_scsi_one(done_SC->SCp.ptr, + done_SC->SCp.this_residual, + esp->edev->my_bus); + } else { + struct scatterlist *scl = (struct scatterlist *)done_SC->buffer; +#ifdef DEBUG_ESP_SG + printk("esp: unmapping sg "); +#endif + mmu_release_scsi_sgl((struct mmu_sglist *) scl, + done_SC->use_sg - 1, + esp->edev->my_bus); +#ifdef DEBUG_ESP_SG + printk("done.\n"); +#endif + } + done_SC->result = error; + if(done_SC->scsi_done) + done_SC->scsi_done(done_SC); + else + panic("esp: esp->current_SC->scsi_done() == NULL"); + + /* Bus is free, issue any commands in the queue. */ + if(esp->issue_SC) + esp_exec_cmd(esp); + + restore_flags(flags); + /* End of critical section... */ + } else + panic("esp: done() called with NULL esp->current_SC"); +} + +#ifdef THREADED_ESP_DRIVER /* planning stage... */ + +/* With multiple lots of commands being processed I frequently + * see a situation where we see galloping esp herds. esp_done() + * wakes the entire world up and each interrupt causes a reschedule. + * This kernel thread fixes some of these unwanted effects during + * IO intensive activity.... I hope... + */ + +static void esp_kernel_thread(void *opaque) +{ + struct Sparc_ESP *esp = opaque; + + for(;;) { + unsigned long flags; + + while(esp->eatme_SC) { + struct Scsi_Cmnd *SCpnt; + + SCpnt = remove_first_SC(esp->eatme_SC); + esp_done(esp, error, SCpnt); + } + sleep(); + } +} +#endif + +/* Read the interrupt status registers on this ESP board */ +static inline void esp_updatesoft(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs) +{ + /* Update our software copies of the three ESP status + * registers for this ESP. Be careful, reading the + * ESP interrupt register clears the status and sequence + * step registers (unlatches them, you get the idea). + * So read the interrupt register last. + */ + + esp->seqreg = eregs->esp_sstep; + esp->sreg = eregs->esp_status; + + /* Supposedly, the ESP100A and above assert the highest + * bit in the status register if an interrupt is pending. + * I've never seen this work properly, so let's clear it + * manually while we are here. If I see any esp chips + * for which this bit is reliable I will conditionalize + * this. However, I don't see what this extra bit can + * buy me with all the tests I'll have to place all over + * the code to actually use it when I 'can'. Plus the + * 'pending interrupt' condition can more than reliably + * be obtained from the DVMA control register. + * + * "Broken hardware" -Linus + */ + esp->sreg &= (~ESP_STAT_INTR); + esp->ireg = eregs->esp_intrpt; /* Must be last or we lose */ +} + +/* #define ESP_IRQ_TRACE */ + +#ifdef ESP_IRQ_TRACE +#define ETRACE(foo) printk foo +#else +#define ETRACE(foo) +#endif + +static char last_fflags, last_status, last_msg; + +/* Main interrupt handler for an esp adapter. */ +static inline void esp_handle(struct Sparc_ESP *esp) +{ + struct sparc_dma_registers *dregs; + struct Sparc_ESP_regs *eregs; + Scsi_Cmnd *SCptr; + + eregs = esp->eregs; + dregs = esp->dregs; + SCptr = esp->current_SC; + + DMA_IRQ_ENTRY(esp->dma, dregs); + esp_updatesoft(esp, eregs); + + ETRACE(("ESPIRQ: <%2x,%2x,%2x> --> ", esp->ireg, esp->sreg, esp->seqreg)); + + /* Check for errors. */ + if(!SCptr) + panic("esp_handle: current_SC == penguin within interrupt!"); + + /* At this point in time, this esp driver should not see + * scsibus resets, parity errors, or gross errors unless + * something truly terrible happens which we are not ready + * to properly recover from yet. + */ + if((esp->ireg & (ESP_INTR_SR | ESP_INTR_IC)) || + (esp->sreg & (ESP_STAT_PERR | ESP_STAT_SPAM))) { + printk("esp: really bad error detected\n"); + printk("esp: intr<%2x> stat<%2x> seq<%2x>", + esp->ireg, esp->sreg, esp->seqreg); + printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase); + panic("esp: cannot continue\n"); + } + if(dregs->cond_reg & DMA_HNDL_ERROR) { + printk("esp: DMA shows an error cond_reg<%08lx> addr<%p>\n", + dregs->cond_reg, dregs->st_addr); + printk("esp: intr<%2x> stat<%2x> seq<%2x>", + esp->ireg, esp->sreg, esp->seqreg); + printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase); + panic("esp: cannot continue\n"); + } + if(esp->sreg & ESP_STAT_PERR) { + printk("esp: SCSI bus parity error\n"); + printk("esp: intr<%2x> stat<%2x> seq<%2x>", + esp->ireg, esp->sreg, esp->seqreg); + printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase); + panic("esp: cannot continue\n"); + } + + /* Service interrupt. */ + switch(SCptr->SCp.phase) { + case not_issued: + panic("Unexpected ESP interrupt, current_SC not issued."); + break; + case in_selection: + if(esp->ireg & ESP_INTR_RSEL) { + /* XXX Some day XXX */ + panic("ESP penguin reselected in async mode."); + } else if(esp->ireg & ESP_INTR_DC) { + /* Either we are scanning the bus and no-one + * lives at this target or it didn't respond. + */ + ETRACE(("DISCONNECT\n")); +#ifdef THREADED_ESP_DRIVER + append_SC(esp->eatme_SC, esp->current_SC); + esp->current_SC = 0; + wake_up(esp_kernel_thread); +#else + esp_done(esp, (DID_NO_CONNECT << 16)); +#endif + goto esp_handle_done; + } else if((esp->ireg & (ESP_INTR_FDONE | ESP_INTR_BSERV)) == + (ESP_INTR_FDONE | ESP_INTR_BSERV)) { + /* Selection successful, check the sequence step. */ + /* XXX I know, I know... add error recovery. XXX */ + switch(esp->seqreg & ESP_STEP_VBITS) { + case ESP_STEP_NCMD: + panic("esp: penguin didn't enter cmd phase."); + break; + case ESP_STEP_PPC: + panic("esp: penguin prematurely changed from cmd phase."); + break; + case ESP_STEP_FINI: + /* At the completion of every command + * or message-out phase, we _must_ + * unlatch the fifo-flags register + * with an ESP nop command. + */ + eregs->esp_cmd = ESP_CMD_NULL; + + /* Selection/Command sequence completed. We + * (at least for this driver) will be in + * either one of the data phases or status + * phase, check the status register to find + * out. + */ + switch(esp->sreg & ESP_STAT_PMASK) { + default: + printk("esp: Not datain/dataout/status.\n"); + panic("esp: penguin phase transition after selection."); + break; + case ESP_DOP: + /* Data out phase. */ + dregs->cond_reg |= DMA_FIFO_INV; + while(dregs->cond_reg & DMA_FIFO_ISDRAIN) + barrier(); + SCptr->SCp.phase = in_dataout; +#ifdef DEBUG_ESP_SG + if(SCptr->use_sg) + printk("esp: sg-start <%p,%d>", + SCptr->SCp.ptr, + SCptr->SCp.this_residual); +#endif + eregs->esp_tclow = SCptr->SCp.this_residual; + eregs->esp_tcmed = (SCptr->SCp.this_residual>>8); + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL); + + /* This is either the one buffer dvma ptr, + * or the first one in the scatter gather + * list. Check out esp_queue to see how + * this is set up. + */ + dregs->st_addr = SCptr->SCp.ptr; + dregs->cond_reg &= ~(DMA_ST_WRITE); + dregs->cond_reg |= (DMA_ENABLE | DMA_INT_ENAB); + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI); + ETRACE(("DATA_OUT\n")); + goto esp_handle_done; + case ESP_DIP: + /* Data in phase. */ + dregs->cond_reg |= DMA_FIFO_INV; + while(dregs->cond_reg & DMA_FIFO_ISDRAIN) + barrier(); + SCptr->SCp.phase = in_datain; +#ifdef DEBUG_ESP_SG + if(SCptr->use_sg) + printk("esp: sg-start <%p,%d>", + SCptr->SCp.ptr, + SCptr->SCp.this_residual); +#endif + eregs->esp_tclow = SCptr->SCp.this_residual; + eregs->esp_tcmed = (SCptr->SCp.this_residual>>8); + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL); + + /* This is either the one buffer dvma ptr, + * or the first one in the scatter gather + * list. Check out esp_queue to see how + * this is set up. + */ + dregs->st_addr = SCptr->SCp.ptr; + dregs->cond_reg |= (DMA_ENABLE | DMA_ST_WRITE | DMA_INT_ENAB); + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI); + ETRACE(("DATA_IN\n")); + goto esp_handle_done; + case ESP_STATP: + /* Status phase. */ + SCptr->SCp.phase = in_status; + eregs->esp_cmd = ESP_CMD_ICCSEQ; + ETRACE(("STATUS\n")); + goto esp_handle_done; /* Wait for message. */ + }; + }; + } else if(esp->ireg & ESP_INTR_FDONE) { + /* I'd like to investigate why this happens... */ + ESPLOG(("esp: This is weird, halfway through ")); + ESPLOG(("selection, trying to continue anyways.\n")); + goto esp_handle_done; + } else { + panic("esp: Did not get bus service during selection."); + goto esp_handle_done; + } + panic("esp: Mr. Potatoe Head is on the loose!"); + + case in_datain: + /* Drain the fifo for writes to memory. */ + switch(esp->dma->revision) { + case dvmarev0: + case dvmarev1: + case dvmarevplus: + case dvmarev2: + case dvmarev3: + /* Force a drain. */ + dregs->cond_reg |= DMA_FIFO_STDRAIN; + + /* fall through */ + case dvmaesc1: + /* Wait for the fifo to drain completely. */ + while(dregs->cond_reg & DMA_FIFO_ISDRAIN) + barrier(); + break; + }; + + case in_dataout: + dregs->cond_reg &= ~DMA_ENABLE; + + /* We may be pipelining an sg-list. */ + if(SCptr->use_sg) { + if(SCptr->SCp.buffers_residual) { + /* If we do not see a BUS SERVICE interrupt + * at this point, or we see that we have left + * the current data phase, then we lose. + */ + if(!(esp->ireg & ESP_INTR_BSERV) || + ((esp->sreg & ESP_STAT_PMASK) > 1)) + panic("esp: Aiee penguin on the SCSI-bus."); + + ++SCptr->SCp.buffer; + --SCptr->SCp.buffers_residual; + SCptr->SCp.this_residual = SCptr->SCp.buffer->length; + SCptr->SCp.ptr = SCptr->SCp.buffer->alt_address; + +#ifdef DEBUG_ESP_SG + printk("<%p,%d> ", SCptr->SCp.ptr, + SCptr->SCp.this_residual); +#endif + + /* Latch in new esp counters... */ + eregs->esp_tclow = SCptr->SCp.this_residual; + eregs->esp_tcmed = (SCptr->SCp.this_residual>>8); + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL); + + /* Reload DVMA gate array with new vaddr and enab. */ + dregs->st_addr = SCptr->SCp.ptr; + dregs->cond_reg |= DMA_ENABLE; + + /* Tell the esp to start transferring. */ + eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI); + goto esp_handle_done; + } +#ifdef DEBUG_ESP_SG + printk("done.\n"); +#endif + } + /* Take a look at what happened. */ + if(esp->ireg & ESP_INTR_DC) { + panic("esp: target disconnects during data transfer."); + goto esp_handle_done; + } else if(esp->ireg & ESP_INTR_BSERV) { + if((esp->sreg & ESP_STAT_PMASK) != ESP_STATP) { + panic("esp: Not status phase after data phase."); + goto esp_handle_done; + } + SCptr->SCp.phase = in_status; + eregs->esp_cmd = ESP_CMD_ICCSEQ; + ETRACE(("STATUS\n")); + goto esp_handle_done; /* Wait for message. */ + } else { + printk("esp: did not get bus service after data transfer."); + printk("esp_status: intr<%2x> stat<%2x> seq<%2x>\n", + esp->ireg, esp->sreg, esp->seqreg); + panic("esp: penguin data transfer."); + goto esp_handle_done; + } + case in_status: + if(esp->ireg & ESP_INTR_DC) { + panic("esp: penguin disconnects in status phase."); + goto esp_handle_done; + } else if (esp->ireg & ESP_INTR_FDONE) { + /* Status and Message now sit in the fifo for us. */ + last_fflags = eregs->esp_fflags; + SCptr->SCp.phase = in_finale; + last_status = SCptr->SCp.Status = eregs->esp_fdata; + last_msg = SCptr->SCp.Message = eregs->esp_fdata; + eregs->esp_cmd = ESP_CMD_MOK; + ETRACE(("FINALE\n")); + goto esp_handle_done; + } else { + panic("esp: penguin status phase."); + } + case in_finale: + if(esp->ireg & ESP_INTR_BSERV) { + panic("esp: penguin doesn't disconnect after status msg-ack."); + goto esp_handle_done; + } else if(esp->ireg & ESP_INTR_DC) { + /* Nexus is complete. */ +#ifdef THREADED_ESP_DRIVER + append_SC(esp->eatme_SC, esp->current_SC); + esp->current_SC = 0; + wake_up(esp_kernel_thread); +#else + esp_done(esp, ((SCptr->SCp.Status & 0xff) | + ((SCptr->SCp.Message & 0xff) << 8) | + (DID_OK << 16))); +#endif + ETRACE(("NEXUS_COMPLETE\n")); + goto esp_handle_done; + } else { + printk("esp: wacky state while in in_finale phase.\n"); + printk("esp_status: intr<%2x> stat<%2x> seq<%2x>\n", + esp->ireg, esp->sreg, esp->seqreg); + panic("esp: penguin esp state."); + goto esp_handle_done; + } + default: + panic("esp: detected penguin phase."); + goto esp_handle_done; + } + panic("esp: Heading to the promised land."); + +esp_handle_done: + DMA_IRQ_EXIT(esp->dma, dregs); + return; +} + +static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs) +{ + struct Sparc_ESP *esp; + + /* Handle all ESP interrupts showing */ + for_each_esp(esp) { + if(DMA_IRQ_P(esp->dregs)) { + esp_handle(esp); + } + } +} diff -u --recursive --new-file v1.3.92/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h --- v1.3.92/linux/drivers/scsi/esp.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/esp.h Sun Apr 21 12:42:05 1996 @@ -0,0 +1,350 @@ +/* esp.h: Defines and structures for the Sparc ESP (Enhanced SCSI + * Processor) driver under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_ESP_H +#define _SPARC_ESP_H + +/* For dvma controller register definitions. */ +#include + +/* The ESP SCSI controllers have their register sets in three + * "classes": + * + * 1) Registers which are both read and write. + * 2) Registers which are read only. + * 3) Registers which are write only. + * + * Yet, they all live within the same IO space. + */ + +/* All the ESP registers are one byte each and are accessed longwords + * apart with a big-endian ordering to the bytes. + */ + +struct Sparc_ESP_regs { + /* Access Description Offset */ + volatile unchar esp_tclow; /* rw Low bits of the transfer count 0x00 */ + unchar tlpad1[3]; + volatile unchar esp_tcmed; /* rw Mid bits of the transfer count 0x04 */ + unchar fdpad[3]; + volatile unchar esp_fdata; /* rw FIFO data bits 0x08 */ + unchar cbpad[3]; + volatile unchar esp_cmd; /* rw SCSI command bits 0x0c */ + unchar stpad[3]; + volatile unchar esp_status; /* ro ESP status register 0x10 */ +#define esp_busid esp_status /* wo Bus ID for select/reselect 0x10 */ + unchar irqpd[3]; + volatile unchar esp_intrpt; /* ro Kind of interrupt 0x14 */ +#define esp_timeo esp_intrpt /* wo Timeout value for select/resel 0x14 */ + unchar sspad[3]; + volatile unchar esp_sstep; /* ro Sequence step register 0x18 */ +#define esp_stp esp_sstep /* wo Transfer period per sync 0x18 */ + unchar ffpad[3]; + volatile unchar esp_fflags; /* ro Bits of current FIFO info 0x1c */ +#define esp_soff esp_fflags /* wo Sync offset 0x1c */ + unchar cf1pd[3]; + volatile unchar esp_cfg1; /* rw First configuration register 0x20 */ + unchar cfpad[3]; + volatile unchar esp_cfact; /* wo Clock conversion factor 0x24 */ + unchar ctpad[3]; + volatile unchar esp_ctest; /* wo Chip test register 0x28 */ + unchar cf2pd[3]; + volatile unchar esp_cfg2; /* rw Second configuration register 0x2c */ + unchar cf3pd[3]; + + /* The following is only found on the 53C9X series SCSI chips */ + volatile unchar esp_cfg3; /* rw Third configuration register 0x30 */ + unchar thpd[7]; + + /* The following is found on all chips except the NCR53C90 (ESP100) */ + volatile unchar esp_tchi; /* rw High bits of transfer count 0x38 */ +#define esp_uid esp_tchi /* ro Unique ID code 0x38 */ + unchar fgpad[3]; + volatile unchar esp_fgrnd; /* rw Data base for fifo 0x3c */ +}; + +/* Various revisions of the ESP board. */ +enum esp_rev { + esp100 = 0x00, /* NCR53C90 */ + esp100a = 0x01, /* NCR53C90A */ + esp236 = 0x02, + fas236 = 0x03, + fas100a = 0x04, + fast = 0x05, + espunknown = 0x06 +}; + +/* We get one of these for each ESP probed. */ +struct Sparc_ESP { + struct Sparc_ESP *next; /* Next ESP on probed or NULL */ + struct Sparc_ESP_regs *eregs; /* All esp registers */ + struct Linux_SBus_DMA *dma; /* Who I do transfers with. */ + struct sparc_dma_registers *dregs; /* And his registers. */ + struct Scsi_Host *ehost; /* Backpointer to SCSI Host */ + + struct linux_sbus_device *edev; /* Pointer to SBus entry */ + char prom_name[64]; /* Name of ESP device from prom */ + int prom_node; /* Prom node where ESP found */ + int esp_id; /* Same as esphost->host_id */ + + /* ESP Configuration Registers */ + unsigned char config1; /* Copy of the 1st config register */ + unsigned char config2; /* Copy of the 2nd config register */ + unsigned char config3[8]; /* Copy of the 3rd config register */ + + /* The current command we are sending to the ESP chip. This esp_command + * ptr needs to be mapped in DVMA area so we can send commands and read + * from the ESP fifo without burning precious CPU cycles. Programmed I/O + * sucks when we have the DVMA to do it for us. + */ + volatile unchar *esp_command; /* Location of command */ + int esp_clen; /* Length of this command */ + + /* To hold onto the dvma buffer ptr. */ + char *dvma_hold; + + /* The following are used to determine the cause of an IRQ. Upon every + * IRQ entry we synchronize these with the hardware registers. + */ + unchar ireg; /* Copy of ESP interrupt register */ + unchar sreg; /* Same for ESP status register */ + unchar seqreg; /* The ESP sequence register */ + + /* Clock periods, frequencies, synchronization, etc. */ + unsigned int cfreq; /* Clock frequency in HZ */ + unsigned int cfact; /* Clock conversion factor */ + unsigned int ccycle; /* One ESP clock cycle */ + unsigned int ctick; /* One ESP clock time */ + unsigned int sync_defp; /* Default negotiation period */ + + /* Misc. info about this ESP */ + enum esp_rev erev; /* ESP revision */ + int irq; /* SBus IRQ for this ESP */ + int scsi_id; /* Who am I as initiator? */ + int scsi_id_mask; /* Bitmask of 'me'. */ + int diff; /* Differential SCSI? */ + int bursts; /* Burst sizes our DVMA supports */ + + /* Our command queues, only one cmd lives in the current_SC queue. */ + Scsi_Cmnd *issue_SC; /* Commands to be issued */ + Scsi_Cmnd *current_SC; /* Who is currently working the bus */ + Scsi_Cmnd *disconnected_SC; /* Commands disconnected from the bus */ + +#ifdef THREADED_ESP_DRIVER + Scsi_Cmnd *eatme_SC; /* Cmds waiting for esp thread to process. */ +#endif + + /* Abortion status */ + int aborting, abortion_complete, abort_result; +}; + +/* Bitfield meanings for the above registers. */ + +/* ESP config reg 1, read-write, found on all ESP chips */ +#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ +#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ +#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ +#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ +#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ +#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ + +/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ +#define ESP_CONFIG2_DMAPARITY 0x01 /* Parity DMA err (200,236) */ +#define ESP_CONFIG2_REGPARITY 0x02 /* Parity reg err (200,236) */ +#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ +#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features */ +#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ +#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ +#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,esp216) */ +#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (esp236) */ +#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ + +/* ESP config register 3 read-write, found only esp236+fas236+fas100a chips */ +#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a) */ +#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ +#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a) */ +#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ +#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a) */ +#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ +#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a) */ +#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ +#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a) */ +#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ +#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ +#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ +#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ + +/* ESP command register read-write */ +/* Group 1 commands: These may be sent at any point in time to the ESP + * chip. None of them can generate interrupts 'cept + * the "SCSI bus reset" command if you have not disabled + * SCSI reset interrupts in the config1 ESP register. + */ +#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ +#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ +#define ESP_CMD_RC 0x02 /* Chip reset */ +#define ESP_CMD_RS 0x03 /* SCSI bus reset */ + +/* Group 2 commands: ESP must be an initiator and connected to a target + * for these commands to work. + */ +#define ESP_CMD_TI 0x10 /* Transfer Information */ +#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ +#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ +#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ +#define ESP_CMD_SATN 0x1a /* Set ATN */ +#define ESP_CMD_RATN 0x1b /* De-assert ATN */ + +/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected + * to a target as the initiator for these commands to work. + */ +#define ESP_CMD_SMSG 0x20 /* Send message */ +#define ESP_CMD_SSTAT 0x21 /* Send status */ +#define ESP_CMD_SDATA 0x22 /* Send data */ +#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ +#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ +#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ +#define ESP_CMD_DCNCT 0x27 /* Disconnect */ +#define ESP_CMD_RMSG 0x28 /* Receive Message */ +#define ESP_CMD_RCMD 0x29 /* Receive Command */ +#define ESP_CMD_RDATA 0x2a /* Receive Data */ +#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ + +/* Group 4 commands: The ESP must be in the disconnected state and must + * not be connected to any targets as initiator for + * these commands to work. + */ +#define ESP_CMD_RSEL 0x40 /* Reselect */ +#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ +#define ESP_CMD_SELA 0x42 /* Select w/ATN */ +#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ +#define ESP_CMD_ESEL 0x44 /* Enable selection */ +#define ESP_CMD_DSEL 0x45 /* Disable selections */ +#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ +#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ + +/* This bit enables the ESP's DMA on the SBus */ +#define ESP_CMD_DMA 0x80 /* Do DMA? */ + + +/* ESP status register read-only */ +#define ESP_STAT_PIO 0x01 /* IO phase bit */ +#define ESP_STAT_PCD 0x02 /* CD phase bit */ +#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ +#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ +#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ +#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ +#define ESP_STAT_PERR 0x20 /* Parity error */ +#define ESP_STAT_SPAM 0x40 /* Real bad error */ +/* This indicates the 'interrupt pending' condition on esp236, it is a reserved + * bit on other revs of the ESP. + */ +#define ESP_STAT_INTR 0x80 /* Interrupt */ + +/* The status register can be masked with ESP_STAT_PMASK and compared + * with the following values to determine the current phase the ESP + * (at least thinks it) is in. For our pusposes we also add our own + * software 'done' bit for our phase management engine. + */ +#define ESP_DOP (0) /* Data Out */ +#define ESP_DIP (ESP_STAT_PIO) /* Data In */ +#define ESP_CMDP (ESP_STAT_PCD) /* Command */ +#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ +#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ +#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ + +/* ESP interrupt register read-only */ +#define ESP_INTR_S 0x01 /* Select w/o ATN */ +#define ESP_INTR_SATN 0x02 /* Select w/ATN */ +#define ESP_INTR_RSEL 0x04 /* Reselected */ +#define ESP_INTR_FDONE 0x08 /* Function done */ +#define ESP_INTR_BSERV 0x10 /* Bus service */ +#define ESP_INTR_DC 0x20 /* Disconnect */ +#define ESP_INTR_IC 0x40 /* Illegal command given */ +#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ + +/* Interrupt status macros */ +#define ESP_SRESET_IRQ(esp) ((esp)->intreg & (ESP_INTR_SR)) +#define ESP_ILLCMD_IRQ(esp) ((esp)->intreg & (ESP_INTR_IC)) +#define ESP_SELECT_WITH_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_SATN)) +#define ESP_SELECT_WITHOUT_ATN_IRQ(esp) ((esp)->intreg & (ESP_INTR_S)) +#define ESP_SELECTION_IRQ(esp) ((ESP_SELECT_WITH_ATN_IRQ(esp)) || \ + (ESP_SELECT_WITHOUT_ATN_IRQ(esp))) +#define ESP_RESELECTION_IRQ(esp) ((esp)->intreg & (ESP_INTR_RSEL)) + +/* ESP sequence step register read-only */ +#define ESP_STEP_VBITS 0x07 /* Valid bits */ +#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ +#define ESP_STEP_SID 0x01 /* One msg byte sent */ +#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ +#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd + * bytes to be lost + */ +#define ESP_STEP_FINI 0x04 /* Command was sent ok */ + +/* ESP chip-test register read-write */ +#define ESP_TEST_TARG 0x01 /* Target test mode */ +#define ESP_TEST_INI 0x02 /* Initiator test mode */ +#define ESP_TEST_TS 0x04 /* Tristate test mode */ + +/* ESP unique ID register read-only, found on fas236+fas100a only */ +#define ESP_UID_F100A 0x00 /* ESP FAS100A */ +#define ESP_UID_F236 0x02 /* ESP FAS236 */ +#define ESP_UID_REV 0x07 /* ESP revision */ +#define ESP_UID_FAM 0xf8 /* ESP family */ + +/* ESP fifo flags register read-only */ +/* Note that the following implies a 16 byte FIFO on the ESP. */ +#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ +#define ESP_FF_SSTEP 0xe0 /* Sequence step */ + +/* ESP clock conversion factor register write-only */ +#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ +#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ +#define ESP_CCF_F2 0x02 /* 10MHz */ +#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ +#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ +#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ +#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ +#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ + +extern int esp_detect(struct SHT *); +extern const char *esp_info(struct Scsi_Host *); +extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +extern int esp_command(Scsi_Cmnd *); +extern int esp_abort(Scsi_Cmnd *); +extern int esp_reset(Scsi_Cmnd *, unsigned int); + +extern struct proc_dir_entry proc_scsi_esp; + +#define SCSI_SPARC_ESP { \ +/* struct SHT *next */ NULL, \ +/* long *usage_count */ NULL, \ +/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \ +/* int (*proc_info)(char *, char **, off_t, int, int, int) */ NULL, \ +/* const char *name */ "Sun ESP 100/100a/200", \ +/* int detect(struct SHT *) */ esp_detect, \ +/* int release(struct Scsi_Host *) */ NULL, \ +/* const char *info(struct Scsi_Host *) */ esp_info, \ +/* int command(Scsi_Cmnd *) */ esp_command, \ +/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \ +/* int abort(Scsi_Cmnd *) */ esp_abort, \ +/* int reset(Scsi_Cmnd *, int) */ esp_reset, \ +/* int slave_attach(int, int) */ NULL, \ +/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \ +/* int can_queue */ 10, \ +/* int this_id */ 7, \ +/* short unsigned int sg_tablesize */ SG_ALL, \ +/* short cmd_per_lun */ 1, \ +/* unsigned char present */ 0, \ +/* unsigned unchecked_isa_dma:1 */ 0, \ +/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, } + +/* For our interrupt engine. */ +#define for_each_esp(esp) \ + for((esp) = espchain; (esp); (esp) = (esp)->next) + +#endif /* !(_SPARC_ESP_H) */ diff -u --recursive --new-file v1.3.92/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v1.3.92/linux/drivers/scsi/hosts.c Mon Apr 15 12:20:19 1996 +++ linux/drivers/scsi/hosts.c Sun Apr 21 12:42:05 1996 @@ -137,13 +137,17 @@ #include "ppa.h" #endif +#ifdef CONFIG_SCSI_SUNESP +#include "esp.h" +#endif + #ifdef CONFIG_SCSI_DEBUG #include "scsi_debug.h" #endif /* -static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $"; +static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.10 1996/04/16 08:09:36 davem Exp $"; */ /* @@ -247,6 +251,9 @@ #endif #ifdef CONFIG_SCSI_PPA PPA, +#endif +#ifdef CONFIG_SCSI_SUNESP + SCSI_SPARC_ESP, #endif #ifdef CONFIG_SCSI_DEBUG SCSI_DEBUG, diff -u --recursive --new-file v1.3.92/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v1.3.92/linux/fs/fat/inode.c Sun Apr 21 12:39:02 1996 +++ linux/fs/fat/inode.c Sun Apr 21 11:11:13 1996 @@ -28,17 +28,25 @@ void fat_put_inode(struct inode *inode) { - struct inode *depend; + struct inode *depend, *linked; struct super_block *sb; + depend = MSDOS_I(inode)->i_depend; + linked = MSDOS_I(inode)->i_linked; + sb = inode->i_sb; if (inode->i_nlink) { + if (depend) { + iput(depend); + } + if (linked) { + iput(linked); + MSDOS_I(inode)->i_linked = NULL; + } if (MSDOS_I(inode)->i_busy) fat_cache_inval_inode(inode); return; } inode->i_size = 0; fat_truncate(inode); - depend = MSDOS_I(inode)->i_depend; - sb = inode->i_sb; clear_inode(inode); if (depend) { if (MSDOS_I(depend)->i_old != inode) { @@ -50,6 +58,16 @@ MSDOS_I(depend)->i_old = NULL; iput(depend); } + if (linked) { + if (MSDOS_I(linked)->i_oldlink != inode) { + printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n", + linked, inode, MSDOS_I(linked)->i_oldlink); + fat_fs_panic(sb,"..."); + return; + } + MSDOS_I(linked)->i_oldlink = NULL; + iput(linked); + } } @@ -368,6 +386,7 @@ /* printk("read inode %d\n",inode->i_ino); */ MSDOS_I(inode)->i_busy = 0; MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL; + MSDOS_I(inode)->i_linked = MSDOS_I(inode)->i_oldlink = NULL; MSDOS_I(inode)->i_binary = 1; inode->i_uid = MSDOS_SB(inode->i_sb)->options.fs_uid; inode->i_gid = MSDOS_SB(inode->i_sb)->options.fs_gid; @@ -461,6 +480,29 @@ struct super_block *sb = inode->i_sb; struct buffer_head *bh; struct msdos_dir_entry *raw_entry; + struct inode *linked; + + linked = MSDOS_I(inode)->i_linked; + if (linked) { + if (MSDOS_I(linked)->i_oldlink != inode) { + printk("Invalid link (0x%p): expected 0x%p, got 0x%p\n", + linked, inode, MSDOS_I(linked)->i_oldlink); + fat_fs_panic(sb,"..."); + return; + } + linked->i_version = ++event; + linked->i_mode = inode->i_mode; + linked->i_uid = inode->i_uid; + linked->i_gid = inode->i_gid; + linked->i_size = inode->i_size; + linked->i_atime = inode->i_atime; + linked->i_mtime = inode->i_mtime; + linked->i_ctime = inode->i_ctime; + linked->i_blocks = inode->i_blocks; + linked->i_atime = inode->i_atime; + MSDOS_I(linked)->i_attrs = MSDOS_I(inode)->i_attrs; + linked->i_dirt = 1; + } inode->i_dirt = 0; if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return; diff -u --recursive --new-file v1.3.92/linux/fs/msdos/namei.c linux/fs/msdos/namei.c --- v1.3.92/linux/fs/msdos/namei.c Thu Mar 21 18:08:30 1996 +++ linux/fs/msdos/namei.c Sun Apr 21 11:11:13 1996 @@ -690,16 +690,19 @@ } msdos_read_inode(free_inode); MSDOS_I(old_inode)->i_busy = 1; + MSDOS_I(old_inode)->i_linked = free_inode; + MSDOS_I(free_inode)->i_oldlink = old_inode; fat_cache_inval_inode(old_inode); old_inode->i_dirt = 1; old_de->name[0] = DELETED_FLAG; mark_buffer_dirty(old_bh, 1); mark_buffer_dirty(free_bh, 1); - if (!exists) iput(free_inode); - else { + if (exists) { MSDOS_I(new_inode)->i_depend = free_inode; MSDOS_I(free_inode)->i_old = new_inode; - /* free_inode is put when putting new_inode */ + /* Two references now exist to free_inode so increase count */ + free_inode->i_count++; + /* free_inode is put after putting new_inode and old_inode */ iput(new_inode); dcache_add(new_dir, new_name, new_len, new_ino); brelse(new_bh); diff -u --recursive --new-file v1.3.92/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v1.3.92/linux/fs/nfs/proc.c Tue Apr 2 13:32:22 1996 +++ linux/fs/nfs/proc.c Sun Apr 21 17:32:02 1996 @@ -29,7 +29,7 @@ * filesystem and type 'ls xyzzy' to turn on debugging. */ -#if 1 +#if 0 #define NFS_PROC_DEBUG #endif diff -u --recursive --new-file v1.3.92/linux/fs/vfat/namei.c linux/fs/vfat/namei.c --- v1.3.92/linux/fs/vfat/namei.c Mon Mar 11 11:28:46 1996 +++ linux/fs/vfat/namei.c Sun Apr 21 11:11:13 1996 @@ -1473,6 +1473,8 @@ vfat_read_inode(new_inode); MSDOS_I(old_inode)->i_busy = 1; + MSDOS_I(old_inode)->i_linked = new_inode; + MSDOS_I(new_inode)->i_oldlink = old_inode; fat_cache_inval_inode(old_inode); PRINTK(("vfat_rename 15: old_slots=%d\n",old_slots)); old_inode->i_dirt = 1; @@ -1493,7 +1495,6 @@ mark_buffer_dirty(new_bh, 1); dcache_add(new_dir, new_name, new_len, new_ino); - iput(new_inode); /* XXX: There is some code in the original MSDOS rename that * is not duplicated here and it might cause a problem in diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/asi.h linux/include/asm-sparc/asi.h --- v1.3.92/linux/include/asm-sparc/asi.h Fri Apr 12 15:52:05 1996 +++ linux/include/asm-sparc/asi.h Sun Apr 21 12:30:32 1996 @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.13 1996/03/01 07:20:51 davem Exp $ */ +/* $Id: asi.h,v 1.15 1996/04/17 22:45:52 davem Exp $ */ #ifndef _SPARC_ASI_H #define _SPARC_ASI_H @@ -101,174 +101,8 @@ #define ASI_M_IC_FLCLEAR 0x36 #define ASI_M_DC_FLCLEAR 0x37 -#define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Register rw, ss */ - -/* Sparc V9 TI UltraSparc ASI's (V8 ploos ploos) */ - -/* ASIs 0x0-0x7f are Supervisor Only. 0x80-0xff are for anyone. */ - -/* You will notice that there are a lot of places where if a normal - * ASI is available on the V9, there is also a little-endian version. - */ - -#define ASI_V9_RESV0 0x00 /* Don't touch... */ -#define ASI_V9_RESV1 0x01 /* Not here */ -#define ASI_V9_RESV2 0x02 /* Or here */ -#define ASI_V9_RESV3 0x03 /* nor here. */ -#define ASI_V9_NUCLEUS 0x04 /* Impl-dep extra virtual access context */ -#define ASI_V9_NUCLEUSL 0x0C /* Nucleus context, little-endian */ -#define ASI_V9_USER_PRIM 0x10 /* User primary address space */ -#define ASI_V9_USER_SEC 0x11 /* User secondary address space */ - -#define ASI_V9_MMUPASS 0x14 /* OBMEM (external cache, no data cache) */ -#define ASI_V9_IOPASS 0x15 /* Like MMUPASS, for I/O areas (uncached) */ -#define ASI_V9_USER_PRIML 0x18 /* User primary addr space, lil-endian. */ -#define ASI_V9_USER_SECL 0x19 /* User secondary addr space, lil-endian. */ -#define ASI_V9_MMUPASSL 0x1C /* OBMEM little-endian */ -#define ASI_V9_IOPASSL 0x1D /* Like IOPASS but little-endian */ -#define ASI_V9_ATOMICQ 0x24 /* Atomic 128-bit load address space */ -#define ASI_V9_ATOMICQL 0x2C /* Atomic 128-bit load little-endian */ -#define ASI_V9_LSTORECTL 0x45 /* ld/st control unit */ -#define ASI_V9_DCACHE_ENT 0x46 /* Data cache entries */ -#define ASI_V9_DCACHE_TAG 0x47 /* Data cache tags */ -#define ASI_V9_IRQDISPS 0x48 /* IRQ dispatch status registers */ -#define ASI_V9_IRQRECVS 0x49 /* IRQ receive status registers */ -#define ASI_V9_MMUREGS 0x4A /* Spitfire MMU control register */ -#define ASI_V9_ESTATE 0x4B /* Error state enable register */ -#define ASI_V9_ASYNC_FSR 0x4C /* Asynchronous Fault Status reg */ -#define ASI_V9_ASYNC_FAR 0x4D /* Asynchronous Fault Address reg */ - -#define ASI_V9_ECACHE_DIAG 0x4E /* External Cache diagnostics */ - -#define ASI_V9_TXTMMU 0x50 /* MMU for program text */ -#define ASI_V9_TXTMMU_D1 0x51 /* XXX */ -#define ASI_V9_TXTMMU_D2 0x52 /* XXX */ -#define ASI_V9_TXTMMU_TDI 0x54 /* Text MMU TLB data in */ -#define ASI_V9_TXTMMU_TDA 0x55 /* Text MMU TLB data access */ -#define ASI_V9_TXTMMU_TTR 0x56 /* Text MMU TLB tag read */ -#define ASI_V9_TXTMMU_TDM 0x57 /* Text MMU TLB de-map */ - -#define ASI_V9_DATAMMU 0x58 /* MMU for program data */ -#define ASI_V9_DATAMMU_D1 0x59 /* XXX */ -#define ASI_V9_DATAMMU_D2 0x5A /* XXX */ -#define ASI_V9_DATAMMU_DD 0x5B /* XXX */ -#define ASI_V9_DATAMMU_TDI 0x5C /* Data MMU TLB data in */ -#define ASI_V9_DATAMMU_TDA 0x5D /* Data MMU TLB data access */ -#define ASI_V9_DATAMMU_TTR 0x5E /* Data MMU TLB tag read */ -#define ASI_V9_DATAMMU_TDM 0x5F /* Data MMU TLB de-map */ - -#define ASI_V9_ICACHE_D 0x66 /* Instruction cache data */ -#define ASI_V9_ICACHE_T 0x67 /* Instruction cache tags */ -#define ASI_V9_ICACHE_DEC 0x6E /* Instruction cache decode */ -#define ASI_V9_ICACHE_NXT 0x6F /* Instruction cache next ent */ - -#define ASI_V9_HUH1 0x70 /* XXX */ -#define ASI_V9_HUH2 0x71 /* XXX */ - -#define ASI_V9_ECACHE_ACC 0x76 /* External cache registers */ - -#define ASI_V9_INTR_DISP 0x77 /* Interrupt dispatch registers */ -#define ASI_V9_HUH1L 0x78 /* XXX */ -#define ASI_V9_HUH2L 0x79 /* XXX */ -#define ASI_V9_INTR_RECV 0x7f /* Interrupt Receive registers */ - -#define ASI_V9_PRIMARY 0x80 /* Primary address space */ -#define ASI_V9_SECONDARY 0x81 /* Secondary address space */ -#define ASI_V9_PRIMARY_NF 0x82 /* Primary address space -- No Fault */ -#define ASI_V9_SECONDARY_NF 0x83 /* Secondary address space -- No Fault */ - -#define ASI_V9_PRIMARYL 0x80 /* Primary address space, little-endian */ -#define ASI_V9_SECONDARYL 0x81 /* Secondary address space, little-endian */ -#define ASI_V9_PRIMARY_NFL 0x82 /* Primary address space, No Fault, l-endian */ -#define ASI_V9_SECONDARY_NFL 0x83 /* Secondary address space, No Fault, l-endian */ - -#define ASI_V9_XXX1 0xC0 /* XXX */ -#define ASI_V9_XXX2 0xC1 /* XXX */ -#define ASI_V9_XXX3 0xC2 /* XXX */ -#define ASI_V9_XXX4 0xC3 /* XXX */ -#define ASI_V9_XXX5 0xC4 /* XXX */ -#define ASI_V9_XXX6 0xC5 /* XXX */ -#define ASI_V9_XXX7 0xC8 /* XXX */ -#define ASI_V9_XXX8 0xC9 /* XXX */ -#define ASI_V9_XXX9 0xCA /* XXX */ -#define ASI_V9_XXX10 0xCB /* XXX */ -#define ASI_V9_XXX11 0xCC /* XXX */ -#define ASI_V9_XXX12 0xCD /* XXX */ - -#define ASI_V9_XXX13 0xD0 /* XXX */ -#define ASI_V9_XXX14 0xD1 /* XXX */ -#define ASI_V9_XXX15 0xD2 /* XXX */ -#define ASI_V9_XXX16 0xD3 /* XXX */ -#define ASI_V9_XXX17 0xD8 /* XXX */ -#define ASI_V9_XXX18 0xD9 /* XXX */ -#define ASI_V9_XXX19 0xDA /* XXX */ -#define ASI_V9_XXX20 0xDB /* XXX */ - -#define ASI_V9_XXX21 0xE0 /* XXX */ -#define ASI_V9_XXX22 0xE1 /* XXX */ -#define ASI_V9_XXX23 0xF0 /* XXX */ -#define ASI_V9_XXX24 0xF1 /* XXX */ -#define ASI_V9_XXX25 0xF8 /* XXX */ -#define ASI_V9_XXX26 0xF9 /* XXX */ - -#ifndef __ASSEMBLY__ - -/* Better to do these inline with gcc __asm__ statements. */ - -/* The following allow you to access physical memory directly without - * translation by the SRMMU. The only other way to do this is to - * turn off the SRMMU completely, and well... thats not good. - * - * TODO: For non-MBus SRMMU units we have to perform the following - * using this sequence. - * 1) Turn off traps - * 2) Turn on AC bit in SRMMU control register - * 3) Do our direct physical memory access - * 4) Restore old SRMMU control register value - * 5) Restore old %psr value - */ - -extern __inline__ unsigned int -ldb_sun4m_bypass(unsigned int addr) -{ - unsigned int retval; - - __asm__("lduba [%2] %1, %0\n\t" : - "=r" (retval) : - "i" (ASI_M_BYPASS), "r" (addr)); - - return retval; -} - -extern __inline__ unsigned int -ldw_sun4m_bypass(unsigned int addr) -{ - unsigned int retval; - - __asm__("lda [%2] %1, %0\n\t" : - "=r" (retval) : - "i" (ASI_M_BYPASS), "r" (addr)); - - return retval; -} - -extern __inline__ void -stb_sun4m_bypass(unsigned char value, unsigned int addr) -{ - __asm__("stba %0, [%2] %1\n\t" : : - "r" (value), "i" (ASI_M_BYPASS), "r" (addr) : - "memory"); -} - -extern __inline__ void -stw_sun4m_bypass(unsigned int value, unsigned int addr) -{ - __asm__("sta %0, [%2] %1\n\t" : : - "r" (value), "i" (ASI_M_BYPASS), "r" (addr) : - "memory"); -} - -#endif /* !(__ASSEMBLY__) */ +#define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Registerl rw, ss */ +#define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */ #endif /* _SPARC_ASI_H */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/asmmacro.h linux/include/asm-sparc/asmmacro.h --- v1.3.92/linux/include/asm-sparc/asmmacro.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/asmmacro.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,207 @@ +/* asmmacro.h: Assembler macros. + * + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + */ + +#ifndef _SPARC_ASMMACRO_H +#define _SPARC_ASMMACRO_H + +/* #define SMP_DEBUG */ + +#define GET_PROCESSOR_ID(reg) \ + rd %tbr, %reg; \ + srl %reg, 12, %reg; \ + and %reg, 3, %reg; + +#define GET_PROCESSOR_MID(reg, tmp) \ + GET_PROCESSOR_ID(reg) \ + set C_LABEL(mid_xlate), %tmp; \ + ldub [%tmp + %reg], %reg; + +#define GET_PROCESSOR_OFFSET(reg) \ + rd %tbr, %reg; \ + srl %reg, 10, %reg; \ + and %reg, 0xc, %reg; + +#define PROCESSOR_OFFSET_TO_ID(reg) \ + srl %reg, 2, %reg; + +#define PROCESSOR_ID_TO_OFFSET(reg) \ + sll %reg, 2, %reg; + +/* All trap entry points _must_ begin with this macro or else you + * lose. It makes sure the kernel has a proper window so that + * c-code can be called. + */ +#ifndef SMP_DEBUG +#define SAVE_ALL \ + sethi %hi(trap_setup), %l4; \ + jmpl %l4 + %lo(trap_setup), %l6; \ + nop; +#else +#define SAVE_ALL \ + GET_PROCESSOR_ID(l4); \ + set C_LABEL(trap_log), %l5; \ + sll %l4, 11, %l6; \ + add %l5, %l6, %l5; \ + set C_LABEL(trap_log_ent), %l6; \ + sll %l4, 2, %l4; \ + add %l6, %l4, %l6; \ + ld [%l6], %l6; \ + sll %l6, 3, %l6; \ + st %l1, [%l5 + %l6]; \ + add %l5, 4, %l5; \ + st %l0, [%l5 + %l6]; \ + set C_LABEL(trap_log_ent), %l5; \ + add %l5, %l4, %l5; \ + srl %l6, 3, %l6; \ + add %l6, 1, %l6; \ + and %l6, 255, %l6; \ + st %l6, [%l5]; \ + sethi %hi(trap_setup), %l4; \ + jmpl %l4 + %lo(trap_setup), %l6; \ + nop; +#endif + +/* All traps low-level code here must end with this macro. + * For SMP configurations the ret_trap_entry routine will + * have to appropriate code to actually release the kernel + * entry lock. + */ +#define RESTORE_ALL \ + b ret_trap_entry; \ + nop; + +#ifndef __SMP__ + +#define ENTER_SYSCALL +#define LEAVE_SYSCALL +#define ENTER_IRQ +#define LEAVE_IRQ + +#else + +#define INCREMENT_COUNTER(symbol, tmp1, tmp2) \ + set C_LABEL(symbol), %tmp1; \ + ld [%tmp1], %tmp2; \ + add %tmp2, 1, %tmp2; \ + st %tmp2, [%tmp1]; + +#define DECREMENT_COUNTER(symbol, tmp1, tmp2) \ + set C_LABEL(symbol), %tmp1; \ + ld [%tmp1], %tmp2; \ + sub %tmp2, 1, %tmp2; \ + st %tmp2, [%tmp1]; + + /* This is so complicated I suggest you don't look at it. */ +#define ENTER_MASK(mask) \ + GET_PROCESSOR_OFFSET(l4) \ + set C_LABEL(smp_spinning), %l6; \ + add %l6, %l4, %l6; \ + mov 1, %l5; \ + st %l5, [%l6]; \ + set C_LABEL(smp_proc_in_lock), %l5; \ + ld [%l5 + %l4], %l6; \ + or %l6, mask, %l6; \ + st %l6, [%l5 + %l4]; \ +1: \ + set C_LABEL(kernel_flag), %l5; \ + ldstub [%l5], %l6; \ + cmp %l6, 0; \ + be 3f; \ + nop; \ + set C_LABEL(active_kernel_processor), %l5; \ + GET_PROCESSOR_ID(l4) \ + ldub [%l5], %l6; \ + cmp %l6, %l4; \ + be 4f; \ + nop; \ +2: \ + GET_PROCESSOR_MID(l4, l5) \ + set C_LABEL(sun4m_interrupts), %l5; \ + ld [%l5], %l5; \ + sll %l4, 12, %l4; \ + add %l5, %l4, %l5; \ + ld [%l5], %l4; \ + sethi %hi(0x80000000), %l6; \ + andcc %l6, %l4, %g0; \ + be 5f; \ + nop; \ + st %l6, [%l5 + 4]; \ + nop; nop; nop; \ + ld [%l5], %g0; \ + nop; nop; nop; \ + or %l0, PSR_PIL, %l4; \ + wr %l4, 0x0, %psr; \ + nop; nop; nop; \ + wr %l4, PSR_ET, %psr; \ + nop; nop; nop; \ + call C_LABEL(smp_message_irq); \ + nop; \ + wr %l0, 0x0, %psr; \ + nop; nop; nop; \ +5: \ + set C_LABEL(kernel_flag), %l5; \ + ldub [%l5], %l6; \ + cmp %l6, 0; \ + bne 2b; \ + nop; \ + b 1b; \ + nop; \ +3: \ + GET_PROCESSOR_ID(l4) \ + set C_LABEL(active_kernel_processor), %l5; \ + stb %l4, [%l5]; \ + GET_PROCESSOR_MID(l4, l5) \ + set C_LABEL(irq_rcvreg), %l5; \ + ld [%l5], %l5; \ + st %l4, [%l5]; \ +4: \ + GET_PROCESSOR_OFFSET(l4) \ + set C_LABEL(smp_spinning), %l6; \ + st %g0, [%l6 + %l4]; + +#define ENTER_SYSCALL \ + ENTER_MASK(SMP_FROM_SYSCALL) \ + INCREMENT_COUNTER(kernel_counter, l6, l5) \ + INCREMENT_COUNTER(syscall_count, l6, l5) + +#define ENTER_IRQ \ + ENTER_MASK(SMP_FROM_INT) \ + INCREMENT_COUNTER(kernel_counter, l6, l5) + +#define LEAVE_MASK(mask) \ + GET_PROCESSOR_OFFSET(l4) \ + set C_LABEL(smp_proc_in_lock), %l5; \ + ld [%l5 + %l4], %l6; \ + andn %l6, mask, %l6; \ + st %l6, [%l5 + %l4]; + +#define LEAVE_SYSCALL \ + LEAVE_MASK(SMP_FROM_SYSCALL) \ + DECREMENT_COUNTER(syscall_count, l6, l5) \ + set C_LABEL(kernel_counter), %l6; \ + ld [%l6], %l5; \ + subcc %l5, 1, %l5; \ + st %l5, [%l6]; \ + bne 1f; \ + nop; \ + set C_LABEL(active_kernel_processor), %l6; \ + mov NO_PROC_ID, %l5; \ + stb %l5, [%l6]; \ + set C_LABEL(kernel_flag), %l6; \ + stb %g0, [%l6]; \ +1: + +#define LEAVE_IRQ \ + LEAVE_MASK(SMP_FROM_INT) \ + INCREMENT_COUNTER(syscall_count, l6, l5) + + +#define RESTORE_ALL_FASTIRQ \ + b ret_irq_entry; \ + nop; + +#endif /* !(__SMP__) */ + +#endif /* !(_SPARC_ASMMACRO_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h --- v1.3.92/linux/include/asm-sparc/atomic.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/atomic.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,60 @@ +/* atomic.h: These really suck for now. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __ARCH_SPARC_ATOMIC__ +#define __ARCH_SPARC_ATOMIC__ + +#ifdef __SMP__ +#include +#include +#endif + +typedef int atomic_t; + +static __inline__ void atomic_add(atomic_t i, atomic_t *v) +{ + unsigned long flags; + + save_flags(flags); cli(); + *v += i; + restore_flags(flags); +} + +static __inline__ void atomic_sub(atomic_t i, atomic_t *v) +{ + unsigned long flags; + + save_flags(flags); cli(); + *v -= i; + restore_flags(flags); +} + +static __inline__ int atomic_sub_and_test(atomic_t i, atomic_t *v) +{ + unsigned long flags, result; + + save_flags(flags); cli(); + *v -= i; + result = (*v == 0); + restore_flags(flags); + return result; +} + +static __inline__ void atomic_inc(atomic_t *v) +{ + atomic_add(1, v); +} + +static __inline__ void atomic_dec(atomic_t *v) +{ + atomic_sub(1, v); +} + +static __inline__ int atomic_dec_and_test(atomic_t *v) +{ + return atomic_sub_and_test(1, v); +} + +#endif /* !(__ARCH_SPARC_ATOMIC__) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/atops.h linux/include/asm-sparc/atops.h --- v1.3.92/linux/include/asm-sparc/atops.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/atops.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,22 @@ +/* atops.h: Atomic SPARC operations. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _SPARC_ATOPS_H +#define _SPARC_ATOPS_H + +#ifdef __SMP__ + +extern __inline volatile unsigned char ldstub(volatile unsigned char *lock) +{ + volatile unsigned char retval; + + __asm__ __volatile__("ldstub [%1], %0\n\t" : + "=&r" (retval) : + "r" (lock)); + return retval; +} + +#endif + +#endif diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h --- v1.3.92/linux/include/asm-sparc/auxio.h Fri Apr 12 15:52:05 1996 +++ linux/include/asm-sparc/auxio.h Sun Apr 21 12:30:33 1996 @@ -1,5 +1,5 @@ /* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $ - * auxio.h: Definitions and code for the Auxiliary I/O register. + * auxio.h: Definitons and code for the Auxiliary I/O register. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h --- v1.3.92/linux/include/asm-sparc/bitops.h Mon Mar 4 08:50:00 1996 +++ linux/include/asm-sparc/bitops.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: bitops.h,v 1.18 1996/01/03 03:53:00 davem Exp $ +/* $Id: bitops.h,v 1.23 1996/04/20 07:54:35 davem Exp $ * bitops.h: Bit string operations on the Sparc. * * Copyright 1995, David S. Miller (davem@caip.rutgers.edu). @@ -13,13 +13,23 @@ #include #endif +#ifdef __SMP__ + +#define SMPVOL volatile + +#else + +#define SMPVOL + +#endif + /* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0' * is in the highest of the four bytes and bit '31' is the high bit * within the first byte. Sparc is BIG-Endian. Unless noted otherwise * all bit-ops return 0 if bit was previously clear and != 0 otherwise. */ -extern __inline__ unsigned long set_bit(unsigned long nr, void *addr) +extern __inline__ unsigned long set_bit(unsigned long nr, SMPVOL void *addr) { int mask, flags; unsigned long *ADDR = (unsigned long *) addr; @@ -34,7 +44,7 @@ return oldbit != 0; } -extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr) +extern __inline__ unsigned long clear_bit(unsigned long nr, SMPVOL void *addr) { int mask, flags; unsigned long *ADDR = (unsigned long *) addr; @@ -49,7 +59,7 @@ return oldbit != 0; } -extern __inline__ unsigned long change_bit(unsigned long nr, void *addr) +extern __inline__ unsigned long change_bit(unsigned long nr, SMPVOL void *addr) { int mask, flags; unsigned long *ADDR = (unsigned long *) addr; @@ -65,9 +75,9 @@ } /* The following routine need not be atomic. */ -extern __inline__ unsigned long test_bit(int nr, const void *addr) +extern __inline__ unsigned long test_bit(int nr, const SMPVOL void *addr) { - return 1UL & (((const unsigned int *) addr)[nr >> 5] >> (nr & 31)); + return ((1UL << (nr & 31)) & (((const unsigned int *) addr)[nr >> 5])) != 0; } /* The easy/cheese version for now. */ @@ -99,7 +109,7 @@ offset &= 31UL; if (offset) { tmp = *(p++); - tmp |= ~0UL << (32-offset); + tmp |= ~0UL >> (32-offset); if (size < 32) goto found_first; if (~tmp) diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/bsderrno.h linux/include/asm-sparc/bsderrno.h --- v1.3.92/linux/include/asm-sparc/bsderrno.h Fri Apr 12 15:52:05 1996 +++ linux/include/asm-sparc/bsderrno.h Sun Apr 21 12:30:33 1996 @@ -1,5 +1,5 @@ /* $Id: bsderrno.h,v 1.2 1995/11/25 02:31:17 davem Exp $ - * bsderrno.h: Error numbers for NetBSD binary compatibility + * bsderrno.h: Error numbers for NetBSD binary compatability * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/cache.h linux/include/asm-sparc/cache.h --- v1.3.92/linux/include/asm-sparc/cache.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/cache.h Sun Apr 21 12:30:33 1996 @@ -14,7 +14,7 @@ * alternate address space. The IDC bit must be off in the ICCR on * HyperSparcs for these accesses to work. The code below does not do * any checking, the caller must do so. These routines are for - * diagnostics only, but could end up being useful. Use with care. + * diagnostics only, but coule end up being useful. Use with care. * Also, you are asking for trouble if you execute these in one of the * three instructions following a %asr/%psr access or modification. */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/checksum.h linux/include/asm-sparc/checksum.h --- v1.3.92/linux/include/asm-sparc/checksum.h Sat Nov 25 04:31:24 1995 +++ linux/include/asm-sparc/checksum.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: checksum.h,v 1.10 1995/11/25 02:31:23 davem Exp $ */ +/* $Id: checksum.h,v 1.13 1996/04/18 03:30:19 davem Exp $ */ #ifndef __SPARC_CHECKSUM_H #define __SPARC_CHECKSUM_H @@ -6,23 +6,67 @@ * * Copyright(C) 1995 Linus Torvalds * Copyright(C) 1995 Miguel de Icaza + * Copyright(C) 1996 David S. Miller + * + * derived from: + * Alpha checksum c-code + * ix86 inline assembly */ +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ + +extern inline unsigned short csum_tcpudp_magic(unsigned long saddr, + unsigned long daddr, + unsigned short len, + unsigned short proto, + unsigned int sum) +{ + __asm__ __volatile__(" + addcc %0, %1, %0 + addxcc %0, %4, %0 + addxcc %0, %5, %0 + addx %0, %%g0, %0 + + ! We need the carry from the addition of 16-bit + ! significant addition, so we zap out the low bits + ! in one half, zap out the high bits in another, + ! shift them both up to the top 16-bits of a word + ! and do the carry producing addition, finally + ! shift the result back down to the low 16-bits. + + ! Actually, we can further optimize away two shifts + ! because we know the low bits of the original + ! value will be added to zero-only bits so cannot + ! affect the addition result nor the final carry + ! bit. + + sll %0, 16, %1 + addcc %0, %1, %0 ! add and set carry, neat eh? + srl %0, 16, %0 ! shift back down the result + addx %0, %%g0, %0 ! get remaining carry bit + xnor %%g0, %0, %0 ! negate, sparc is cool + " + : "=&r" (sum), "=&r" (saddr) + : "0" (daddr), "1" (saddr), "r" (len+proto), "r" (sum)); + return ((unsigned short) sum); +} -/* 32 bits version of the checksum routines written for the Alpha by Linus */ extern inline unsigned short from32to16(unsigned long x) { - /* add up 16-bit and 17-bit words for 17+c bits */ - x = (x & 0xffff) + (x >> 16); - /* add up 16-bit and 2-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); + __asm__ __volatile__(" + addcc %0, %1, %0 + srl %0, 16, %0 + addx %%g0, %0, %0 + " + : "=r" (x) + : "r" (x << 16), "0" (x)); return x; } -extern inline unsigned long -do_csum(unsigned char * buff, int len) +extern inline unsigned long do_csum(unsigned char * buff, int len) { int odd, count; unsigned long result = 0; @@ -31,7 +75,7 @@ goto out; odd = 1 & (unsigned long) buff; if (odd) { - result = *buff << 8; + result = *buff; len--; buff++; } @@ -50,7 +94,6 @@ unsigned long w = *(unsigned long *) buff; count--; buff += 4; - len -= 4; result += carry; result += w; carry = (w > result); @@ -64,7 +107,7 @@ } } if (len & 1) - result += (*buff) << 8; + result += (*buff << 8); result = from32to16(result); if (odd) result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); @@ -72,9 +115,43 @@ return result; } -extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +/* ihl is always 5 or greater, almost always is 5, iph is always word + * aligned but can fail to be dword aligned very often. + */ +extern inline unsigned short ip_fast_csum(const unsigned char *iph, unsigned int ihl) { - return ~do_csum(iph,ihl*4); + unsigned int sum; + + __asm__ __volatile__(" + ld [%1], %0 + sub %2, 4, %2 + ld [%1 + 0x4], %%g1 + ld [%1 + 0x8], %%g2 + addcc %%g1, %0, %0 + addxcc %%g2, %0, %0 + ld [%1 + 0xc], %%g1 + ld [%1 + 0x10], %%g2 + addxcc %%g1, %0, %0 + addxcc %0, %%g0, %0 +1: + addcc %%g2, %0, %0 + add %1, 0x4, %1 + addxcc %0, %%g0, %0 + subcc %2, 0x1, %2 + bne,a 1b + ld [%1 + 0x10], %%g2 + + sll %0, 16, %2 + addcc %0, %2, %2 + srl %2, 16, %0 + addx %0, %%g0, %2 + xnor %%g0, %2, %0 +2: + " + : "=&r" (sum), "=&r" (iph), "=&r" (ihl) + : "1" (iph), "2" (ihl) + : "g1", "g2"); + return sum; } /* @@ -91,13 +168,101 @@ */ extern inline unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum) { - unsigned long result = do_csum(buff, len); + __asm__ __volatile__(" + mov 0, %%g5 ! g5 = result + cmp %1, 0 + bgu,a 1f + andcc %0, 1, %%g7 ! g7 = odd + + b,a 9f + +1: + be,a 1f + srl %1, 1, %%g6 ! g6 = count = (len >> 1) + + sub %1, 1, %1 ! if(odd) { result = *buff; + ldub [%0], %%g5 ! len--; + add %0, 1, %0 ! buff++ } + + srl %1, 1, %%g6 +1: + cmp %%g6, 0 ! if (count) { + be,a 8f + andcc %1, 1, %%g0 + + andcc %0, 2, %%g0 ! if (2 & buff) { + be,a 1f + srl %%g6, 1, %%g6 + + sub %1, 2, %1 ! result += *(unsigned short *) buff; + lduh [%0], %%g1 ! count--; + sub %%g6, 1, %%g6 ! len -= 2; + add %%g1, %%g5, %%g5! buff += 2; + add %0, 2, %0 ! } + + srl %%g6, 1, %%g6 +1: + cmp %%g6, 0 ! if (count) { + be,a 2f + andcc %1, 2, %%g0 + + ld [%0], %%g1 ! csum aligned 32bit words +1: + add %0, 4, %0 + addcc %%g1, %%g5, %%g5 + addx %%g5, %%g0, %%g5 + subcc %%g6, 1, %%g6 + bne,a 1b + ld [%0], %%g1 + + sethi %%hi(0xffff), %%g3 + srl %%g5, 16, %%g2 + or %%g3, %%lo(0xffff), %%g3 + and %%g5, %%g3, %%g5 + add %%g2, %%g5, %%g5! } + + andcc %1, 2, %%g0 +2: + be,a 8f ! if (len & 2) { + andcc %1, 1, %%g0 + + lduh [%0], %%g1 ! result += *(unsigned short *) buff; + add %%g5, %%g1, %%g5! buff += 2; + add %0, 2, %0 ! } + + + andcc %1, 1, %%g0 +8: + be,a 1f ! if (len & 1) { + sll %%g5, 16, %%g1 + + ldub [%0], %%g1 + sll %%g1, 8, %%g1 ! result += (*buff << 8); + add %%g5, %%g1, %%g5! } + + sll %%g5, 16, %%g1 +1: + addcc %%g1, %%g5, %%g5! result = from32to16(result); + srl %%g5, 16, %%g1 + addx %%g0, %%g1, %%g5 + + orcc %%g7, %%g0, %%g0! if(odd) { + be 9f + srl %%g5, 8, %%g1 + + and %%g5, 0xff, %%g2! result = ((result >> 8) & 0xff) | + and %%g1, 0xff, %%g1! ((result & 0xff) << 8); + sll %%g2, 8, %%g2 + or %%g2, %%g1, %%g5! } +9: + addcc %2, %%g5, %2 ! add result and sum with carry + addx %%g0, %2, %2 + " : + "=&r" (buff), "=&r" (len), "=&r" (sum) : + "0" (buff), "1" (len), "2" (sum) : + "g1", "g2", "g3", "g5", "g6", "g7"); - /* add in old sum, and carry.. */ - result += sum; - /* 32+c bits -> 32 bits */ - result = (result & 0xffff) + (result >> 16); - return result; + return sum; } /* @@ -136,27 +301,17 @@ /* * Fold a partial checksum without adding pseudo headers */ - -static inline unsigned short csum_fold(unsigned int sum) +extern inline unsigned int csum_fold(unsigned int sum) { - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - return ~sum; -} - -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) -{ - return ~from32to16 (((saddr >> 16) + (saddr & 0xffff) + (daddr >> 16) - + (daddr & 0xffff) + (sum >> 16) + - (sum & 0xffff) + proto + len)); + __asm__ __volatile__(" + addcc %0, %1, %0 + srl %0, 16, %0 + addx %%g0, %0, %0 + xnor %%g0, %0, %0 + " + : "=r" (sum) + : "r" (sum << 16), "0" (sum)); + return sum; } #endif /* !(__SPARC_CHECKSUM_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/cypress.h linux/include/asm-sparc/cypress.h --- v1.3.92/linux/include/asm-sparc/cypress.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/cypress.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: cypress.h,v 1.2 1995/11/25 02:31:29 davem Exp $ +/* $Id: cypress.h,v 1.4 1996/03/12 17:48:12 davem Exp $ * cypress.h: Cypress module specific definitions and defines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -24,7 +24,7 @@ * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode * C: Cacheable -- Indicates whether accesses are cacheable while * the MMU is off. 0=no 1=yes - * MR: MemoryReflection -- Indicates whether the bus attached to the + * MR: MemoryReflection -- Indicates whether the bus attacted to the * MBus supports memory reflection. 0=no 1=yes (605 only) * CM: CacheMode -- Indicates whether the cache is operating in write * through or copy-back mode. 0=write-through 1=copy-back @@ -71,5 +71,9 @@ __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : "i" (ASI_M_FLUSH_CTX)); } + +/* XXX Displacement flushes for buggy chips and initial testing + * XXX go here. + */ #endif /* !(_SPARC_CYPRESS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/dma.h linux/include/asm-sparc/dma.h --- v1.3.92/linux/include/asm-sparc/dma.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/dma.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.13 1996/02/17 17:32:33 miguel Exp $ +/* $Id: dma.h,v 1.15 1996/03/23 02:40:00 davem Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) @@ -96,16 +96,20 @@ #define DMA_RST_ENET DMA_RST_SCSI /* Reset the ENET controller */ #define DMA_ST_WRITE 0x00000100 /* write from device to memory */ #define DMA_ENABLE 0x00000200 /* Fire up DMA, handle requests */ -#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pending Read */ +#define DMA_PEND_READ 0x00000400 /* DMA_VERS1/0/PLUS Pendind Read */ +#define DMA_DSBL_RD_DRN 0x00001000 /* No EC drain on slave reads */ #define DMA_BCNT_ENAB 0x00002000 /* If on, use the byte counter */ #define DMA_TERM_CNTR 0x00004000 /* Terminal counter */ #define DMA_CSR_DISAB 0x00010000 /* No FIFO drains during csr */ #define DMA_SCSI_DISAB 0x00020000 /* No FIFO drains during reg */ +#define DMA_DSBL_WR_INV 0x00020000 /* No EC inval. on slave writes */ #define DMA_ADD_ENABLE 0x00040000 /* Special ESC DVMA optimization */ -#define DMA_BRST_SZ 0x000c0000 /* SBUS transfer r/w burst size */ +#define DMA_E_BURST8 0x00040000 /* ENET: SBUS r/w burst size */ +#define DMA_BRST_SZ 0x000c0000 /* SCSI: SBUS r/w burst size */ #define DMA_ADDR_DISAB 0x00100000 /* No FIFO drains during addr */ #define DMA_2CLKS 0x00200000 /* Each transfer = 2 clock ticks */ #define DMA_3CLKS 0x00400000 /* Each transfer = 3 clock ticks */ +#define DMA_EN_ENETAUI DMA_3CLKS /* Put lance into AUI-cable mode */ #define DMA_CNTR_DISAB 0x00800000 /* No IRQ when DMA_TERM_CNTR set */ #define DMA_AUTO_NADDR 0x01000000 /* Use "auto nxt addr" feature */ #define DMA_SCSI_ON 0x02000000 /* Enable SCSI dma */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/ecc.h linux/include/asm-sparc/ecc.h --- v1.3.92/linux/include/asm-sparc/ecc.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/ecc.h Sun Apr 21 12:30:33 1996 @@ -101,7 +101,7 @@ * 31-18 17 16 15-8 7-4 3 2 1 0 * * C2E: A C2 graphics error occurred. 0=no 1=yes (SS10 only) - * MULT: Multiple errors occurred ;-O 0=no 1=prom_panic(yes) + * MULT: Multiple errors occurres ;-O 0=no 1=prom_panic(yes) * SYNDROME: Controller is mentally unstable. * DWORD: * UNC: Uncorrectable error. 0=no 1=yes diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/fbio.h linux/include/asm-sparc/fbio.h --- v1.3.92/linux/include/asm-sparc/fbio.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/fbio.h Sun Apr 21 12:30:33 1996 @@ -72,7 +72,7 @@ int emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */ }; #define FBIOSATTR _IOW('F', 5, struct fbgattr) /* Unsupported: */ -#define FBIOGATTR _IOR('F', 6, struct fbgattr) /* supported */ +#define FBIOGATTR _IOR('F', 6, struct fbgattr) /* supporoted */ #define FBIOSVIDEO _IOW('F', 7, int) #define FBIOGVIDEO _IOR('F', 8, int) diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/floppy.h linux/include/asm-sparc/floppy.h --- v1.3.92/linux/include/asm-sparc/floppy.h Sun Apr 21 12:39:02 1996 +++ linux/include/asm-sparc/floppy.h Sun Apr 21 12:30:33 1996 @@ -66,7 +66,6 @@ #define fd_cacheflush(addr, size) /* nothing... */ #define fd_request_irq() sun_fd_request_irq() #define fd_free_irq() /* nothing... */ -#define fd_eject(x) sun_fd_eject() #define FLOPPY_MOTOR_MASK 0x10 @@ -94,7 +93,7 @@ #define N_FDC 1 #define N_DRIVE 8 -/* No 64k boundary crossing problems on the Sparc. */ +/* No 64k boundry crossing problems on the Sparc. */ #define CROSS_64KB(a,s) (0) /* Routines unique to each controller type on a Sun. */ @@ -132,14 +131,12 @@ * drive attached to a Sun controller * and it will be at drive zero. */ -#if 0 - if(value & 0xf0) -#else - if(value & 0x10) -#endif - set_auxio(AUXIO_FLPY_DSEL, 0); - else - set_auxio(0, AUXIO_FLPY_DSEL); + { + unsigned bits = 0; + if (value & 0x10) bits |= AUXIO_FLPY_DSEL; + if ((value & 0x80) == 0) bits |= AUXIO_FLPY_EJCT; + set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT)); + } break; case 5: /* FD_DATA */ sun_fdc->data_82072 = value; @@ -261,21 +258,6 @@ pdma_areasize = pdma_size; } -static int sun_fd_eject(void) -{ - if(sparc_cpu_model == sun4c) { - set_auxio(AUXIO_FLPY_DSEL, AUXIO_FLPY_EJCT); - udelay(1000); - set_auxio(AUXIO_FLPY_EJCT, AUXIO_FLPY_DSEL); - } else { - set_dor(fdc, ~0, 0x90); - udelay(500); - set_dor(fdc, ~0x80, 0); - udelay(500); - } - return 0; -} - /* Our low-level entry point in arch/sparc/kernel/entry.S */ extern void floppy_hardint(int irq, void *unused, struct pt_regs *regs); @@ -343,34 +325,17 @@ goto no_sun_fdc; } - /* We need the version as early as possible to set up the - * function pointers correctly. Assume 82077 for probing - * purposes. - */ - sun_fdops.fd_inb = sun_82077_fd_inb; - sun_fdops.fd_outb = sun_82077_fd_outb; - fdc_status = &sun_fdc->status_82077; - - /* This controller detection technique is from the netbsd - * Sun floppy driver, originally Chris Torek of BSDI came - * up with this. It seems to work pretty well. - */ - if(sun_fdc->dor_82077 == 0x80) { - sun_fdc->dor_82077 = 2; - if(sun_fdc->dor_82077 == 0x80) { - /* Ok, it's really an 82072. */ - sun_fdops.fd_inb = sun_82072_fd_inb; - sun_fdops.fd_outb = sun_82072_fd_outb; - fdc_status = &sun_fdc->status_82072; - } + if(sparc_cpu_model == sun4c) { + sun_fdops.fd_inb = sun_82072_fd_inb; + sun_fdops.fd_outb = sun_82072_fd_outb; + fdc_status = &sun_fdc->status_82072; + /* printk("AUXIO @0x%p\n", auxio_register); */ /* P3 */ + } else { + sun_fdops.fd_inb = sun_82077_fd_inb; + sun_fdops.fd_outb = sun_82077_fd_outb; + fdc_status = &sun_fdc->status_82077; + /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */ } - - /* P3: The only reliable way which I found for ejection - * of boot floppy. AUXIO_FLPY_EJCT is not enough alone. - */ - set_auxio(AUXIO_FLPY_EJCT, 0); /* Bring EJECT line to normal. */ - udelay(1000); - sun_fd_eject(0); /* Send Eject Pulse. */ /* Success... */ return (int) sun_fdc; diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h --- v1.3.92/linux/include/asm-sparc/head.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/head.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: head.h,v 1.23 1996/02/15 09:12:55 davem Exp $ */ +/* $Id: head.h,v 1.26 1996/03/25 20:21:08 davem Exp $ */ #ifndef __SPARC_HEAD_H #define __SPARC_HEAD_H @@ -8,7 +8,7 @@ #define SRMMU_L1_KBASE_OFFSET ((KERNBASE>>24)<<2) /* Used in boot remapping. */ #define INTS_ENAB 0x01 /* entry.S uses this. */ -#define NCPUS 4 /* Architectural limit of sun4m. */ +#define NCPUS 4 /* Architectual limit of sun4m. */ #define SUN4_PROM_VECTOR 0xFFE81000 /* To safely die on a SUN4 */ #define SUN4_PRINTF 0x84 /* Offset into SUN4_PROM_VECTOR */ @@ -25,6 +25,8 @@ /* Data/text faults. Defaults to sun4c version at boot time. */ #define SPARC_TFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 1, %l7; #define SPARC_DFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 0, %l7; +#define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 1, %l7; +#define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b C_LABEL(srmmu_fault); mov 0, %l7; /* This is for traps we should NEVER get. */ #define BAD_TRAP(num) \ @@ -54,23 +56,23 @@ #define SOLARIS_SYSCALL_TRAP \ sethi %hi(C_LABEL(sys_call_table)), %l7; \ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ - b linux_sparc_syscall; \ + b solaris_syscall; \ rd %psr, %l0; /* Software trap for Sparc-netbsd system calls. */ #define NETBSD_SYSCALL_TRAP \ sethi %hi(C_LABEL(sys_call_table)), %l7; \ or %l7, %lo(C_LABEL(sys_call_table)), %l7; \ - b linux_sparc_syscall; \ + b bsd_syscall; \ rd %psr, %l0; /* The Get Condition Codes software trap for userland. */ #define GETCC_TRAP \ - b getcc_trap_handler; mov %psr, %l0; nop; nop + b getcc_trap_handler; mov %psr, %l0; nop; nop; /* The Set Condition Codes software trap for userland. */ #define SETCC_TRAP \ - b setcc_trap_handler; mov %psr, %l0; nop; nop + b setcc_trap_handler; mov %psr, %l0; nop; nop; /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and * gets handled with another macro. @@ -80,7 +82,7 @@ /* NMI's (Non Maskable Interrupts) are special, you can't keep them * from coming in, and basically if you get one, the shows over. ;( - * On the sun4c they are usually asynchronous memory errors, on the + * On the sun4c they are usually asyncronous memory errors, on the * the sun4m they could be either due to mem errors or a software * initiated interrupt from the prom/kern on an SMP box saying "I * command you to do CPU tricks, read your mailbox for more info." diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/ioctls.h linux/include/asm-sparc/ioctls.h --- v1.3.92/linux/include/asm-sparc/ioctls.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/ioctls.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,113 @@ +#ifndef _ASM_SPARC_IOCTLS_H +#define _ASM_SPARC_IOCTLS_H + +#include + +/* Big T */ +#define TCGETA _IOR('T', 1, struct termio) +#define TCSETA _IOW('T', 2, struct termio) +#define TCSETAW _IOW('T', 3, struct termio) +#define TCSETAF _IOW('T', 4, struct termio) +#define TCSBRK _IO('T', 5) +#define TCXONC _IO('T', 6) +#define TCFLSH _IO('T', 7) +#define TCGETS _IOR('T', 8, struct termios) +#define TCSETS _IOW('T', 9, struct termios) +#define TCSETSW _IOW('T', 10, struct termios) +#define TCSETSF _IOW('T', 11, struct termios) + +/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it + * someday. This is completely bogus, I know... + */ +#define TCGETSTAT _IO('T', 200) /* Rutgers specific */ +#define TCSETSTAT _IO('T', 201) /* Rutgers specific */ + +/* Little t */ +#define TIOCGETD _IOR('t', 0, int) +#define TIOCSETD _IOW('t', 1, int) +#define TIOCHPCL _IO('t', 2) /* SunOS Specific */ +#define TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ +#define TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ +#define TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ +#define TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ +#define TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ +#define TIOCEXCL _IO('t', 13) +#define TIOCNXCL _IO('t', 14) +#define TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ +#define TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ +#define TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ +#define TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ +#define TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ +#define TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ +#define TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ +#define TIOCCONS _IO('t', 36) +#define TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ +#define TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ +#define TIOCGSOFTCAR _IOR('t', 100, int) +#define TIOCSSOFTCAR _IOW('t', 101, int) +#define TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ +#define TIOCSWINSZ _IOW('t', 103, struct winsize) +#define TIOCGWINSZ _IOR('t', 104, struct winsize) +#define TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ +#define TIOCMGET _IOR('t', 106, int) +#define TIOCMBIC _IOW('t', 107, int) +#define TIOCMBIS _IOW('t', 108, int) +#define TIOCMSET _IOW('t', 109, int) +#define TIOCSTART _IO('t', 110) /* SunOS Specific */ +#define TIOCSTOP _IO('t', 111) /* SunOS Specific */ +#define TIOCPKT _IOW('t', 112, int) +#define TIOCNOTTY _IO('t', 113) +#define TIOCSTI _IOW('t', 114, char) +#define TIOCOUTQ _IOR('t', 115, int) +#define TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ +#define TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ +/* 118 is the non-posix setpgrp tty ioctl */ +/* 119 is the non-posix getpgrp tty ioctl */ +#define TIOCCDTR _IO('t', 120) /* SunOS Specific */ +#define TIOCSDTR _IO('t', 121) /* SunOS Specific */ +#define TIOCCBRK _IO('t', 122) /* SunOS Specific */ +#define TIOCSBRK _IO('t', 123) /* SunOS Specific */ +#define TIOCLGET _IOW('t', 124, int) /* SunOS Specific */ +#define TIOCLSET _IOW('t', 125, int) /* SunOS Specific */ +#define TIOCLBIC _IOW('t', 126, int) /* SunOS Specific */ +#define TIOCLBIS _IOW('t', 127, int) /* SunOS Specific */ +#define TIOCISPACE _IOR('t', 128, int) /* SunOS Specific */ +#define TIOCISIZE _IOR('t', 129, int) /* SunOS Specific */ +#define TIOCSPGRP _IOW('t', 130, int) +#define TIOCGPGRP _IOR('t', 131, int) +#define TIOCSCTTY _IO('t', 132) + +/* Little f */ +#define FIOCLEX _IO('f', 1) +#define FIONCLEX _IO('f', 2) +#define FIOASYNC _IOW('f', 125, int) +#define FIONBIO _IOW('f', 126, int) +#define FIONREAD _IOR('f', 127, int) +#define TIOCINQ FIONREAD + +/* Linux specific, no SunOS equivalent. */ +#define TIOCLINUX 0x541C +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TCSBRKP 0x5425 +#define TIOCTTYGSTRUCT 0x5426 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#endif /* !(_ASM_SPARC_IOCTLS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/iommu.h linux/include/asm-sparc/iommu.h --- v1.3.92/linux/include/asm-sparc/iommu.h Mon Mar 4 08:50:00 1996 +++ linux/include/asm-sparc/iommu.h Sun Apr 21 12:30:33 1996 @@ -92,6 +92,7 @@ /* The format of an iopte in the page tables */ #define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */ +#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */ #define IOPTE_WRITE 0x00000004 /* Writeable */ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -99,6 +100,8 @@ struct iommu_struct { struct iommu_regs *regs; iopte_t *page_table; + iopte_t *lowest; /* to speed up searches... */ + unsigned long plow; /* For convenience */ unsigned long start; /* First managed virtual address */ unsigned long end; /* Last managed virtual address */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/irq.h linux/include/asm-sparc/irq.h --- v1.3.92/linux/include/asm-sparc/irq.h Mon Mar 4 08:50:00 1996 +++ linux/include/asm-sparc/irq.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.8 1995/11/25 02:31:54 davem Exp $ +/* $Id: irq.h,v 1.12 1996/04/03 02:17:34 davem Exp $ * irq.h: IRQ registers on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -13,8 +13,26 @@ #define NR_IRQS 15 -extern void disable_irq(unsigned int); -extern void enable_irq(unsigned int); +/* Dave Redman (djhr@tadpole.co.uk) + * changed these to function pointers.. it saves cycles and will allow + * the irq dependancies to be split into different files at a later date + * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size. + */ +extern void (*disable_irq)(unsigned int); +extern void (*enable_irq)(unsigned int); +extern void (*clear_clock_irq)( void ); +extern void (*clear_profile_irq)( void ); +extern void (*load_profile_irq)( unsigned int timeout ); +extern void (*init_timers)(void (*lvl10_irq)(int, void *, struct pt_regs *)); +extern void claim_ticker14(void (*irq_handler)(int, void *, struct pt_regs *), + int irq, + unsigned int timeout); + +#ifdef __SMP__ +extern void (*set_cpu_int)(int, int); +extern void (*clear_cpu_int)(int, int); +extern void (*set_irq_udt)(int); +#endif extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname); @@ -23,7 +41,7 @@ */ /* These registers are used for sending/receiving irqs from/to - * different cpu's. + * different cpu's. */ struct sun4m_intreg_percpu { unsigned int tbt; /* Interrupts still pending for this cpu. */ @@ -36,6 +54,19 @@ unsigned char space[PAGE_SIZE - 12]; }; +/* + * djhr + * Actually the clear and set fields in this struct are misleading.. + * according to the SLAVIO manual (and the same applies for the SEC) + * the clear field clears bits in the mask which will ENABLE that IRQ + * the set field sets bits in the mask to DISABLE the IRQ. + * + * Also the undirected_xx address in the SLAVIO is defined as + * RESERVED and write only.. + * + * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor + * sun4m machines, for MP the layout makes more sense. + */ struct sun4m_intregs { struct sun4m_intreg_percpu cpu_intregs[NCPUS]; unsigned int tbt; /* IRQ's that are still pending. */ @@ -51,7 +82,8 @@ extern struct sun4m_intregs *sun4m_interrupts; -/* Bit field defines for the interrupt registers on various +/* + * Bit field defines for the interrupt registers on various * Sparc machines. */ @@ -64,11 +96,31 @@ #define SUN4C_INT_E4 0x04 /* Enable level 4 IRQ. */ #define SUN4C_INT_E1 0x02 /* Enable level 1 IRQ. */ -/* The sun4m interrupt registers. MUST RESEARCH THESE SOME MORE XXX */ -#define SUN4M_INT_ENABLE 0x80000000 -#define SUN4M_INT_E14 0x00000080 -#define SUN4M_INT_E10 0x00080000 +/* Dave Redman (djhr@tadpole.co.uk) + * The sun4m interrupt registers. + */ +#define SUN4M_INT_ENABLE 0x80000000 +#define SUN4M_INT_E14 0x00000080 +#define SUN4M_INT_E10 0x00080000 + +#define SUN4M_HARD_INT(x) (0x000000001 << (x)) +#define SUN4M_SOFT_INT(x) (0x000010000 << (x)) + +#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ +#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ +#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ +#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ +#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ +#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ +#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ +#define SUN4M_INT_REALTIME 0x00080000 /* system timer */ +#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */ +#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */ +#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */ +#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ +#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ +#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ -/* XXX add cross-cpu ipi functions XXX */ +#define SUN4M_INT_SBUS(x) (1 << (x+7)) #endif diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mbus.h linux/include/asm-sparc/mbus.h --- v1.3.92/linux/include/asm-sparc/mbus.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/mbus.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: mbus.h,v 1.5 1995/11/25 02:32:00 davem Exp $ +/* $Id: mbus.h,v 1.6 1996/04/16 09:34:31 zaitcev Exp $ * mbus.h: Various defines for MBUS modules. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -45,7 +45,7 @@ extern unsigned int hwbug_bitmask; /* First the module type values. To find out which you have, just load - * the mmu control register from ASI_M_MMUREG alternate address space and + * the mmu control register from ASI_M_MMUREG alternate adress space and * shift the value right 28 bits. */ /* IMPL field means the company which produced the chip. */ @@ -79,7 +79,7 @@ /* The CPU ID is encoded in the trap base register, 20 bits to the left of * bit zero, with 2 bits being significant. */ -#define TBR_ID_SHIFT 0x20 +#define TBR_ID_SHIFT 20 extern inline int get_cpuid(void) { diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/memreg.h linux/include/asm-sparc/memreg.h --- v1.3.92/linux/include/asm-sparc/memreg.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/memreg.h Sun Apr 21 12:30:33 1996 @@ -16,7 +16,7 @@ #define SUN4C_SYNC_SIZE 0x0002 /* bad access size? whuz this? */ #define SUN4C_SYNC_PARITY 0x0008 /* bad ram chips caused a parity error */ #define SUN4C_SYNC_SBUS 0x0010 /* the SBUS had some problems... */ -#define SUN4C_SYNC_NOMEM 0x0020 /* translation to non-existent ram */ +#define SUN4C_SYNC_NOMEM 0x0020 /* translation to non-existant ram */ #define SUN4C_SYNC_PROT 0x0040 /* access violated pte protections */ #define SUN4C_SYNC_NPRESENT 0x0080 /* pte said that page was not present */ #define SUN4C_SYNC_BADWRITE 0x8000 /* while writing something went bogus */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mman.h linux/include/asm-sparc/mman.h --- v1.3.92/linux/include/asm-sparc/mman.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/mman.h Sun Apr 21 12:30:33 1996 @@ -18,7 +18,7 @@ #define MAP_NORESERVE 0x40 /* don't reserve swap pages */ #define MAP_INHERIT 0x80 /* SunOS doesn't do this, but... */ #define MAP_LOCKED 0x100 /* lock the mapping */ -#define _MAP_NEW 0x80000000 /* Binary compatibility is fun... */ +#define _MAP_NEW 0x80000000 /* Binary compatability is fun... */ #define MAP_GROWSDOWN 0x0100 /* stack-like segment */ #define MAP_DENYWRITE 0x0800 /* ETXTBSY */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mostek.h linux/include/asm-sparc/mostek.h --- v1.3.92/linux/include/asm-sparc/mostek.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/mostek.h Sun Apr 21 12:30:33 1996 @@ -29,7 +29,7 @@ /* Control register values. */ #define MSTK_CREG_WRITE 0x80 /* Must set this before placing values. */ #define MSTK_CREG_READ 0x40 /* Stop the clock, I want to fetch values. */ -#define MSTK_CREG_SIGN 0x20 /* Grrr... what's this??? */ +#define MSTK_CREG_SIGN 0x20 /* Grrr... whats this??? */ #define MSTK_YR_ZERO 1968 /* If year reg has zero, it is 1968 */ #define MSTK_CVT_YEAR(yr) ((yr) + MSTK_YR_ZERO) diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mp.h linux/include/asm-sparc/mp.h --- v1.3.92/linux/include/asm-sparc/mp.h Sat Nov 25 04:32:08 1995 +++ linux/include/asm-sparc/mp.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: mp.h,v 1.2 1995/11/25 02:32:06 davem Exp $ +/* $Id: mp.h,v 1.3 1996/03/25 20:21:09 davem Exp $ * mp.h: Multiprocessing definitions for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -10,11 +10,9 @@ #include #include -extern int linux_smp_still_initting; - struct sparc_percpu { - struct tt_entry trap_table[NUM_SPARC_TRAPS]; /* One page */ - unsigned int kernel_stack[PAGE_SIZE/4]; /* One page */ + struct tt_entry *trap_table; + char *kernel_stack[PAGE_SIZE<<1]; int cpuid; /* Who am I? */ int cpu_is_alive; /* Linux has fired it up. */ int cpu_is_idling; /* Is sitting in the idle loop. */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mpmbox.h linux/include/asm-sparc/mpmbox.h --- v1.3.92/linux/include/asm-sparc/mpmbox.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/mpmbox.h Sun Apr 21 12:30:33 1996 @@ -38,7 +38,7 @@ */ #define MAILBOX_BPT_SPIN 0xfd -/* Oh geese, some other nitwit got a damn watchdog reset. The party's +/* Oh geese, some other nitwit got a damn watchdog reset. The partys * over so go call prom_stopcpu(). */ #define MAILBOX_WDOG_STOP 0xfe diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/msi.h linux/include/asm-sparc/msi.h --- v1.3.92/linux/include/asm-sparc/msi.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/msi.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,31 @@ +/* $Id: msi.h,v 1.1 1996/04/20 10:14:32 davem Exp $ + * msi.h: Defines specific to the MBus - Sbus - Interface. + * + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Eddie C. Dost (ecd@pool.informatik.rwth-aachen.de) + */ + +#ifndef _SPARC_MSI_H +#define _SPARC_MSI_H + +/* + * Locations of MSI Registers. + */ +#define MSI_MBUS_ARBEN 0xe0001008 /* MBus Arbiter Enable register */ + +/* + * Useful bits in the MSI Registers. + */ +#define MSI_ASYNC_MODE 0x80000000 /* Operate the MSI asynchronously */ + + +extern inline void msi_set_sync(void) +{ + __asm__ __volatile__ ("lda [%0] %1, %%g3\n\t" + "andn %%g3, %2, %%g3\n\t" + "sta %%g3, [%0] %1\n\t" : : + "r" (MSI_MBUS_ARBEN), + "i" (ASI_M_CTL), "r" (MSI_ASYNC_MODE) : "g3"); +} + +#endif /* !(_SPARC_MSI_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/mxcc.h linux/include/asm-sparc/mxcc.h --- v1.3.92/linux/include/asm-sparc/mxcc.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/mxcc.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: mxcc.h,v 1.2 1995/11/25 02:32:11 davem Exp $ +/* $Id: mxcc.h,v 1.3 1996/04/20 10:15:44 davem Exp $ * mxcc.h: Definitions of the Viking MXCC registers * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -19,6 +19,9 @@ #define MXCC_EREG 0x1C00E00 /* Error code register */ #define MXCC_PREG 0x1C00F04 /* Address port register */ +/* Some MXCC constants. */ +#define MXCC_STREAM_SIZE 0x20 /* Size in bytes of one stream r/w */ + /* The MXCC Control Register: * * ---------------------------------------------------------------------- @@ -48,7 +51,7 @@ * 31 30 29 28 27 26 25 24-15 14-7 6 5-3 2-0 * * ME: Multiple Errors have occurred - * CE: Cache consistency Error + * CE: Cache consistancy Error * PEW: Parity Error during a Write operation * PEE: Parity Error involving the External cache * ASE: ASynchronous Error @@ -79,5 +82,31 @@ * * MID: The moduleID of the cpu your read this from. */ + +extern inline void mxcc_set_stream_src(unsigned long *paddr) +{ + unsigned long data0 = paddr[0]; + unsigned long data1 = paddr[1]; + + __asm__ __volatile__ ("or %%g0, %0, %%g2\n\t" + "or %%g0, %1, %%g3\n\t" + "stda %%g2, [%2] %3\n\t" : : + "r" (data0), "r" (data1), + "r" (MXCC_SRCSTREAM), + "i" (ASI_M_MXCC) : "g2", "g3"); +} + +extern inline void mxcc_set_stream_dst(unsigned long *paddr) +{ + unsigned long data0 = paddr[0]; + unsigned long data1 = paddr[1]; + + __asm__ __volatile__ ("or %%g0, %0, %%g2\n\t" + "or %%g0, %1, %%g3\n\t" + "stda %%g2, [%2] %3\n\t" : : + "r" (data0), "r" (data1), + "r" (MXCC_DESSTREAM), + "i" (ASI_M_MXCC) : "g2", "g3"); +} #endif /* !(_SPARC_MXCC_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/oplib.h linux/include/asm-sparc/oplib.h --- v1.3.92/linux/include/asm-sparc/oplib.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/oplib.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.6 1996/01/01 02:47:19 davem Exp $ +/* $Id: oplib.h,v 1.7 1996/04/04 16:31:25 tridge Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * @@ -15,10 +15,11 @@ /* Enumeration to describe the prom major version we have detected. */ enum prom_major_version { - PROM_V0, /* Original sun4c V0 prom */ + PROM_V0, /* Origional sun4c V0 prom */ PROM_V2, /* sun4c and early sun4m V2 prom */ PROM_V3, /* sun4m and later, up to sun4d/sun4e machines V3 */ PROM_P1275, /* IEEE compliant ISA based Sun PROM, only sun4u */ + PROM_AP1000, /* actually no prom at all */ }; extern enum prom_major_version prom_vers; @@ -83,7 +84,7 @@ * entries. One for the total amount of physical ram on the machine, one * for the amount of physical ram available, and one describing the virtual * areas which are allocated by the prom. So, in a sense the physical - * available is a calculation of the total physical minus the physical mapped + * available is a calculation of the total physical minus the physcial mapped * by the prom with virtual mappings. * * These lists are returned pre-sorted, this should make your life easier diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h --- v1.3.92/linux/include/asm-sparc/page.h Mon Mar 4 08:50:01 1996 +++ linux/include/asm-sparc/page.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: page.h,v 1.26 1996/01/03 03:53:07 davem Exp $ +/* $Id: page.h,v 1.27 1996/04/18 01:33:42 davem Exp $ * page.h: Various defines and such for MMU operations on the Sparc for * the Linux kernel. * @@ -43,7 +43,9 @@ extern struct cache_palias *sparc_aliases; -#define STRICT_MM_TYPECHECKS +/* passing structs on the Sparc slow us down tremendously... */ + +/* #define STRICT_MM_TYPECHECKS */ #ifdef STRICT_MM_TYPECHECKS /* diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/pconf.h linux/include/asm-sparc/pconf.h --- v1.3.92/linux/include/asm-sparc/pconf.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/pconf.h Sun Apr 21 12:30:33 1996 @@ -1,6 +1,6 @@ /* $Id: pconf.h,v 1.2 1995/11/25 02:32:20 davem Exp $ * pconf.h: pathconf() and fpathconf() defines for SunOS - * system call compatibility. + * system call compatability. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -13,7 +13,7 @@ #define _PCONF_LINK 1 /* Max number of links to an object */ #define _PCONF_CANON 2 /* TTY input buffer line size */ -#define _PCONF_INPUT 3 /* Biggest packet a tty can imbibe at once */ +#define _PCONF_INPUT 3 /* Biggest packet a tty can inbibe at once */ #define _PCONF_NAME 4 /* Filename length max */ #define _PCONF_PATH 5 /* Max size of a pathname */ #define _PCONF_PIPE 6 /* Buffer size for a pipe */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h --- v1.3.92/linux/include/asm-sparc/pgtable.h Mon Mar 4 08:50:01 1996 +++ linux/include/asm-sparc/pgtable.h Sun Apr 21 17:32:02 1996 @@ -1,4 +1,4 @@ -/* $Id: pgtable.h,v 1.35 1996/02/21 17:57:30 miguel Exp $ */ +/* $Id: pgtable.h,v 1.45 1996/04/18 03:29:21 davem Exp $ */ #ifndef _SPARC_PGTABLE_H #define _SPARC_PGTABLE_H @@ -17,6 +17,8 @@ #include extern void load_mmu(void); +extern int io_remap_page_range(unsigned long from, unsigned long to, + unsigned long size, pgprot_t prot, int space); extern void (*quick_kernel_fault)(unsigned long); @@ -24,13 +26,25 @@ extern void (*mmu_exit_hook)(void); extern void (*mmu_flush_hook)(void); +/* translate between physical and virtual addresses */ +extern unsigned long (*mmu_v2p)(unsigned long); +extern unsigned long (*mmu_p2v)(unsigned long); + /* Routines for data transfer buffers. */ extern char *(*mmu_lockarea)(char *, unsigned long); extern void (*mmu_unlockarea)(char *, unsigned long); /* Routines for getting a dvma scsi buffer. */ -extern char *(*mmu_get_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus); -extern void (*mmu_release_scsi_buffer)(char *, unsigned long, struct linux_sbus *sbus); +struct mmu_sglist { + /* ick, I know... */ + char *addr; + char *alt_addr; + unsigned int len; +}; +extern char *(*mmu_get_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +extern void (*mmu_get_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); +extern void (*mmu_release_scsi_one)(char *, unsigned long, struct linux_sbus *sbus); +extern void (*mmu_release_scsi_sgl)(struct mmu_sglist *, int, struct linux_sbus *sbus); extern unsigned int pmd_shift; extern unsigned int pmd_size; @@ -130,7 +144,7 @@ #define BAD_PAGETABLE __bad_pagetable() #define BAD_PAGE __bad_page() -#define ZERO_PAGE (&empty_zero_page) +#define ZERO_PAGE ((unsigned long)(&(empty_zero_page))) /* number of bits that fit into a memory pointer */ #define BITS_PER_PTR (8*sizeof(unsigned long)) @@ -156,23 +170,17 @@ extern int (*pte_none)(pte_t); extern int (*pte_present)(pte_t); -extern int (*pte_inuse)(pte_t *); extern void (*pte_clear)(pte_t *); -extern void (*pte_reuse)(pte_t *); extern int (*pmd_none)(pmd_t); extern int (*pmd_bad)(pmd_t); extern int (*pmd_present)(pmd_t); -extern int (*pmd_inuse)(pmd_t *); extern void (*pmd_clear)(pmd_t *); -extern void (*pmd_reuse)(pmd_t *); extern int (*pgd_none)(pgd_t); extern int (*pgd_bad)(pgd_t); extern int (*pgd_present)(pgd_t); -extern int (*pgd_inuse)(pgd_t *); extern void (*pgd_clear)(pgd_t *); -extern void (*pgd_reuse)(pgd_t *); /* * The following only work if pte_present() is true. @@ -194,7 +202,7 @@ * and a page entry and page directory to the page they refer to. */ extern pte_t (*mk_pte)(unsigned long, pgprot_t); -extern pte_t (*mk_pte_io)(unsigned long, pgprot_t); +extern pte_t (*mk_pte_io)(unsigned long, pgprot_t, int); extern void (*pgd_set)(pgd_t *, pmd_t *); @@ -242,11 +250,51 @@ extern pgd_t * (*pgd_alloc)(void); -/* Fine grained invalidation. */ -extern void (*invalidate_all)(void); -extern void (*invalidate_mm)(struct mm_struct *); -extern void (*invalidate_range)(struct mm_struct *, unsigned long start, unsigned long end); -extern void (*invalidate_page)(struct vm_area_struct *, unsigned long address); +/* Fine grained cache/tlb flushing. */ + +#ifdef __SMP__ +extern void (*local_flush_cache_all)(void); +extern void (*local_flush_cache_mm)(struct mm_struct *); +extern void (*local_flush_cache_range)(struct mm_struct *, unsigned long start, + unsigned long end); +extern void (*local_flush_cache_page)(struct vm_area_struct *, unsigned long address); + +extern void (*local_flush_tlb_all)(void); +extern void (*local_flush_tlb_mm)(struct mm_struct *); +extern void (*local_flush_tlb_range)(struct mm_struct *, unsigned long start, + unsigned long end); +extern void (*local_flush_tlb_page)(struct vm_area_struct *, unsigned long address); + +extern void (*local_flush_page_to_ram)(unsigned long address); + +extern void smp_flush_cache_all(void); +extern void smp_flush_cache_mm(struct mm_struct *mm); +extern void smp_flush_cache_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); + +extern void smp_flush_tlb_all(void); +extern void smp_flush_tlb_mm(struct mm_struct *mm); +extern void smp_flush_tlb_range(struct mm_struct *mm, + unsigned long start, + unsigned long end); +extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); +extern void smp_flush_page_to_ram(unsigned long page); +#endif + +extern void (*flush_cache_all)(void); +extern void (*flush_cache_mm)(struct mm_struct *); +extern void (*flush_cache_range)(struct mm_struct *, unsigned long start, + unsigned long end); +extern void (*flush_cache_page)(struct vm_area_struct *, unsigned long address); + +extern void (*flush_tlb_all)(void); +extern void (*flush_tlb_mm)(struct mm_struct *); +extern void (*flush_tlb_range)(struct mm_struct *, unsigned long start, unsigned long end); +extern void (*flush_tlb_page)(struct vm_area_struct *, unsigned long address); + +extern void (*flush_page_to_ram)(unsigned long page); /* The permissions for pgprot_val to make a page mapped on the obio space */ extern unsigned int pg_iobits; @@ -258,7 +306,13 @@ * within a page table are directly modified. Thus, the following * hook is made available. */ + +#if 0 /* XXX try this soon XXX */ +extern void (*set_pte)(struct vm_area_struct *vma, unsigned long address, + pte_t *pteptr, pte_t pteval); +#else extern void (*set_pte)(pte_t *pteptr, pte_t pteval); +#endif extern char *(*mmu_info)(void); @@ -271,13 +325,13 @@ extern int invalid_segment; #define SWP_TYPE(entry) (((entry)>>2) & 0x7f) -#define SWP_OFFSET(entry) ((entry) >> 9) +#define SWP_OFFSET(entry) (((entry) >> 9) & 0x7ffff) #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9)) struct ctx_list { struct ctx_list *next; struct ctx_list *prev; - unsigned char ctx_number; + unsigned int ctx_number; struct mm_struct *ctx_mm; }; diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/pgtsrmmu.h linux/include/asm-sparc/pgtsrmmu.h --- v1.3.92/linux/include/asm-sparc/pgtsrmmu.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/pgtsrmmu.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: pgtsrmmu.h,v 1.13 1996/03/01 07:20:54 davem Exp $ +/* $Id: pgtsrmmu.h,v 1.16 1996/04/04 16:31:32 tridge Exp $ * pgtsrmmu.h: SRMMU page table defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ #ifndef _SPARC_PGTSRMMU_H #define _SPARC_PGTSRMMU_H +#include #include /* PMD_SHIFT determines the size of the area a second-level page table can map */ @@ -29,7 +30,7 @@ #define SRMMU_PMD_TABLE_SIZE 0x100 /* 64 entries, 4 bytes a piece */ #define SRMMU_PGD_TABLE_SIZE 0x400 /* 256 entries, 4 bytes a piece */ -#define SRMMU_VMALLOC_START (0xfe100000) +#define SRMMU_VMALLOC_START (0xfe200000) /* Definition of the values in the ET field of PTD's and PTE's */ #define SRMMU_ET_MASK 0x3 @@ -106,6 +107,10 @@ extern inline void srmmu_set_ctable_ptr(unsigned long paddr) { paddr = ((paddr >> 4) & SRMMU_CTX_PMASK); +#if CONFIG_AP1000 + /* weird memory system on the AP1000 */ + paddr |= (0x8<<28); +#endif __asm__ __volatile__("sta %0, [%1] %2\n\t" : : "r" (paddr), "r" (SRMMU_CTXTBL_PTR), "i" (ASI_M_MMUREGS) : @@ -160,7 +165,7 @@ return retval; } -/* This is guaranteed on all SRMMU's. */ +/* This is guarenteed on all SRMMU's. */ extern inline void srmmu_flush_whole_tlb(void) { __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : @@ -210,6 +215,7 @@ { unsigned long retval; + vaddr &= PAGE_MASK; __asm__ __volatile__("lda [%1] %2, %0\n\t" : "=r" (retval) : "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE)); diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h --- v1.3.92/linux/include/asm-sparc/pgtsun4c.h Mon Mar 4 08:50:02 1996 +++ linux/include/asm-sparc/pgtsun4c.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: pgtsun4c.h,v 1.22 1996/01/24 02:33:45 davem Exp $ +/* $Id: pgtsun4c.h,v 1.24 1996/03/26 06:51:56 miguel Exp $ * pgtsun4c.h: Sun4c specific pgtable.h defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -37,7 +37,7 @@ * translations at KERNBASE + 128MB for 1MB, then we begin the VMALLOC * area, makes sense. This works out to the value below. */ -#define SUN4C_VMALLOC_START (0xfe100000) +#define SUN4C_VMALLOC_START (0xfe200000) /* * Sparc SUN4C pte fields. @@ -64,9 +64,6 @@ #define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \ _SUN4C_PAGE_PRIV | _SUN4C_PAGE_DIRTY | \ _SUN4C_PAGE_REF | _SUN4C_PAGE_NOCACHE) - -extern char *sun4c_lockarea(char *vaddr, unsigned long size); -extern void sun4c_unlockarea(char *vaddr, unsigned long size); extern __inline__ unsigned long sun4c_get_synchronous_error(void) { diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/posix_types.h linux/include/asm-sparc/posix_types.h --- v1.3.92/linux/include/asm-sparc/posix_types.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/posix_types.h Sun Apr 21 12:30:33 1996 @@ -0,0 +1,90 @@ +#ifndef __ARCH_SPARC_POSIX_TYPES_H +#define __ARCH_SPARC_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +/* When cross-compilation is no longer an issue, fix this. */ +#ifdef __svr4__ +typedef unsigned int __kernel_size_t; /* solaris sucks */ +#else +typedef long unsigned int __kernel_size_t; /* sunos is much better */ +#endif /* !(__svr4__) */ + +typedef int __kernel_ssize_t; +typedef long int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_clock_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_umode_t; +typedef short __kernel_nlink_t; +typedef long __kernel_daddr_t; +typedef long __kernel_off_t; +typedef char * __kernel_caddr_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] |= (1UL<<_rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); +} + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant cases (4 or 8 longs, + * for 256 and 512-bit fd_sets respectively) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(__kernel_fd_set *p) +{ + unsigned int *tmp = p->fds_bits; + int i; + + if (__builtin_constant_p(__FDSET_INTS)) { + switch (__FDSET_INTS) { + case 8: + tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; + tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; + return; + case 4: + tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; + return; + } + } + i = __FDSET_INTS; + while (i) { + i--; + *tmp = 0; + tmp++; + } +} + +#endif /* !(__ARCH_SPARC_POSIX_TYPES_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h --- v1.3.92/linux/include/asm-sparc/processor.h Mon Mar 4 08:50:02 1996 +++ linux/include/asm-sparc/processor.h Sun Apr 21 12:30:33 1996 @@ -1,4 +1,4 @@ -/* $Id: processor.h,v 1.40 1996/02/03 10:06:01 davem Exp $ +/* $Id: processor.h,v 1.43 1996/03/23 02:40:05 davem Exp $ * include/asm-sparc/processor.h * * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) @@ -24,10 +24,10 @@ #define MCA_bus__is_a_macro /* for versions in ksyms.c */ /* - * Write Protection works right in supervisor mode on the Sparc... - * And then there came the Swift module, which isn't so swift... + * The sparc has no problems with write protection */ -extern char wp_works_ok; +#define wp_works_ok 1 +#define wp_works_ok__is_a_macro /* for versions in ksyms.c */ /* Whee, this is STACK_TOP and the lowest kernel address too... */ #define TASK_SIZE (KERNBASE) @@ -122,14 +122,14 @@ regs->pc = ((pc & (~3)) - 4); regs->npc = regs->pc + 4; regs->psr = saved_psr; - regs->u_regs[UREG_G1] = sp; /* Base of arg/env stack area */ - regs->u_regs[UREG_G2] = regs->u_regs[UREG_G7] = regs->npc; regs->u_regs[UREG_FP] = (sp - REGWIN_SZ); } +#ifdef __KERNEL__ extern unsigned long (*alloc_kernel_stack)(struct task_struct *tsk); extern void (*free_kernel_stack)(unsigned long stack); extern struct task_struct *(*alloc_task_struct)(void); extern void (*free_task_struct)(struct task_struct *tsk); +#endif #endif /* __ASM_SPARC_PROCESSOR_H */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/ross.h linux/include/asm-sparc/ross.h --- v1.3.92/linux/include/asm-sparc/ross.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/ross.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: ross.h,v 1.4 1996/01/03 03:53:20 davem Exp $ +/* $Id: ross.h,v 1.9 1996/04/08 08:34:21 davem Exp $ * ross.h: Ross module specific definitions and defines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -52,60 +52,11 @@ #define HYPERSPARC_NFAULT 0x00000002 #define HYPERSPARC_MENABLE 0x00000001 -/* Flushes which clear out only the on-chip Ross HyperSparc ICACHE. */ -extern inline void hyper_flush_i_page(unsigned int addr) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : - "r" (addr), "i" (ASI_M_IFLUSH_PAGE) : - "memory"); - return; -} - -extern inline void hyper_flush_i_seg(unsigned int addr) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : - "r" (addr), "i" (ASI_M_IFLUSH_SEG) : - "memory"); - return; -} - -extern inline void hyper_flush_i_region(unsigned int addr) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : - "r" (addr), "i" (ASI_M_IFLUSH_REGION) : - "memory"); - return; -} - -extern inline void hyper_flush_i_ctx(unsigned int addr) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : - "r" (addr), "i" (ASI_M_IFLUSH_CTX) : - "memory"); - return; -} - -extern inline void hyper_flush_i_user(unsigned int addr) -{ - __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : - "r" (addr), "i" (ASI_M_IFLUSH_USER) : - "memory"); - return; -} - -/* Finally, flush the entire ICACHE. */ -extern inline void hyper_flush_whole_icache(void) -{ - __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : - "i" (ASI_M_FLUSH_IWHOLE)); - return; -} - /* The ICCR instruction cache register on the HyperSparc. * * ----------------------------------------------- - * | | FTD | IDC | + * | | FTD | ICE | * ----------------------------------------------- * 31 1 0 * @@ -125,13 +76,29 @@ * * All other bits are read as zeros, and writes to them have no * effect. + * + * Wheee, not many assemblers understand the %iccr register nor + * the generic asr r/w instructions. + * + * 1000 0011 0100 0111 1100 0000 0000 0000 ! rd %iccr, %g1 + * + * 0x 8 3 4 7 c 0 0 0 ! 0x8347c000 + * + * 1011 1111 1000 0000 0110 0000 0000 0000 ! wr %g1, 0x0, %iccr + * + * 0x b f 8 0 6 0 0 0 ! 0xbf806000 + * */ +#define HYPERSPARC_ICCR_FTD 0x00000002 +#define HYPERSPARC_ICCR_ICE 0x00000001 + extern inline unsigned int get_ross_icr(void) { unsigned int icreg; - __asm__ __volatile__(".word 0xbf402000\n\t" : /* rd %iccr, %g1 */ + __asm__ __volatile__(".word 0x8347c000\n\t" /* rd %iccr, %g1 */ + "mov %%g1, %0\n\t" : "=r" (icreg) : : "g1", "memory"); @@ -141,7 +108,7 @@ extern inline void put_ross_icr(unsigned int icreg) { __asm__ __volatile__("or %%g0, %0, %%g1\n\t" - ".word 0xbf802000\n\t" /* wr %g1, 0x0, %iccr */ + ".word 0xbf806000\n\t" /* wr %g1, 0x0, %iccr */ "nop\n\t" "nop\n\t" "nop\n\t" : : @@ -153,17 +120,55 @@ /* HyperSparc specific cache flushing. */ +/* This is for the on-chip instruction cache. */ +extern inline void hyper_flush_whole_icache(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i" (ASI_M_FLUSH_IWHOLE)); + return; +} + extern int hyper_cache_size; +extern int hyper_line_size; + +extern inline void hyper_clear_all_tags(void) +{ + unsigned long addr; + + for(addr = 0; addr < hyper_cache_size; addr += hyper_line_size) + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_DATAC_TAG)); +} -extern inline void hyper_flush_all_combined(void) +extern inline void hyper_flush_unconditional_combined(void) { unsigned long addr; - for(addr = 0; addr < hyper_cache_size; addr += 32) - __asm__ __volatile__("sta %%g0, [%0] 0xe\n\t" : : - "r" (addr)); + for(addr = 0; addr < hyper_cache_size; addr += hyper_line_size) + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_FLUSH_CTX)); } +extern inline void hyper_flush_cache_user(void) +{ + unsigned long addr; + for(addr = 0; addr < hyper_cache_size; addr += hyper_line_size) + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_FLUSH_USER)); +} + +extern inline void hyper_flush_cache_page(unsigned long page) +{ + unsigned long end; + + page &= PAGE_MASK; + end = page + PAGE_SIZE; + while(page < end) { + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (page), "i" (ASI_M_FLUSH_PAGE)); + page += hyper_line_size; + } +} #endif /* !(_SPARC_ROSS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/segment.h linux/include/asm-sparc/segment.h --- v1.3.92/linux/include/asm-sparc/segment.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/segment.h Sun Apr 21 12:30:34 1996 @@ -1,8 +1,10 @@ -/* $Id: segment.h,v 1.9 1996/01/14 00:05:33 davem Exp $ */ +/* $Id: segment.h,v 1.10 1996/03/08 01:19:38 miguel Exp $ */ #ifndef _ASM_SEGMENT_H #define _ASM_SEGMENT_H +#ifdef __KERNEL__ #include +#endif #ifndef __ASSEMBLY__ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/signal.h linux/include/asm-sparc/signal.h --- v1.3.92/linux/include/asm-sparc/signal.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/signal.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.17 1996/03/01 07:21:02 davem Exp $ */ +/* $Id: signal.h,v 1.20 1996/03/24 20:21:27 davem Exp $ */ #ifndef _ASMSPARC_SIGNAL_H #define _ASMSPARC_SIGNAL_H @@ -120,13 +120,28 @@ * irq handling routines. * * SA_INTERRUPT is also used by the irq handling routines. + * + * DJHR + * SA_STATIC_ALLOC is used for the SPARC system to indicate that this + * interupt handler's irq structure should be statically allocated + * by the request_irq routine. + * The alternative is that arch/sparc/kernel/irq.c has carnal knowledge + * of interrupt usage and that sucks. Also without a flag like this + * it may be possible for the free_irq routine to attempt to free + * statically allocated data.. which is NOT GOOD. + * */ #define SA_PROBE SA_ONESHOT #define SA_SAMPLE_RANDOM SA_RESTART +#define SA_STATIC_ALLOC 0x80 #endif /* Type of a signal handler. */ +#ifdef __KERNEL__ typedef void (*__sighandler_t)(int, int, struct sigcontext_struct *, char *); +#else +typedef void (*__sighandler_t)(int); +#endif #define SIG_DFL ((__sighandler_t)0) /* default signal handling */ #define SIG_IGN ((__sighandler_t)1) /* ignore signal */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/smp.h linux/include/asm-sparc/smp.h --- v1.3.92/linux/include/asm-sparc/smp.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/smp.h Sun Apr 21 12:30:34 1996 @@ -6,73 +6,142 @@ #ifndef _SPARC_SMP_H #define _SPARC_SMP_H -#include -#include +#ifdef __SMP__ -/* Per processor Sparc parameters. */ +#ifndef __ASSEMBLY__ + +/* PROM provided per-processor information we need + * to start them all up. + */ + +struct prom_cpuinfo { + int prom_node; + int mid; +}; + +extern struct prom_cpuinfo linux_cpus[NCPUS]; + +/* Per processor Sparc parameters we need. */ struct cpuinfo_sparc { - unsigned char impl; - unsigned char vers; - unsigned long udelay_val; + unsigned long udelay_val; /* thats it */ }; extern struct cpuinfo_sparc cpu_data[NR_CPUS]; -typedef klock_t volatile unsigned char; -extern klock_t kernel_lock; +typedef volatile unsigned char klock_t; +extern klock_t kernel_flag; #define KLOCK_HELD 0xff #define KLOCK_CLEAR 0x00 -struct sparc_ipi_invalidate { - struct mm_struct *mm; - unsigned long addr; /* page for inv_pg, start for inv_rnge */ - unsigned long end; /* Used for inv_rnge only. */ -}; - -struct sparc_ipimsg { - union { - /* Add more here as we need them. */ - struct sparc_ipi_invalidate invmsg; - }; -}; - -extern void smp_scan_prom_for_cpus(unsigned long, unsigned long); -extern unsigned long smp_alloc_memory(unsigned long mem_base); -extern unsigned long *kernel_stacks[NR_CPUS]; +/* + * Private routines/data + */ + +extern int smp_found_cpus; extern unsigned char boot_cpu_id; extern unsigned long cpu_present_map; -extern volatile unsigned long smp_invalidate_needed; -extern unsigned long kernel_counter; +extern volatile unsigned long smp_invalidate_needed[NR_CPUS]; +extern volatile unsigned long kernel_counter; extern volatile unsigned char active_kernel_processor; -extern void smp_message_irq(int cpl, struct pt_regs *regs); -extern void smp_reschedule_irq(int cpl, struct pt_regs *regs); -extern void smp_invalidate_rcv(void); -extern volatils unsigned long syscall_count; - -extern void (*smp_invalidate_all)(void); -extern void (*smp_invalidate_mm)(struct mm_struct *); -extern void (*smp_invalidate_range)(struct mm_struct *, unsigned long, unsigned long); -extern void (*smp_invalidate_page)(struct vm_area_struct *, unsigned long); +extern void smp_message_irq(void); +extern unsigned long ipi_count; +extern volatile unsigned long kernel_counter; +extern volatile unsigned long syscall_count; + +extern void print_lock_state(void); + +typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long, + unsigned long, unsigned long); + +/* + * General functions that each host system must provide. + */ extern void smp_callin(void); extern void smp_boot_cpus(void); extern void smp_store_cpu_info(int id); +extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5); +extern void smp_capture(void); +extern void smp_release(void); + +extern inline void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); } +extern inline void xc1(smpfunc_t func, unsigned long arg1) +{ smp_cross_call(func, arg1, 0, 0, 0, 0); } +extern inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2) +{ smp_cross_call(func, arg1, arg2, 0, 0, 0); } +extern inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); } +extern inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4) +{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); } +extern inline void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2, + unsigned long arg3, unsigned long arg4, unsigned long arg5) +{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); } -extern _inline_ int smp_processor_id(void) +extern volatile int cpu_number_map[NR_CPUS]; +extern volatile int cpu_logical_map[NR_CPUS]; + +extern __inline int smp_processor_id(void) { int cpuid; __asm__ __volatile__("rd %%tbr, %0\n\t" - "srl %0, 24, %0\n\t" + "srl %0, 12, %0\n\t" "and %0, 3, %0\n\t" : - "=&r" (cpuid) : - "0" (cpuid)); + "=&r" (cpuid)); return cpuid; } -/* Empirical PROM processor mailbox constants. If the per-cpu mailbox + +extern volatile unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */ +extern volatile int smp_process_available; + +extern inline int smp_swap(volatile int *addr, int value) +{ + __asm__ __volatile__("swap [%2], %0\n\t" : + "=&r" (value) : + "0" (value), "r" (addr)); + return value; +} + +extern inline volatile void inc_smp_counter(volatile int *ctr) +{ + int tmp; + + while((tmp = smp_swap(ctr, -1)) == -1) + ; + smp_swap(ctr, (tmp + 1)); +} + +extern inline volatile void dec_smp_counter(volatile int *ctr) +{ + int tmp; + + while((tmp = smp_swap(ctr, -1)) == -1) + ; + smp_swap(ctr, (tmp - 1)); +} + +extern inline volatile int read_smp_counter(volatile int *ctr) +{ + int value; + + while((value = *ctr) == -1) + ; + return value; +} + +#endif /* !(__ASSEMBLY__) */ + +/* Sparc specific messages. */ +#define MSG_CAPTURE 0x0004 /* Park a processor. */ +#define MSG_CROSS_CALL 0x0005 /* run func on cpus */ + +/* Imperical PROM processor mailbox constants. If the per-cpu mailbox * contains something other than one of these then the ipi is from * Linux's active_kernel_processor. This facility exists so that * the boot monitor can capture all the other cpus when one catches @@ -86,6 +155,11 @@ #define NO_PROC_ID 0xFF -#define PROC_CHANGE_PENALTY 0x23 +#define PROC_CHANGE_PENALTY 20 + +#define SMP_FROM_INT 1 +#define SMP_FROM_SYSCALL 2 + +#endif /* !(__SMP__) */ #endif /* !(_SPARC_SMP_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/smp_lock.h linux/include/asm-sparc/smp_lock.h --- v1.3.92/linux/include/asm-sparc/smp_lock.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/smp_lock.h Sun Apr 21 12:30:34 1996 @@ -6,31 +6,33 @@ #ifndef __SPARC_SMPLOCK_H #define __SPARC_SMPLOCK_H -#ifdef __SMP__ +#include +#include +#include +#include -extern _inline_ unsigned char ldstub(klock_t *lock) -{ - klock_t retval; +#ifdef __SMP__ - __asm__ __volatile__("ldstub [%1], %0\n\t" : - "=r" (retval) : - "r" (lock)); - return retval; -} +/* + * Locking the kernel + */ /* Knock knock... */ -extern _inline_ void lock_kernel(void) +extern __inline void lock_kernel(void) { unsigned long flags; int proc = smp_processor_id(); save_flags(flags); cli(); /* need this on sparc? */ - while(ldstub(&kernel_lock)) { + while(ldstub(&kernel_flag)) { if(proc == active_kernel_processor) break; - if(test_bit(proc, (unsigned long *)&smp_invalidate_needed)) - if(clear_bit(proc, (unsigned long *)&smp_invalidate_needed)) - local_invalidate(); + do { +#ifdef __SMP_PROF__ + smp_spins[smp_processor_id()]++; +#endif + barrier(); + } while(kernel_flag); /* Don't lock the bus more than we have to. */ } active_kernel_processor = proc; kernel_counter++; @@ -38,18 +40,19 @@ } /* I want out... */ -extern _inline_ void unlock_kernel(void) +extern __inline void unlock_kernel(void) { unsigned long flags; save_flags(flags); cli(); /* need this on sparc? */ if(kernel_counter == 0) panic("Bogus kernel counter.\n"); + if(!--kernel_counter) { active_kernel_processor = NO_PROC_ID; - kernel_lock = KLOCK_CLEAR; + kernel_flag = KLOCK_CLEAR; } - restore_flag(flags); + restore_flags(flags); } #endif /* !(__SPARC_SMPLOCK_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/socket.h linux/include/asm-sparc/socket.h --- v1.3.92/linux/include/asm-sparc/socket.h Sun Nov 26 11:50:02 1995 +++ linux/include/asm-sparc/socket.h Sun Apr 21 12:30:34 1996 @@ -1,14 +1,8 @@ -/* $Id: socket.h,v 1.5 1995/11/26 01:32:36 davem Exp $ */ +/* $Id: socket.h,v 1.6 1996/04/04 12:51:26 davem Exp $ */ #ifndef _ASM_SOCKET_H #define _ASM_SOCKET_H -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp */ +#include /* For setsockoptions(2) */ #define SOL_SOCKET 0xffff diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/sockios.h linux/include/asm-sparc/sockios.h --- v1.3.92/linux/include/asm-sparc/sockios.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/sockios.h Sun Apr 21 12:30:34 1996 @@ -0,0 +1,13 @@ +#ifndef _ASM_SPARC_SOCKIOS_H +#define _ASM_SPARC_SOCKIOS_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif /* !(_ASM_SPARC_SOCKIOS_H) */ + diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/solerrno.h linux/include/asm-sparc/solerrno.h --- v1.3.92/linux/include/asm-sparc/solerrno.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/solerrno.h Sun Apr 21 12:30:34 1996 @@ -1,5 +1,5 @@ -/* $Id: solerrno.h,v 1.3 1995/11/25 02:32:51 davem Exp $ - * solerrno.h: Solaris error return codes for compatibility. +/* $Id: solerrno.h,v 1.4 1996/03/23 02:40:09 davem Exp $ + * solerrno.h: Solaris error return codes for compatability. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) */ @@ -41,7 +41,7 @@ #define SOL_EPIPE 32 /* Call a plumber */ #define SOL_EDOM 33 /* Argument was out of fct domain */ #define SOL_ERANGE 34 /* Could not represent math result */ -#define SOL_ENOMSG 35 /* Message of req type doesn't exist */ +#define SOL_ENOMSG 35 /* Message of req type doesnt exist */ #define SOL_EIDRM 36 /* Identifier has been removed */ #define SOL_ECHRNG 37 /* Req channel number out of range */ #define SOL_EL2NSYNC 38 /* Could not sync at run level 2 */ @@ -122,7 +122,7 @@ #define SOL_ETOOMANYREFS 144 /* Reference limit exceeded */ #define SOL_ETIMEDOUT 145 /* Timed out connection */ #define SOL_ECONNREFUSED 146 /* Connection refused by remote host*/ -#define SOL_EHOSTDOWN 147 /* Remote host in up in flames */ +#define SOL_EHOSTDOWN 147 /* Remote host is up in flames */ #define SOL_EHOSTUNREACH 148 /* Make a left at Easton Ave..... */ #define SOL_EWOULDBLOCK EAGAIN /* Just an alias */ #define SOL_EALREADY 149 /* Operation is already occurring */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/string.h linux/include/asm-sparc/string.h --- v1.3.92/linux/include/asm-sparc/string.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/string.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: string.h,v 1.17 1995/12/10 06:25:48 davem Exp $ +/* $Id: string.h,v 1.19 1996/03/23 02:40:10 davem Exp $ * string.h: External definitions for optimized assembly string * routines for the Linux Kernel. * @@ -11,5 +11,7 @@ #define __HAVE_ARCH_BCOPY #define __HAVE_ARCH_MEMMOVE #define __HAVE_ARCH_MEMCPY +#define __HAVE_ARCH_MEMSET +#define __HAVE_ARCH_STRLEN #endif /* !(__SPARC_STRING_H__) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/swift.h linux/include/asm-sparc/swift.h --- v1.3.92/linux/include/asm-sparc/swift.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/swift.h Sun Apr 21 12:30:34 1996 @@ -1,5 +1,5 @@ /* swift.h: Specific definitions for the _broken_ Swift SRMMU - * MMU. + * MMU module. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ @@ -38,6 +38,33 @@ "r" (addr), "i" (ASI_M_DATAC_TAG)); } +extern inline void swift_flush_dcache(void) +{ + unsigned long addr; + + for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) + swift_inv_data_tag(addr); +} + +extern inline void swift_flush_icache(void) +{ + unsigned long addr; + + for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) + swift_inv_insn_tag(addr); +} + +extern inline void swift_idflash_clear(void) +{ + unsigned long addr; + + for(addr = 0; addr < (PAGE_SIZE << 2); addr += 16) { + swift_inv_insn_tag(addr); + swift_inv_data_tag(addr); + } +} + +/* Swift is so broken, it isn't even safe to use the following. */ extern inline void swift_flush_page(unsigned long page) { __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h --- v1.3.92/linux/include/asm-sparc/system.h Mon Mar 4 08:50:03 1996 +++ linux/include/asm-sparc/system.h Sun Apr 21 12:30:34 1996 @@ -1,13 +1,16 @@ -/* $Id: system.h,v 1.24 1996/02/11 00:42:39 davem Exp $ */ +/* $Id: system.h,v 1.29 1996/04/03 02:17:52 davem Exp $ */ #ifndef __SPARC_SYSTEM_H #define __SPARC_SYSTEM_H #include #include + +#ifdef __KERNEL__ #include #include #include +#endif #define EMPTY_PGT (&empty_bad_page) #define EMPTY_PGE (&empty_bad_page_table) @@ -44,13 +47,40 @@ extern void flush_user_windows(void); extern void synchronize_user_stack(void); extern void sparc_switch_to(void *new_task); -#define switch_to(p) do { \ +#ifndef __SMP__ +#define switch_to(prev, next) do { \ + flush_user_windows(); \ + switch_to_context(next); \ + prev->tss.current_ds = active_ds; \ + active_ds = next->tss.current_ds; \ + if(last_task_used_math != next) \ + next->tss.kregs->psr &= ~PSR_EF; \ + sparc_switch_to(next); \ + } while(0) +#else + +extern void fpsave(unsigned long *fpregs, unsigned long *fsr, + void *fpqueue, unsigned long *fpqdepth); + +#define switch_to(prev, next) do { \ + cli(); \ + if(prev->flags & PF_USEDFPU) { \ + fpsave(&prev->tss.float_regs[0], &prev->tss.fsr, \ + &prev->tss.fpqueue[0], &prev->tss.fpqdepth); \ + prev->flags &= ~PF_USEDFPU; \ + prev->tss.kregs->psr &= ~PSR_EF; \ + } \ + prev->lock_depth = syscall_count; \ + kernel_counter += (next->lock_depth - prev->lock_depth); \ + syscall_count = next->lock_depth; \ flush_user_windows(); \ - switch_to_context(p); \ - current->tss.current_ds = active_ds; \ - active_ds = p->tss.current_ds; \ - sparc_switch_to(p); \ + switch_to_context(next); \ + prev->tss.current_ds = active_ds; \ + active_ds = next->tss.current_ds; \ + sparc_switch_to(next); \ + sti(); \ } while(0) +#endif /* Changing the IRQ level on the Sparc. */ extern inline void setipl(int __new_ipl) diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/termbits.h linux/include/asm-sparc/termbits.h --- v1.3.92/linux/include/asm-sparc/termbits.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-sparc/termbits.h Sun Apr 21 12:30:34 1996 @@ -0,0 +1,191 @@ +#ifndef _SPARC_TERMBITS_H +#define _SPARC_TERMBITS_H + +#include + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned long tcflag_t; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 17 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VEOL 5 +#define VEOL2 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */ +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VMIN VEOF +#define VTIME VEOL + +/* c_iflag bits */ +#define IGNBRK 0x00000001 +#define BRKINT 0x00000002 +#define IGNPAR 0x00000004 +#define PARMRK 0x00000008 +#define INPCK 0x00000010 +#define ISTRIP 0x00000020 +#define INLCR 0x00000040 +#define IGNCR 0x00000080 +#define ICRNL 0x00000100 +#define IUCLC 0x00000200 +#define IXON 0x00000400 +#define IXANY 0x00000800 +#define IXOFF 0x00001000 +#define IMAXBEL 0x00002000 + +/* c_oflag bits */ +#define OPOST 0x00000001 +#define OLCUC 0x00000002 +#define ONLCR 0x00000004 +#define OCRNL 0x00000008 +#define ONOCR 0x00000010 +#define ONLRET 0x00000020 +#define OFILL 0x00000040 +#define OFDEL 0x00000080 +#define NLDLY 0x00000100 +#define NL0 0x00000000 +#define NL1 0x00000100 +#define CRDLY 0x00000600 +#define CR0 0x00000000 +#define CR1 0x00000200 +#define CR2 0x00000400 +#define CR3 0x00000600 +#define TABDLY 0x00001800 +#define TAB0 0x00000000 +#define TAB1 0x00000800 +#define TAB2 0x00001000 +#define TAB3 0x00001800 +#define XTABS 0x00001800 +#define BSDLY 0x00002000 +#define BS0 0x00000000 +#define BS1 0x00002000 +#define VTDLY 0x00004000 +#define VT0 0x00000000 +#define VT1 0x00004000 +#define FFDLY 0x00008000 +#define FF0 0x00000000 +#define FF1 0x00008000 +#define PAGEOUT 0x00010000 /* SUNOS specific */ +#define WRAP 0x00020000 /* SUNOS specific */ + +/* c_cflag bit meaning */ +#define CBAUD 0x0000000f +#define B0 0x00000000 /* hang up */ +#define B50 0x00000001 +#define B75 0x00000002 +#define B110 0x00000003 +#define B134 0x00000004 +#define B150 0x00000005 +#define B200 0x00000006 +#define B300 0x00000007 +#define B600 0x00000008 +#define B1200 0x00000009 +#define B1800 0x0000000a +#define B2400 0x0000000b +#define B4800 0x0000000c +#define B9600 0x0000000d +#define B19200 0x0000000e +#define B38400 0x0000000f +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0x00000030 +#define CS5 0x00000000 +#define CS6 0x00000010 +#define CS7 0x00000020 +#define CS8 0x00000030 +#define CSTOPB 0x00000040 +#define CREAD 0x00000080 +#define PARENB 0x00000100 +#define PARODD 0x00000200 +#define HUPCL 0x00000400 +#define CLOCAL 0x00000800 +/* We'll never see these speeds with the Zilogs' but for completeness... */ +#define CBAUDEX 0x00010000 +#define B57600 0x00010001 +#define B115200 0x00010002 +#define B230400 0x00010003 +#define CIBAUD 0x000f0000 /* input baud rate (not used) */ +#define CRTSCTS 0x80000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0x00000001 +#define ICANON 0x00000002 +#define XCASE 0x00000004 +#define ECHO 0x00000008 +#define ECHOE 0x00000010 +#define ECHOK 0x00000020 +#define ECHONL 0x00000040 +#define NOFLSH 0x00000080 +#define TOSTOP 0x00000100 +#define ECHOCTL 0x00000200 +#define ECHOPRT 0x00000400 +#define ECHOKE 0x00000800 +#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */ +#define FLUSHO 0x00002000 +#define PENDIN 0x00004000 +#define IEXTEN 0x00008000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* !(_SPARC_TERMBITS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h --- v1.3.92/linux/include/asm-sparc/termios.h Sun Mar 10 09:28:56 1996 +++ linux/include/asm-sparc/termios.h Sun Apr 21 12:30:34 1996 @@ -1,10 +1,9 @@ -/* $Id: termios.h,v 1.11 1996/02/10 04:31:03 davem Exp $ */ +/* $Id: termios.h,v 1.13 1996/04/04 12:51:30 davem Exp $ */ #ifndef _SPARC_TERMIOS_H #define _SPARC_TERMIOS_H -#include - -#include +#include +#include struct sgttyb { char sg_ispeed; @@ -37,104 +36,6 @@ int st_columns; /* Columns on the terminal */ }; -/* Big T */ -#define TCGETA _IOR('T', 1, struct termio) -#define TCSETA _IOW('T', 2, struct termio) -#define TCSETAW _IOW('T', 3, struct termio) -#define TCSETAF _IOW('T', 4, struct termio) -#define TCSBRK _IO('T', 5) -#define TCXONC _IO('T', 6) -#define TCFLSH _IO('T', 7) -#define TCGETS _IOR('T', 8, struct termios) -#define TCSETS _IOW('T', 9, struct termios) -#define TCSETSW _IOW('T', 10, struct termios) -#define TCSETSF _IOW('T', 11, struct termios) - -/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it - * someday. This is completely bogus, I know... - */ -#define TCGETSTAT _IO('T', 200) /* Rutgers specific */ -#define TCSETSTAT _IO('T', 201) /* Rutgers specific */ - -/* Little t */ -#define TIOCGETD _IOR('t', 0, int) -#define TIOCSETD _IOW('t', 1, int) -#define TIOCHPCL _IO('t', 2) /* SunOS Specific */ -#define TIOCMODG _IOR('t', 3, int) /* SunOS Specific */ -#define TIOCMODS _IOW('t', 4, int) /* SunOS Specific */ -#define TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */ -#define TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */ -#define TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */ -#define TIOCEXCL _IO('t', 13) -#define TIOCNXCL _IO('t', 14) -#define TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */ -#define TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */ -#define TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */ -#define TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */ -#define TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */ -#define TIOCSETX _IOW('t', 34, int) /* SunOS Specific */ -#define TIOCGETX _IOR('t', 35, int) /* SunOS Specific */ -#define TIOCCONS _IO('t', 36) -#define TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */ -#define TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */ -#define TIOCGSOFTCAR _IOR('t', 100, int) -#define TIOCSSOFTCAR _IOW('t', 101, int) -#define TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */ -#define TIOCSWINSZ _IOW('t', 103, struct winsize) -#define TIOCGWINSZ _IOR('t', 104, struct winsize) -#define TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */ -#define TIOCMGET _IOR('t', 106, int) -#define TIOCMBIC _IOW('t', 107, int) -#define TIOCMBIS _IOW('t', 108, int) -#define TIOCMSET _IOW('t', 109, int) -#define TIOCSTART _IO('t', 110) /* SunOS Specific */ -#define TIOCSTOP _IO('t', 111) /* SunOS Specific */ -#define TIOCPKT _IOW('t', 112, int) -#define TIOCNOTTY _IO('t', 113) -#define TIOCSTI _IOW('t', 114, char) -#define TIOCOUTQ _IOR('t', 115, int) -#define TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */ -#define TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */ -/* 118 is the non-posix setpgrp tty ioctl */ -/* 119 is the non-posix getpgrp tty ioctl */ -#define TIOCCDTR _IO('t', 120) /* SunOS Specific */ -#define TIOCSDTR _IO('t', 121) /* SunOS Specific */ -#define TIOCCBRK _IO('t', 122) /* SunOS Specific */ -#define TIOCSBRK _IO('t', 123) /* SunOS Specific */ -#define TIOCLGET _IOW('t', 124, int) /* SunOS Specific */ -#define TIOCLSET _IOW('t', 125, int) /* SunOS Specific */ -#define TIOCLBIC _IOW('t', 126, int) /* SunOS Specific */ -#define TIOCLBIS _IOW('t', 127, int) /* SunOS Specific */ -#define TIOCISPACE _IOR('t', 128, int) /* SunOS Specific */ -#define TIOCISIZE _IOR('t', 129, int) /* SunOS Specific */ -#define TIOCSPGRP _IOW('t', 130, int) -#define TIOCGPGRP _IOR('t', 131, int) -#define TIOCSCTTY _IO('t', 132) - -/* Little f */ -#define FIOCLEX _IO('f', 1) -#define FIONCLEX _IO('f', 2) -#define FIOASYNC _IOW('f', 125, int) -#define FIONBIO _IOW('f', 126, int) -#define FIONREAD _IOR('f', 127, int) -#define TIOCINQ FIONREAD - -/* Linux specific, no SunOS equivalent. */ -#define TIOCLINUX 0x541C -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TCSBRKP 0x5425 -#define TIOCTTYGSTRUCT 0x5426 -#define TIOCSERCONFIG 0x5453 -#define TIOCSERGWILD 0x5454 -#define TIOCSERSWILD 0x5455 -#define TIOCGLCKTRMIOS 0x5456 -#define TIOCSLCKTRMIOS 0x5457 -#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TIOCSERSETMULTI 0x545B /* Set multiport config */ - /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 @@ -151,45 +52,11 @@ unsigned short ws_ypixel; }; -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -#define NCCS 17 -struct termios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ -}; - -/* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VEOL 5 -#define VEOL2 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VDSUSP 11 /* SunOS POSIX nicety I do believe... */ -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VMIN VEOF -#define VTIME VEOL +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 #ifdef __KERNEL__ /* intr=^C quit=^\ erase=del kill=^U @@ -198,156 +65,6 @@ reprint=^R discard=^U werase=^W lnext=^V */ #define INIT_C_CC "\003\034\177\025\001\000\000\000\021\023\032\031\022\025\027\026" -#endif - -/* c_iflag bits */ -#define IGNBRK 0x00000001 -#define BRKINT 0x00000002 -#define IGNPAR 0x00000004 -#define PARMRK 0x00000008 -#define INPCK 0x00000010 -#define ISTRIP 0x00000020 -#define INLCR 0x00000040 -#define IGNCR 0x00000080 -#define ICRNL 0x00000100 -#define IUCLC 0x00000200 -#define IXON 0x00000400 -#define IXANY 0x00000800 -#define IXOFF 0x00001000 -#define IMAXBEL 0x00002000 - -/* c_oflag bits */ -#define OPOST 0x00000001 -#define OLCUC 0x00000002 -#define ONLCR 0x00000004 -#define OCRNL 0x00000008 -#define ONOCR 0x00000010 -#define ONLRET 0x00000020 -#define OFILL 0x00000040 -#define OFDEL 0x00000080 -#define NLDLY 0x00000100 -#define NL0 0x00000000 -#define NL1 0x00000100 -#define CRDLY 0x00000600 -#define CR0 0x00000000 -#define CR1 0x00000200 -#define CR2 0x00000400 -#define CR3 0x00000600 -#define TABDLY 0x00001800 -#define TAB0 0x00000000 -#define TAB1 0x00000800 -#define TAB2 0x00001000 -#define TAB3 0x00001800 -#define XTABS 0x00001800 -#define BSDLY 0x00002000 -#define BS0 0x00000000 -#define BS1 0x00002000 -#define VTDLY 0x00004000 -#define VT0 0x00000000 -#define VT1 0x00004000 -#define FFDLY 0x00008000 -#define FF0 0x00000000 -#define FF1 0x00008000 -#define PAGEOUT 0x00010000 /* SUNOS specific */ -#define WRAP 0x00020000 /* SUNOS specific */ - -/* c_cflag bit meaning */ -#define CBAUD 0x0000000f -#define B0 0x00000000 /* hang up */ -#define B50 0x00000001 -#define B75 0x00000002 -#define B110 0x00000003 -#define B134 0x00000004 -#define B150 0x00000005 -#define B200 0x00000006 -#define B300 0x00000007 -#define B600 0x00000008 -#define B1200 0x00000009 -#define B1800 0x0000000a -#define B2400 0x0000000b -#define B4800 0x0000000c -#define B9600 0x0000000d -#define B19200 0x0000000e -#define B38400 0x0000000f -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0x00000030 -#define CS5 0x00000000 -#define CS6 0x00000010 -#define CS7 0x00000020 -#define CS8 0x00000030 -#define CSTOPB 0x00000040 -#define CREAD 0x00000080 -#define PARENB 0x00000100 -#define PARODD 0x00000200 -#define HUPCL 0x00000400 -#define CLOCAL 0x00000800 -/* We'll never see these speeds with the Zilogs' but for completeness... */ -#define CBAUDEX 0x00010000 -#define B57600 0x00010001 -#define B115200 0x00010002 -#define B230400 0x00010003 -#define CIBAUD 0x000f0000 /* input baud rate (not used) */ -#define CRTSCTS 0x80000000 /* flow control */ - -/* c_lflag bits */ -#define ISIG 0x00000001 -#define ICANON 0x00000002 -#define XCASE 0x00000004 -#define ECHO 0x00000008 -#define ECHOE 0x00000010 -#define ECHOK 0x00000020 -#define ECHONL 0x00000040 -#define NOFLSH 0x00000080 -#define TOSTOP 0x00000100 -#define ECHOCTL 0x00000200 -#define ECHOPRT 0x00000400 -#define ECHOKE 0x00000800 -#define DEFECHO 0x00001000 /* SUNOS thing, what is it? */ -#define FLUSHO 0x00002000 -#define PENDIN 0x00004000 -#define IEXTEN 0x00008000 - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ -#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - -/* tcsetattr uses these */ -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 - -/* line disciplines */ -#define N_TTY 0 -#define N_SLIP 1 -#define N_MOUSE 2 -#define N_PPP 3 - -#ifdef __KERNEL__ /* * Translate a "termio" structure into a "termios". Ugh. diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/timer.h linux/include/asm-sparc/timer.h --- v1.3.92/linux/include/asm-sparc/timer.h Mon Mar 4 08:50:04 1996 +++ linux/include/asm-sparc/timer.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: timer.h,v 1.11 1996/01/03 03:53:23 davem Exp $ +/* $Id: timer.h,v 1.12 1996/03/24 20:21:29 davem Exp $ * timer.h: Definitions for the timer chips on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -31,8 +31,6 @@ }; #define SUN4C_TIMER_PHYSADDR 0xf3000000 - -volatile struct sun4c_timer_info *sun4c_timers; /* A sun4m has two blocks of registers which are probably of the same * structure. LSI Logic's L64851 is told to _decrement_ from the limit diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/traps.h linux/include/asm-sparc/traps.h --- v1.3.92/linux/include/asm-sparc/traps.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/traps.h Sun Apr 21 12:30:34 1996 @@ -67,7 +67,7 @@ /* First, hardware traps. */ #define SP_TRAP_TFLT 0x1 /* Text fault */ #define SP_TRAP_II 0x2 /* Illegal Instruction */ -#define SP_TRAP_PI 0x3 /* Privileged Instruction */ +#define SP_TRAP_PI 0x3 /* Priviledged Instruction */ #define SP_TRAP_FPD 0x4 /* Floating Point Disabled */ #define SP_TRAP_WOVF 0x5 /* Window Overflow */ #define SP_TRAP_WUNF 0x6 /* Window Underflow */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/tsunami.h linux/include/asm-sparc/tsunami.h --- v1.3.92/linux/include/asm-sparc/tsunami.h Mon Mar 4 08:50:04 1996 +++ linux/include/asm-sparc/tsunami.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: tsunami.h,v 1.3 1996/01/10 21:00:12 davem Exp $ +/* $Id: tsunami.h,v 1.4 1996/04/04 12:51:32 davem Exp $ * tsunami.h: Module specific definitions for Tsunami V8 Sparcs * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -45,13 +45,13 @@ #define TSUNAMI_NF 0x00000002 #define TSUNAMI_ME 0x00000001 -extern inline void tsunami_invalidate_icache(void) +extern inline void tsunami_flush_icache(void) { __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : "i" (ASI_M_IC_FLCLEAR) : "memory"); } -extern inline void tsunami_invalidate_dcache(void) +extern inline void tsunami_flush_dcache(void) { __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : "i" (ASI_M_DC_FLCLEAR) : "memory"); diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/types.h linux/include/asm-sparc/types.h --- v1.3.92/linux/include/asm-sparc/types.h Sat Nov 25 04:33:09 1995 +++ linux/include/asm-sparc/types.h Sun Apr 21 12:30:34 1996 @@ -1,51 +1,21 @@ -/* $Id: types.h,v 1.8 1995/11/25 02:33:08 davem Exp $ */ +/* $Id: types.h,v 1.9 1996/04/04 12:51:34 davem Exp $ */ #ifndef _SPARC_TYPES_H #define _SPARC_TYPES_H /* * _xx is ok: it doesn't pollute the POSIX namespace. Use these in the - * header files exported to user space <-- Linus sez this + * header files exported to user space. + */ + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. */ -#ifndef _SIZE_T -#define _SIZE_T -#ifdef __svr4__ -typedef unsigned int size_t; /* solaris sucks */ -#else -typedef long unsigned int size_t; /* sunos is much better */ -#endif /* !(__svr4__) */ -#endif - -#ifndef _SSIZE_T -#define _SSIZE_T -typedef int ssize_t; -#endif - -#ifndef _PTRDIFF_T -#define _PTRDIFF_T -typedef long int ptrdiff_t; -#endif - -#ifndef _TIME_T -#define _TIME_T -typedef long time_t; -#endif - -#ifndef _CLOCK_T -#define _CLOCK_T -typedef long clock_t; -#endif - -typedef int pid_t; -typedef unsigned short uid_t; -typedef unsigned short gid_t; -typedef unsigned short dev_t; -typedef unsigned long ino_t; -typedef unsigned short mode_t; typedef unsigned short umode_t; -typedef short nlink_t; -typedef long daddr_t; -typedef long off_t; typedef signed char __s8; typedef unsigned char __u8; @@ -74,58 +44,5 @@ typedef unsigned long long u64; #endif /* __KERNEL__ */ - -#undef __FD_SET -static __inline__ void __FD_SET(unsigned long fd, fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] |= (1UL<<_rem); -} - -#undef __FD_CLR -static __inline__ void __FD_CLR(unsigned long fd, fd_set *fdsetp) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); -} - -#undef __FD_ISSET -static __inline__ int __FD_ISSET(unsigned long fd, fd_set *p) -{ - unsigned long _tmp = fd / __NFDBITS; - unsigned long _rem = fd % __NFDBITS; - return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; -} - -/* - * This will unroll the loop for the normal constant cases (4 or 8 longs, - * for 256 and 512-bit fd_sets respectively) - */ -#undef __FD_ZERO -static __inline__ void __FD_ZERO(fd_set *p) -{ - unsigned int *tmp = p->fds_bits; - int i; - - if (__builtin_constant_p(__FDSET_INTS)) { - switch (__FDSET_INTS) { - case 8: - tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; - tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; - return; - case 4: - tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; - return; - } - } - i = __FDSET_INTS; - while (i) { - i--; - *tmp = 0; - tmp++; - } -} #endif /* defined(_SPARC_TYPES_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/unistd.h linux/include/asm-sparc/unistd.h --- v1.3.92/linux/include/asm-sparc/unistd.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/unistd.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.16 1995/12/29 23:14:26 miguel Exp $ */ +/* $Id: unistd.h,v 1.20 1996/04/20 07:54:39 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H @@ -11,7 +11,7 @@ * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * - * SunOS compatibility based upon preliminary work which is: + * SunOS compatability based upon preliminary work which is: * * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ @@ -257,6 +257,19 @@ #define __NR_munlock 238 #define __NR_mlockall 239 #define __NR_munlockall 240 +#define __NR_sched_setparam 241 +#define __NR_sched_getparam 242 +#define __NR_sched_setscheduler 243 +#define __NR_sched_getscheduler 244 +#define __NR_sched_yield 245 +#define __NR_sched_get_priority_max 246 +#define __NR_sched_get_priority_min 247 +#define __NR_sched_rr_get_interval 248 +#define __NR_nanosleep 249 +#define __NR_mremap 250 +#define __NR__sysctl 251 +#define __NR_getsid 252 +#define __NR_fdatasync 253 #define _syscall0(type,name) \ type name(void) \ @@ -270,7 +283,7 @@ "1:\n\t" \ : "=r" (__res)\ : "0" (__NR_##name) \ - : "g1"); \ + : "g1", "o0"); \ if (__res >= 0) \ return (type) __res; \ errno = -__res; \ @@ -366,24 +379,28 @@ errno = -__res; \ return -1; \ } - +# #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ -long __res; \ -__asm__ volatile ("or %%g0, %0, %%g1\n\t" \ - "or %%g0, %1, %%o0\n\t" \ + long __res; \ +\ +__asm__ volatile ("or %%g0, %1, %%o0\n\t" \ "or %%g0, %2, %%o1\n\t" \ "or %%g0, %3, %%o2\n\t" \ "or %%g0, %4, %%o3\n\t" \ "or %%g0, %5, %%o4\n\t" \ + "or %%g0, %6, %%g1\n\t" \ "t 0x10\n\t" \ + "bcc 1f\n\t" \ "or %%g0, %%o0, %0\n\t" \ - : "=r" (__res), "=r" ((long)(arg1)), "=r" ((long)(arg2)), \ - "=r" ((long)(arg3)), "=r" ((long)(arg4)), "=r" ((long)(arg5)) \ - : "0" (__NR_##name),"1" ((long)(arg1)),"2" ((long)(arg2)), \ - "3" ((long)(arg3)),"4" ((long)(arg4)),"5" ((long)(arg5)) \ + "sub %%g0, %%o0, %0\n\t" \ + "1:\n\t" \ + : "=r" (__res) \ + : "0" ((long)(arg1)),"1" ((long)(arg2)), \ + "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \ + "i" (__NR_##name) \ : "g1", "o0", "o1", "o2", "o3", "o4"); \ if (__res>=0) \ return (type) __res; \ @@ -405,11 +422,11 @@ * some others too. */ #define __NR__exit __NR_exit -/* static inline _syscall0(int,idle) */ +static inline _syscall0(int,idle) static inline _syscall0(int,fork) static inline _syscall2(int,clone,unsigned long,flags,char *,ksp) static inline _syscall0(int,pause) -/* static inline _syscall0(int,setup) */ +static inline _syscall0(int,setup) static inline _syscall0(int,sync) static inline _syscall0(pid_t,setsid) static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) @@ -420,24 +437,9 @@ static inline _syscall1(int,_exit,int,exitcode) static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -extern void sys_idle(void); -static inline void idle(void) -{ - sys_idle(); -} - -extern int sys_setup(void); -static inline int setup(void) -{ - return sys_setup(); -} - -extern int sys_waitpid(int, int *, int); static inline pid_t wait(int * wait_stat) { - long retval; - retval = waitpid(-1,wait_stat,0); - return retval; + return waitpid(-1,wait_stat,0); } /* diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/vac-ops.h linux/include/asm-sparc/vac-ops.h --- v1.3.92/linux/include/asm-sparc/vac-ops.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/vac-ops.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: vac-ops.h,v 1.9 1995/12/17 09:02:00 davem Exp $ */ +/* $Id: vac-ops.h,v 1.10 1996/04/04 12:51:36 davem Exp $ */ #ifndef _SPARC_VAC_OPS_H #define _SPARC_VAC_OPS_H @@ -67,7 +67,7 @@ /* The indexing of cache lines creates a problem. Because the line * field of a virtual address extends past the page offset within * the virtual address it is possible to have what are called - * 'bad aliases' which will create inconsistencies. So we must make + * 'bad aliases' which will create inconsistancies. So we must make * sure that within a context that if a physical page is mapped * more than once, that 'extra' line bits are the same. If this is * not the case, and thus is a 'bad alias' we must turn off the @@ -121,7 +121,5 @@ "g1"); sun4c_vacinfo.on = 0; } - -extern void sun4c_flush_context(void); #endif /* !(_SPARC_VAC_OPS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/vaddrs.h linux/include/asm-sparc/vaddrs.h --- v1.3.92/linux/include/asm-sparc/vaddrs.h Fri Apr 12 15:52:06 1996 +++ linux/include/asm-sparc/vaddrs.h Sun Apr 21 12:30:34 1996 @@ -1,4 +1,4 @@ -/* $Id: vaddrs.h,v 1.17 1996/01/10 21:00:16 davem Exp $ */ +/* $Id: vaddrs.h,v 1.19 1996/03/26 06:51:58 miguel Exp $ */ #ifndef _SPARC_VADDRS_H #define _SPARC_VADDRS_H @@ -17,13 +17,13 @@ * a pointer and then the value in the assembly code */ #define IOBASE_VADDR 0xfe000000 /* Base for mapping pages */ -#define IOBASE_LEN 0x00100000 /* Length of the IO area */ -#define IOBASE_END 0xfe100000 +#define IOBASE_LEN 0x00200000 /* Length of the IO area */ +#define IOBASE_END 0xfe200000 #define DVMA_VADDR 0xfff00000 /* Base area of the DVMA on suns */ #define DVMA_LEN 0x00040000 /* Size of the DVMA address space */ #define DVMA_END 0xfff40000 -/* IOMMU Mapping area, must be on a 16MB boundary! Note this +/* IOMMU Mapping area, must be on a 16MB boundry! Note this * doesn't count the DVMA areas, the prom lives between the * iommu mapping area (for scsi transfer buffers) and the * dvma upper range (for lance packet ring buffers). @@ -49,17 +49,17 @@ #define SUN4C_LOCK_END 0xffc00000 /* On sun4m machines we need per-cpu virtual areas */ -#define PERCPU_VADDR 0xff000000 /* Base for per-cpu virtual mappings */ +#define PERCPU_VADDR 0xffc00000 /* Base for per-cpu virtual mappings */ #define PERCPU_ENTSIZE 0x00100000 #define PERCPU_LEN ((PERCPU_ENTSIZE*NCPUS)) /* per-cpu offsets */ #define PERCPU_TBR_OFFSET 0x00000 /* %tbr, mainly used for identification. */ #define PERCPU_KSTACK_OFFSET 0x01000 /* Beginning of kernel stack for this cpu */ -#define PERCPU_MBOX_OFFSET 0x02000 /* Prom SMP Mailbox */ -#define PERCPU_CPUID_OFFSET 0x03000 /* Per-cpu ID number. */ -#define PERCPU_ISALIVE_OFFSET 0x03004 /* Has CPU been initted yet? */ -#define PERCPU_ISIDLING_OFFSET 0x03008 /* Is CPU in idle loop spinning? */ +#define PERCPU_MBOX_OFFSET 0x03000 /* Prom SMP Mailbox */ +#define PERCPU_CPUID_OFFSET 0x04000 /* Per-cpu ID number. */ +#define PERCPU_ISALIVE_OFFSET 0x04004 /* Has CPU been initted yet? */ +#define PERCPU_ISIDLING_OFFSET 0x04008 /* Is CPU in idle loop spinning? */ #endif /* !(_SPARC_VADDRS_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h --- v1.3.92/linux/include/asm-sparc/viking.h Mon Mar 4 08:50:04 1996 +++ linux/include/asm-sparc/viking.h Sun Apr 21 12:30:35 1996 @@ -1,5 +1,5 @@ -/* $Id: viking.h,v 1.6 1996/03/01 07:21:05 davem Exp $ - * viking.h: Defines specific to the TI Viking MBUS module. +/* $Id: viking.h,v 1.12 1996/04/20 10:15:46 davem Exp $ + * viking.h: Defines specific to the GNU/Viking MBUS module. * This is SRMMU stuff. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -9,47 +9,101 @@ #include -/* Bits in the SRMMU control register for TI Viking modules. +/* Bits in the SRMMU control register for GNU/Viking modules. + * + * ----------------------------------------------------------- + * |impl-vers| RSV |TC|AC|SP|BM|PC|MBM|SB|IC|DC|PSO|RSV|NF|ME| + * ----------------------------------------------------------- + * 31 24 23-17 16 15 14 13 12 11 10 9 8 7 6-2 1 0 + * + * TC: Tablewalk Cacheable -- 0 = Twalks are not cacheable in E-cache + * 1 = Twalks are cacheable in E-cache + * + * GNU/Viking will only cache tablewalks in the E-cache (mxcc) if present + * and never caches them internally (or so states the docs). Therefore + * for machines lacking an E-cache (ie. in MBUS mode) this bit must + * remain cleared. + * + * AC: Alternate Cacheable -- 0 = Passthru physical accesses not cacheable + * 1 = Passthru physical accesses cacheable + * + * This indicates whether accesses are cacheable when no cachable bit + * is present in the pte when the processor is in boot-mode or the + * access does not need pte's for translation (ie. pass-thru ASI's). + * "Cachable" is only referring to E-cache (if present) and not the + * on chip split I/D caches of the GNU/Viking. * - * ------------------------------------------------------------- - * |implvers| RSV |DP|RSV|TC|AC|SP|BM|PC|MBM|SB|IC|DC|RSV|NF|ME| - * ------------------------------------------------------------- - * 31 24 23-20 19 18 17 16 15 14 13 12 11 10 9 8-2 1 0 - * - * DP: Data Prefetcher Enable -- 0 = DP is off, 1 = DP is on - * TC: Tablewalk Cacheable -- 0 = Twalks are not cacheable - * 1 = Twalks are cacheable - * AC: Alternate Cacheable -- 0 = Direct physical accesses not cacheable - * 1 = Direct physical accesses are cacheable * SP: SnooP Enable -- 0 = bus snooping off, 1 = bus snooping on + * + * This enables snooping on the GNU/Viking bus. This must be on + * for the hardware cache consistancy mechanisms of the GNU/Viking + * to work at all. On non-mxcc GNU/Viking modules the split I/D + * caches will snoop regardless of whether they are enabled, this + * takes care of the case where the I or D or both caches are turned + * off yet still contain valid data. Note also that this bit does + * not affect GNU/Viking store-buffer snoops, those happen if the + * store-buffer is enabled no matter what. + * * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode + * + * This indicates whether the GNU/Viking is in boot-mode or not, + * if it is then all instruction fetch physical addresses are + * computed as 0xff0000000 + low 28 bits of requested address. + * GNU/Viking boot-mode does not affect data accesses. Also, + * in boot mode instruction accesses bypass the split on chip I/D + * caches, they may be cached by the GNU/MXCC if present and enabled. + * * MBM: MBus Mode -- 0 = not in MBus mode, 1 = in MBus mode + * + * This indicated the GNU/Viking configuration present. If in + * MBUS mode, the GNU/Viking lacks a GNU/MXCC E-cache. If it is + * not then the GNU/Viking is on a module VBUS connected directly + * to a GNU/MXCC cache controller. The GNU/MXCC can be thus connected + * to either an GNU/MBUS (sun4m) or the packet-switched GNU/XBus (sun4d). + * * SB: StoreBuffer enable -- 0 = store buffer off, 1 = store buffer on + * + * The GNU/Viking store buffer allows the chip to continue execution + * after a store even if the data cannot be placed in one of the + * caches during that cycle. If disabled, all stores operations + * occur synchronously. + * * IC: Instruction Cache -- 0 = off, 1 = on * DC: Data Cache -- 0 = off, 1 = 0n + * + * These bits enable the on-cpu GNU/Viking split I/D caches. Note, + * as mentioned above, these caches will snoop the bus in GNU/MBUS + * configurations even when disabled to avoid data corruption. + * * NF: No Fault -- 0 = faults generate traps, 1 = faults don't trap * ME: MMU enable -- 0 = mmu not translating, 1 = mmu translating * */ +#define VIKING_MMUENABLE 0x00000001 +#define VIKING_NOFAULT 0x00000002 +#define VIKING_PSO 0x00000080 #define VIKING_DCENABLE 0x00000100 /* Enable data cache */ #define VIKING_ICENABLE 0x00000200 /* Enable instruction cache */ #define VIKING_SBENABLE 0x00000400 /* Enable store buffer */ #define VIKING_MMODE 0x00000800 /* MBUS mode */ #define VIKING_PCENABLE 0x00001000 /* Enable parity checking */ - -/* Boot mode, 0 at boot-time, 1 after prom initializes the MMU. */ #define VIKING_BMODE 0x00002000 #define VIKING_SPENABLE 0x00004000 /* Enable bus cache snooping */ - -/* The deal with this AC bit is that if you are going to modify the - * contents of physical ram using the MMU bypass, you had better set - * this bit or things will get unsynchronized. This is only applicable - * if an E-cache (ie. a PAC) is around and the Viking is not in MBUS mode. - */ #define VIKING_ACENABLE 0x00008000 /* Enable alternate caching */ #define VIKING_TCENABLE 0x00010000 /* Enable table-walks to be cached */ -#define VIKING_DPENABLE 0x00040000 /* Enable the data prefetcher */ + +/* + * GNU/Viking Breakpoint Action Register fields. + */ +#define VIKING_ACTION_MIX 0x00001000 /* Enable multiple instructions */ + +/* + * GNU/Viking Cache Tags. + */ +#define VIKING_PTAG_VALID 0x01000000 /* Cache block is valid */ +#define VIKING_PTAG_DIRTY 0x00010000 /* Block has been modified */ +#define VIKING_PTAG_SHARED 0x00000100 /* Shared with some other cache */ extern inline void viking_flush_icache(void) { @@ -63,16 +117,50 @@ "i" (ASI_M_DC_FLCLEAR)); } -/* MXCC stuff... */ -extern inline void viking_enable_mxcc(void) +extern inline void viking_unlock_icache(void) { + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (0x80000000), "i" (ASI_M_IC_FLCLEAR)); } -extern inline void viking_mxcc_scrape(void) +extern inline void viking_unlock_dcache(void) { - /* David, what did you learn in school today? */ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (0x80000000), "i" (ASI_M_DC_FLCLEAR)); +} +extern inline void viking_set_bpreg(unsigned long regval) +{ + __asm__ __volatile__("sta %0, [%%g0] %1\n\t" : : + "r" (regval), + "i" (ASI_M_ACTION)); +} + +extern inline unsigned long viking_get_bpreg(void) +{ + unsigned long regval; + __asm__ __volatile__("lda [%%g0] %1, %0\n\t" : + "=r" (regval) : + "i" (ASI_M_ACTION)); + return regval; +} + +extern inline void viking_get_dcache_ptag(int set, int block, + unsigned long *data) +{ + unsigned long ptag = ((set & 0x7f) << 5) | ((block & 0x3) << 26) | + 0x80000000; + unsigned long info, page; + + __asm__ __volatile__ ("ldda [%2] %3, %%g2\n\t" + "or %%g0, %%g2, %0\n\t" + "or %%g0, %%g3, %1\n\t" : + "=r" (info), "=r" (page) : + "r" (ptag), "i" (ASI_M_DATAC_TAG) : + "g2", "g3"); + data[0] = info; + data[1] = page; } #endif /* !(_SPARC_VIKING_H) */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/vuid_event.h linux/include/asm-sparc/vuid_event.h --- v1.3.92/linux/include/asm-sparc/vuid_event.h Mon Mar 4 08:50:04 1996 +++ linux/include/asm-sparc/vuid_event.h Sun Apr 21 12:30:35 1996 @@ -24,7 +24,7 @@ /* Set input device byte stream format (any of VUID_{NATIVE,FIRM_EVENT}) */ #define VUIDSFORMAT _IOW('v', 1, int) /* Retrieve input device byte stream format */ -#define VUIDGFORMAT _IOR(v, 2, int) +#define VUIDGFORMAT _IOR('v', 2, int) /* Possible tag values */ /* mouse buttons: */ diff -u --recursive --new-file v1.3.92/linux/include/asm-sparc/winmacro.h linux/include/asm-sparc/winmacro.h --- v1.3.92/linux/include/asm-sparc/winmacro.h Mon Mar 4 08:50:04 1996 +++ linux/include/asm-sparc/winmacro.h Sun Apr 21 12:30:36 1996 @@ -1,4 +1,4 @@ -/* $Id: winmacro.h,v 1.13 1995/12/29 21:48:04 davem Exp $ +/* $Id: winmacro.h,v 1.16 1996/03/27 02:43:18 davem Exp $ * winmacro.h: Window loading-unloading macros. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -111,15 +111,15 @@ add %scratch, 1, %scratch; \ st %scratch, [%cur_reg + THREAD_W_SAVED]; -/* For now on a uniprocessor this is ok. */ #ifdef __SMP__ -#error SMP not yet #define LOAD_CURRENT(dest_reg, idreg) \ rd %tbr, %idreg; \ - srl %idreg, 24, %idreg; \ + srl %idreg, 10, %idreg; \ + and %idreg, 0xc, %idreg; \ sethi %hi(C_LABEL(current_set)), %dest_reg; \ or %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \ - add %dest_reg, %idreg, %dest_reg; + add %dest_reg, %idreg, %dest_reg; \ + ld [%dest_reg], %dest_reg; #else #define LOAD_CURRENT(dest_reg, idreg) \ sethi %hi(C_LABEL(current_set)), %dest_reg; \ diff -u --recursive --new-file v1.3.92/linux/include/linux/a.out.h linux/include/linux/a.out.h --- v1.3.92/linux/include/linux/a.out.h Wed Dec 13 12:39:47 1995 +++ linux/include/linux/a.out.h Sun Apr 21 17:32:02 1996 @@ -132,7 +132,9 @@ #ifdef __i386__ #define SEGMENT_SIZE 1024 #else +#ifndef SEGMENT_SIZE #define SEGMENT_SIZE PAGE_SIZE +#endif #endif #endif diff -u --recursive --new-file v1.3.92/linux/include/linux/blk.h linux/include/linux/blk.h --- v1.3.92/linux/include/linux/blk.h Wed Mar 27 08:19:29 1996 +++ linux/include/linux/blk.h Sun Apr 21 18:10:08 1996 @@ -170,16 +170,12 @@ /* Kludge to use the same number for both char and block major numbers */ #elif (MAJOR_NR == MD_MAJOR) && defined(MD_DRIVER) -#ifndef MD_PERSONALITY - #define DEVICE_NAME "Multiple devices driver" #define DEVICE_REQUEST do_md_request #define DEVICE_NR(device) (MINOR(device)) #define DEVICE_ON(device) #define DEVICE_OFF(device) -#endif - #elif (MAJOR_NR == SCSI_TAPE_MAJOR) #define DEVICE_NAME "scsitape" @@ -313,7 +309,7 @@ #endif /* MAJOR_NR == whatever */ -#if ((MAJOR_NR != SCSI_TAPE_MAJOR) && !defined(IDE_DRIVER) && !defined(MD_DRIVER)) +#if ((MAJOR_NR != SCSI_TAPE_MAJOR) && !defined(IDE_DRIVER)) #ifndef CURRENT #define CURRENT (blk_dev[MAJOR_NR].current_request) @@ -345,9 +341,7 @@ #endif /* DEVICE_TIMEOUT */ -#ifndef MD_PERSONALITY static void (DEVICE_REQUEST)(void); -#endif #ifdef DEVICE_INTR #define CLEAR_INTR SET_INTR(NULL) @@ -372,7 +366,7 @@ /* end_request() - SCSI devices have their own version */ /* - IDE drivers have their own copy too */ -#if ! SCSI_MAJOR(MAJOR_NR) || (defined(MD_DRIVER) && !defined(MD_PERSONALITY)) +#if ! SCSI_MAJOR(MAJOR_NR) #if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); @@ -381,8 +375,6 @@ #ifdef IDE_DRIVER void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup) { struct request *req = hwgroup->rq; -#elif defined(MD_DRIVER) -static void end_request (int uptodate, struct request * req) { #else static void end_request(int uptodate) { struct request *req = CURRENT; @@ -420,7 +412,7 @@ #ifdef IDE_DRIVER blk_dev[MAJOR(req->rq_dev)].current_request = req->next; hwgroup->rq = NULL; -#elif !defined(MD_DRIVER) +#else DEVICE_OFF(req->rq_dev); CURRENT = req->next; #endif /* IDE_DRIVER */ @@ -431,36 +423,6 @@ } #endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */ #endif /* ! SCSI_MAJOR(MAJOR_NR) */ - -#ifdef MD_PERSONALITY -extern inline void end_redirect (struct request *req) -{ - struct buffer_head * bh; - - req->errors = 0; - - if ((bh = req->bh) != NULL) - { - req->bh = bh->b_reqnext; - bh->b_reqnext = NULL; - - if ((bh = req->bh) != NULL) - { - req->sector += req->current_nr_sectors; - req->current_nr_sectors = bh->b_size >> 9; - - if (req->nr_sectors < req->current_nr_sectors) - { - req->nr_sectors = req->current_nr_sectors; - printk("end_redirect : buffer-list destroyed\n"); - } - - req->buffer = bh->b_data; - return; - } - } -} -#endif /* MD_PERSONALITY */ #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ diff -u --recursive --new-file v1.3.92/linux/include/linux/blkdev.h linux/include/linux/blkdev.h --- v1.3.92/linux/include/linux/blkdev.h Wed Mar 27 08:19:29 1996 +++ linux/include/linux/blkdev.h Sun Apr 21 18:10:08 1996 @@ -50,9 +50,8 @@ extern struct wait_queue * wait_for_request; extern void resetup_one_dev(struct gendisk *dev, int drive); -/* md needs those functions to requeue requests */ -extern void add_request(struct blk_dev_struct * dev, struct request * req); -extern struct request *get_md_request (int max_req, kdev_t dev); +/* md needs this function to remap requests */ +extern int md_map (int minor, kdev_t *rdev, unsigned long *rsector, unsigned long size); extern int * blk_size[MAX_BLKDEV]; diff -u --recursive --new-file v1.3.92/linux/include/linux/fdreg.h linux/include/linux/fdreg.h --- v1.3.92/linux/include/linux/fdreg.h Sun Apr 21 12:39:03 1996 +++ linux/include/linux/fdreg.h Sun Apr 21 17:38:55 1996 @@ -91,8 +91,23 @@ #define FD_LOCK 0x94 /* Fifo config lock */ #define FD_RSEEK_OUT 0x8f /* seek out (i.e. to lower tracks) */ #define FD_RSEEK_IN 0xcf /* seek in (i.e. to higher tracks) */ + +/* the following commands are new in the 82078. They are not used in the + * floppy driver, except the first three. These commands may be useful for apps + * which use the FDRAWCMD interface. For doc, get the 82078 spec sheets at + * http://www-techdoc.intel.com/docs/periph/fd_contr/datasheets/ */ + #define FD_PARTID 0x18 /* part id ("extended" version cmd) */ #define FD_SAVE 0x2e /* save fdc regs for later restore */ +#define FD_DRIVESPEC 0x8e /* drive specification: Access to the + * 2 Mbps data transfer rate for tape + * drives */ + +#define FD_RESTORE 0x4e /* later restore */ +#define FD_POWERDOWN 0x27 /* configure FDC's powersave features */ +#define FD_FORMAT_N_WRITE 0xef /* format and write in one go. */ +#define FD_OPTION 0x33 /* ISO format (which is a clean way to + * pack more sectors on a track) */ /* DMA commands */ #define DMA_READ 0x46 @@ -108,7 +123,7 @@ #define FDC_82072A 0x50 /* 82072A (on Sparcs) */ #define FDC_82077_ORIG 0x51 /* Original version of 82077AA, sans LOCK */ #define FDC_82077 0x52 /* 82077AA-1 */ -#define FDC_82077_UNKN 0x53 /* Unknown 82077 variant */ +#define FDC_82078_UNKN 0x5f /* Unknown 82078 variant */ #define FDC_82078 0x60 /* 44pin 82078 or 64pin 82078SL */ #define FDC_82078_1 0x61 /* 82078-1 (2Mbps fdc) */ #define FDC_S82078B 0x62 /* S82078B (first seen on Adaptec AVA-2825 VLB diff -u --recursive --new-file v1.3.92/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.3.92/linux/include/linux/fs.h Fri Apr 19 10:08:02 1996 +++ linux/include/linux/fs.h Sun Apr 21 18:10:08 1996 @@ -154,7 +154,8 @@ /* First cache line: */ unsigned long b_blocknr; /* block number */ kdev_t b_dev; /* device (B_FREE = free) */ - kdev_t b_rdev; /* Real device */ + kdev_t b_rdev; /* Real device */ + unsigned long b_rsector; /* Real buffer location on disk */ struct buffer_head * b_next; /* Hash queue list */ struct buffer_head * b_this_page; /* circular list of buffers in one page */ diff -u --recursive --new-file v1.3.92/linux/include/linux/isdn.h linux/include/linux/isdn.h --- v1.3.92/linux/include/linux/isdn.h Fri Apr 12 15:52:07 1996 +++ linux/include/linux/isdn.h Sun Apr 21 11:56:15 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.2 1996/02/11 02:10:02 fritz Exp fritz $ +/* $Id: isdn.h,v 1.3 1996/04/20 16:54:58 fritz Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.3 1996/04/20 16:54:58 fritz + * Increased maximum number of channels. + * Added some flags for isdn_net to handle callback more reliable. + * Fixed delay-definitions to be more accurate. + * Misc. typos + * * Revision 1.2 1996/02/11 02:10:02 fritz * Changed IOCTL-names * Added rx_netdev, st_netdev, first_skb, org_hcb, and org_hcu to @@ -45,15 +51,15 @@ * the correspondent code in isdn.c */ -#define ISDN_MAX_DRIVERS 16 -#define ISDN_MAX_CHANNELS 16 +#define ISDN_MAX_DRIVERS 32 +#define ISDN_MAX_CHANNELS 64 #define ISDN_MINOR_B 0 #define ISDN_MINOR_BMAX (ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_CTRL ISDN_MAX_CHANNELS #define ISDN_MINOR_CTRLMAX (2*ISDN_MAX_CHANNELS-1) #define ISDN_MINOR_PPP (2*ISDN_MAX_CHANNELS) #define ISDN_MINOR_PPPMAX (3*ISDN_MAX_CHANNELS-1) -#define ISDN_MINOR_STATUS 128 +#define ISDN_MINOR_STATUS 255 /* New ioctl-codes */ #define IIOCNETAIF _IO('I',1) @@ -76,6 +82,7 @@ #define IIOCSETMAP _IO('I',18) #define IIOCNETASL _IO('I',19) #define IIOCNETDIL _IO('I',20) +#define IIOCGETCPS _IO('I',21) #define IIOCNETALN _IO('I',32) #define IIOCNETDLN _IO('I',33) @@ -90,6 +97,7 @@ #define ISDN_NET_ENCAP_IPTYP 2 #define ISDN_NET_ENCAP_CISCOHDLC 3 #define ISDN_NET_ENCAP_SYNCPPP 4 +#define ISDN_NET_ENCAP_UIHDLC 5 /* Facility which currently uses an ISDN-channel */ #define ISDN_USAGE_NONE 0 @@ -128,17 +136,20 @@ char slave[10]; /* Name of Slave for Bundling */ char eaz[256]; /* EAZ/MSN */ char drvid[25]; /* DriverId for Bindings */ - int secure; /* Flag: Secure */ - int callback; /* Flag: Callback */ int onhtime; /* Hangup-Timeout */ int charge; /* Charge-Units */ - int chargehup; /* Flag: Charge-Hangup */ int l2_proto; /* Layer-2 protocol */ int l3_proto; /* Layer-3 protocol */ int p_encap; /* Encapsulation */ - int ihup; /* Flag: Hangup-Timeout on incoming line */ int exclusive; /* Channel, if bound exclusive */ + int dialmax; /* Dial Retry-Counter */ int slavedelay; /* Delay until slave starts up */ + int cbdelay; /* Delay before Callback */ + int chargehup; /* Flag: Charge-Hangup */ + int ihup; /* Flag: Hangup-Timeout on incoming line */ + int secure; /* Flag: Secure */ + int callback; /* Flag: Callback */ + int cbhup; /* Flag: Reject Call before Callback */ } isdn_net_ioctl_cfg; #ifdef __KERNEL__ @@ -211,8 +222,8 @@ /* Timer-delays and scheduling-flags */ #define ISDN_TIMER_RES 3 /* Main Timer-Resolution */ -#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 (0.2 sec.) */ -#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 (1 sec.) */ +#define ISDN_TIMER_02SEC (HZ/(ISDN_TIMER_RES+1)/5) /* Slow-Timer1 .2 sec */ +#define ISDN_TIMER_1SEC (HZ/(ISDN_TIMER_RES+1)) /* Slow-Timer2 1 sec */ #define ISDN_TIMER_MODEMREAD 1 #define ISDN_TIMER_MODEMPLUS 2 #define ISDN_TIMER_MODEMRING 4 @@ -226,8 +237,8 @@ ISDN_TIMER_NETDIAL) /* Timeout-Values for isdn_net_dial() */ -#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*ISDN_TIMER_RES)) -#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*ISDN_TIMER_RES)) +#define ISDN_TIMER_DTIMEOUT10 (10*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) +#define ISDN_TIMER_DTIMEOUT15 (15*HZ/(ISDN_TIMER_02SEC*(ISDN_TIMER_RES+1))) /* GLOBAL_FLAGS */ #define ISDN_GLOBAL_STOPPED 1 @@ -237,10 +248,15 @@ /* Feature- and status-flags for a net-interface */ #define ISDN_NET_CONNECTED 0x01 /* Bound to ISDN-Channel */ #define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */ -#define ISDN_NET_CALLBACK 0x04 /* callback incoming phonenumber */ +#define ISDN_NET_CALLBACK 0x04 /* activate callback */ +#define ISDN_NET_CBHUP 0x08 /* hangup before callback */ +#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */ +#if 0 +/* Unused??? */ #define ISDN_NET_CLONE 0x08 /* clone a tmp interface when called */ #define ISDN_NET_TMP 0x10 /* tmp interface until getting an IP */ #define ISDN_NET_DYNAMIC 0x20 /* this link is dynamically allocated */ +#endif #define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */ /* Phone-list-element */ @@ -261,11 +277,13 @@ int pre_channel; /* Preselected isdn-channel */ int exclusive; /* If non-zero idx to reserved chan.*/ int flags; /* Connection-flags */ - int dialstate; /* State for dialing */ int dialretry; /* Counter for Dialout-retries */ int dialmax; /* Max. Number of Dial-retries */ - char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */ + int cbdelay; /* Delay before Callback starts */ int dtimer; /* Timeout-counter for dialing */ + char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */ + u_char cbhup; /* Flag: Reject Call before Callback*/ + u_char dialstate; /* State for dialing */ u_char p_encap; /* Packet encapsulation */ /* 0 = Ethernet over ISDN */ /* 1 = RAW-IP */ @@ -554,6 +572,8 @@ modem mdm; /* tty-driver-data */ isdn_net_dev *rx_netdev[ISDN_MAX_CHANNELS]; /* rx netdev-pointers */ isdn_net_dev *st_netdev[ISDN_MAX_CHANNELS]; /* stat netdev-pointers */ + ulong ibytes[ISDN_MAX_CHANNELS]; /* Statistics incoming bytes */ + ulong obytes[ISDN_MAX_CHANNELS]; /* Statistics outgoing bytes */ } isdn_dev; extern isdn_dev *dev; diff -u --recursive --new-file v1.3.92/linux/include/linux/isdnif.h linux/include/linux/isdnif.h --- v1.3.92/linux/include/linux/isdnif.h Mon Feb 26 11:58:16 1996 +++ linux/include/linux/isdnif.h Sun Apr 21 11:56:15 1996 @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.1 1996/01/09 05:50:51 fritz Exp fritz $ +/* $Id: isdnif.h,v 1.2 1996/04/20 17:02:40 fritz Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.2 1996/04/20 17:02:40 fritz + * Changes to support skbuffs for Lowlevel-Drivers. + * Misc. typos + * * Revision 1.1 1996/01/09 05:50:51 fritz * Initial revision * diff -u --recursive --new-file v1.3.92/linux/include/linux/major.h linux/include/linux/major.h --- v1.3.92/linux/include/linux/major.h Mon Apr 8 19:01:46 1996 +++ linux/include/linux/major.h Sun Apr 21 17:32:02 1996 @@ -55,12 +55,14 @@ #define MATSUSHITA_CDROM4_MAJOR 28 #define STL_SIOMEMMAJOR 28 #define AZTECH_CDROM_MAJOR 29 +#define GRAPHDEV_MAJOR 29 /* SparcLinux /dev/fb */ #define CM206_CDROM_MAJOR 32 #define IDE2_MAJOR 33 #define IDE3_MAJOR 34 #define NETLINK_MAJOR 36 #define IDETAPE_MAJOR 37 - +#define APBLOCK_MAJOR 60 /* AP1000 Block device */ +#define DDV_MAJOR 61 /* AP1000 DDV block device */ /* * Tests for SCSI devices. */ diff -u --recursive --new-file v1.3.92/linux/include/linux/md.h linux/include/linux/md.h --- v1.3.92/linux/include/linux/md.h Fri Apr 19 10:08:02 1996 +++ linux/include/linux/md.h Sun Apr 21 11:03:54 1996 @@ -23,7 +23,7 @@ #include #include -#define MD_VERSION "0.34" +#define MD_VERSION "0.35" /* ioctls */ #define REGISTER_DEV _IO (MD_MAJOR, 1) @@ -60,13 +60,10 @@ #ifdef __KERNEL__ -#include #include #include #include -#undef MD_COUNT_SIZE /* Define this to have stats about - chunk size in /proc/mdstat */ #define MAX_REAL 8 /* Max number of physical dev per md dev */ #define MAX_MD_DEV 4 /* Max number of md dev */ @@ -108,7 +105,8 @@ struct md_personality { char *name; - int (*map)(int minor, struct md_dev *md_dev, struct request *req); + int (*map)(struct md_dev *md_dev, kdev_t *rdev, + unsigned long *rsector, unsigned long size); int (*run)(int minor, struct md_dev *md_dev); int (*stop)(int minor, struct md_dev *md_dev); int (*status)(char *page, int minor, struct md_dev *md_dev); @@ -125,24 +123,13 @@ int busy; int nb_dev; void *private; -#ifdef MD_COUNT_SIZE - unsigned int smallest_count; - unsigned int biggest_count; - unsigned int equal_count; -#endif }; extern struct real_dev devices[MAX_MD_DEV][MAX_REAL]; extern struct md_dev md_dev[MAX_MD_DEV]; extern int md_size[MAX_MD_DEV]; -extern void make_md_request(struct request *pending, int n); extern char *partition_name (kdev_t dev); - -#if defined(CONFIG_MD_SUPPORT_RAID1) || defined(CONFIG_MD_SUPPORT_RAID5) -extern int md_valid_device (int minor, kdev_t dev, int mode); -extern int md_can_reemit (int minor); -#endif extern int register_md_personality (int p_num, struct md_personality *p); extern int unregister_md_personality (int p_num); diff -u --recursive --new-file v1.3.92/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h --- v1.3.92/linux/include/linux/miscdevice.h Tue Apr 2 13:32:22 1996 +++ linux/include/linux/miscdevice.h Sun Apr 21 17:32:02 1996 @@ -5,6 +5,7 @@ #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 +#define SUN_MOUSE_MINOR 6 #define MISC_DYNAMIC_MINOR 255 extern int misc_init(void); diff -u --recursive --new-file v1.3.92/linux/include/linux/msdos_fs_i.h linux/include/linux/msdos_fs_i.h --- v1.3.92/linux/include/linux/msdos_fs_i.h Tue Mar 12 16:10:39 1996 +++ linux/include/linux/msdos_fs_i.h Sun Apr 21 11:11:13 1996 @@ -33,6 +33,10 @@ current inode */ struct inode *i_old; /* pointer to the old inode this inode depends on */ + struct inode *i_linked; /* pointer to inode linked to the current one, + happens when an open file is moved */ + struct inode *i_oldlink;/* pointer to open inode that references + the same file */ int i_binary; /* file contains non-text data */ }; diff -u --recursive --new-file v1.3.92/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v1.3.92/linux/include/linux/proc_fs.h Mon Apr 15 12:20:21 1996 +++ linux/include/linux/proc_fs.h Sun Apr 21 18:10:15 1996 @@ -130,6 +130,7 @@ PROC_SCSI_SSC, PROC_SCSI_NCR53C406A, PROC_SCSI_PPA, + PROC_SCSI_ESP, PROC_SCSI_SCSI_DEBUG, PROC_SCSI_NOT_PRESENT, PROC_SCSI_FILE, /* I'm assuming here that we */ diff -u --recursive --new-file v1.3.92/linux/include/linux/tty.h linux/include/linux/tty.h --- v1.3.92/linux/include/linux/tty.h Wed Apr 3 16:06:57 1996 +++ linux/include/linux/tty.h Sun Apr 21 18:10:08 1996 @@ -72,6 +72,8 @@ #define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */ +#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */ + /* * This character is the same as _POSIX_VDISABLE: it cannot be used as * a c_cc[] character, but indicates that a particular special character diff -u --recursive --new-file v1.3.92/linux/init/main.c linux/init/main.c --- v1.3.92/linux/init/main.c Wed Apr 17 09:06:33 1996 +++ linux/init/main.c Sun Apr 21 11:56:15 1996 @@ -135,6 +135,10 @@ #ifdef CONFIG_DIGI extern void pcxx_setup(char *str, int *ints); #endif +#ifdef CONFIG_ISDN_DRV_PCBIT +extern void pcbit_setup(char *str, int *ints); +#endif + #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD) extern void ipc_init(void); @@ -335,6 +339,9 @@ #endif #ifdef CONFIG_ISDN_DRV_TELES { "teles=", teles_setup }, +#endif +#ifdef CONFIG_ISDN_DRV_PCBIT + { "pcbit=", pcbit_setup }, #endif #ifdef CONFIG_DIGI { "digi=", pcxx_setup }, diff -u --recursive --new-file v1.3.92/linux/kernel/module.c linux/kernel/module.c --- v1.3.92/linux/kernel/module.c Fri Apr 12 15:52:09 1996 +++ linux/kernel/module.c Sun Apr 21 11:26:08 1996 @@ -304,9 +304,9 @@ GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN; (*mp->cleanup)(); mp->state = MOD_DELETED; - free_modules(); } } + free_modules(); } return 0; } diff -u --recursive --new-file v1.3.92/linux/mm/filemap.c linux/mm/filemap.c --- v1.3.92/linux/mm/filemap.c Sun Apr 21 12:39:03 1996 +++ linux/mm/filemap.c Sun Apr 21 12:41:33 1996 @@ -104,8 +104,10 @@ p = &page->next; offset = start - offset; /* partial truncate, clear end of page */ - if (offset < PAGE_SIZE) + if (offset < PAGE_SIZE) { memset((void *) (offset + page_address(page)), 0, PAGE_SIZE - offset); + flush_page_to_ram(page_address(page)); + } } } @@ -391,9 +393,9 @@ * * Synchronous read-ahead benefits: * -------------------------------- - * Using reasonnable IO xfer length from peripheral devices increase system + * Using reasonable IO xfer length from peripheral devices increase system * performances. - * Reasonnable means, in this context, not too large but not too small. + * Reasonable means, in this context, not too large but not too small. * The actual maximum value is MAX_READAHEAD + PAGE_SIZE = 32k * * Asynchronous read-ahead benefits: @@ -415,9 +417,9 @@ * ------------------------------ * In order to maximize overlapping, we must start some asynchronous read * request from the device, as soon as possible. - * We must be very carefull about: + * We must be very careful about: * - The number of effective pending IO read requests. - * ONE seems to be the only reasonnable value. + * ONE seems to be the only reasonable value. * - The total memory pool usage for the file access stream. * We try to have a limit of MAX_READWINDOW = 48K. */ @@ -436,16 +438,20 @@ ppos = pos & PAGE_MASK; rapos = filp->f_rapos & PAGE_MASK; max_ahead = 0; + /* - * If the current page is locked, try some synchronous read-ahead in order + * If the current page is locked, and if the current position is outside the + * previous read IO request, try some synchronous read-ahead in order * to avoid too small IO requests. */ if (PageLocked(page)) { - rapos = ppos; - if (rapos < inode->i_size) - max_ahead = filp->f_ramax; - filp->f_rawin = 0; - filp->f_ralen = PAGE_SIZE; + if (!rapos || ppos >= rapos || ppos + filp->f_ralen < rapos) { + rapos = ppos; + if (rapos < inode->i_size) + max_ahead = filp->f_ramax; + filp->f_rawin = 0; + filp->f_ralen = PAGE_SIZE; + } } /* * The current page is not locked @@ -749,11 +755,14 @@ page = fill_page(inode, offset); if (page && no_share) { unsigned long new_page = __get_free_page(GFP_KERNEL); - if (new_page) + if (new_page) { memcpy((void *) new_page, (void *) page, PAGE_SIZE); + flush_page_to_ram(new_page); + } free_page(page); return new_page; } + flush_page_to_ram(page); return page; } @@ -881,6 +890,7 @@ return 0; if (!pte_dirty(pte)) return 0; + flush_page_to_ram(pte_page(pte)); flush_cache_page(vma, address); set_pte(ptep, pte_mkclean(pte)); flush_tlb_page(vma, address); diff -u --recursive --new-file v1.3.92/linux/mm/memory.c linux/mm/memory.c --- v1.3.92/linux/mm/memory.c Wed Apr 17 09:06:33 1996 +++ linux/mm/memory.c Sun Apr 21 17:32:03 1996 @@ -468,7 +468,7 @@ pte_t oldpage = *pte; pte_clear(pte); if (offset >= high_memory || PageReserved(mem_map+MAP_NR(offset))) - set_pte(pte, mk_pte(offset, prot)); + set_pte(pte, mk_pte(offset, prot)); forget_pte(oldpage); address += PAGE_SIZE; offset += PAGE_SIZE; @@ -506,7 +506,7 @@ offset -= from; dir = pgd_offset(current->mm, from); - flush_cache_range(current->mm, beg, from); + flush_cache_range(current->mm, beg, end); while (from < end) { pmd_t *pmd = pmd_alloc(dir, from); error = -ENOMEM; @@ -518,7 +518,7 @@ from = (from + PGDIR_SIZE) & PGDIR_MASK; dir++; } - flush_tlb_range(current->mm, beg, from); + flush_tlb_range(current->mm, beg, end); return error; } @@ -532,7 +532,7 @@ free_page(pte_page(pte)); return; } -/* no need for invalidate */ +/* no need for flush_tlb */ set_pte(page_table, pte); } @@ -568,8 +568,9 @@ free_page(page); return 0; } + flush_page_to_ram(page); set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)))); -/* no need for flush_tlb */ +/* no need for invalidate */ return page; } @@ -764,6 +765,7 @@ oom(tsk); pte = BAD_PAGE; } + flush_page_to_ram(page); } put_page(page_table, pte); } @@ -797,11 +799,13 @@ pte = *page_table; if (!pte_present(pte)) return; + flush_cache_page(vma, address); address &= ~PAGE_MASK; address += pte_page(pte); if (address >= high_memory) return; memset((void *) address, 0, PAGE_SIZE - (address & ~PAGE_MASK)); + flush_page_to_ram(pte_page(pte)); } /* @@ -876,6 +880,7 @@ 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; } page = vma->vm_ops->swapin(vma, address - vma->vm_start + vma->vm_offset, pte_val(entry)); @@ -887,6 +892,7 @@ page = pte_wrprotect(page); ++vma->vm_mm->rss; ++tsk->maj_flt; + flush_page_to_ram(pte_page(page)); set_pte(page_table, page); return; } @@ -945,6 +951,7 @@ * so we can make it writable and dirty to avoid having to * handle that later. */ + flush_page_to_ram(page); entry = mk_pte(page, vma->vm_page_prot); if (write_access) { entry = pte_mkwrite(pte_mkdirty(entry)); @@ -976,10 +983,12 @@ return; } set_pte(pte, pte_mkyoung(*pte)); + flush_tlb_page(vma, address); if (!write_access) return; if (pte_write(*pte)) { set_pte(pte, pte_mkdirty(*pte)); + flush_tlb_page(vma, address); return; } do_wp_page(current, vma, address, write_access); diff -u --recursive --new-file v1.3.92/linux/net/ipv4/ip_output.c linux/net/ipv4/ip_output.c --- v1.3.92/linux/net/ipv4/ip_output.c Fri Apr 19 10:08:03 1996 +++ linux/net/ipv4/ip_output.c Sun Apr 21 10:47:27 1996 @@ -23,6 +23,9 @@ * Mike Kilburn : htons() missing in ip_build_xmit. * Bradford Johnson: Fix faulty handling of some frames when * no route is found. + * Alexander Demenshin: Missing sk/skb free in ip_queue_xmit + * (in case if packet not accepted by + * output firewall rules) */ #include @@ -360,12 +363,6 @@ iph = skb->ip_hdr; iph->tot_len = htons(skb->len-(((unsigned char *)iph)-skb->data)); -#ifdef CONFIG_FIREWALL - if(call_out_firewall(PF_INET, skb->dev, iph) < FW_ACCEPT) - /* just don't send this packet */ - return; -#endif - /* * No reassigning numbers to fragments... */ @@ -380,6 +377,17 @@ free = 1; skb->free = free; + +#ifdef CONFIG_FIREWALL + if(call_out_firewall(PF_INET, skb->dev, iph) < FW_ACCEPT) { + /* just don't send this packet */ + /* and free socket buffers ;) */ + if (free) + skb->sk = sk; /* I am not sure *this* really need, */ + kfree_skb(skb, FREE_WRITE); /* but *this* must be here */ + return; + } +#endif /* * Do we need to fragment. Again this is inefficient.