]> git.neil.brown.name Git - history.git/commitdiff
Import 1.3.93 1.3.93
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:52 +0000 (15:10 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:10:52 +0000 (15:10 -0500)
226 files changed:
Documentation/Configure.help
Documentation/devices.tex
Documentation/devices.txt
Documentation/isdn/CREDITS
Documentation/isdn/README
Documentation/isdn/README.pcbit [new file with mode: 0644]
Documentation/isdn/README.syncppp
Documentation/isdn/syncPPP.FAQ [new file with mode: 0644]
MAINTAINERS
Makefile
arch/i386/kernel/signal.c
arch/sparc/Makefile
arch/sparc/boot/README
arch/sparc/boot/empirical.h
arch/sparc/boot/init_me.c
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/kernel/auxio.c
arch/sparc/kernel/c_mp.c [deleted file]
arch/sparc/kernel/cpu.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/entry.S
arch/sparc/kernel/etrap.S
arch/sparc/kernel/head.S
arch/sparc/kernel/idprom.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.c
arch/sparc/kernel/mp.S [deleted file]
arch/sparc/kernel/probe.c
arch/sparc/kernel/process.c
arch/sparc/kernel/rirq.S [new file with mode: 0644]
arch/sparc/kernel/rtrap.S
arch/sparc/kernel/sclow.S
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/solaris.c [new file with mode: 0644]
arch/sparc/kernel/sparc-stub.c
arch/sparc/kernel/sun4c_irq.c [new file with mode: 0644]
arch/sparc/kernel/sun4m_irq.c [new file with mode: 0644]
arch/sparc/kernel/sunos_asm.S
arch/sparc/kernel/sunos_ioctl.c
arch/sparc/kernel/switch.S
arch/sparc/kernel/sys_bsd.c [deleted file]
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/tadpole.c [new file with mode: 0644]
arch/sparc/kernel/tick14.c [new file with mode: 0644]
arch/sparc/kernel/time.c
arch/sparc/kernel/trampoline.S [new file with mode: 0644]
arch/sparc/kernel/traps.c
arch/sparc/kernel/wof.S
arch/sparc/kernel/wuf.S
arch/sparc/lib/Makefile
arch/sparc/lib/memset.c [new file with mode: 0644]
arch/sparc/lib/strlen.S [new file with mode: 0644]
arch/sparc/mm/Makefile
arch/sparc/mm/fault.c
arch/sparc/mm/generic.c [new file with mode: 0644]
arch/sparc/mm/init.c
arch/sparc/mm/loadmmu.c
arch/sparc/mm/s4cflsh.S [deleted file]
arch/sparc/mm/s4ckflt.S [deleted file]
arch/sparc/mm/s4clow.h [deleted file]
arch/sparc/mm/s4cuflt.S [deleted file]
arch/sparc/mm/srmmu.c
arch/sparc/mm/srmmu_mp.S [new file with mode: 0644]
arch/sparc/mm/srmmuinv.c [deleted file]
arch/sparc/mm/sun4c.c
arch/sparc/prom/bootstr.c
arch/sparc/prom/console.c
arch/sparc/prom/devops.c
arch/sparc/prom/devtree.c [deleted file]
arch/sparc/prom/init.c
arch/sparc/prom/memory.c
arch/sparc/prom/misc.c
arch/sparc/prom/mp.c
arch/sparc/prom/palloc.c
arch/sparc/prom/printf.c
arch/sparc/prom/tree.c
drivers/block/floppy.c
drivers/block/linear.c
drivers/block/ll_rw_blk.c
drivers/block/md.c
drivers/block/raid0.c
drivers/char/README.cyclomY
drivers/char/suncons.c [new file with mode: 0644]
drivers/char/sunmouse.c [new file with mode: 0644]
drivers/isdn/Config.in
drivers/isdn/Makefile
drivers/isdn/icn/icn.c
drivers/isdn/icn/icn.h
drivers/isdn/isdn_cards.c
drivers/isdn/isdn_cards.h
drivers/isdn/isdn_common.c
drivers/isdn/isdn_common.h
drivers/isdn/isdn_net.c
drivers/isdn/isdn_net.h
drivers/isdn/isdn_ppp.c
drivers/isdn/isdn_ppp.h
drivers/isdn/isdn_tty.c
drivers/isdn/pcbit/Makefile [new file with mode: 0644]
drivers/isdn/pcbit/callbacks.c [new file with mode: 0644]
drivers/isdn/pcbit/callbacks.h [new file with mode: 0644]
drivers/isdn/pcbit/capi.c [new file with mode: 0644]
drivers/isdn/pcbit/capi.h [new file with mode: 0644]
drivers/isdn/pcbit/drv.c [new file with mode: 0644]
drivers/isdn/pcbit/edss1.c [new file with mode: 0644]
drivers/isdn/pcbit/edss1.h [new file with mode: 0644]
drivers/isdn/pcbit/layer2.c [new file with mode: 0644]
drivers/isdn/pcbit/layer2.h [new file with mode: 0644]
drivers/isdn/pcbit/module.c [new file with mode: 0644]
drivers/isdn/pcbit/pcbit.h [new file with mode: 0644]
drivers/isdn/teles/buffers.c
drivers/isdn/teles/callc.c
drivers/isdn/teles/card.c
drivers/isdn/teles/config.c
drivers/isdn/teles/fsm.c
drivers/isdn/teles/isdnl2.c
drivers/isdn/teles/isdnl3.c
drivers/isdn/teles/l3_1TR6.c
drivers/isdn/teles/l3_1TR6.h
drivers/isdn/teles/llglue.c
drivers/isdn/teles/mod.c
drivers/isdn/teles/q931.c
drivers/isdn/teles/tei.c
drivers/isdn/teles/teles.h
drivers/net/3c509.c
drivers/net/Makefile
drivers/net/Space.c
drivers/net/arcnet.c
drivers/net/dgrs.c
drivers/net/dgrs_driver.c
drivers/net/dgrs_es4h.h
drivers/net/dgrs_ether.h
drivers/net/dgrs_i82596.h
drivers/net/dgrs_plx9060.h
drivers/net/sunlance.c
drivers/sbus/Makefile [new file with mode: 0644]
drivers/sbus/dvma.c [new file with mode: 0644]
drivers/sbus/sbus.c [new file with mode: 0644]
drivers/scsi/aic7xxx.c
drivers/scsi/esp.c [new file with mode: 0644]
drivers/scsi/esp.h [new file with mode: 0644]
drivers/scsi/hosts.c
fs/fat/inode.c
fs/msdos/namei.c
fs/nfs/proc.c
fs/vfat/namei.c
include/asm-sparc/asi.h
include/asm-sparc/asmmacro.h [new file with mode: 0644]
include/asm-sparc/atomic.h [new file with mode: 0644]
include/asm-sparc/atops.h [new file with mode: 0644]
include/asm-sparc/auxio.h
include/asm-sparc/bitops.h
include/asm-sparc/bsderrno.h
include/asm-sparc/cache.h
include/asm-sparc/checksum.h
include/asm-sparc/cypress.h
include/asm-sparc/dma.h
include/asm-sparc/ecc.h
include/asm-sparc/fbio.h
include/asm-sparc/floppy.h
include/asm-sparc/head.h
include/asm-sparc/ioctls.h [new file with mode: 0644]
include/asm-sparc/iommu.h
include/asm-sparc/irq.h
include/asm-sparc/mbus.h
include/asm-sparc/memreg.h
include/asm-sparc/mman.h
include/asm-sparc/mostek.h
include/asm-sparc/mp.h
include/asm-sparc/mpmbox.h
include/asm-sparc/msi.h [new file with mode: 0644]
include/asm-sparc/mxcc.h
include/asm-sparc/oplib.h
include/asm-sparc/page.h
include/asm-sparc/pconf.h
include/asm-sparc/pgtable.h
include/asm-sparc/pgtsrmmu.h
include/asm-sparc/pgtsun4c.h
include/asm-sparc/posix_types.h [new file with mode: 0644]
include/asm-sparc/processor.h
include/asm-sparc/ross.h
include/asm-sparc/segment.h
include/asm-sparc/signal.h
include/asm-sparc/smp.h
include/asm-sparc/smp_lock.h
include/asm-sparc/socket.h
include/asm-sparc/sockios.h [new file with mode: 0644]
include/asm-sparc/solerrno.h
include/asm-sparc/string.h
include/asm-sparc/swift.h
include/asm-sparc/system.h
include/asm-sparc/termbits.h [new file with mode: 0644]
include/asm-sparc/termios.h
include/asm-sparc/timer.h
include/asm-sparc/traps.h
include/asm-sparc/tsunami.h
include/asm-sparc/types.h
include/asm-sparc/unistd.h
include/asm-sparc/vac-ops.h
include/asm-sparc/vaddrs.h
include/asm-sparc/viking.h
include/asm-sparc/vuid_event.h
include/asm-sparc/winmacro.h
include/linux/a.out.h
include/linux/blk.h
include/linux/blkdev.h
include/linux/fdreg.h
include/linux/fs.h
include/linux/isdn.h
include/linux/isdnif.h
include/linux/major.h
include/linux/md.h
include/linux/miscdevice.h
include/linux/msdos_fs_i.h
include/linux/proc_fs.h
include/linux/tty.h
init/main.c
kernel/module.c
mm/filemap.c
mm/memory.c
net/ipv4/ip_output.c

index 99d6b0be7d83e972b1d7e1883cc70ab31ceaf526..8c81d09f6797c38d3c6ad30bd529ffa6918c8bd2 100644 (file)
@@ -3179,6 +3179,21 @@ CONFIG_ISDN_DRV_TELES
   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.
 
 #
index b876a7b5b35230450ce02c0b8ac6e2784c68b788..48e985a82c1f86918df5a060a52b6b2a7853e4a1 100644 (file)
@@ -42,7 +42,7 @@ foo \kill}%
 %
 \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 @@ that semantically altered versions are not distributed without
 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 @@ an unreasonable effort.
 \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 @@ physical disks.
        \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 @@ number 3).
        \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 @@ driver with this number should not cause ill effects to the system
 \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 @@ driver with this number should not cause ill effects to the system
 \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}
index a5092a3420390ccc043a5f132e3f4a9be54e6113..a29f4d1213c6eceaf6cc0e0d52c63079b68f8388 100644 (file)
@@ -2,14 +2,14 @@
 
             Maintained by H. Peter Anvin <hpa@zytor.com>
 
-                    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 @@ that semantically altered versions are not distributed without
 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 @@ an unreasonable effort.
                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 @@ an unreasonable effort.
                  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 @@ an unreasonable effort.
                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 @@ an unreasonable effort.
  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 @@ an unreasonable effort.
                  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
index bdc4f3dd4d03a56f3ad9a2f41e06a852ed9e45e9..6c546c4e1e6d495355f3a1da48a2aaee46557fdb 100644 (file)
@@ -5,7 +5,7 @@ I want to thank all who contributed to this project and especially to:
 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 @@ Michael Knigge (knick@cove.han.de)
 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
index 553364ca92a9e6ce9a82289bd0d648b8842f9be0..23418379bb4b18bb0469fc98a1c21f60655e1e4d 100644 (file)
@@ -44,7 +44,7 @@ README for the ISDN-subsystem
   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 @@ README for the ISDN-subsystem
 
    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 @@ README for the ISDN-subsystem
    In this case use ping with the option -i <sec> to increase the interval
    between echo-packets.
 
+   "isdnctrl cbdelay <InterfaceName> [seconds]"
+   Sets the delay (default 5 sec) between an incoming call and start of
+   dialing when callback is enabled.
+
+   "isdnctrl cbhup <InterfaceName> [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 <InterfaceName> <EncapType>"
    Selects the type of packet-encapsulation. The encapsulation can be changed
    only while an interface is down.
@@ -490,6 +498,8 @@ README for the ISDN-subsystem
             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
    without MAC-header. A patch for tcpdump is included in the utility-package
diff --git a/Documentation/isdn/README.pcbit b/Documentation/isdn/README.pcbit
new file mode 100644 (file)
index 0000000..2b6b479
--- /dev/null
@@ -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.
+               
+<roque@di.fc.ul.pt>
index dc900472388ce8abe34213b76a47199f0dd3512f..5bdc48fdfe6a4622e012065dc4cc73a8c4dca2d8 100644 (file)
@@ -12,7 +12,8 @@ To compile isdn4linux with the sync PPP part, you have
 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 @@ devices .. and so on.
 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 --git a/Documentation/isdn/syncPPP.FAQ b/Documentation/isdn/syncPPP.FAQ
new file mode 100644 (file)
index 0000000..32b5683
--- /dev/null
@@ -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.
+   
+
+
+
index 6205f084cbf4ae61fa8537cdf5506894fcf7f7eb..1bd8df739e778042deb8aaf6cf4cec88f0cef37b 100644 (file)
@@ -248,6 +248,13 @@ M: mj@k332.feld.cvut.cz
 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
index b35fc42d4e1ba7565970e3ea5a5d3e0d9305f5cc..933570efa0ad67dbd42882de644f8801bdfe827a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 3
-SUBLEVEL = 92
+SUBLEVEL = 93
 
 ARCH = i386
 
@@ -116,15 +116,16 @@ endif
 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
 endif
index edf4ac9f2607744cd60db30d67da98b0079a015e..0b655da1b7eba60f12902fc3a169888ab1943570 100644 (file)
@@ -61,7 +61,7 @@ static inline void restore_i387_hard(struct _fpstate *buf)
        }
 #endif
        current->used_math = 1;
-       current->flags &= PF_USEDFPU;
+       current->flags &= ~PF_USEDFPU;
        memcpy_fromfs(&current->tss.i387.hard, buf, sizeof(*buf));
 }
 
@@ -133,7 +133,7 @@ static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
        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) {
index c22f18054f859f901ec51f048008c16bbf1c1328..512eb61224b904359b7f58be11e72d811a468163 100644 (file)
@@ -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 @@ ARCHIVES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(ARCHIVES)
 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
index 48c93ddbe10da9d640cc4b7c625465afc51dfa37..77f34dacc18064615a4e68c489edc5259c00635c 100644 (file)
@@ -17,5 +17,5 @@ our data area either way because we can be dual purpose.
 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 ;(
 
index bd9bc493e6163c8e734e0b0f24e80a875a942f25..aaa16f57785d0e9c1bd8477cfffaca603aac418d 100644 (file)
@@ -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)
index 0e209170193db566583329db3fc319f0fac35e09..ad26a1969cf93d1faa63def4ad2124640d11bb0b 100644 (file)
@@ -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;
index fceee826085c482bad51583aaeaed757f4e7b0fc..0d5d042b9601c81faa188b0c2eb125931fafa06b 100644 (file)
@@ -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,16 +7,24 @@ mainmenu_name "Kernel configuration of Linux for SparcStations"
 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
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
index 8e333e98b45c333440aa8b5a0870258b4e5a31ac..e6f2b3ccd7ae649f65f037942041197f2c506112 100644 (file)
@@ -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_IP_NOSR=y
 # 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_SCSI=y
 #
 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_BLK_DEV_SD=y
 #
 # 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_EXT2_FS=y
 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
 
index 99b901345a5b34ec713d084e138b1e3d6433e822..41de109291b053f454407309de4a62de0d3a3227 100644 (file)
@@ -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
index db2509f6d810f3911b8f58c51141c91f8d6c7890..ba37f425d5073981f770b458e2b7aebd71a8a820 100644 (file)
@@ -31,7 +31,7 @@ auxio_probe(void)
        /* 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 --git a/arch/sparc/kernel/c_mp.c b/arch/sparc/kernel/c_mp.c
deleted file mode 100644 (file)
index e5b8096..0000000
+++ /dev/null
@@ -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 <linux/kernel.h>
-
-#include <asm/mp.h>
-#include <asm/mbus.h>
-
-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;
-}      
index 0233c39a540c2c3d7f857a178d0a4fd0699ee0a0..6b4f2f628b8ca3bdde642a13ef495b3f11c35f0b 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 
 #include <asm/oplib.h>
+#include <asm/page.h>
 #include <asm/head.h>
 #include <asm/psr.h>
 #include <asm/mbus.h>
index 4d7c61bf7d3bf52efebdd7ba75fcda889498f8e7..45c1db194f83ab4387c6389926a448b631101ede 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/config.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
@@ -15,7 +16,7 @@ struct prom_cpuinfo linux_cpus[NCPUS];
 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 @@ device_scan(unsigned long mem_start)
        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 @@ device_scan(unsigned long mem_start)
                                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 <node=%08lx,mid=%d>\n",
+                                           cpu_ctr, (unsigned long) scan,
+                                           thismid);
                                cpu_ctr++;
                        }
                };
@@ -55,7 +67,13 @@ device_scan(unsigned long mem_start)
        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;
 }
index bfd8c26bf743f1a7021350a4c10496d291870497..97cc1f7e06cdb7898d1e2911a2a038b7a6f81894 100644 (file)
@@ -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 <asm/head.h>
 #include <asm/asi.h>
+#include <asm/smp.h>
 #include <asm/kgdb.h>
 #include <asm/contregs.h>
 #include <asm/ptrace.h>
 #include <asm/winmacro.h>
 #include <asm/signal.h>
 
-#define NR_SYSCALLS 255      /* Each OS is different... */
+#include <asm/asmmacro.h>
 
-/* 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 @@ in_trap_handler:
 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 @@ floppy_tdone:
        /* 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_overrun:
 floppy_dosoftint:
        rd      %wim, %l3
        SAVE_ALL
+       ENTER_IRQ
 
        /* Set all IRQs off. */
        or      %l0, PSR_PIL, %l4
@@ -288,6 +287,7 @@ floppy_dosoftint:
        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 @@ floppy_dosoftint:
        .globl  bad_trap_handler
 bad_trap_handler:
        SAVE_ALL
+       ENTER_SYSCALL
 
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
@@ -316,6 +317,52 @@ bad_trap_handler:
        .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 @@ real_irq_entry:
         * 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 @@ rie_checkbh:
        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 @@ rie_checkbh:
 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 @@ bad_instruction:
        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 @@ priv_instruction:
        .globl  mna_handler
 mna_handler:
        SAVE_ALL
+       ENTER_SYSCALL
 
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
@@ -427,6 +474,7 @@ mna_handler:
        .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 @@ fpd_trap_handler:
 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 @@ fpe_trap_handler:
        .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 @@ do_tag_overflow:
        .globl  do_watchpoint
 do_watchpoint:
        SAVE_ALL
+       ENTER_SYSCALL
 
        wr      %l0, PSR_ET, %psr               ! re-enable traps
        WRITE_PAUSE
@@ -506,6 +568,7 @@ do_watchpoint:
        .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 @@ do_reg_access:
        .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 @@ do_cp_disabled:
        .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 @@ do_bad_flush:
        .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 @@ do_cp_exception:
        .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 @@ do_hw_divzero:
        .globl  do_flush_windows
 do_flush_windows:
        SAVE_ALL
+       ENTER_SYSCALL
 
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
@@ -612,6 +680,13 @@ do_flush_windows:
        /* 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 @@ setcc_trap_handler:
        .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 @@ linux_trap_nmi_sun4c:
 
        RESTORE_ALL
 
-#if 0 /* WIP */
-       /* Inter-Processor Interrupts on the Sun4m. */
+#ifdef __SMP__
+
        .align  4
-       .globl  sun4m_ipi
-sun4m_ipi:
-       SAVE_ALL_IPI4M
+       .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
 
-       set     MAILBOX_ADDRESS, %l4
-       ldub    [%l4], %l5
-       subcc   %l5, MBOX_STOPCPU, %g0
-       bne,a   1f
-        subcc  %l5, MBOX_STOPCPU2, %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_IDLECPU, %g0
+       wr      %l4, PSR_ET, %psr
+       WRITE_PAUSE
 
-       call    C_LABEL(prom_stopcpu)
-        mov    0, %o0
-       ba,a    2f      
+       call    C_LABEL(smp_message_irq)
+        nop
 
-1:
-       bne,a   1f
-        subcc  %l5, MBOX_IDLECPU2, %g0
+       RESTORE_ALL_FASTIRQ
 
-       call    C_LABEL(prom_idlecpu)
-        mov    0, %o0
-       ba,a    2f      
+       .align  4
+       .globl  linux_trap_ipi13_sun4m
+linux_trap_ipi13_sun4m:
+       /* NOTE: real_irq_entry saved state and grabbed klock already. */
 
-1:
-       bne,a   2f
+       /* 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 @@ sun4c_fault:
        .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 @@ C_LABEL(sunos_indir):
        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 @@ C_LABEL(sys_ptrace):
        .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 @@ C_LABEL(sys_sigpause):
         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 @@ C_LABEL(sys_sigreturn):
        .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 @@ C_LABEL(sys_fork):
        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 @@ C_LABEL(sys_clone):
        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 @@ linux_sparc_syscall:
        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 @@ linux_sparc_syscall:
 syscall_is_too_hard:
        rd      %wim, %l3
        SAVE_ALL
+       ENTER_SYSCALL
 
        wr      %l0, PSR_ET, %psr
        WRITE_PAUSE
@@ -985,7 +1160,6 @@ syscall_is_too_hard:
        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 @@ C_LABEL(ret_sys_call):
 
        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 @@ C_LABEL(ret_sys_call):
 
        .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 @@ fpsave_catch:
        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 @@ C_LABEL(udelay):
        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:
index dc605816a4d84bf74989c05498ac377f5f331ada..cc4faddb2773e2d76c68e5c518ccba7cf4b69df8 100644 (file)
@@ -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 @@ tsetup_7win_patch6:   and     %g2, 0x7f, %g2
         * T == Window entered when trap occurred
         * S == Window we will need to save if (1<<T) == %wim
         *
-        * Before execution gets here, it must be guaranteed that
+        * Before execution gets here, it must be guarenteed that
         * %l0 contains trap time %psr, %l1 and %l2 contain the
         * trap pc and npc, and %l3 contains the trap time %wim.
         */
@@ -181,7 +181,7 @@ tsetup_patch3:      and     %g2, 0xff, %g2                  ! patched on 7win Sparcs
                 mov    %t_kstack, %sp                  ! and onto kernel stack
 
 trap_setup_user_spill:
-               /* A spill occurred from either kernel or user mode
+               /* A spill occured from either kernel or user mode
                 * and there exist some user windows to deal with.
                 * A mask of the currently valid user windows
                 * is in %g1 upon entry to here.
@@ -200,7 +200,7 @@ tsetup_patch6:      and     %g2, 0xff, %g2          ! patched on 7win Sparcs
        wr      %g2, 0x0, %wim
        WRITE_PAUSE
 
-       /* Call MMU-architecture dependent stack checking
+       /* Call MMU-architecture dependant stack checking
         * routine.
         */
        .globl  C_LABEL(tsetup_mmu_patchme)
index 9e64d3aba7a6ae32e3a923116ad4210c0883a312..74632d15ee0446cf0fae979096001c0b1c92c345 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.47 1996/02/15 09:11:57 davem Exp $
+/* $Id: head.S,v 1.56 1996/04/04 16:30:22 tridge Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -6,6 +6,7 @@
  */
 
 #include <linux/version.h>
+#include <linux/config.h>
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
@@ -80,6 +81,9 @@ __stext:
 _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_irq11:TRAP_ENTRY_INTERRUPT(11)            /* IRQ Floppy Intr.              */
 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_cpdis:TRAP_ENTRY(0x24, do_cp_disabled)    /* Co-Processor Disabled         */
 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 @@ dbtrap2:BAD_TRAP(0xff)                      /* Debugger/PROM breakpoint #2   */
        .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 @@ C_LABEL(end_traptable):
        .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 @@ gokernel:
                 * 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 @@ already_mapped:
 
                /* 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 @@ copy_prom_lvl14:
 /* 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 @@ srmmu_remap:
 
                /* 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 @@ srmmu_nviking:
                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 @@ go_to_highmem:
  * 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 @@ sun4m_init:
  * 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 @@ sun4c_continue_boot:
                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 @@ sun4c_continue_boot:
                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 @@ sun4c_continue_boot:
                /* 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 @@ C_LABEL(linux_dbvec):
        .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
+
index 5c6b63a48b6644779100fa9f6cd7a2d68bbeb3ff..d7393937d4b32d2527e0ae8d9d6431a466aaca7d 100644 (file)
@@ -21,7 +21,7 @@ static struct idp_struct idprom_buff;
 
 /* 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 */
index b4880661005e97ced7ca3c389f00c9e8b4cc3c10..b6220e498ae058a8fe919d8cda8fc85efab6d98b 100644 (file)
@@ -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 next_free_region = IOBASE_VADDR;
 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 @@ void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
                
        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 @@ void *sparc_alloc_io (void *address, void *virtual, int len, char *name,
        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)
index ca59cad4764a076e0233d462366aff9c3172403e..3b858f0490cdbfc2c90e7911e8f8eea0a88d1b55 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -22,6 +24,7 @@
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/psr.h>
+#include <asm/smp.h>
 #include <asm/vaddrs.h>
 #include <asm/timer.h>
 #include <asm/openprom.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
-/* Pointer to the interrupt enable byte */
-unsigned char *interrupt_enable = 0;
-struct sun4m_intregs *sun4m_interrupts;
+/*
+ * 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 sun4c_disable_irq(unsigned int irq_nr)
+static void irq_panic(void)
 {
-       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);
+    extern char *cputypval;
+    prom_printf("machine: %s doesn't have irq handlers defined!\n",cputypval);
+    prom_halt();
 }
 
-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.");
+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 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);
-}
-
-void sun4m_enable_irq(unsigned int irq_nr)
-{
-#if 0
-       printk("IRQ routines not written for the sun4m yet.\n");
-       panic("IRQ unsupported arch.");
-#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 *);
-
-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
-};
+#define MAX_STATIC_ALLOC       4
+static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
+static int static_irq_count = 0;
 
-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 @@ int get_irq_list(char *buf)
 
 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 @@ void free_irq(unsigned int irq, void *dev_id)
                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 free_irq(unsigned int irq, void *dev_id)
 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 unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
 
 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 @@ void handler_irq(int irq, struct pt_regs * regs)
  */
 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_IRQ(int irq, struct pt_regs * regs)
  */
 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 @@ asmlinkage void do_fast_IRQ(int irq)
 /* 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 @@ int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_re
 
        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 @@ int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_re
        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 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        }
 
        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 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *)
        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 @@ int probe_irq_off(unsigned long mask)
   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 --git a/arch/sparc/kernel/mp.S b/arch/sparc/kernel/mp.S
deleted file mode 100644 (file)
index 5758a3e..0000000
+++ /dev/null
@@ -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 <asm/cprefix.h>
-#include <asm/head.h>
-#include <asm/psr.h>
-#include <asm/asi.h>
-#include <asm/vaddrs.h>
-#include <asm/contregs.h>
-
-
-       .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
-
index dba40d4f98c1e04d88ed9d10247a25315b49f2bd..6abc9189fbaec49262ed80a227ad7688387c9502 100644 (file)
@@ -380,7 +380,7 @@ probe_clock(int fchild)
        }
 }
 
-/* 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 @@ probe_auxio(void)
        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);
index 8dd5dfe4991460dc31db0c3509d846e5e029e3c1..e3433c0fe3378540552f0a03b023fe19d747fbbf 100644 (file)
@@ -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 <stdarg.h>
+
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/psr.h>
+#include <asm/system.h>
 
 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 @@ asmlinkage int sys_idle(void)
        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 show_regs(struct pt_regs * regs)
 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(&current->tss.float_regs[0], &current->tss.fsr,
                       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+#ifndef __SMP__
                last_task_used_math = NULL;
+#else
+               current->flags &= ~PF_USEDFPU;
+#endif
        }
        mmu_exit_hook();
 }
@@ -122,11 +184,20 @@ void flush_thread(void)
        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(&current->tss.float_regs[0], &current->tss.fsr,
                       &current->tss.fpqueue[0], &current->tss.fpqdepth);
+#ifndef __SMP__
+               last_task_used_math = NULL;
+#else
+               current->flags &= ~PF_USEDFPU;
+#endif
        }
 
        memset(&current->tss.reg_window[0], 0,
@@ -144,7 +215,7 @@ void flush_thread(void)
  * 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 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        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 --git a/arch/sparc/kernel/rirq.S b/arch/sparc/kernel/rirq.S
new file mode 100644 (file)
index 0000000..f5dea3b
--- /dev/null
@@ -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 <asm/cprefix.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/smp.h>
+#include <asm/contregs.h>
+#include <asm/winmacro.h>
+#include <asm/asmmacro.h>
+
+#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
index 4a36852559de97aaf5546ac3cdcb00b0d1fdf461..5eaa3b02f16b93be83984d3c444cf4bf9eea55be 100644 (file)
@@ -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 <asm/ptrace.h>
 #include <asm/psr.h>
 #include <asm/asi.h>
+#include <asm/smp.h>
 #include <asm/contregs.h>
 #include <asm/winmacro.h>
+#include <asm/asmmacro.h>
 
 #define t_psr     l0
 #define t_pc      l1
@@ -90,19 +92,7 @@ ret_trap_continue:
        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 @@ ret_trap_userwins_ok:
        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
@@ -231,6 +213,8 @@ rtrap_patch5:       and     %g1, 0xff, %g1
 1:
        LOAD_PT_ALL(sp, t_psr, t_pc, t_npc, g1)
 
+       LEAVE_SYSCALL
+
        wr      %t_psr, 0x0, %psr
        WRITE_PAUSE
 
index 3cacaccd8fa9d715203c7d9e852e5cca70ca2ebc..91e3e11e0b8bc8a59cd41b313f825cf8918fb1d6 100644 (file)
@@ -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.
  *
index 42011bc0082fd05eb10f539eb8d4b34ba78e1e6b..7027600a12423b85fa073dbcbc731a4b85758921 100644 (file)
@@ -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 <linux/ptrace.h>
 #include <linux/malloc.h>
 #include <linux/ldt.h>
+#include <linux/smp.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
@@ -47,7 +48,6 @@ struct screen_info screen_info = {
        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 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
        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 @@ unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 
 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 @@ void prom_sync_me(void)
                             "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 @@ unsigned int boot_flags;
 #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 @@ boot_flags_init(char *commands)
                                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 @@ static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
 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 @@ void setup_arch(char **cmdline_p,
        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 @@ void setup_arch(char **cmdline_p,
        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 @@ void setup_arch(char **cmdline_p,
 
        {
                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 @@ void setup_arch(char **cmdline_p,
                        prom_printf("Inconsistent console\n");
                        prom_halt();
                }
+#endif
        }
 #if 1
        /* XXX ROOT_DEV hack for kgdb - davem XXX */
@@ -301,6 +352,8 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 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 @@ int get_cpuinfo(char *buffer)
        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
             );
 
 }
index 263594d8a7634458f2a33fe5d1d4a8c0eecbbeba..9f12ac964171532bde08ad9c86749e194e180766 100644 (file)
@@ -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 @@ asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs)
        _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 @@ setup_frame(struct sigaction *sa, struct sigcontext_struct **fp,
           (((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.
                 */
index 62f87c52c175b77d5c46ce4c655eb84949d0eff0..4ce0add854b2b5291c977159caba73c11b646017 100644 (file)
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <asm/head.h>
+#include <asm/ptrace.h>
+
 #include <linux/kernel.h>
+#include <linux/tasks.h>
 #include <linux/smp.h>
 
-int smp_num_cpus;
-int smp_threads_ready;
-volatile unsigned long smp_msg_data;
-volatile int smp_src_cpu;
-volatile int smp_msg_id;
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
 
-static volatile int smp_commenced = 0;
+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);
 
-/* The only guaranteed locking primitive available on all Sparc
- * processors is 'ldstub [%addr_reg + imm], %dest_reg' which atomically
+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 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<<i);
+       for(i=0; i < NR_CPUS; i++)
+               cpu_number_map[i] = -1;
+       for(i=0; i < NR_CPUS; i++)
+               cpu_logical_map[i] = -1;
+       mid_xlate[boot_cpu_id] = (linux_cpus[boot_cpu_id].mid & ~8);
+       cpu_number_map[boot_cpu_id] = 0;
+       cpu_logical_map[0] = boot_cpu_id;
+       active_kernel_processor = boot_cpu_id;
+       smp_store_cpu_info(boot_cpu_id);
+       set_irq_udt(0);
+       local_flush_cache_all();
+       if(linux_num_cpus == 1)
+               return;  /* Not an MP box. */
+       for(i = 0; i < NR_CPUS; i++) {
+               if(i == boot_cpu_id)
+                       continue;
+
+               if(cpu_present_map & (1 << i)) {
+                       extern unsigned long sparc_cpu_startup;
+                       unsigned long *entry = &sparc_cpu_startup;
+                       int timeout;
+
+                       /* See trampoline.S for details... */
+                       entry += ((i-1) * 6);
+
+                       /* whirrr, whirrr, whirrrrrrrrr... */
+                       printk("Starting CPU %d at %p\n", i, entry);
+                       mid_xlate[i] = (linux_cpus[i].mid & ~8);
+                       current_set[i] = &init_task;
+                       local_flush_cache_all();
+                       prom_startcpu(linux_cpus[i].prom_node,
+                                     &penguin_ctable, 0, (char *)entry);
+
+                       /* wheee... it's going... */
+                       for(timeout = 0; timeout < 5000000; timeout++) {
+                               if(cpu_callin_map[i])
+                                       break;
+                               udelay(100);
+                       }
+                       if(cpu_callin_map[i]) {
+                               /* Another "Red Snapper". */
+                               cpucount++;
+                               cpu_number_map[i] = i;
+                               cpu_logical_map[i] = i;
+                       } else {
+                               printk("Penguin %d is stuck in the bottle.\n", i);
+                       }
+                       current_set[i] = 0;
+               }
+               if(!(cpu_callin_map[i])) {
+                       cpu_present_map &= ~(1 << i);
+                       cpu_number_map[i] = -1;
+               }
+       }
+       local_flush_cache_all();
+       if(cpucount == 0) {
+               printk("Error: only one Penguin found.\n");
+               cpu_present_map = (1 << smp_processor_id());
+       } else {
+               unsigned long bogosum = 0;
+               for(i = 0; i < NR_CPUS; i++) {
+                       if(cpu_present_map & (1 << i))
+                               bogosum += cpu_data[i].udelay_val;
+               }
+               printk("Total of %d Penguins activated (%lu.%02lu PenguinMIPS).\n",
+                      cpucount + 1,
+                      (bogosum + 2500)/500000,
+                      ((bogosum + 2500)/5000)%100);
+               smp_activated = 1;
+               smp_num_cpus = cpucount + 1;
+       }
+       smp_processors_ready = 1;
+}
+
+static inline void send_ipi(unsigned long target_map, int irq)
+{
+       int i;
+
+       for(i = 0; i < 4; i++) {
+               if((1<<i) & target_map)
+                       set_cpu_int(mid_xlate[i], irq);
+       }
 }
 
+/*
+ * A non wait message cannot pass data or cpu source info. This current
+ * setup is only safe because the kernel lock owner is the only person
+ * who can send a message.
+ *
+ * Wrapping this whole block in a spinlock is not the safe answer either.
+ * A processor may get stuck with irq's off waiting to send a message and
+ * thus not replying to the person spinning for a reply....
+ *
+ * In the end invalidate ought to be the NMI and a very very short
+ * function (to avoid the old IDE disk problems), and other messages sent
+ * with IRQ's enabled in a civilised fashion. That will also boost
+ * performance.
+ */
+
+static volatile int message_cpu = NO_PROC_ID;
+
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-       struct sparc_ipimsg *msg = (struct sparc_ipimsg *) data;
        unsigned long target_map;
        int p = smp_processor_id();
-       static volatile int message_cpu = NO_PROC_ID;
+       int irq = 15;
+       int i;
 
-       if(!smp_activated || !smp_commenced)
+       /* Before processors have been placed into their initial
+        * patterns do not send messages.
+        */
+       if(!smp_processors_ready)
                return;
 
+       /* Skip the reschedule if we are waiting to clear a
+        * message at this time. The reschedule cannot wait
+        * but is not critical.
+        */
        if(msg == MSG_RESCHEDULE) {
+               irq = 13;
                if(smp_cpu_in_msg[p])
                        return;
        }
 
-       if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU) {
-               panic("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
+       /* Sanity check we don't re-enter this across CPU's. Only the kernel
+        * lock holder may send messages. For a STOP_CPU we are bringing the
+        * entire box to the fastest halt we can.. A reschedule carries
+        * no data and can occur during a flush.. guess what panic
+        * I got to notice this bug...
+        */
+       if(message_cpu != NO_PROC_ID && msg != MSG_STOP_CPU && msg != MSG_RESCHEDULE) {
+               printk("CPU #%d: Message pass %d but pass in progress by %d of %d\n",
                      smp_processor_id(),msg,message_cpu, smp_msg_id);
+
+               /* I don't know how to gracefully die so that debugging
+                * this doesn't completely eat up my filesystems...
+                * let's try this...
+                */
+               smp_cpu_in_msg[p] = 0; /* In case we come back here... */
+               intr_count = 0;        /* and so panic don't barf... */
+               smp_swap(&message_cpu, NO_PROC_ID); /* push the store buffer */
+               sti();
+               printk("spinning, please L1-A, type ctrace and send output to davem\n");
+               while(1)
+                       barrier();
        }
-       message_cpu = smp_processor_id();
+       smp_swap(&message_cpu, smp_processor_id()); /* store buffers... */
+
+       /* We are busy. */
        smp_cpu_in_msg[p]++;
+
+       /* Reschedule is currently special. */
        if(msg != MSG_RESCHEDULE) {
                smp_src_cpu = p;
                smp_msg_id = msg;
                smp_msg_data = data;
        }
 
+#if 0
+       printk("SMP message pass from cpu %d to cpu %d msg %d\n", p, target, msg);
+#endif
+
+       /* Set the target requirement. */
+       for(i = 0; i < smp_num_cpus; i++)
+               swap((unsigned long *) &cpu_callin_map[i], 0);
        if(target == MSG_ALL_BUT_SELF) {
-               target_map = cpu_present_map;
-               cpu_callin_map[0] = (1<<smp_src_cpu);
+               target_map = (cpu_present_map & ~(1<<p));
+               swap((unsigned long *) &cpu_callin_map[p], 1);
        } else if(target == MSG_ALL) {
                target_map = cpu_present_map;
-               cpu_callin_map[0] = 0;
        } else {
+               for(i = 0; i < smp_num_cpus; i++)
+                       if(i != target)
+                               swap((unsigned long *) &cpu_callin_map[i], 1);
                target_map = (1<<target);
-               cpu_callin_map[0] = 0;
        }
 
-       /* XXX Send lvl15 soft interrupt to cpus here XXX */
+       /* Fire it off. */
+       send_ipi(target_map, irq);
 
        switch(wait) {
        case 1:
-               while(cpu_callin_map[0] != target_map);
+               for(i = 0; i < smp_num_cpus; i++)
+                       while(!cpu_callin_map[i])
+                               barrier();
                break;
        case 2:
-               while(smp_invalidate_needed);
+               for(i = 0; i < smp_num_cpus; i++)
+                       while(smp_invalidate_needed[i])
+                               barrier();
                break;
+       case 3:
+               /* For cross calls we hold message_cpu and smp_cpu_in_msg[]
+                * until all processors disperse.  Else we have _big_ problems.
+                */
+               return;
        }
        smp_cpu_in_msg[p]--;
-       message_cpu = NO_PROC_ID;
+       smp_swap(&message_cpu, NO_PROC_ID);
 }
 
-inline void smp_invalidate(int type, unsigned long a, unsigned long b, unsigned long c)
+struct smp_funcall {
+       smpfunc_t func;
+       unsigned long arg1;
+       unsigned long arg2;
+       unsigned long arg3;
+       unsigned long arg4;
+       unsigned long arg5;
+       unsigned long processors_in[NR_CPUS];  /* Set when ipi entered. */
+       unsigned long processors_out[NR_CPUS]; /* Set when ipi exited. */
+} ccall_info;
+
+/* Returns failure code if for example any of the cpu's failed to respond
+ * within a certain timeout period.
+ */
+
+#define CCALL_TIMEOUT   5000000 /* enough for initial testing */
+
+/* #define DEBUG_CCALL */
+
+/* Some nice day when we really thread the kernel I'd like to synchronize
+ * this with either a broadcast conditional variable, a resource adaptive
+ * generic mutex, or a convoy semaphore scheme of some sort.  No reason
+ * we can't let multiple processors in here if the appropriate locking
+ * is done.  Note that such a scheme assumes we will have a
+ * prioritized ipi scheme using different software level irq's.
+ */
+void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
+                   unsigned long arg3, unsigned long arg4, unsigned long arg5)
 {
+       unsigned long me = smp_processor_id();
        unsigned long flags;
+       int i, timeout;
 
-       smp_invalidate_needed = cpu_present_map & ~(1<<smp_processor_id());
-       save_flags(flags); cli();
-       smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
-       local_invalidate();
+#ifdef DEBUG_CCALL
+       printk("xc%d<", me);
+#endif
+       if(smp_processors_ready) {
+               save_flags(flags); cli();
+               if(me != active_kernel_processor)
+                       goto cross_call_not_master;
+
+               /* Init function glue. */
+               ccall_info.func = func;
+               ccall_info.arg1 = arg1;
+               ccall_info.arg2 = arg2;
+               ccall_info.arg3 = arg3;
+               ccall_info.arg4 = arg4;
+               ccall_info.arg5 = arg5;
+
+               /* Init receive/complete mapping. */
+               for(i = 0; i < smp_num_cpus; i++) {
+                       ccall_info.processors_in[i] = 0;
+                       ccall_info.processors_out[i] = 0;
+               }
+               ccall_info.processors_in[me] = 1;
+               ccall_info.processors_out[me] = 1;
+
+               /* Fire it off. */
+               smp_message_pass(MSG_ALL_BUT_SELF, MSG_CROSS_CALL, 0, 3);
+
+               /* For debugging purposes right now we can timeout
+                * on both callin and callexit.
+                */
+               timeout = CCALL_TIMEOUT;
+               for(i = 0; i < smp_num_cpus; i++) {
+                       while(!ccall_info.processors_in[i] && timeout-- > 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]++;
-               }
-#endif
-       }
 
-       /*
-        * 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);
-       }
+       need_resched=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);
+/* 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);
+}
+
+void smp_release(void)
+{
+       unsigned long flags;
+       int i;
 
-       if(0 > --current->counter || current->pid == 0) {
-               current->counter = 0;
-               need_resched = 1;
+       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++<NR_CPUS)
-               printk("IPI %d->%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<<smp_processor_id();
-                       break;
-                       
+
+       switch(smp_msg_id) {
+       case MSG_CROSS_CALL:
+               /* Do it to it. */
+               ccall_info.processors_in[i] = 1;
+               ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3,
+                               ccall_info.arg4, ccall_info.arg5);
+               ccall_info.processors_out[i] = 1;
+               break;
+
                /*
                 *      Halt other CPU's for a panic or reboot
                 */
-               case MSG_STOP_CPU:
-                       while(1)
-                       {
-                               if(cpu_data[smp_processor_id()].hlt_works_ok)
-                                       __asm__("hlt");
-                       }
-               default:
-                       printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
-                               smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
-                       break;
+       case MSG_STOP_CPU:
+               sti();
+               while(1)
+                       barrier();
+
+       default:
+               printk("CPU #%d sent invalid cross CPU message to CPU #%d: %X(%lX).\n",
+                      smp_src_cpu,smp_processor_id(),smp_msg_id,smp_msg_data);
+               break;
        }
-       /*
-        *      Clear the IPI, so we can receive future IPI's
-        */
-        
-       apic_read(APIC_SPIV);           /* Dummy read */
-       apic_write(APIC_EOI, 0);        /* Docs say use 0 for future compatibility */
 }
diff --git a/arch/sparc/kernel/solaris.c b/arch/sparc/kernel/solaris.c
new file mode 100644 (file)
index 0000000..bb741c8
--- /dev/null
@@ -0,0 +1,59 @@
+/* solaris.c: Solaris binary emulation, whee...
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+
+#include <asm/errno.h>
+#include <asm/solerrno.h>
+
+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);
+}
+
+
index 56875ba0179376cb40976ec2e48d5276ca12b725..436a65f85d38fe39839dd1bd5916cd6f4303a736 100644 (file)
@@ -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.
  */
 
 #include <asm/system.h>
 #include <asm/vac-ops.h>
 #include <asm/kgdb.h>
-
+#include <asm/pgtable.h>
 /*
  *
  * external low-level support routines
@@ -163,6 +163,10 @@ unsigned long get_sun4csegmap(unsigned long addr)
        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 @@ void
 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 @@ set_debug_traps(void)
        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 @@ hexToInt(char **ptr, int *intValue)
 }
 
 /*
- * 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 @@ handle_exception (unsigned long *registers)
  * 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 --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
new file mode 100644 (file)
index 0000000..e20871b
--- /dev/null
@@ -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 <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+/* 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 --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
new file mode 100644 (file)
index 0000000..bca4a28
--- /dev/null
@@ -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 <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/psr.h>
+#include <asm/vaddrs.h>
+#include <asm/timer.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/traps.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+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; i<linux_num_cpus; i++)
+               sun4m_interrupts->cpu_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();
+}
index d7ea7cc31649c66fdf8cdfa70613e116a9e676a8..eda4cd9680256cb954e2215afd47a1a148303994 100644 (file)
@@ -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 @@ C_LABEL(sunos_execv):
        call    C_LABEL(sparc_execve)
         add    %sp, REGWIN_SZ, %o0
 
-       st      %o0, [%sp + REGWIN_SZ + PT_I0]
-
        b       C_LABEL(ret_sys_call)
         nop
 
+        
+
index 3876efdaa4c13e25f9e278a5858255302952f019..a77dbb128ea784b05464fa1fc3ccde53569cee6d 100644 (file)
@@ -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 <linux/route.h>
 #include <linux/sockios.h>
 #include <linux/if.h>
+#include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
@@ -52,7 +53,7 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg)
                }
        }
 
-       /* Binary compatibility is good American knowhow fuckin' up. */
+       /* Binary compatability is good American knowhow fuckin' up. */
        if(cmd == TIOCNOTTY)
                return sys_setsid();
 
index 305f31644f59d7bfad1b7123304f59b9adcc0e93..1153b5eabdf25f9a28c0536714e18e88bef38010 100644 (file)
@@ -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 <asm/contregs.h>
 #include <asm/cprefix.h>
 #include <asm/psr.h>
+#include <asm/asmmacro.h>
 #include <asm/ptrace.h>
 #include <asm/winmacro.h>
 
@@ -40,8 +41,14 @@ C_LABEL(sparc_switch_to):
        /* 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 @@ C_LABEL(sparc_switch_to):
 
        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 --git a/arch/sparc/kernel/sys_bsd.c b/arch/sparc/kernel/sys_bsd.c
deleted file mode 100644 (file)
index fce1c58..0000000
+++ /dev/null
@@ -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 <linux/kernel.h>
-
-#include <asm/ptrace.h>
-#include <asm/bsderrno.h>
-
-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;
-}
index 69ca40876f133fe60d20b2f31255a19a6de2f79a..dd1d7b84c5ad699450275c3a256069d1c94fceb3 100644 (file)
@@ -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 @@ asmlinkage unsigned long sys_getpagesize(void)
 
 /*
  * 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];
        }
 }
 
@@ -165,3 +165,43 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
                }
        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;
+}
index 9e00101f1f318138d0cc32b1f313c730891d30bf..1ea96bd7173097736d0bdcbba46428881e8e67c7 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/mman.h>
-#include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/fs.h>
 #include <linux/utsname.h>
 #include <linux/fs.h>
 #include <linux/major.h>
+#include <linux/stat.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+
+#include <asm/segment.h>
+#ifndef KERNEL_DS
+#include <linux/segment.h>
+#endif
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/pconf.h>
 #include <asm/idprom.h> /* for gethostid() */
 #include <asm/unistd.h>
+#include <asm/system.h>
 
 /* For the nfs mount emulation */
 #include <linux/socket.h>
 #include <linux/time.h>
 #include <linux/personality.h>
 
-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 @@ asmlinkage int sunos_brk(unsigned long brk)
         * 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 @@ asmlinkage unsigned long sunos_sbrk(int increment)
 }
 
 /* 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 @@ asmlinkage void sunos_madvise(unsigned long address, unsigned long len,
  * 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 @@ asmlinkage int sunos_mincore(unsigned long addr, unsigned long len, char *array)
 }
 
 /* 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 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt)
        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 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
                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 @@ extern asmlinkage long sunos_sysconf (int name)
        }
        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;
+}
+
index 1f9b2408b1898c6f06f42063b3f3e9fea27b18d6..0640aa821f793b567f7036dea77ac162174bd2fe 100644 (file)
@@ -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)
        .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 @@ C_LABEL(sys_call_table):
        .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 @@ C_LABEL(sys_call_table):
        .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 @@ C_LABEL(sunos_sys_table):
        .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 @@ C_LABEL(sunos_sys_table):
        .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 @@ C_LABEL(sunos_sys_table):
        .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 @@ C_LABEL(bsd_sys_table):
        .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 --git a/arch/sparc/kernel/tadpole.c b/arch/sparc/kernel/tadpole.c
new file mode 100644 (file)
index 0000000..5255cb2
--- /dev/null
@@ -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 <linux/string.h>
+
+#include <asm/asi.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+
+#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 --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
new file mode 100644 (file)
index 0000000..edfc09e
--- /dev/null
@@ -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 <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/timex.h>
+
+#include <asm/oplib.h>
+#include <asm/segment.h>
+#include <asm/timer.h>
+#include <asm/mostek.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+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);
+       }
+}
index 98338ad2efa9e6b1b603e0af0c692d6aaea9a825..dc12ac83ad2f7afdc232c60fc3c3bded51700a58 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
-#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 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        /* 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 @@ static void clock_probe(void)
        /* 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 @@ static void clock_probe(void)
                        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 @@ void time_init(void)
        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 @@ void time_init(void)
        mregs->creg &= ~MSTK_CREG_READ;
        return;
 }
+
 /* Nothing fancy on the Sparc yet. */
 void do_gettimeofday(struct timeval *tv)
 {
@@ -263,6 +195,9 @@ void do_gettimeofday(struct timeval *tv)
 
        save_flags(flags);
        cli();
+#if CONFIG_AP1000
+       ap_gettimeofday(&xtime);
+#endif
        *tv = xtime;
        restore_flags(flags);
 }
diff --git a/arch/sparc/kernel/trampoline.S b/arch/sparc/kernel/trampoline.S
new file mode 100644 (file)
index 0000000..0a1cb14
--- /dev/null
@@ -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 <asm/cprefix.h>
+#include <asm/head.h>
+#include <asm/psr.h>
+#include <asm/asi.h>
+#include <asm/ptrace.h>
+#include <asm/vaddrs.h>
+#include <asm/contregs.h>
+
+
+       .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
index 5736b70f6f28f8cedadbcdf768b6e957a13efabe..614cd9c5b7ac3f2c4b6cecd59345702313549441 100644 (file)
@@ -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 <linux/sched.h>  /* for jiffies */
 #include <linux/kernel.h>
+#include <linux/config.h>
 #include <linux/signal.h>
 
 #include <asm/delay.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/mp.h>
 #include <asm/kdebug.h>
 #include <asm/unistd.h>
+#include <asm/smp.h>
+
+/* #define TRAP_DEBUG */
 
 struct trap_trace_entry {
        unsigned long pc;
@@ -41,20 +44,47 @@ void syscall_trace_exit(struct pt_regs *regs)
 {
 }
 
+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 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
        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 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon
 {
        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_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n
 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 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 {
        /* 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 @@ void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                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(&current->tss.float_regs[0], &current->tss.fsr);
+       }
+       current->flags |= PF_USEDFPU;
+#endif
 }
 
 static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
@@ -149,22 +197,33 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                 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 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                                      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_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long n
 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_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc
 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_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long np
 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 @@ void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc
 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 @@ int thiscpus_mid;
 
 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; i<linux_num_cpus; i++) {
-               if((linux_cpus[i].mid & (~8)) != 0x0) {
-                       static int cpuid = 0;
-                       cpuid = (linux_cpus[i].mid & (~8));
-                       percpu_table[cpuid].cpu_is_alive = 0;
-                       thiscpus_mid = linux_cpus[i].mid;
-                       thiscpus_tbr = (unsigned int)
-                               percpu_table[cpuid].trap_table;
-                       prom_startcpu(linux_cpus[i].prom_node, &ctx_reg, 0x0,
-                                     (char *) sparc_cpu_startup);
-                       prom_printf("Waiting for cpu %d to start up...\n", i);
-                       while(percpu_table[cpuid].cpu_is_alive == 0) {
-                               static int counter = 0;
-                               counter++;
-                               if(counter>200)
-                                       break;
-                               __delay(200000);
-                       }
-               }
-       }
-
-       linux_smp_still_initting = 1;
 }
index 69003289114aba13ded15bd27b478541f1a04fec..0aaf19999fd0f35d9f31c7db2956657575d2a62d 100644 (file)
@@ -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 <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
+#include <asm/smp.h>
 #include <asm/asi.h>
 #include <asm/winmacro.h>
+#include <asm/asmmacro.h>
 
 /* 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 @@ spnwin_patch3:    and     %twin_tmp, 0xff, %twin_tmp      ! patched on 7win Sparcs
        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
index ab6259a7bc35bc681a07d319fc40f305b08b4d44..08672ef0e9dfee4a7dfa2ded33aa7be7da07a92f 100644 (file)
@@ -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 <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/psr.h>
+#include <asm/smp.h>
 #include <asm/asi.h>
 #include <asm/winmacro.h>
+#include <asm/asmmacro.h>
 
 /* Just like the overflow handler we define macros for registers
  * with fixed meanings in this routine.
@@ -178,6 +180,8 @@ fwin_user_stack_is_bolixed:
        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 @@ fwin_user_finish_up:
         * 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 @@ C_LABEL(srmmu_fwin_stackchk):
        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.
index 7e0aa8739480c0111fd05327d87eea880724646e..e1dd6018fe9ac54b3fe00ef0fb489f3139ac5c13 100644 (file)
@@ -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)
@@ -13,6 +14,9 @@ lib.a: $(OBJS)
 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 --git a/arch/sparc/lib/memset.c b/arch/sparc/lib/memset.c
new file mode 100644 (file)
index 0000000..1e81dff
--- /dev/null
@@ -0,0 +1,71 @@
+/* linux/arch/sparc/lib/memset.c
+ *
+ * This is from GNU libc.
+ */
+
+#include <linux/types.h>
+
+#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 --git a/arch/sparc/lib/strlen.S b/arch/sparc/lib/strlen.S
new file mode 100644 (file)
index 0000000..3037d80
--- /dev/null
@@ -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 <asm/cprefix.h>
+
+#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
index 3e084f17ac848cd4aeefff8a017dbf73dba71859..2792bf6e3ecb22a2932139db5558ee1116f9ce76 100644 (file)
@@ -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
index d39663ae0ff51c4cceacdd8a1eaecc8956f6cc03..c4a6fc805f7501d7f763f769a319403914b17283 100644 (file)
@@ -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 <asm/head.h>
+
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/ptrace.h>
 #include <linux/mman.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
 
@@ -20,6 +24,7 @@
 #include <asm/memreg.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/smp.h>
 #include <asm/traps.h>
 #include <asm/kdebug.h>
 
@@ -81,6 +86,12 @@ int prom_probe_memory (void)
        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 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        struct vm_area_struct *vma;
        int from_user = !(regs->psr & PSR_PS);
 
+#if 0
+       printk("CPU[%d]: f<pid=%d,tf=%d,wr=%d,addr=%08lx",
+              smp_processor_id(), current->pid, text_fault,
+              write, address);
+       printk(",pc=%08lx> ", regs->pc);
+#endif
+
        if(text_fault)
                address = regs->pc;
 
@@ -131,8 +149,15 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
         * 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,21 +190,15 @@ good_area:
         */
 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) {
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
        } else
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
new file mode 100644 (file)
index 0000000..8387eda
--- /dev/null
@@ -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 <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+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;
+}
index fcd2dfc6e252c718f7d94f4c70fbc30e8961a5fe..423770579cccdf01e57546ae7d9ce55cf47e05be 100644 (file)
@@ -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 @@ void show_mem(void)
        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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        };
 
        /* 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 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
        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<<PG_reserved);
+                       }
+               }
+       } else {
+               for(addr = start_mem; addr < end_mem; addr += PAGE_SIZE)
+                       mem_map[MAP_NR(addr)].flags &= ~(1<<PG_reserved);
+       }
+}
+
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
        int codepages = 0;
@@ -178,23 +199,13 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
 
        addr = PAGE_OFFSET;
        while(addr < start_mem) {
-               mem_map[MAP_NR(addr)].reserved = 1;
+               mem_map[MAP_NR(addr)].flags |= (1<<PG_reserved);
                addr += PAGE_SIZE;
        }
 
-       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)].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 @@ void mem_init(unsigned long start_mem, unsigned long end_mem)
        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 @@ void si_meminfo(struct sysinfo *val)
        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)
index d5ee840af9d204c014b9c795e5b633efe79ddcad..611af1074de1320ee8e3a38c3618c42ea3c79ebc 100644 (file)
@@ -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 <linux/kernel.h>
+#include <linux/mm.h>
 
 #include <asm/system.h>
 #include <asm/page.h>
@@ -26,18 +27,48 @@ void (*quick_kernel_fault)(unsigned long);
 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 @@ void (*switch_to_context)(struct task_struct *tsk);
 
 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 @@ load_mmu(void)
                printk("load_mmu:sparc_cpu_model = %d\n", (int) sparc_cpu_model);
                printk("load_mmu:Halting...\n");
                panic("load_mmu()");
-       };
+       }
 }
diff --git a/arch/sparc/mm/s4cflsh.S b/arch/sparc/mm/s4cflsh.S
deleted file mode 100644 (file)
index 3f287f3..0000000
+++ /dev/null
@@ -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 --git a/arch/sparc/mm/s4ckflt.S b/arch/sparc/mm/s4ckflt.S
deleted file mode 100644 (file)
index bb006ba..0000000
+++ /dev/null
@@ -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 --git a/arch/sparc/mm/s4clow.h b/arch/sparc/mm/s4clow.h
deleted file mode 100644 (file)
index 3c568f0..0000000
+++ /dev/null
@@ -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 --git a/arch/sparc/mm/s4cuflt.S b/arch/sparc/mm/s4cuflt.S
deleted file mode 100644 (file)
index 7b11731..0000000
+++ /dev/null
@@ -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:
index 0b305d4835beac2b761ab6a1c7ac95e13770f2ad..44267a773139401b18fe7485fed9cc5a165386d2 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/mm.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/kdebug.h>
 #include <asm/vaddrs.h>
 #include <asm/traps.h>
-#include <asm/mp.h>
+#include <asm/smp.h>
 #include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
 #include <asm/sbus.h>
 #include <asm/iommu.h>
+#include <asm/asi.h>
+#include <asm/msi.h>
 
 /* Now the cpu specific definitions. */
 #include <asm/viking.h>
+#include <asm/mxcc.h>
 #include <asm/ross.h>
 #include <asm/tsunami.h>
 #include <asm/swift.h>
 
 enum mbus_module srmmu_modtype;
 unsigned int hwbug_bitmask;
-
 int hyper_cache_size;
-
+int hyper_line_size;
+
+#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;
+
+static char *srmmu_name;
+
+ctxd_t *srmmu_ctx_table_phys;
 ctxd_t *srmmu_context_table;
 
-/* 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 struct srmmu_trans {
+       unsigned long vbase;
+       unsigned long pbase;
+       int size;
+} srmmu_map[SPARC_PHYS_BANKS];
 
-/* Functions really use this, not srmmu_swap directly. */
-#define srmmu_set_entry(ptr, newentry) \
-        srmmu_swap((unsigned long *) (ptr), (newentry))
+static int can_cache_ptables = 0;
+static int viking_mxcc_present = 0;
 
-/* We still don't use these at all, perhaps we don't need them
- * at all.
+/* 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_vmalloc_start(void)
 }
 
 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_bad(pmd_t pmd)
 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_bad(pgd_t pgd)
 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 @@ static pte_t srmmu_pte_mkyoung(pte_t pte)     { pte_val(pte) |= SRMMU_REF; retur
  * 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 @@ static pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address)
 /* 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_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp)
  */
 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 pte_t *srmmu_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 
 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 pmd_t *srmmu_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
 
 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,402 +407,886 @@ static pmd_t *srmmu_pmd_alloc(pgd_t * pgd, unsigned long address)
 
 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)
+{
+       flush_user_windows();
+       tsunami_flush_icache();
+       tsunami_flush_dcache();
+}
+
+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)
 {
-       unsigned long addr = 0;
+#ifndef __SMP__
+       if(mm->context != NO_CONTEXT) {
+#endif
+               flush_user_windows();
+               tsunami_flush_icache();
+               tsunami_flush_dcache();
+#ifndef __SMP__
+       }
+#endif
+}
 
-       /* 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_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();
+
+               srmmu_set_context(mm->context);
+               srmmu_flush_tlb_page(page);
+               TSUNAMI_SUCKS;
+               srmmu_set_context(octx);
+#ifndef __SMP__
+       }
+#endif
+       module_stats.invpg++;
+}
 
-       if(cc != ncc)
-               srmmu_set_context(cc);
-       restore_flags(flags);
+static void tsunami_flush_tlb_page_for_cbit(unsigned long page)
+{
+       srmmu_flush_tlb_page(page);
 }
 
-static void swift_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+/* 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)
 {
-       unsigned long flags, addr;
-       int cc, ncc = mm->context;
+       flush_user_windows();
+       swift_idflash_clear();
+}
 
-       if(ncc == NO_CONTEXT)
-               return;
+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);
+       paddr0 = (ppage >> 28) | 0x10;          /* Set cacheable bit. */
+       paddr1 = (ppage << 4) & PAGE_MASK;
 
-       /* 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;
+       /* 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_no_mxcc_flush_page(unsigned long page)
+{
+       unsigned long ppage = srmmu_hwprobe(page) >> 8;
+       int set, block;
+       unsigned long ptag[2];
+       unsigned long vaddr;
+       int i;
+
+       if (!ppage)
+               return;
+
+       for (set = 0; set < 128; set++) {
+               for (block = 0; block < 4; block++) {
+
+                       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;
+                       }
+
+                       /* Continue with next set. */
+                       break;
+               }
        }
+}
 
-       if(cc != ncc)
-               srmmu_set_context(cc);
-       restore_flags(flags);
+static void viking_flush_tlb_all(void)
+{
+       module_stats.invall++;
+       srmmu_flush_whole_tlb();
 }
-static void viking_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+
+static void viking_flush_tlb_mm(struct mm_struct *mm)
 {
-       unsigned long flags;
-       int cc, ncc = vmp->vm_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
+}
+
+static void viking_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       int octx;
+       module_stats.invrnge++;
 
-       save_flags(flags); cli();
-       cc = srmmu_get_context();
-       if(cc != ncc)
-               srmmu_set_context(ncc);
+#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
+}
 
-       viking_flush_icache();
-       viking_flush_dcache();
-       srmmu_flush_tlb_page(page);
+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
 }
 
-/* Cypress invalidates. */
-static inline void cypress_invalidate_all(void)
+static void viking_flush_tlb_page_for_cbit(unsigned long page)
 {
-       srmmu_flush_whole_tlb();
+       srmmu_flush_tlb_page(page);
 }
-static void cypress_invalidate_mm(struct mm_struct *mm)
+
+/* Cypress flushes. */
+
+static void cypress_flush_tlb_all(void)
 {
-       unsigned long flags;
-       int cc, ncc = mm->context;
+       module_stats.invall++;
+       srmmu_flush_whole_tlb();
+}
 
-       if(ncc == NO_CONTEXT)
-               return;
+static void cypress_flush_tlb_mm(struct mm_struct *mm)
+{
+       int octx;
 
-       /* have context will travel... */
-       save_flags(flags); cli();
-       cc = srmmu_get_context();
-       if(cc != ncc)
-               srmmu_set_context(ncc);
+       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
+}
 
-       cypress_flush_context(); /* POOF! */
-       srmmu_flush_whole_tlb(); /* POW! */
+static void cypress_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       int octx;
 
-       if(cc != ncc)
-               srmmu_set_context(cc);
-       restore_flags(flags);
+       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
 }
-static void cypress_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+
+static void cypress_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
-       unsigned long flags, addr;
-       int cc, ncc = mm->context;
+       int octx;
+       struct mm_struct *mm = vma->vm_mm;
 
-       if(ncc == NO_CONTEXT)
-               return;
+       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
+}
 
-       save_flags(flags); cli();
-       cc = srmmu_get_context();
-       if(cc != ncc)
-               srmmu_set_context(ncc);
+/* Hypersparc flushes.  Very nice chip... */
+static void hypersparc_flush_cache_all(void)
+{
+       flush_user_windows();
+       hyper_flush_unconditional_combined();
+       hyper_flush_whole_icache();
+}
 
-       /* 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 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__
        }
-       srmmu_flush_whole_tlb();
+#endif
+}
 
-       if(cc != ncc)
-               srmmu_set_context(cc);
-       restore_flags(flags);
+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 cypress_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+/* 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)
 {
-       unsigned long flags;
-       int cc, ncc = vmp->vm_mm->context;
+       struct mm_struct *mm = vma->vm_mm;
+       volatile unsigned long clear;
+       int octx;
 
-       if(ncc == NO_CONTEXT)
-               return;
+#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
+}
 
-       save_flags(flags); cli();
-       cc = srmmu_get_context();
-       if(cc != ncc)
-               srmmu_set_context(ncc);
+/* HyperSparc is copy-back. */
+static void hypersparc_flush_page_to_ram(unsigned long page)
+{
+       volatile unsigned long clear;
 
-       swift_flush_page(page);
-       srmmu_flush_whole_tlb();
+       if(srmmu_hwprobe(page))
+               hyper_flush_cache_page(page);
+       clear = srmmu_get_fstatus();
+}
+
+/* HyperSparc is IO cache coherent. */
+static void hypersparc_flush_page_for_dma(unsigned long page)
+{
+       volatile unsigned long clear;
 
-       if(cc != ncc)
-               srmmu_set_context(cc);
-       restore_flags(flags);
+       if(srmmu_hwprobe(page))
+               hyper_flush_cache_page(page);
+       clear = srmmu_get_fstatus();
 }
 
-/* Hypersparc invalidates. */
-static inline void hypersparc_invalidate_all(void)
+static void hypersparc_flush_cache_page_to_uncache(unsigned long page)
 {
+       volatile unsigned long clear;
 
-       hyper_flush_whole_icache();
+       if(srmmu_hwprobe(page))
+               hyper_flush_cache_page(page);
+       clear = srmmu_get_fstatus();
+}
+
+static void hypersparc_flush_tlb_all(void)
+{
+       module_stats.invall++;
        srmmu_flush_whole_tlb();
 }
 
-static void hypersparc_invalidate_mm(struct mm_struct *mm)
+static void hypersparc_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 hypersparc_invalidate_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+static void hypersparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
+       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__
+       }
+#endif
 }
 
-static void hypersparc_invalidate_page(struct vm_area_struct *vmp, unsigned long page)
+static void hypersparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
+       struct mm_struct *mm = vma->vm_mm;
+       int octx;
+
+       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 srmmu_set_pte(pte_t *ptep, pte_t pteval)
+static void hypersparc_flush_tlb_page_for_cbit(unsigned long page)
 {
-       srmmu_set_entry(ptep, pte_val(pteval));
+       srmmu_flush_tlb_page(page);
 }
 
-static void srmmu_quick_kernel_fault(unsigned long address)
+static void hypersparc_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp)
 {
-       printk("SRMMU: quick_kernel_fault called for %08lx\n", address);
-       panic("Srmmu bolixed...");
+       hyper_flush_whole_icache();
+       srmmu_set_entry(ctxp, (SRMMU_ET_PTD | (srmmu_v2p((unsigned long) pgdp) >> 4)));
 }
 
-static inline void alloc_context(struct mm_struct *mm)
+static void hypersparc_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdp) 
 {
-       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;
+       if(tsk->mm->context != NO_CONTEXT) {
+               hyper_flush_whole_icache();
+               ctxd_set(&srmmu_context_table[tsk->mm->context], pgdp);
        }
-       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;
 }
 
-static void srmmu_switch_to_context(struct task_struct *tsk)
+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);
-               srmmu_ctxd_set(&srmmu_context_table[tsk->mm->context], tsk->mm->pgd);
+               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 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();
-}
-
-static char *srmmu_lockarea(char *vaddr, unsigned long len)
-{
-       return vaddr;
-}
-
-static void srmmu_unlockarea(char *vaddr, unsigned long len)
-{
-}
-
 /* IOMMU things go here. */
 
 #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 @@ static inline void srmmu_map_dvma_pages_for_iommu(struct iommu_struct *iommu)
        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 @@ unsigned long iommu_init(int iommund, unsigned long memory_start,
        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 @@ unsigned long iommu_init(int iommund, unsigned long memory_start,
        /* 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 @@ unsigned long iommu_init(int iommund, unsigned long memory_start,
        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.");
-
-       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();
-
-       return vaddr;
+
+       flush_page_for_dma(page);
+       vaddr = (char *) (start | offset);
+       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_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_buffer(char *vaddr, unsigned long len, struct linux_sbus *sbus)
+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 @@ static void srmmu_release_scsi_buffer(char *vaddr, unsigned long len, struct lin
        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 @@ static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned
                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 @@ static inline void srmmu_allocate_ptable_skeleton(unsigned long start, unsigned
  * 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 @@ static inline void srmmu_map_dvma_pages_for_cpu(unsigned long first, unsigned lo
        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 @@ unsigned long srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
                        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 @@ static void srmmu_exit_hook(void)
        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_exit_hook(void)
        }
 }
 
-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 @@ void srmmu_is_bad(void)
        prom_halt();
 }
 
+void poke_hypersparc(void)
+{
+       volatile unsigned long clear;
+       unsigned long mreg = srmmu_get_mmureg();
+
+       hyper_flush_unconditional_combined();
+
+       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();
+       clear = srmmu_get_faddr();
+       clear = srmmu_get_fstatus();
+}
+
 void init_hypersparc(void)
 {
        unsigned long mreg = srmmu_get_mmureg();
 
-       prom_printf("HyperSparc MMU detected.\n");
-       if(mreg & HYPERSPARC_CSIZE)
+       srmmu_name = "ROSS HyperSparc";
+       can_cache_ptables = 0;
+       if(mreg & HYPERSPARC_CSIZE) {
                hyper_cache_size = (256 * 1024);
-       else
+               hyper_line_size = 64;
+       } else {
                hyper_cache_size = (128 * 1024);
+               hyper_line_size = 32;
+       }
 
-       srmmu_modtype = HyperSparc;
-       hwbug_bitmask |= HWBUG_VACFLUSH_BITROT;
+       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;
 
-       hyper_flush_whole_icache();
-       hyper_flush_all_combined();
+       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;
 
-       /* 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;
+       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 @@ void init_cypress_605(unsigned long mrev)
        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 @@ void init_swift(void)
                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);
+       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;
 
-       invalidate_all = swift_invalidate_all;
-       invalidate_mm = swift_invalidate_mm;
-       invalidate_page = swift_invalidate_page;
-       invalidate_range = swift_invalidate_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);
+       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 poke_viking(void)
+{
+       unsigned long mreg = srmmu_get_mmureg();
+       static int smp_catch = 0;
+
+       if(viking_mxcc_present) {
+               unsigned long mxcc_control;
+
+               __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 {
+               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();
+               }
+       }
+
+       viking_unlock_icache();
+       viking_flush_icache();
+#if 0
+       viking_unlock_dcache();
+       viking_flush_dcache();
+#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 = tsunami_invalidate_all;
-       invalidate_mm = tsunami_invalidate_mm;
-       invalidate_page = tsunami_invalidate_page;
-       invalidate_range = tsunami_invalidate_range;
 }
 
-void init_viking(unsigned long psr_vers, unsigned long mod_rev)
+void init_viking(void)
 {
        unsigned long mreg = srmmu_get_mmureg();
 
        /* Ahhh, the viking.  SRMMU VLSI abortion number two... */
 
-       prom_printf("Viking MMU detected.\n");
-       if(!psr_vers && ! mod_rev) {
-               srmmu_modtype = Viking_12;
-               hwbug_bitmask |= (HWBUG_MODIFIED_BITROT | HWBUG_PC_BADFAULT_ADDR);
+       if(mreg & VIKING_MMODE) {
+               unsigned long bpreg;
 
-               /* 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...
-                */
+               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 {
-               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;
-                       }
-               }
+               srmmu_name = "TI Viking/MXCC";
+               viking_mxcc_present = 1;
+               can_cache_ptables = 1;
+               flush_cache_page_to_uncache = viking_mxcc_flush_page;
        }
-       /* XXX Dave, play with the MXCC you pinhead XXX */
-       viking_flush_icache();
-       viking_flush_dcache();
-       mreg |= (VIKING_DCENABLE | VIKING_ICENABLE | VIKING_SBENABLE |
-                VIKING_TCENABLE | VIKING_DPENABLE);
-       srmmu_set_mmureg(mreg);
-       invalidate_all = viking_invalidate_all;
-       invalidate_mm = viking_invalidate_mm;
-       invalidate_page = viking_invalidate_page;
-       invalidate_range = viking_invalidate_range;
+
+       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 @@ static void get_srmmu_type(void)
        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_mmu_patchme, fwin_mmu_patchme,
 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 @@ static void patch_window_trap_handlers(void)
        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 @@ void ld_mmu_srmmu(void)
 
        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 @@ void ld_mmu_srmmu(void)
        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 @@ void ld_mmu_srmmu(void)
 
        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 --git a/arch/sparc/mm/srmmu_mp.S b/arch/sparc/mm/srmmu_mp.S
new file mode 100644 (file)
index 0000000..ae018e6
--- /dev/null
@@ -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 <asm/cprefix.h>
+#include <asm/asi.h>
+
+       /* 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 --git a/arch/sparc/mm/srmmuinv.c b/arch/sparc/mm/srmmuinv.c
deleted file mode 100644 (file)
index 50f3f96..0000000
+++ /dev/null
@@ -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 */
index 6754f906daafc1af25ac704fa77cb8709176cae3..81c6fcbc3ad4c868f75a811dc7a6661f6bf51044 100644 (file)
@@ -20,6 +20,19 @@ extern int num_segmaps, num_contexts;
 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 @@ void sun4c_flush_all(void)
 }
 
 /* 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 @@ static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp, unsigned char ctx
 }
 
 /* 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 @@ static void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long add
 /* 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 @@ static void sun4c_quick_kernel_fault(unsigned long address)
 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 struct task_struct *sun4c_alloc_task_struct(void)
 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 @@ static unsigned long sun4c_alloc_kernel_stack(struct task_struct *tsk)
                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_end;
 static unsigned long *sun4c_iobuffer_map;
 static int iobuffer_map_size;
 
-static char *sun4c_lockpage(char *vaddr, unsigned long _unused)
-{
-       unsigned long vpage, voffset, search, pte;
-       unsigned long npage;
+/*
+ * 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 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);
+       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_unlockpage(char *vaddr, unsigned long _unused)
+static void sun4c_unlockarea(char *vaddr, unsigned long size)
 {
-       unsigned long vpage, nr;
+       unsigned long vpage, npages;
 
-       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);
+       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 @@ static void sun4c_unlockpage(char *vaddr, unsigned long _unused)
  * 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_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_buffer(char *bufptr, unsigned long len, struct linux_sbus *sbus)
+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);
 }
 
-#define TASK_ENTRY_SIZE    (3 * PAGE_SIZE)
+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    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 @@ static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
        }
 
        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 @@ static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
        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 @@ static void sun4c_invalidate_range(struct mm_struct *mm, unsigned long start, un
                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 @@ static void sun4c_invalidate_range(struct mm_struct *mm, unsigned long start, un
        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 @@ static void sun4c_exit_hook(void)
        }
 }
 
-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 @@ static char *sun4c_mmu_info(void)
        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 unsigned long sun4c_vmalloc_start(void)
 
 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_bad(pmd_t pmd)
 }
 
 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 @@ static pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
        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_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
  */
 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 @@ static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
                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 @@ void ld_mmu_sun4c(void)
            | _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 @@ void ld_mmu_sun4c(void)
 
        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 @@ void ld_mmu_sun4c(void)
        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 @@ void ld_mmu_sun4c(void)
 
        /* These should _never_ get called with two level tables. */
        pgd_set = 0;
-       pgd_reuse = 0;
        pgd_page = 0;
 }
index bcaa389bc1d59e9545e0abc23df12c8d9a9cf0f2..1a08738122f2b6eda70f7f8904ebe324cabf4f97 100644 (file)
@@ -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 <linux/config.h>
 #include <asm/oplib.h>
 
 static char barg_buf[256];
@@ -33,6 +34,14 @@ prom_getbootargs(void)
                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;
index 16a83e42fdc72cb917e143004bfec0ff6ee2139a..7df31045eb5e966cce96d6f8733ec799be008b2e 100644 (file)
@@ -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 <linux/config.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <linux/string.h>
@@ -28,6 +29,9 @@ prom_nbgetchar(void)
                        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 @@ prom_nbputchar(char c)
                        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 @@ prom_query_input_device()
                                return PROMDEV_ITTYB;
                }
                return PROMDEV_I_UNK;
+       case PROM_AP1000:
+               return PROMDEV_I_UNK;
        };
 }
 
@@ -162,6 +177,8 @@ prom_query_output_device()
                        };
                }
                break;
+       case PROM_AP1000:
+               return PROMDEV_I_UNK;
        };
        return PROMDEV_O_UNK;
 }
index 4268cc3d0cd39d06eadbc1058db26c4f1ff6e50e..81795dc68f1214f6fc73b77fb21652489dc7c9aa 100644 (file)
@@ -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 @@ prom_devopen(char *dstr)
                handle = (*(romvec->pv_v2devops.v2_dev_open))(dstr);
                return handle;
                break;
+        case PROM_AP1000:
+               break;
        };
 
        return -1;
@@ -45,6 +47,8 @@ prom_close(int dhandle)
        case PROM_P1275:
                (*(romvec->pv_v2devops.v2_dev_close))(dhandle);
                return;
+        case PROM_AP1000:
+               return;
        };
        return;
 }
@@ -64,6 +68,8 @@ prom_seek(int dhandle, unsigned int seekhi, unsigned int seeklo)
        case PROM_P1275:
                (*(romvec->pv_v2devops.v2_dev_seek))(dhandle, seekhi, seeklo);
                break;
+        case PROM_AP1000:
+               break;
        };
 
        return;
diff --git a/arch/sparc/prom/devtree.c b/arch/sparc/prom/devtree.c
deleted file mode 100644 (file)
index 65af43e..0000000
+++ /dev/null
@@ -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 <asm/openprom.h>
-#include <asm/oplib.h>
-
-/* 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;
-}
index 3e181e3c1b97673cb41a56dd127491d8ba1c87ca..4cdc064af6a4b66148e04670f785d1d68c99e725 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/kernel.h>
 
 #include <asm/openprom.h>
@@ -33,6 +34,12 @@ prom_init(struct linux_romvec *rp)
 {
        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;
index e471898669a1353c30e42d61c9da8363889e4172..3e0cd4e4565d04cf5362b03215a41246db4545d7 100644 (file)
@@ -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 <linux/kernel.h>
+
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
-/* 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 @@ prom_meminit(void)
                /* 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. */
index efdfdb0ba83532c0fa8ab7013fe4e39ed90ab060..f71fdb4bf78f4dab20d3e483aa33ce2216c31389 100644 (file)
@@ -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 <linux/config.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 
@@ -30,8 +31,11 @@ prom_feval(char *fstring)
 }
 
 /* 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 @@ extern void set_palette(void);
 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 @@ typedef void (*sfunc_t)(void);
 void
 prom_setsync(sfunc_t funcp)
 {
+#if CONFIG_AP1000
+  printk("not doing setsync\n");
+  return;
+#endif
        if(!funcp) return;
        *romvec->pv_synchook = funcp;
        return;
index 3d26ab84f18cf4ffd46366f9660b7e862c802d39..fd431e0d927a2c7f401f505bbd4d3749a877a345 100644 (file)
@@ -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 @@ prom_startcpu(int cpunode, struct linux_prom_registers *ctable_reg, int ctx, cha
        switch(prom_vers) {
        case PROM_V0:
        case PROM_V2:
+       case PROM_AP1000:
                break;
        case PROM_V3:
        case PROM_P1275:
@@ -38,6 +39,7 @@ prom_stopcpu(int cpunode)
        switch(prom_vers) {
        case PROM_V0:
        case PROM_V2:
+       case PROM_AP1000:
                break;
        case PROM_V3:
        case PROM_P1275:
@@ -57,6 +59,7 @@ prom_idlecpu(int cpunode)
        switch(prom_vers) {
        case PROM_V0:
        case PROM_V2:
+       case PROM_AP1000:
                break;
        case PROM_V3:
        case PROM_P1275:
@@ -76,6 +79,7 @@ prom_restartcpu(int cpunode)
        switch(prom_vers) {
        case PROM_V0:
        case PROM_V2:
+       case PROM_AP1000:
                break;
        case PROM_V3:
        case PROM_P1275:
index 388f71a3c59f9239ab7a1342590b7b2db9211bd8..c90b2c59dad9f85b726e793ed4a6af954d2e49f9 100644 (file)
@@ -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 *
index 11653771c7918761b9b4676d4259b2becdd96c2e..72a6cd6cc5dd6298851a83503c89cc71a1d9d32b 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/kernel.h>
 
 #include <asm/openprom.h>
@@ -27,13 +28,16 @@ prom_printf(char *fmt, ...)
 
        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;
 }
index a0665519fe4aa81d88ff299b24488ca259f0a0e5..f5a0fb4c5f4d2e76c19df7a61715f9da08949c89 100644 (file)
@@ -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 <linux/config.h>
 #include <linux/string.h>
 
 #include <asm/openprom.h>
@@ -20,6 +21,10 @@ prom_getchild(int node)
 {
        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 @@ prom_getsibling(int node)
 {
        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 @@ prom_getsibling(int node)
 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 @@ prom_getproperty(int node, char *prop, char *buffer, int bufsize)
 {
        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 @@ prom_getint(int node, char *prop)
 {
        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 @@ prom_getintdefault(int node, char *property, int deflt)
 {
        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 @@ prom_getbool(int node, char *prop)
 {
        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 @@ prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
 {
        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;
index 5ee08c899a070a4f35f0a4f1e19e9bece1ceac1a..1982953e9ec3e29b6f50aa15028928cc85f8c13f 100644 (file)
@@ -1232,6 +1232,15 @@ static void fdc_specify(void)
                        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 @@ static inline int raw_cmd_copyin(int cmd, char *param,
                        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 @@ static char get_fdc_version(void)
                        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 */
 
index b89a9908fb46729bbe5f5fcfbac9768a507c1677..740ec2d54bd5960ecf9399303e875b5df13f9bd0 100644 (file)
@@ -27,8 +27,6 @@
 #define MD_DRIVER
 #define MD_PERSONALITY
 
-#include <linux/blk.h>
-
 static int linear_run (int minor, struct md_dev *mddev)
 {
   int cur=0, i, size, dev0_size, nb_zone;
@@ -105,77 +103,39 @@ static int linear_stop (int minor, struct md_dev *mddev)
 }
 
 
-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)
 {
   int sz=0;
index ed58abee632892a69cf43262783e17e89b1e4cd4..7278e9ab621a224c9bfa0315cd03e85948bfb262 100644 (file)
@@ -226,14 +226,11 @@ static inline void drive_stat_acct(int cmd, unsigned long nr_sectors, short disk
  * 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 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
 
        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 @@ void add_request(struct blk_dev_struct * dev, struct request * req)
        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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
        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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                                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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                         * 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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
        }
 
 /* look for a free request. */
-       down (&request_lock);
 
        /*
         * Try to coalesce the new request with old requests
@@ -371,7 +365,6 @@ static void make_request(int major,int rw, struct buffer_head * bh)
 
             case SCSI_DISK_MAJOR:
             case SCSI_CDROM_MAJOR:
-            case MD_MAJOR:
 
                do {
                        if (req->sem)
@@ -380,7 +373,7 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                                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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
 
                        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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
                        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 @@ static void make_request(int major,int rw, struct buffer_head * bh)
        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 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
                               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 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
                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 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
 {
        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 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
        {
                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) {
index f8dfc276b2adfd199b9ec2814c19e5c8d4bad82c..e02fbbd0443a9622e0c64b6c73944aa6ac81b77d 100644 (file)
 
 #include <linux/blk.h>
 
-#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 @@ static struct file_operations md_fops=
   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 (reqsize<chunksize) (md_dev+MINOR(req->rq_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<n; i++)
-  {
-    if (!pending[i].bh)
-      continue;
-
-    found=0;
-    rw=pending[i].cmd;
-    bh=pending[i].bh;
-    major=MAJOR(dev=pending[i].rq_dev);
-    
-    max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
-    if ((   major == IDE0_MAJOR        /* same as HD_MAJOR */
-        || major == IDE1_MAJOR
-        || major == SCSI_DISK_MAJOR
-        || major == IDE2_MAJOR
-        || major == IDE3_MAJOR)
-       && (req = blk_dev[major].current_request))
-    {
-      /*
-       * Thanx to Gadi Oxman <gadio@netvision.net.il>
-       * (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<n; j++)
-  {
-    if (!pending[j].bh)
-      continue;
-    
-    pending[j].bh=NULL;
-  }
-}
-
+  printk ("Got md request, not good...");
+  return;
+}  
 
 static struct symbol_table md_symbol_table=
 {
@@ -570,17 +394,6 @@ static struct symbol_table md_symbol_table=
 
   X(devices),
   X(md_size),
-  X(add_request),
-  X(make_md_request),
-
-#ifdef CONFIG_MD_SUPPORT_RAID1
-  X(support_for_raid1),
-#endif
-
-#ifdef CONFIG_MD_SUPPORT_RAID5
-  X(support_for_raid5),
-#endif
-
   X(register_md_personality),
   X(unregister_md_personality),
   X(partition_name),
@@ -665,12 +478,6 @@ int get_md_status (char *page)
     if (md_dev[i].pers != pers[(LINEAR>>PERSONALITY_SHIFT)])
     {
       sz+=sprintf (page+sz, " %dk chunks", 1<<FACTOR_SHIFT(FACTOR(md_dev+i)));
-#ifdef MD_COUNT_SIZES
-      sz+=sprintf (page+sz, " (%d/%d/%d)",
-                  md_dev[i].smallest_count,
-                  md_dev[i].equal_count,
-                  md_dev[i].biggest_count);
-#endif
     }
     sz+=sprintf (page+sz, "\n");
     sz+=md_dev[i].pers->status (page+sz, i, md_dev+i);
@@ -679,90 +486,6 @@ int get_md_status (char *page)
   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; i<md_dev[minor].nb_dev; i++)
-    if (devices[minor][i].dev==dev)
-      break;
-
-  if (i>md_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);
@@ -818,12 +541,6 @@ int md_init (void)
 #ifdef CONFIG_MD_STRIPED
   raid0_init ();
 #endif
-#ifdef CONFIG_MD_RAID1
-  raid1_init ();
-#endif
-#ifdef CONFIG_MD_RAID5
-  raid5_init ();
-#endif
   
   return (0);
 }
index 75bca7e954261e5a6fa9a1292c1c18ffeff1b1ea..899a82b166ec4e7fa56b0ec092b409b942fdd733 100644 (file)
@@ -17,7 +17,6 @@
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/md.h>
 #include <linux/raid0.h>
@@ -27,8 +26,6 @@
 #define MD_DRIVER
 #define MD_PERSONALITY
 
-#include <linux/blk.h>
-
 static void create_strip_zones (int minor, struct md_dev *mddev)
 {
   int i, j, c=0;
@@ -179,92 +176,54 @@ static int raid0_stop (int minor, struct md_dev *mddev)
  * 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<<FACTOR_SHIFT(factor));
-    tmp_dev=zone->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<<FACTOR_SHIFT(factor));
+  tmp_dev=zone->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;
index 1d78a577543aca7bfb981a678172feb3dbeefdf5..9ccf2e8b188764c4833e8d85624adc7a4700d191 100644 (file)
@@ -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 --git a/drivers/char/suncons.c b/drivers/char/suncons.c
new file mode 100644 (file)
index 0000000..d21fe88
--- /dev/null
@@ -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 <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/fbio.h>
+#include <asm/io.h>
+#include <asm/pgtsun4c.h>      /* 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; i<MAX_NR_CONSOLES; i++)
+                       if (vc_cons_allocated(i)) {
+                               int j, k ;
+                               for (j=k=0; j<16; j++) {
+                                       vc_cons[i].d->vc_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 --git a/drivers/char/sunmouse.c b/drivers/char/sunmouse.c
new file mode 100644 (file)
index 0000000..a226fcc
--- /dev/null
@@ -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 <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fcntl.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/vuid_event.h>
+#include <linux/random.h>
+/* 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<Left %s, Middle %s, Right %s>",
+                      ((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;
+}
index 3d35089cfb2db6bcddf2e36efc4ae10ae6afb261..119cae68ee99f81417b1c3f46bec3d43b08b56ca 100644 (file)
@@ -10,3 +10,4 @@ if [ "$CONFIG_INET" != "n" ]; then
 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
index 5d025fa3c8584ba2aa4b509e1f216b2d5dd36280..65f670558ffbabce48894b6219470d6b5b889455 100644 (file)
@@ -1,6 +1,6 @@
 SUB_DIRS     :=
 MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn teles
+ALL_SUB_DIRS := icn teles pcbit
 
 L_OBJS :=
 LX_OBJS :=
@@ -50,5 +50,15 @@ else
   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
+
 include $(TOPDIR)/Rules.make
 
index 8c4b64b5cf677d78f5226e4a697bab79774eddfb..9c8e068d81396a267d040e9a69943711300ac92e 100644 (file)
  * 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.
 #undef LOADEXTERN
 
 static char
-*revision = "$Revision: 1.17 $";
+*revision = "$Revision: 1.18 $";
 
 static void icn_pollcard(unsigned long dummy);
 
@@ -466,7 +470,10 @@ static void icn_pollit(icn_dev * dev)
                        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 @@ static int icn_loadboot(u_char * buffer, icn_dev * dev)
        }
        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 @@ static int icn_readstatus(u_char * buf, int len, int user, icn_dev * dev)
        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
index a30657056a21b284eda4a4ac104c67cc87326ca8..7e690a297c81f2d62c1c0b82d3c60f74a8e1bf99 100644 (file)
@@ -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.
  *
  * 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 @@ typedef struct {
 } 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 @@ typedef struct {
        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         */
index b28c0458563959417450feef5b33872892b7ec95..28ca52c4ea62e8b30d97b82a0a99677b02ce2cf3 100644 (file)
@@ -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 <linux/config.h>
 
@@ -9,6 +34,10 @@ extern void icn_init(void);
 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
@@ -17,5 +46,8 @@ void isdn_cards_init(void)
 #if CONFIG_ISDN_DRV_TELES
         teles_init();
 #endif
+#if CONFIG_ISDN_DRV_PCBIT
+        pcbit_init();
+#endif
 }
 
index 9ebb2f36da85b163b8bfd54453542d6a51d6c06c..5bece603b93be6fb2b277e33ba6236e2602cd393 100644 (file)
@@ -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);
 
index 785f85761614701846966b16994a64af218ab6fa..761a8d9c481687d4453ac487d8c1e419cb461d65 100644 (file)
@@ -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).
  *
  * 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 @@ static void isdn_timer_funct(ulong dummy)
                        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 @@ static void isdn_receive_callback(int di, int channel, u_char * buf, int len)
                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 @@ static int isdn_status_callback(isdn_ctrl * c)
                                         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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
 
        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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
                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 @@ static int isdn_read(struct inode *inode, struct file *file, char *buf, int coun
                        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 @@ static int isdn_write(struct inode *inode, struct file *file, const char *buf, i
                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 @@ static int isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong ar
        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;i<ISDN_MAX_CHANNELS;i++) {
+                                                put_fs_long(dev->ibytes[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 @@ static int isdn_open(struct inode *ino, struct file *filep)
 
        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 @@ static void isdn_close(struct inode *ino, struct file *filep)
        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 @@ static void isdn_close(struct inode *ino, struct file *filep)
                        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 @@ static void isdn_close(struct inode *ino, struct file *filep)
                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 @@ void isdn_free_channel(int di, int ch, int usage)
                    (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_unexclusive_channel(int di, int ch)
 
 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,27 +1661,54 @@ void isdn_receive_skb_callback(int drvidx, int chan, struct sk_buff *skb)
 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;
+          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);
+          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);
+          return dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, skb);
+        }
 }
+
 /*
- * Low-level-driver registration
+ * 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.
  */
 
+int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb)
+{
+        int ret;
+
+        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)
 {
@@ -1648,11 +1723,15 @@ int register_isdn(isdn_if * i)
                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 @@ int register_isdn(isdn_if * i)
                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 @@ int isdn_init(void)
                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 @@ int isdn_init(void)
                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;
index 9782b027b7cae928d9dd09117041376825311296..87b3b849614e6367a7db9fcb52e5405334d27bc8 100644 (file)
@@ -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 char* isdn_map_eaz2msn(char *msn, int di);
 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
index bdade37be672d8878b5b6220fc1272c4535d6c57..6f9d76b36f32a2909a6816403c6ed73ef72d943d 100644 (file)
@@ -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).
  *
  * 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_wildmat(char *s, char *p);
 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 @@ isdn_net_stat_callback(int idx, int cmd)
                                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 @@ isdn_net_stat_callback(int idx, int cmd)
                                 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_net_dial(void)
        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 @@ isdn_net_dial(void)
                        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 @@ isdn_net_dial(void)
                                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 @@ isdn_net_dial(void)
                        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 @@ isdn_net_dial(void)
                        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);
@@ -475,24 +525,6 @@ isdn_net_dial(void)
        isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore);
 }
 
-/*
- * 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.
  */
@@ -505,6 +537,10 @@ isdn_net_hangup(struct device *d)
 
        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 @@ isdn_net_log_packet(u_char * buf, isdn_net_local * lp)
                         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 @@ isdn_net_send_skb(struct device *ndev, isdn_net_local *lp,
        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 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                                 /* 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_net_receive(struct device *ndev, struct sk_buff *skb)
         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;
+                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;
+                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 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
                         *((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 @@ isdn_net_header(struct sk_buff *skb, struct device *dev, unsigned short type,
                         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 @@ isdn_net_swap_usage(int i1, int i2)
  *
  * 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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                                        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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                                                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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
 #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 @@ isdn_net_find_icall(int di, int ch, int idx, char *num)
                                        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 @@ isdn_net_force_dial(char *name)
  * 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 @@ char *
        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 *
 }
 
 char *
- isdn_net_newslave(char *parm)
+isdn_net_newslave(char *parm)
 {
        char *p = strchr(parm, ',');
        isdn_net_dev *n;
@@ -1860,9 +1907,7 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                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 @@ int isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                        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 @@ int isdn_net_getcfg(isdn_net_ioctl_cfg * cfg)
                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 @@ int isdn_net_getphones(isdn_net_ioctl_phone * phone, char *phones)
                n = n->next;
                more = 1;
        }
+        put_fs_byte(0,phones);
        restore_flags(flags);
        return count;
 }
index 0f809c5532fbecdfe9b97ee07b2fb0f96be01c6f..5b6754e662712ea4d33bb781c16135358ce1a939 100644 (file)
@@ -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
  *
index d632c86aad1f1dccd53fa07408c830aefa05348b..994ed9a797602d39d1ccdb9865e3460f542c2636 100644 (file)
@@ -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).
  *
  * 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 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb,
                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 @@ int isdn_ppp_free(isdn_net_local * lp)
 
        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 @@ int isdn_ppp_bind(isdn_net_local * lp)
          * 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 @@ int isdn_ppp_bind(isdn_net_local * lp)
                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 @@ static int isdn_ppp_hangup(int minor)
        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 @@ static int isdn_ppp_hangup(int minor)
 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 @@ void isdn_ppp_release(int minor, struct file *file)
                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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
 
 #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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
                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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
        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 @@ int isdn_ppp_ioctl(int minor, struct file *file, unsigned int cmd, unsigned long
        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 @@ int isdn_ppp_select(int minor, struct file *file, int type, select_table * st)
        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 @@ static int isdn_ppp_fill_rq(char *buf, int len, int minor)
                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 @@ static int isdn_ppp_fill_rq(char *buf, int len, int minor)
 
        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 @@ static int isdn_ppp_fill_rq(char *buf, int len, int minor)
 
 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 @@ int isdn_ppp_write(int minor, struct file *file,  const char *buf, int count)
 {
        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 @@ int isdn_ppp_write(int minor, struct file *file,  const char *buf, int count)
 
                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 isdn_ppp_init(void)
 {
        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 @@ int isdn_ppp_init(void)
 
 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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
 
        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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                (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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                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 @@ void isdn_ppp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buf
                                }
                                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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
                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 @@ static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, stru
                        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 @@ int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev)
        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 @@ static int isdn_ppp_bundle(int minor, int unit)
        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 @@ static int isdn_ppp_bundle(int minor, int unit)
 
        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
 
index e9c12ad5d3cd522cafb16a35e2364a05d68c254d..05a8036895d607ad729998916eb2e3467a6f2f96 100644 (file)
@@ -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).
  *
  * 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 int  isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long);
 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];
index 88e6362c151882dbbbb222870727721730d9bdb4..f03078fe6bbe837df8cf564e25eb054f659256da 100644 (file)
@@ -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).
  *
  * 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 void isdn_tty_modem_reset_regs(atemu *, int);
 
 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 @@ void isdn_tty_modem_hup(modem_info * info)
 {
        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 @@ void isdn_tty_modem_hup(modem_info * info)
                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 @@ static void isdn_tty_change_speed(modem_info * info)
        } 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 @@ static void isdn_tty_shutdown(modem_info * info)
        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 @@ static int isdn_tty_write(struct tty_struct *tty, int from_user, const u_char *
                                        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 @@ static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
                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 @@ static int isdn_tty_set_modem_info(modem_info * info, uint cmd, uint * value)
                             | ((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 @@ static int isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, m
         */
        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 @@ int isdn_tty_modem_init(void)
        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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
        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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
        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 @@ int isdn_tty_find_icall(int di, int ch, char *num)
        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 @@ static void isdn_tty_at_cout(char *msg, modem_info * info)
        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 @@ static void isdn_tty_parse_at(modem_info * info)
                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 @@ void isdn_tty_modem_xmit(void)
                                                        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 --git a/drivers/isdn/pcbit/Makefile b/drivers/isdn/pcbit/Makefile
new file mode 100644 (file)
index 0000000..50a6726
--- /dev/null
@@ -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 --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
new file mode 100644 (file)
index 0000000..374238c
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#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 --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h
new file mode 100644 (file)
index 0000000..55ca14b
--- /dev/null
@@ -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 --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
new file mode 100644 (file)
index 0000000..9f0f416
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/isdnif.h>
+
+#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; i<len; i++)
+                printk(KERN_DEBUG "Cause Octect %d: %02x\n", i+3, 
+                       *(skb->data + 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 --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h
new file mode 100644 (file)
index 0000000..083959a
--- /dev/null
@@ -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 --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
new file mode 100644 (file)
index 0000000..174623c
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#include <asm/string.h>
+#include <asm/io.h>
+
+#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; i<len; i++)
+                               writeb(cbuf[i], dev->sh_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; i<strlen(str); i++)
+       {
+               statbuf[i]=str[i];
+               stat_end = (stat_end + 1) % STATBUF_LEN;
+               if (stat_end == stat_st)
+                       stat_st = (stat_st + 1) % STATBUF_LEN;
+       }
+
+       ictl.command=ISDN_STAT_STAVAIL;
+       ictl.driver=dev->id;
+       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 --git a/drivers/isdn/pcbit/edss1.c b/drivers/isdn/pcbit/edss1.c
new file mode 100644 (file)
index 0000000..1e654f2
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+#include <linux/timer.h>
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#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 --git a/drivers/isdn/pcbit/edss1.h b/drivers/isdn/pcbit/edss1.h
new file mode 100644 (file)
index 0000000..02fd9f1
--- /dev/null
@@ -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 --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
new file mode 100644 (file)
index 0000000..802e973
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+
+#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 --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
new file mode 100644 (file)
index 0000000..48d7bf6
--- /dev/null
@@ -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 <bytesex.h>
+
+#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) ((a<b)?a:b)
+
+extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum, 
+                          struct sk_buff *skb, unsigned short hdr_len);
+
+extern void pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs);
+
+extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
+
+#ifdef DEBUG
+static __inline__ void log_state(struct pcbit_dev *dev) {
+        printk(KERN_DEBUG "writeptr = %ld\n", 
+              (ulong) (dev->writeptr - 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; i<MAX_PCBIT_CARDS; i++)
+                if ((dev=dev_pcbit[i]))
+                        if (dev->b1 == 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; i<MAX_PCBIT_CARDS; i++)
+    if ((dev=dev_pcbit[i]))
+      if (dev->id == 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 --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c
new file mode 100644 (file)
index 0000000..5320c7e
--- /dev/null
@@ -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 <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#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<MAX_PCBIT_CARDS)) {
+
+               if (argc) {
+                       mem[i]  = ints[j];
+                       j++; argc--;
+               }
+               
+               if (argc) {
+                       irq[i]  = ints[j];
+                       j++; argc--;
+               }
+
+               i++;
+       }
+}
+#endif
+
+
+
diff --git a/drivers/isdn/pcbit/pcbit.h b/drivers/isdn/pcbit/pcbit.h
new file mode 100644 (file)
index 0000000..731e436
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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 device driver definitions
+ */
+
+#ifndef PCBIT_H
+#define PCBIT_H
+
+#define MAX_PCBIT_CARDS 4
+
+
+#define BLOCK_TIMER
+
+#ifdef __KERNEL__
+
+struct pcbit_chan {
+       unsigned short id;
+       unsigned short callref;                   /* Call Reference */
+       unsigned char  proto;                     /* layer2protol  */
+       unsigned char  queued;                    /* unacked data messages */
+       unsigned char  layer2link;                /* used in TData */
+       unsigned char  snum;                      /* used in TData */
+       unsigned short s_refnum;
+       unsigned short r_refnum;
+       unsigned short fsm_state;
+       struct timer_list fsm_timer;
+#ifdef  BLOCK_TIMER
+       struct timer_list block_timer;
+#endif
+};
+
+struct msn_entry {
+       char *msn;
+       struct msn_entry * next;
+};
+
+struct pcbit_dev {
+       /* board */
+
+       volatile unsigned char* sh_mem;         /* RDP address  */
+       unsigned int irq;
+       unsigned int id;
+       unsigned int interrupt;                 /* set during interrupt 
+                                                  processing */
+       
+       /* isdn4linux */
+
+       struct msn_entry * msn_list;            /* ISDN address list */
+       
+       isdn_if * dev_if;
+       
+       ushort ll_hdrlen;
+       ushort hl_hdrlen;
+
+       /* link layer */
+       unsigned char l2_state;
+
+       struct frame_buf *read_queue;
+       struct frame_buf *read_frame;
+       struct frame_buf *write_queue;
+
+       /* Protocol start */
+       struct wait_queue *set_running_wq;
+       struct timer_list set_running_timer;
+
+       struct timer_list error_recover_timer;
+
+       struct tq_struct qdelivery;
+
+       u_char w_busy;
+       u_char r_busy;
+
+       volatile unsigned char *readptr;
+       volatile unsigned char *writeptr;
+
+       ushort loadptr;
+
+       unsigned short fsize[8];                /* sent layer2 frames size */
+
+       unsigned char send_seq;
+       unsigned char rcv_seq;
+       unsigned char unack_seq;
+  
+       unsigned short free;
+
+       /* channels */
+
+       struct pcbit_chan *b1;
+       struct pcbit_chan *b2;  
+};
+
+#define STATS_TIMER (10*HZ)
+#define ERRTIME     (0.1*HZ)
+
+/* MRU */
+#define MAXBUFSIZE  1534
+#define MRU   MAXBUFSIZE
+
+#define STATBUF_LEN 2048
+/*
+ * 
+ */
+
+#endif /* __KERNEL__ */
+
+/* isdn_ctrl only allows a long sized argument */
+
+struct pcbit_ioctl {
+       union {
+               struct byte_op {
+                       ushort addr;
+                       ushort value;
+               } rdp_byte;
+               unsigned long l2_status;
+       } info;
+};
+
+
+
+#define PCBIT_IOCTL_GETSTAT  0x01    /* layer2 status */
+#define PCBIT_IOCTL_LWMODE   0x02    /* linear write mode */
+#define PCBIT_IOCTL_STRLOAD  0x03    /* start load mode */
+#define PCBIT_IOCTL_ENDLOAD  0x04    /* end load mode */
+#define PCBIT_IOCTL_SETBYTE  0x05    /* set byte */
+#define PCBIT_IOCTL_GETBYTE  0x06    /* get byte */
+#define PCBIT_IOCTL_RUNNING  0x07    /* set protocol running */
+#define PCBIT_IOCTL_WATCH188 0x08    /* set watch 188 */
+#define PCBIT_IOCTL_PING188  0x09    /* ping 188 */
+#define PCBIT_IOCTL_FWMODE   0x0A    /* firmware write mode */
+#define PCBIT_IOCTL_STOP     0x0B    /* stop protocol */
+#define PCBIT_IOCTL_APION    0x0C    /* issue API_ON  */
+
+#ifndef __KERNEL__
+
+#define PCBIT_GETSTAT  (PCBIT_IOCTL_GETSTAT  + IIOCDRVCTL)
+#define PCBIT_LWMODE   (PCBIT_IOCTL_LWMODE   + IIOCDRVCTL)
+#define PCBIT_STRLOAD  (PCBIT_IOCTL_STRLOAD  + IIOCDRVCTL)
+#define PCBIT_ENDLOAD  (PCBIT_IOCTL_ENDLOAD  + IIOCDRVCTL)
+#define PCBIT_SETBYTE  (PCBIT_IOCTL_SETBYTE  + IIOCDRVCTL)
+#define PCBIT_GETBYTE  (PCBIT_IOCTL_GETBYTE  + IIOCDRVCTL)
+#define PCBIT_RUNNING  (PCBIT_IOCTL_RUNNING  + IIOCDRVCTL)
+#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
+#define PCBIT_PING188  (PCBIT_IOCTL_PING188  + IIOCDRVCTL)
+#define PCBIT_FWMODE   (PCBIT_IOCTL_FWMODE   + IIOCDRVCTL)
+#define PCBIT_STOP     (PCBIT_IOCTL_STOP     + IIOCDRVCTL)
+#define PCBIT_APION    (PCBIT_IOCTL_APION    + IIOCDRVCTL)
+
+#define MAXSUPERLINE 3000
+
+#endif
+
+#define L2_DOWN     0
+#define L2_LOADING  1
+#define L2_LWMODE   2
+#define L2_FWMODE   3
+#define L2_STARTING 4
+#define L2_RUNNING  5
+#define L2_ERROR    6
+
+#endif
+
+
+
+
+
+
+
index 96a214ed64833b995b25f6118477a9af9ba12e3c..c747dcb5ffd9be5f39c7406ff9b8c13e1f1b4957 100644 (file)
@@ -1,3 +1,11 @@
+/* $Id: buffers.c,v 1.1 1996/04/13 10:19:28 fritz Exp $
+ *
+ * $Log: buffers.c,v $
+ * Revision 1.1  1996/04/13 10:19:28  fritz
+ * Initial revision
+ *
+ *
+ */
 #define __NO_VERSION__
 #include "teles.h"
 #include <linux/mm.h>
index c08d34b6550475684da1b21efbe6345147216816..7ed0da48b3c96a97e5cf51a75d5f1bbd68f9753d 100644 (file)
@@ -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 @@ enum {
         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 @@ static char    *strState[] =
         "ST_PRO_W",
         "ST_ANT_W",
         "ST_DISC_BC_HANGUP",
+        "ST_OUT_W_HANGUP",
         "ST_D_ERR",
 };
 
@@ -267,6 +280,29 @@ r2(struct FsmInst *fi, int event, void *arg)
         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 @@ r3(struct FsmInst *fi, int event, void *arg)
         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 @@ r7(struct FsmInst *fi, int event, void *arg)
         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 @@ r7(struct FsmInst *fi, int event, void *arg)
                 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 @@ r17(struct FsmInst *fi, int event, void *arg)
         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 @@ static void
 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)
 {
@@ -522,6 +600,22 @@ r23(struct FsmInst *fi, int event, void *arg)
         chanp->is.l4.l4l3(&chanp->is, CC_DISCONNECT_REQ, NULL);
 }
 
+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)
 {
@@ -562,32 +656,51 @@ r26(struct FsmInst *fi, int event, void *arg)
 
 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 @@ lc_r5(struct FsmInst *fi, int event, void *arg)
 
 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,16 +1388,17 @@ teles_writebuf(int id, int chan, const u_char * buf, int count, int user)
         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;
 
         if (user)
index 98346b87dd617f43afb7403b5916e1b8c47edb96..1bc320f3feb979f509fc71aaa8c1fe3276a201f2 100644 (file)
@@ -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__
index 7524d0225f74319e88684b2386846d5b8cce5ce8..1a9d2d87322fe687b61bd7aaaa5a8357a4992c86 100644 (file)
@@ -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 <linux/types.h>
 #include <linux/stddef.h>
index 94ef1fe162f4cf9eac3151f1b4c44a12410cea71..b75cd9bcf4f02e3329c03eb4f79c1b32ad7e171d 100644 (file)
@@ -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"
 
index b0ae25311cd028a78c1bcbc10aad94723e92543b..6beaf2fab112a883529f9d12b64a92088c714ae7 100644 (file)
@@ -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"
 
index c7d6a67c7116c5b1325d56bb65612c51609d06d4..143bee7c74e3334e09ee865076bfb5335895e900 100644 (file)
@@ -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"
@@ -60,6 +73,17 @@ l3s4(struct PStack *st, byte pr, void *arg)
        st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
 }
 
+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 @@ static void
 l3s12(struct PStack *st, byte pr, void *arg)
 {
        byte           *p;
+       int             bcfound = 0;
        struct BufHeader *ibh = arg;
 
        p = DATAPTR(ibh);
@@ -202,6 +227,7 @@ l3s12(struct PStack *st, byte pr, void *arg)
        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 @@ l3s12(struct PStack *st, byte pr, void *arg)
                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 @@ struct stateentry {
 
 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 @@ sizeof(struct stateentry);
 
 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) /
index 98f16f67f790c5ba5cf930a61bfd5f27e28bcace..71568e7ab43c776abe2f580848bedf3da335414d 100644 (file)
@@ -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 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
        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 @@ l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
 
        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 @@ static void
 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 @@ l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
        *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 @@ l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
 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}
index 7cca59970373124f9c255ef6405a5c61a680f56b..451d7af586622e505cf2b7fdba352364389ae9c4 100644 (file)
@@ -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
 
index f9fe2dce91b65bc7e165a947b9d217a5847cd2b6..8c164333032dbbdabdf9e183e8d5c2ed4a4efa2d 100644 (file)
@@ -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 <linux/malloc.h>
index 7e4fd4e0db17e2fd13e8b2e5ba786c42d8577891..821ac8ee3495575efb04df6b08df64c8d9b75a68 100644 (file)
@@ -1,7 +1,13 @@
+/* $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;
 
index 6e8169ee914ba765e3cc6480e55a126fbd132ff5..4e740bd639c73348c5bb5c441baeeb7856cda679 100644 (file)
@@ -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
+ *
+ *
  */
 
 
index d67d3aec96dad1267dba6249d118b690e2a09924..3ab9f3646000f113e83ebe4177bea01057306d2a 100644 (file)
@@ -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"
 
index f6818cf523da890d6d92a4aeb1e312108adb6e3f..f0007f58d8d63906d815f622f361846aa7d128e0 100644 (file)
@@ -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 <linux/module.h>
 #include <linux/version.h>
 #include <linux/errno.h>
index e8517c89da16b741cd163525427c03cf9805cda3..a96ee074ad03d5cff3c9c9acdde0c2c9000cea79 100644 (file)
@@ -221,6 +221,7 @@ int el3_probe(struct device *dev)
                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 @@ int el3_probe(struct device *dev)
 
        /* 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;
index 63c81b2a3642aa1614e5e7b82f60501acd274508..e59afeb94a63bd65f5ce81df40b50511066f6a38 100644 (file)
@@ -242,6 +242,10 @@ L_OBJS += lance.o
   endif
 endif
 
+ifeq ($(CONFIG_SUNLANCE),y)
+L_OBJS += sunlance.o
+endif
+
 ifeq ($(CONFIG_AT1700),y)
 L_OBJS += at1700.o
 else
index f9b21f59c6b312ce0dbb8664bcb16242f14b08a9..8ccd863fdf52643c3567d4d9154edceca2292449 100644 (file)
@@ -73,6 +73,7 @@ extern int seeq8005_probe(struct device *);
 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 *);
@@ -189,6 +190,9 @@ ethif_probe(struct device *dev)
 #endif
 #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 @@ ethif_probe(struct device *dev)
 #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 @@ static struct device strip_bootstrap = {
 #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 @@ struct device eql_dev = {
 #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          */
index 2c6e10c289ceab3b6fca8263e1fbc0eb7be0262a..0c2a69e7e514a170896f2219b60e7f1ca0e77764 100644 (file)
          
        **********************
        
+       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.
          
        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
 */
 
 static const char *version =
- "arcnet.c: v2.51 96/02/29 Avery Pennarun <apenwarr@foxnet.net>\n";
+ "arcnet.c: v2.52 96/04/20 Avery Pennarun <apenwarr@foxnet.net>\n";
 
  
 
@@ -340,7 +345,8 @@ int arcnet_debug = ARCNET_DEBUG;
 #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 @@ int arcnet_probe(struct device *dev)
        
        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 @@ int arcnet_probe(struct device *dev)
 
        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 @@ int arcnet_probe(struct device *dev)
                }
                else
                {
+                       /* just one shmem and port, assume they match */
                        *(u_char *)(shmems[0]) = TESTvalue;
                }
 #else
@@ -1091,7 +1098,8 @@ int arcnet_probe(struct device *dev)
         */
        for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
                *(u_char *)(*shmem) = TESTvalue;
-
+               
+       if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
        return retval;
 }
 
@@ -1174,7 +1182,7 @@ int arcnet_found(struct device *dev,int port,int airq, u_long shmem)
        /* get and check the station ID from offset 1 in shmem */
        lp->stationid = 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 @@ arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
                
                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 @@ arcnet_inthandler(struct device *dev)
                        {
                                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);
                                }
index a7b1c20411f32d981776caffa9100c8e2cfde02d..96be192eaff0055ac26a019161ef3add53e52b7a 100644 (file)
@@ -1259,7 +1259,7 @@ dgrs_scan(struct device *dev)
 #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;
index a7b1c20411f32d981776caffa9100c8e2cfde02d..96be192eaff0055ac26a019161ef3add53e52b7a 100644 (file)
@@ -1259,7 +1259,7 @@ dgrs_scan(struct device *dev)
 #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;
index a35a0973a874470c5f5071d1315752cd1c015d55..eb0297d2a2889fe69e354f717bd78cceef3e6777 100644 (file)
 /*
  *     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 */
index 4a59134593740e9084eea3780cb7f24f6d1ac472..b0720c1f6bb4a9ab977da7258737da88f2013c10 100644 (file)
@@ -114,7 +114,7 @@ extern PORT Port[1+SE_NPORTS+1];
 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 */
 
 /*
index 5664fd482d2c4c940bf5fc98df37ea7bc23535f7..82b2b511edc1e76a0dfc99b3b5c9240af7315810 100644 (file)
@@ -381,7 +381,7 @@ typedef volatile struct
        /* 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 @@ typedef volatile struct
        /* 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 */
 
index 5e012c841158035fff0a305ab748a29b459f5693..6888ae0d0ce0ae2eb06ccfa29b61c808a721595c 100644 (file)
@@ -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 */
index fa3edbf4f75a9897090b2b4dfe7ccddf5a75ae82..4b30eebca5549c320eaa1812dea048405cc6768d 100644 (file)
 
 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 <linux/kernel.h>
 #include <linux/sched.h>
@@ -48,9 +54,9 @@ static char *lancestr = "LANCE";
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 
-/* 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 @@ static char *lancestr = "LANCE";
 
 #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 @@ static char *lancestr = "LANCE";
 #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 */
+       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];
+       /* 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 @@ struct lance_private {
 
 /* 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 @@ int sparc_lance_debug = 2;
 /* 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;
-
-    /* Point back to csr0 */
-    ll->rap = LE_CSR0;
+       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;
 }
 
 #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;
+       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");
+       /* 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 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 && 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 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;
+       /* 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)
+static int init_restart_lance (struct lance_private *lp)
 {
-    volatile struct lance_regs *ll = lp->ll;
-    int i;
+       volatile struct lance_regs *ll = lp->ll;
+       int i;
 
-    ll->rap = LE_CSR0;
-    ll->rdp = LE_C0_INIT;
+       if (lp->ledma) {
+               struct sparc_dma_registers *dregs = lp->ledma->regs;
+               unsigned long creg;
 
-    /* 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;
-    }
+               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;
 
-    /* Clear IDON by writing a "1", enable interrupts and start lance */
-    ll->rdp = LE_C0_IDON;
-    ll->rdp = LE_C0_INEA | LE_C0_STRT;
+               creg |= (DMA_DSBL_RD_DRN | DMA_DSBL_WR_INV | DMA_FIFO_INV);
 
-    /* On the 4m, enable dma interrupts */
-    if (lp->ledma)
-       lp->ledma->regs->cond_reg |= DMA_INT_ENAB;
+               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;
+       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;
+       return 0;
 }
 
-static int
-lance_tx (struct device *dev)
+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;
+       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 (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;
-
-    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");
+#ifdef OLD_STYLE_IRQ
+       dev = (struct device *) (irq2dev_map [irq]);
+#else
+       dev = (struct device *) dev_id;
+#endif
+
+       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;
+       struct lance_private *lp = (struct lance_private *)dev->priv;
+       volatile struct lance_regs *ll = lp->ll;
+       int status = 0;
 
-    last_dev = dev;
+       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;
+       if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, (void *) dev)) {
+               printk ("Lance: Can't get irq %d\n", dev->irq);
+               return -EAGAIN;
+       }
 
-    irq2dev_map [dev->irq] = dev;
+       /* 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;
+       /* 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);
+       lance_init_ring (dev);
+       load_csrs (lp);
 
-    dev->tbusy = 0;
-    dev->interrupt = 0;
-    dev->start = 1;
+       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;
+       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;
+       dev->start = 0;
+       dev->tbusy = 1;
 
-    /* Stop the card */
-    ll->rap = LE_CSR0;
-    ll->rdp = LE_C0_STOP;
+       /* Stop the card */
+       ll->rap = LE_CSR0;
+       ll->rdp = LE_C0_STOP;
 
-    free_irq (dev->irq, NULL);
-    irq2dev_map [dev->irq] = NULL;
+       free_irq (dev->irq, NULL);
+#ifdef OLD_STYLE_IRQ
+       irq2dev_map [dev->irq] = NULL;
+#endif
     
-    return 0;
+       return 0;
 }
 
-inline static int
-lance_reset (struct device *dev)
+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;
+       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);
+       /* 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;
+       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);
-    }
+       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);
+       /* 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;
+
+       /* 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;
+       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));
+       struct linux_sbus *bus;
+       struct linux_sbus_device *sdev = 0;
+       struct Linux_SBus_DMA *ledma = 0;
+       int cards = 0, v;
     
-    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;
+       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 --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile
new file mode 100644 (file)
index 0000000..b452fa9
--- /dev/null
@@ -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 --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
new file mode 100644 (file)
index 0000000..1b5939a
--- /dev/null
@@ -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 <linux/kernel.h>
+#include <linux/malloc.h>
+
+#include <asm/oplib.h>
+#include <asm/contregs.h>
+#include <asm/sysen.h>
+#include <asm/delay.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/sbus.h>
+#include <asm/vac-ops.h>
+#include <asm/vaddrs.h>
+
+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 --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
new file mode 100644 (file)
index 0000000..0484ae0
--- /dev/null
@@ -0,0 +1,256 @@
+/* sbus.c:  SBus support routines.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+
+#include <asm/system.h>
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/oplib.h>
+
+/* 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; grrr<sbus_dev->num_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; len<sbus_dev->num_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; len<sbus_dev->num_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;
+}
index bc9b9b6dd4a38fbdb5703b66fa819756afdb98de..0ad5eea77833024d82d785334fdba84758c671fc 100644 (file)
@@ -700,7 +700,7 @@ debug_config(struct aic7xxx_host_config *p)
   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 @@ aic7xxx_register(Scsi_Host_Template *template,
 
   /*
    * 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 --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
new file mode 100644 (file)
index 0000000..2b1b8a5
--- /dev/null
@@ -0,0 +1,1128 @@
+/* esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "esp.h"
+
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/vaddrs.h>
+#include <asm/io.h>
+
+#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<NUM_ESP_COMMANDS; i++)
+               if(esp_cmd_strings[i].cmdchar == espcmd)
+                       break;
+       if(i==NUM_ESP_COMMANDS)
+               printk("ESP_Unknown");
+       else
+               printk("%s%s", esp_cmd_strings[i].text,
+                      ((dma_bit) ? "+DMA" : ""));
+}
+
+/* Print the status register's value */
+static inline void esp_print_statreg(unchar statreg)
+{
+       unchar phase;
+
+       printk("STATUS<");
+       phase = statreg & ESP_STAT_PMASK;
+       printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
+                      (phase == ESP_DIP ? "DATA-IN" :
+                       (phase == ESP_CMDP ? "COMMAND" :
+                        (phase == ESP_STATP ? "STATUS" :
+                         (phase == ESP_MOP ? "MSG-OUT" :
+                          (phase == ESP_MIP ? "MSG_IN" :
+                           "unknown")))))));
+       if(statreg & ESP_STAT_TDONE)
+               printk("TRANS_DONE,");
+       if(statreg & ESP_STAT_TCNT)
+               printk("TCOUNT_ZERO,");
+       if(statreg & ESP_STAT_PERR)
+               printk("P_ERROR,");
+       if(statreg & ESP_STAT_SPAM)
+               printk("SPAM,");
+       if(statreg & ESP_STAT_INTR)
+               printk("IRQ,");
+       printk(">");
+}
+
+/* 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 --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
new file mode 100644 (file)
index 0000000..3d09b2e
--- /dev/null
@@ -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 <asm/dma.h>
+
+/* 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) */
index d0f6d684f4524820014776a8d3864f5aab4fac6c..b728ea9dbcc1b37ec82154b70f6eedd6d4f582b9 100644 (file)
 #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 $";
 */
 
 /*
@@ -248,6 +252,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_PPA
     PPA,
 #endif
+#ifdef CONFIG_SCSI_SUNESP
+    SCSI_SPARC_ESP,
+#endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
 #endif
index 56134b8a1bce231787ca725dd949f3f4808ff940..0fd901474d9a8d531621070a1600841ecffa51b5 100644 (file)
 
 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 @@ void fat_put_inode(struct inode *inode)
                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 @@ void fat_read_inode(struct inode *inode, struct inode_operations *fs_dir_inode_o
 /* 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 @@ void fat_write_inode(struct inode *inode)
        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;
index 118c13f43043d17fd89dc9a751e6cc840978655f..a6dc77f73bba275981e23597321c4412ca08a8ee 100644 (file)
@@ -690,16 +690,19 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,int old_len,
        }
        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);
index 411d1e668ebde597a100bb97ab6ad21651b9cf35..41d635f76a48788bb4f92c31ad9f3fd8c54696d1 100644 (file)
@@ -29,7 +29,7 @@
  * filesystem and type 'ls xyzzy' to turn on debugging.
  */
 
-#if 1
+#if 0
 #define NFS_PROC_DEBUG
 #endif
 
index c0258cb9f2424e6fa8d4e86e8b3f00fec79ec7c6..31d0c36fba35a77780ab57db7421488a7d368944 100644 (file)
@@ -1473,6 +1473,8 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
 
        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 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
 
        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
index d52e0bba778427a38a1f1924d552b4980f0f280c..63136c29dfacfd21eb0a43833e9857e0eb407bd5 100644 (file)
@@ -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
 
 #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 --git a/include/asm-sparc/asmmacro.h b/include/asm-sparc/asmmacro.h
new file mode 100644 (file)
index 0000000..1ece6df
--- /dev/null
@@ -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 --git a/include/asm-sparc/atomic.h b/include/asm-sparc/atomic.h
new file mode 100644 (file)
index 0000000..3e8fe01
--- /dev/null
@@ -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 <asm/smp.h>
+#include <asm/smp_lock.h>
+#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 --git a/include/asm-sparc/atops.h b/include/asm-sparc/atops.h
new file mode 100644 (file)
index 0000000..688f425
--- /dev/null
@@ -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
index 619f3b22574534418b577caec00781a302e8e72b..4578cd20329c786dcf02b89acee7d627a80dd819 100644 (file)
@@ -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)
  */
index 36148bcc57874ede6864781b96e0d0535cef23da..088831059fcf1b873f9890b04ced214d3417effd 100644 (file)
@@ -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).
 #include <asm/system.h>
 #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 @@ extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
        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 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
        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 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
 }
 
 /* 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 @@ extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long siz
        offset &= 31UL;
        if (offset) {
                tmp = *(p++);
-               tmp |= ~0UL << (32-offset);
+               tmp |= ~0UL >> (32-offset);
                if (size < 32)
                        goto found_first;
                if (~tmp)
index 663b61d1a2b9ad15371ab0316bebc6bbc9022c71..d5aa64fe2504fb4a72f7e3f1b1ce27082a1acfbb 100644 (file)
@@ -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)
  */
index 9ad2ad54264efa5bf1f075ef7d2e9cc56e0fb0d0..1326f87fed9fb6da0f297f830551b1814fb807eb 100644 (file)
@@ -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.
  */
index 8d7dc5fda77e5ae368fbec45d5bc2659a532e2aa..c893af2f6ddaa805e8dbcfed54590cf8057bd9a2 100644 (file)
@@ -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 @@ do_csum(unsigned char * buff, int len)
                goto out;
        odd = 1 & (unsigned long) buff;
        if (odd) {
-               result = *buff << 8;
+               result = *buff;
                len--;
                buff++;
        }
@@ -50,7 +94,6 @@ do_csum(unsigned char * buff, int len)
                                unsigned long w = *(unsigned long *) buff;
                                count--;
                                buff += 4;
-                               len -= 4;
                                result += carry;
                                result += w;
                                carry = (w > result);
@@ -64,7 +107,7 @@ do_csum(unsigned char * buff, int len)
                }
        }
        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 @@ out:
        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 short ip_fast_csum(unsigned char * iph, unsigned int ihl)
  */
 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
 
-       /* add in old sum, and carry.. */
-       result += sum;
-       /* 32+c bits -> 32 bits */
-       result = (result & 0xffff) + (result >> 16);
-       return result;
+               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"); 
+
+       return sum;
 }
 
 /*
@@ -136,27 +301,17 @@ extern inline unsigned short ip_compute_csum(unsigned char * buff, int len)
 /*
  *     Fold a partial checksum without adding pseudo headers
  */
-
-static inline unsigned short 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)
+extern inline unsigned int csum_fold(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) */
index 4ffcab39c667e06836e0c7b4b392f8e63e46d6e0..a7ac8cace80568d1693b9d4efd698badb49e8deb 100644 (file)
@@ -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
@@ -72,4 +72,8 @@ extern inline void cypress_flush_context(void)
                             "i" (ASI_M_FLUSH_CTX));
 }
 
+/* XXX Displacement flushes for buggy chips and initial testing
+ * XXX go here.
+ */
+
 #endif /* !(_SPARC_CYPRESS_H) */
index 2c50d712e21c4e4bd77ceefed4c1582d3e464232..e10f326e93eacb6092bc67ce5a9f871fcb475a46 100644 (file)
@@ -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 @@ extern unsigned long dvma_init(struct linux_sbus *, unsigned long);
 #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 */
index 1bd3e0bc5935d5eb0cf71f8606d82158d5ac817d..d804231da3af8daf4e8e27a75dbfb7f752995d98 100644 (file)
  *  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
index b77ed292973000e82a770115d283644ae88e6a8d..0ab7fbecef4df79128ad78ae9ab22d8a939301f6 100644 (file)
@@ -72,7 +72,7 @@ struct fbgattr {
         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)
index b4a2b005a672a56538c298ff1b0b17cd54002476..81c3354b5239deca426ef0063b0909ca31c80d72 100644 (file)
@@ -66,7 +66,6 @@ static struct sun_floppy_ops sun_fdops;
 #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 @@ static int FDC2=-1;
 #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 @@ static void sun_82072_fd_outb(unsigned char value, int port)
                 *               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 @@ static inline void sun_fd_enable_dma(void)
        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,35 +325,18 @@ static int sun_floppy_init(void)
                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;
 
index 1dadaa44167fd36e2b1e869ddfc338170c25f328..ba02a00acdf16c539425882db011f8acb4cc7205 100644 (file)
@@ -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) \
 #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 --git a/include/asm-sparc/ioctls.h b/include/asm-sparc/ioctls.h
new file mode 100644 (file)
index 0000000..0f065c9
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _ASM_SPARC_IOCTLS_H
+#define _ASM_SPARC_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+/* 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) */
index 702e489d3066820a452349c4f3f26cb77ba1f747..fe58ba121b6564790a53c4c568fb223c2b90fdbe 100644 (file)
@@ -92,6 +92,7 @@ struct iommu_regs {
 
 /* 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_regs {
 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 */
index b6d7639af6a6063badbc24cf8839501f5a576eb0..163080153c5e290cdb098bd62b085dbb5cca1d56 100644 (file)
@@ -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)
 
 #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 @@ extern int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struc
  */
 
 /* 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 @@ struct sun4m_intreg_percpu {
        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 @@ struct sun4m_intregs {
 
 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 @@ extern struct sun4m_intregs *sun4m_interrupts;
 #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
-
-/* XXX add cross-cpu ipi functions XXX */
+/* 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 */
+
+#define SUN4M_INT_SBUS(x)      (1 << (x+7))
 
 #endif
index 0d1860d493c7b79cacf1ff2bcc9c625b09fdf826..4d9a59fa941d5dec21c67d56eda39980f7c6f782 100644 (file)
@@ -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 viking_rev, swift_rev, cypress_rev;
 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 @@ extern unsigned int hwbug_bitmask;
 /* 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)
 {
index 6f9adf6ba2d074429ca1658ca58e78c4f7bf6ca2..71442dd24bd479c23da1500a326f369cc7be701c 100644 (file)
@@ -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 */
index 2198ef59af243c584d78803d87068beb8aadac28..b4968bdaf079c2d5ee87bab5e3cd4ce23770d673 100644 (file)
@@ -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 */
index e90aa01132a7cef25a70cfd08ebb667bd8efdcef..27d792a9df507c9657e1b6fe34644a9e97d99f3b 100644 (file)
@@ -29,7 +29,7 @@ extern struct mostek48t02 *mstk48t02_regs;
 /* 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)
index 6d48a5aef4211515640c31c7e4390e8bae182d6f..fc4c8a69f40cd5c0db4d7d454ef0ce29c8053747 100644 (file)
@@ -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)
 #include <asm/page.h>
 #include <asm/vaddrs.h>
 
-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. */
index a8fa3240f33530d0e248e939dae9f060057f5e32..9bece9fb40d3ef48fa35bb4019c824b983ac8f8e 100644 (file)
@@ -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 --git a/include/asm-sparc/msi.h b/include/asm-sparc/msi.h
new file mode 100644 (file)
index 0000000..612d184
--- /dev/null
@@ -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) */
index 278e245a84c808fdf5a7fa38db5caec6ab6e2791..cdbd1cb4591e821c4113e63d1e2af28990443739 100644 (file)
@@ -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
  * 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) */
index e2b9c41ddd3b78e0dc383db5962eccfd7110f857..5bac9311e4b0bbfe59a36f00846a44cb57e5ea90 100644 (file)
@@ -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 @@ extern struct linux_romvec *romvec;
 
 /* 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 @@ extern void prom_seek(int device_handle, unsigned int seek_hival,
  * 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
index 626088fff3136d62c7059b2a586f1602c9109afd..1fe74cf079618f2a8675f6e8e7a1d81276a2f85e 100644 (file)
@@ -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 @@ struct cache_palias {
 
 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
 /*
index 84cc8dd242dad918b4f86583c2ffe636acb23947..bbbda73b2652b3544d28a543d2ba6df5d6fb6b3c 100644 (file)
@@ -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                  */
index 1f93306bb173a3f5ae7ffc7db9e1b0c5ff8418f1..41bdebf611143fe2959e3ec6ae3e22b8deb3e885 100644 (file)
@@ -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 <asm/sbus.h>
 
 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 (*quick_kernel_fault)(unsigned long);
 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 @@ extern unsigned long empty_zero_page;
 
 #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 unsigned long high_memory;
 
 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 @@ extern pte_t (*pte_mkyoung)(pte_t);
  * 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 void (*pgd_free)(pgd_t *);
 
 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 @@ extern void (*switch_to_context)(struct task_struct *tsk);
  * 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 void (*update_mmu_cache)(struct vm_area_struct *vma, unsigned long addres
 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;
 };
 
index 782a3d82cae2b953c95ed70d31940de56a9f931c..71c080cb481c14caea4302e260376f963214d36b 100644 (file)
@@ -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 <linux/config.h>
 #include <asm/page.h>
 
 /* 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_mmureg(unsigned long regval)
 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 @@ extern inline unsigned int srmmu_get_faddr(void)
        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 @@ extern inline unsigned long srmmu_hwprobe(unsigned long vaddr)
 {
        unsigned long retval;
 
+       vaddr &= PAGE_MASK;
        __asm__ __volatile__("lda [%1] %2, %0\n\t" :
                             "=r" (retval) :
                             "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
index d9e001ca1289f1fb0e7458ba49ce9c0221907ccf..d61f06f3a9877f931ee920deef0bbcf50a42111e 100644 (file)
@@ -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.
@@ -65,9 +65,6 @@
                                     _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)
 {
        unsigned long sync_err;
diff --git a/include/asm-sparc/posix_types.h b/include/asm-sparc/posix_types.h
new file mode 100644 (file)
index 0000000..417a0d4
--- /dev/null
@@ -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) */
index 81f6df3a725efdae99af0b89ef631990fd50ed66..b06e267c9a45ea20e8beec3dbb9cb1ab5a8f82e3 100644 (file)
@@ -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)
 #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 @@ extern inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigne
        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 */
index 53050fdd2196ac43ffac46d7f840cfdde430e3cd..13d3857a4cadf6115bf3a91209c48d94551193d8 100644 (file)
@@ -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)
 #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 @@ extern inline void hyper_flush_whole_icache(void)
  *
  * 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 unsigned int get_ross_icr(void)
 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 @@ extern inline void put_ross_icr(unsigned int icreg)
 
 /* 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_flush_all_combined(void)
+extern inline void hyper_clear_all_tags(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_DATAC_TAG));
 }
 
+extern inline void hyper_flush_unconditional_combined(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_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) */
index ab6279ff490b549df66618d3cfa8a50a06a0b1a9..129ca03931a1d469e187288cf06ff9178e29d7f4 100644 (file)
@@ -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 <asm/vac-ops.h>
+#endif
 
 #ifndef __ASSEMBLY__
 
index 15ced3450887414860df63319f98c218e041f305..b666e865d590627139735943e1d78d3cd094c098 100644 (file)
@@ -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 @@ struct sigstack {
  * 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 */
index 56e43756dd6da4ebb90f49968e2a77644eb08b05..6f6ceba98ed8a8cd05426b7be98673f0d951db06 100644 (file)
 #ifndef _SPARC_SMP_H
 #define _SPARC_SMP_H
 
-#include <asm/bitops.h>
-#include <asm/ptrace.h>
+#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_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);
 
-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);
+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 _inline_ int smp_processor_id(void)
+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 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 @@ extern _inline_ int smp_processor_id(void)
 
 #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) */
index aeb49140a865f09b4381bf070c139fb13daabf33..41d3329ce831269383c16e116b1a1f5ca00f0716 100644 (file)
@@ -6,31 +6,33 @@
 #ifndef __SPARC_SMPLOCK_H
 #define __SPARC_SMPLOCK_H
 
-#ifdef __SMP__
+#include <asm/smp.h>
+#include <asm/bitops.h>
+#include <asm/atops.h>
+#include <asm/pgtable.h>
 
-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 @@ extern _inline_ void lock_kernel(void)
 }
 
 /* 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) */
index 3c8f08fe2e005405f064562105b9cb3c4faf8d6b..1c53480303f35f3e4f20cc5497f3658ddf53435d 100644 (file)
@@ -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 <asm/sockios.h>
 
 /* For setsockoptions(2) */
 #define SOL_SOCKET     0xffff
diff --git a/include/asm-sparc/sockios.h b/include/asm-sparc/sockios.h
new file mode 100644 (file)
index 0000000..0c01b59
--- /dev/null
@@ -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) */
+
index 23f3ea1cbad218282ca84ca936938e8639d2482a..fe2a83f653451cea53acf6cd73987f8614342086 100644 (file)
@@ -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    */
 #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   */
index d6dcb425733219b2a8e7b33ecf44d70ed8583443..c2bd841e9d4f093b7a4d61e8da5dec8cfd81bab2 100644 (file)
@@ -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__) */
index ff1e9082636d04cf9a6a3c33c1730b588b800bcd..f59fa320d04b5061c338e13ec89c95d247137e0f 100644 (file)
@@ -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 @@ extern inline void swift_inv_data_tag(unsigned long addr)
                             "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" : :
index 5808615a1b43436b8e0644320eeb69b60b801125..4e9854d66d1ff805897b9893112103aad44ee65d 100644 (file)
@@ -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 <linux/kernel.h>
 
 #include <asm/segment.h>
+
+#ifdef __KERNEL__
 #include <asm/page.h>
 #include <asm/oplib.h>
 #include <asm/psr.h>
+#endif
 
 #define EMPTY_PGT       (&empty_bad_page)
 #define EMPTY_PGE      (&empty_bad_page_table)
@@ -44,13 +47,40 @@ extern struct linux_romvec *romvec;
 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 --git a/include/asm-sparc/termbits.h b/include/asm-sparc/termbits.h
new file mode 100644 (file)
index 0000000..623b330
--- /dev/null
@@ -0,0 +1,191 @@
+#ifndef _SPARC_TERMBITS_H
+#define _SPARC_TERMBITS_H
+
+#include <linux/posix_types.h>
+
+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) */
index 113d4f13bfc725bd359c258c08fb14a4c3e8d769..1839148ae4eddb491dea7e6b990f3d6eb9e7bbbc 100644 (file)
@@ -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 <linux/types.h>
-
-#include <asm/ioctl.h>
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
 
 struct sgttyb {
        char    sg_ispeed;
@@ -37,104 +36,6 @@ struct sunos_ttysize {
        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 @@ struct winsize {
        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 @@ struct termios {
        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.
index a21fea1ad8fb4e645f7ff5a87f2bb77b95a08024..0cd77ff3cf6b489389987dd718caa24438b3a548 100644 (file)
@@ -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)
@@ -32,8 +32,6 @@ struct sun4c_timer_info {
 
 #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
  * value. Aurora behaves similarly but its limit value is compacted in
index 8bdc39f3c17c10f621deeec96dd0a3bcf353bd4c..5093779fb1095120dafe98abb131d367da7a768e 100644 (file)
@@ -67,7 +67,7 @@ extern __inline__ unsigned long get_tbr(void)
 /* 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 */
index ab65b37a1a71d8d7bab5a0d5b52db4202e64c19c..2da4f1b7de52a66866f341be786f522dbdc0c2f5 100644 (file)
@@ -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)
 #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");
index 31996c455b221158cfa8f52c29c45c4c7f5311b5..3181c64a8aefc11b7fa4291d876357012ae11b3a 100644 (file)
@@ -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.
  */
 
-#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
+/*
+ * 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.
+ */
 
-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;
@@ -75,57 +45,4 @@ 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) */
index 801f3c04a84bca2f410ca66ac7249761e8acad9a..b2692b731d34848ce7d4980316fb8fb624b0d365 100644 (file)
@@ -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)
  */
 #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 @@ __asm__ volatile ("or %%g0, %0, %%g1\n\t" \
                  "1:\n\t" \
                  : "=r" (__res)\
                  : "0" (__NR_##name) \
-                 : "g1"); \
+                 : "g1", "o0"); \
 if (__res >= 0) \
     return (type) __res; \
 errno = -__res; \
@@ -366,24 +379,28 @@ if (__res>=0) \
 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 @@ return -1; \
  * 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,close,int,fd)
 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);
 }
 
 /*
index 5c2ce4c29c679e41bff3c48d4fcd49c63dea6195..4971177e5de5bff8d8f391bb8d0037aef06da1a2 100644 (file)
@@ -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
@@ -122,6 +122,4 @@ extern __inline__ void sun4c_disable_vac(void)
   sun4c_vacinfo.on = 0;
 }
 
-extern void sun4c_flush_context(void);
-
 #endif /* !(_SPARC_VAC_OPS_H) */
index 8ce95e8633ee69e9aeeb2448336dde29791fa991..459f12c5ca091ad4348c2956991362bad83e2563 100644 (file)
@@ -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
 
  * 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).
 #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) */
 
index 476daa3271839b6a4aebdd3e7d5e64d20e6a623b..4f413142e99247f2bc022a4ef9a0c46ddacfb9df 100644 (file)
@@ -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)
 
 #include <asm/mxcc.h>
 
-/* Bits in the SRMMU control register for TI Viking modules.
- *
- * -------------------------------------------------------------
- * |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
+/* 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.
+ *
  * 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 @@ extern inline void viking_flush_dcache(void)
                             "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_unlock_dcache(void)
+{
+       __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 void viking_mxcc_scrape(void)
+extern inline unsigned long viking_get_bpreg(void)
 {
-       /* David, what did you learn in school today? */
+       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) */
index 15dcbdf1df65197486a6c93c95bfc342e9dafce2..7781e9f2fdd31ed568753206cf308e62011c8e0d 100644 (file)
@@ -24,7 +24,7 @@ enum {
     /* 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: */
index 1359f5c634e43012c50ddaad329cddc03deb7739..b04ac599029775f1da9762231f8a3e8e8f44059b 100644 (file)
@@ -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)
         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; \
index 269f16b132142ecc382887cb084a35ac34ce0bf9..670349fc4ff6fee96b9dea78209c1ecfc164e8d4 100644 (file)
@@ -132,9 +132,11 @@ enum machine_type {
 #ifdef __i386__
 #define SEGMENT_SIZE   1024
 #else
+#ifndef SEGMENT_SIZE
 #define SEGMENT_SIZE   PAGE_SIZE
 #endif
 #endif
+#endif
 
 #define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
 
index 04d1c88f9ad679610629c5d84474c4778ef8846c..b1e66ce622edc76135137c80e411b5a2634964cd 100644 (file)
@@ -170,16 +170,12 @@ static void floppy_off(unsigned int nr);
 /* 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 @@ static void floppy_off(unsigned int nr);
 
 #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 @@ else \
 
 #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 @@ static void (DEVICE_REQUEST)(void);
 /* 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 @@ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup);
 #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 @@ static void end_request(int uptodate) {
 #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 */
@@ -432,36 +424,6 @@ static void end_request(int uptodate) {
 #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) */
 
 #endif /* _BLK_H */
index 4b65a538c693f0832114f4e5566c8407d1fd6b6b..b0c8c4bac2a85dd644ba9be477cc3390bab71b78 100644 (file)
@@ -50,9 +50,8 @@ extern struct blk_dev_struct blk_dev[MAX_BLKDEV];
 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];
 
index a787189035c8e982761d7314beba2034f688b15a..238466e994d22fa3330eac98d9a7fd08345c2f10 100644 (file)
 #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
 #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
index b7c951e3c3da169691f28acfb8760ba8cd6b62d8..2bbfc745c8f8b50ce20ddc3d723dfb4a641a8ad8 100644 (file)
@@ -154,7 +154,8 @@ struct buffer_head {
        /* 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 */
 
index f764824a153d0e08b84fd50ded0e07b5b814d663..8e9c037fd77048677b61eb3aa90cdd7e1bd4f6ee 100644 (file)
@@ -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).
  *
  * 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
  * 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 @@ typedef struct {
   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 @@ typedef struct {
 
 /* 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 @@ typedef struct {
                               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 @@ typedef struct {
 /* 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 @@ typedef struct isdn_net_local_s {
   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 @@ typedef struct isdn_devt {
   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;
index 25e34f8a722bab87488f68fbf0cafd5877320cf9..ab8d35dd6033f108a338fecbbdb1a06913ddaeb3 100644 (file)
@@ -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
  *
  * 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
  *
index 3cba53fffdc6054fbee9386104d9c91b363209e5..27c31d8ef2bc7191d9752f7765fa12b36d946643 100644 (file)
 #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.
  */
index 1ee4b54d6690669bbef2d9861bda237d570af3cd..cec403132e2402cf2489e2df2eb54b59747d1fa0 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/mm.h>
 #include <linux/ioctl.h>
 
-#define MD_VERSION "0.34"
+#define MD_VERSION "0.35"
 
 /* ioctls */
 #define REGISTER_DEV _IO (MD_MAJOR, 1)
 
 #ifdef __KERNEL__
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 
-#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_dev;
 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,25 +123,14 @@ struct md_dev
   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);
 
index 68fffca71acbb8b514df88092fece09603459643..07c74e1165dad5ebe04b12a980d25d810727cf9e 100644 (file)
@@ -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);
index b11e224835cb0305049d2c61b30b74f4e7d816de..cc9d9ac85ebe4f0815c6f9043f46851c4ee9e582 100644 (file)
@@ -33,6 +33,10 @@ struct msdos_inode_info {
                                   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 */
 };
 
index 46c3a2e6a37f7c08e998986e2627f83ebecc7090..267c33f30024e1446f756c24e772bfac6f2d7def 100644 (file)
@@ -130,6 +130,7 @@ enum scsi_directory_inos {
        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 */
index c5ce9ef09ca2294b6f106f93dc60373e2c3ee532..58871c04f3cab596a4d7527e13fba50eba1ce4a6 100644 (file)
@@ -72,6 +72,8 @@ extern struct screen_info screen_info;
 
 #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
index 025669ff90523492cea99e7af88715db9e703924..cde80eb8beda19480afc88def41e63c8d8e12860 100644 (file)
@@ -135,6 +135,10 @@ extern void teles_setup(char *str, int *ints);
 #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);
@@ -336,6 +340,9 @@ struct {
 #ifdef CONFIG_ISDN_DRV_TELES
        { "teles=", teles_setup },
 #endif
+#ifdef CONFIG_ISDN_DRV_PCBIT
+       { "pcbit=", pcbit_setup },
+#endif
 #ifdef CONFIG_DIGI
        { "digi=", pcxx_setup },
 #endif
index 19e5d72da41fadb43e9a4d6672d2e7155b98e47c..edde5fbec3b35d0339b2c72f26d7ff46435efef1 100644 (file)
@@ -304,9 +304,9 @@ sys_delete_module(char *module_name)
                                GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN;
                                (*mp->cleanup)();
                                mp->state = MOD_DELETED;
-                               free_modules();
                        }
                }
+               free_modules();
        }
        return 0;
 }
index 379117050ac807dbbc0a11e2e884451e93189195..308babe37c37e877800e2333cb11a6545c40c7d6 100644 (file)
@@ -104,8 +104,10 @@ repeat:
                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 @@ static void profile_readahead(int async, struct file *filp)
  *
  * 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 @@ static void profile_readahead(int async, struct file *filp)
  * ------------------------------
  * 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 @@ static inline unsigned long generic_file_readahead(struct file * filp, struct in
        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 @@ static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long
        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 @@ static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
                        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);
index dfb068c6b43bbddf6c129781e193b5d53fc4a3a2..0dd32690eb1e9728294ada034b04ae1b99912b69 100644 (file)
@@ -468,7 +468,7 @@ static inline void remap_pte_range(pte_t * pte, unsigned long address, unsigned
                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 @@ int remap_page_range(unsigned long from, unsigned long offset, unsigned long siz
 
        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 @@ int remap_page_range(unsigned long from, unsigned long offset, unsigned long siz
                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 @@ static void put_page(pte_t * page_table, pte_t pte)
                free_page(pte_page(pte));
                return;
        }
-/* no need for invalidate */
+/* no need for flush_tlb */
        set_pte(page_table, pte);
 }
 
@@ -568,8 +568,9 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
                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 @@ static inline void get_empty_page(struct task_struct * tsk, struct vm_area_struc
                        oom(tsk);
                        pte = BAD_PAGE;
                }
+               flush_page_to_ram(page);
        }
        put_page(page_table, pte);
 }
@@ -797,11 +799,13 @@ static void partial_clear(struct vm_area_struct *vma, unsigned long address)
        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 @@ static inline void do_swap_page(struct task_struct * tsk,
 
        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 @@ static inline void do_swap_page(struct task_struct * tsk,
                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 @@ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma,
         * 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 @@ static inline void handle_pte_fault(struct vm_area_struct * vma, unsigned long a
                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);
index 17283641ec970ac045d77aabe9f4da23359f21fe..4af27193ae9dd967bdf824a8d76f5e2d3e6fccec 100644 (file)
@@ -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 <asm/segment.h>
@@ -360,12 +363,6 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
        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...
         */
@@ -381,6 +378,17 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
 
        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 ;) <aldem@barnet.kharkov.ua> */
+               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.
         *      We need to somehow lock the original buffer and use