]> git.neil.brown.name Git - history.git/commitdiff
Linux-2.1.124... 2.1.124
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:52 +0000 (15:16 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:52 +0000 (15:16 -0500)
.. is out there now, and includes:

 - subtle fix for lazy FP save and restore on x86. The bug has been there
   for a long time, but was apparently triggered by the re-write of the
   low-level scheduling function. It could result in corrupted i387 state
   under certain (admittedly fairly unlikely) circumstances.
 - various networking updates. Some of the bugs fixed could result in
   kernel Oopses. None of them were common, though.
 - fixes for both filesystem accounting and quota handling.
 - the much-ado-about-little video driver merge.
 - PPC and Sparc updates
 - i386/SMP interrupt handling falls back on the safe mode.. Please tell
   me whether there are still machines with problems.
 - some new network drivers and updates
 - final (we hope) IP masquerade update

I still have a problem with certain machines that apparently don't want to
boot with the keyboard not plugged in even though they should. Kill me
now. If you have problems with i386/SMP on a machine without a keyboard,
plug one in and send me a report..

289 files changed:
CREDITS
Documentation/Changes
Documentation/Configure.help
Documentation/fb/vesafb.txt
Documentation/networking/ip_masq/ip_masq-API-ex.c [new file with mode: 0644]
Makefile
arch/i386/config.in
arch/i386/defconfig
arch/i386/kernel/io_apic.c
arch/i386/kernel/smp.c
arch/i386/kernel/traps.c
arch/ppc/8xx_io/commproc.c
arch/ppc/amiga/amiints.c
arch/ppc/amiga/time.c
arch/ppc/boot/mbxtty.c
arch/ppc/kernel/residual.c
arch/sparc/Makefile
arch/sparc/boot/Makefile
arch/sparc/boot/btfixupprep.c
arch/sparc/config.in
arch/sparc/defconfig
arch/sparc/kernel/Makefile
arch/sparc/kernel/auxio.c
arch/sparc/kernel/ebus.c [new file with mode: 0644]
arch/sparc/kernel/irq.c
arch/sparc/kernel/pcic.c [new file with mode: 0644]
arch/sparc/kernel/process.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/signal.c
arch/sparc/kernel/smp.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/sys_sunos.c
arch/sparc/kernel/systbls.S
arch/sparc/kernel/time.c
arch/sparc/kernel/traps.c
arch/sparc/lib/copy_user.S
arch/sparc/lib/debuglocks.c
arch/sparc/mm/Makefile
arch/sparc/mm/asyncd.c
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/mm/turbosparc.S [deleted file]
arch/sparc/prom/console.c
arch/sparc/prom/tree.c
arch/sparc/vmlinux.lds
arch/sparc64/Makefile
arch/sparc64/config.in
arch/sparc64/defconfig
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/binfmt_aout32.c
arch/sparc64/kernel/binfmt_elf32.c
arch/sparc64/kernel/check_asm.sh
arch/sparc64/kernel/dtlb_backend.S
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/entry.S
arch/sparc64/kernel/ioctl32.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/psycho.c
arch/sparc64/kernel/rtrap.S
arch/sparc64/kernel/setup.c
arch/sparc64/kernel/signal.c
arch/sparc64/kernel/signal32.c
arch/sparc64/kernel/smp.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sunos_ioctl32.c
arch/sparc64/kernel/sys32.S
arch/sparc64/kernel/sys_sparc.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/sys_sunos32.c
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/ttable.S
arch/sparc64/kernel/unaligned.c
arch/sparc64/kernel/winfixup.S
arch/sparc64/lib/checksum.S
arch/sparc64/lib/strlen.S
arch/sparc64/mm/asyncd.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/ultra.S
arch/sparc64/solaris/conv.h
arch/sparc64/solaris/socksys.c
drivers/block/ns87415.c
drivers/char/Makefile
drivers/char/console.c
drivers/char/mem.c
drivers/net/8390.h
drivers/net/Config.in
drivers/net/Makefile
drivers/net/Space.c
drivers/net/a2065.c
drivers/net/apne.c
drivers/net/ariadne2.c [new file with mode: 0644]
drivers/net/dummy.c
drivers/net/mace.c
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/sbus/audio/Config.in
drivers/sbus/audio/Makefile
drivers/sbus/audio/amd7930.c
drivers/sbus/audio/audio.c
drivers/sbus/audio/cs4215.h
drivers/sbus/audio/dbri.c
drivers/sbus/audio/dbri.h
drivers/sbus/char/Config.in
drivers/sbus/char/Makefile
drivers/sbus/char/bpp.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/pcikbd.c
drivers/sbus/char/rtc.c
drivers/sbus/char/sab82532.c
drivers/sbus/char/su32.c [new file with mode: 0644]
drivers/sbus/char/sunkbd.c
drivers/sbus/char/sunmouse.c
drivers/sbus/char/sunserial.c
drivers/sbus/char/vfc_dev.c
drivers/sbus/char/zs.c
drivers/sbus/dvma.c
drivers/sbus/sbus.c
drivers/scsi/qlogicpti.c
drivers/video/S3triofb.c
drivers/video/acornfb.c
drivers/video/amifb.c
drivers/video/atafb.c
drivers/video/atyfb.c
drivers/video/bwtwofb.c
drivers/video/chipsfb.c
drivers/video/clgenfb.c
drivers/video/controlfb.c
drivers/video/controlfb.h
drivers/video/cyberfb.c
drivers/video/dnfb.c
drivers/video/fbcon.c
drivers/video/g364fb.c
drivers/video/hpfb.c
drivers/video/imsttfb.c
drivers/video/macfb.c
drivers/video/mdacon.c
drivers/video/offb.c
drivers/video/platinumfb.c
drivers/video/retz3fb.c
drivers/video/sbusfb.c
drivers/video/skeletonfb.c
drivers/video/tgafb.c
drivers/video/valkyriefb.c
drivers/video/vesafb.c
drivers/video/vfb.c
drivers/video/virgefb.c
fs/binfmt_elf.c
fs/ext2/ialloc.c
fs/proc/openpromfs.c
include/asm-alpha/linux_logo.h
include/asm-i386/bugs.h
include/asm-i386/system.h
include/asm-sparc/bitops.h
include/asm-sparc/ebus.h [new file with mode: 0644]
include/asm-sparc/elf.h
include/asm-sparc/fbio.h
include/asm-sparc/fcntl.h
include/asm-sparc/floppy.h
include/asm-sparc/hardirq.h
include/asm-sparc/io.h
include/asm-sparc/ioctls.h
include/asm-sparc/keyboard.h [new file with mode: 0644]
include/asm-sparc/mostek.h
include/asm-sparc/openprom.h
include/asm-sparc/oplib.h
include/asm-sparc/pbm.h [new file with mode: 0644]
include/asm-sparc/pcic.h [new file with mode: 0644]
include/asm-sparc/shmparam.h
include/asm-sparc/siginfo.h
include/asm-sparc/smp.h
include/asm-sparc/softirq.h
include/asm-sparc/spinlock.h
include/asm-sparc/system.h
include/asm-sparc/termios.h
include/asm-sparc/timer.h
include/asm-sparc/turbosparc.h
include/asm-sparc/uaccess.h
include/asm-sparc/unistd.h
include/asm-sparc64/asm_offsets.h
include/asm-sparc64/elf.h
include/asm-sparc64/fcntl.h
include/asm-sparc64/floppy.h
include/asm-sparc64/hardirq.h
include/asm-sparc64/ide.h
include/asm-sparc64/io.h
include/asm-sparc64/mmu_context.h
include/asm-sparc64/ns87303.h
include/asm-sparc64/pgtable.h
include/asm-sparc64/posix_types.h
include/asm-sparc64/shmparam.h
include/asm-sparc64/smp.h
include/asm-sparc64/softirq.h
include/asm-sparc64/string.h
include/asm-sparc64/system.h
include/asm-sparc64/termios.h
include/asm-sparc64/ttable.h
include/asm-sparc64/uaccess.h
include/asm-sparc64/unistd.h
include/asm-sparc64/visasm.h
include/linux/errqueue.h [new file with mode: 0644]
include/linux/fb.h
include/linux/in.h
include/linux/in6.h
include/linux/ip.h
include/linux/ip_fw.h
include/linux/ip_masq.h [new file with mode: 0644]
include/linux/sysctl.h
include/net/ip.h
include/net/ip_autofw.h [deleted file]
include/net/ip_fib.h
include/net/ip_masq.h
include/net/ip_masq_mod.h
include/net/ip_portfw.h [deleted file]
include/net/ipv6.h
include/net/snmp.h
include/net/sock.h
init/main.c
kernel/acct.c
kernel/fork.c
net/core/datagram.c
net/core/neighbour.c
net/core/sock.c
net/core/sysctl_net_core.c
net/ipv4/Config.in
net/ipv4/Makefile
net/ipv4/af_inet.c
net/ipv4/fib_hash.c
net/ipv4/fib_rules.c
net/ipv4/fib_semantics.c
net/ipv4/icmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_fw.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_masq.c
net/ipv4/ip_masq_app.c
net/ipv4/ip_masq_autofw.c
net/ipv4/ip_masq_cuseeme.c
net/ipv4/ip_masq_ftp.c
net/ipv4/ip_masq_irc.c
net/ipv4/ip_masq_mod.c
net/ipv4/ip_masq_portfw.c
net/ipv4/ip_masq_raudio.c
net/ipv4/ip_masq_user.c [new file with mode: 0644]
net/ipv4/ip_masq_vdolive.c
net/ipv4/ip_nat_dumb.c
net/ipv4/ip_options.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipip.c
net/ipv4/ipmr.c
net/ipv4/proc.c
net/ipv4/raw.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/ipv6/datagram.c
net/ipv6/exthdrs.c
net/ipv6/icmp.c
net/ipv6/ip6_output.c
net/ipv6/ipv6_sockglue.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/udp.c
net/netlink/af_netlink.c
net/netsyms.c
net/packet/af_packet.c
net/sched/sch_cbq.c
net/sched/sch_red.c
net/unix/af_unix.c

diff --git a/CREDITS b/CREDITS
index 2d56f8b27603b0c1ff122ae63f2e3d63619bd308..49c4584a0efd968cd35d99ca53a005a22b9f88ee 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -943,8 +943,8 @@ S: L-1148 Luxembourg-City
 S: Luxembourg
 
 N: Gerd Knorr
-E: kraxel@cs.tu-berlin.de
-D: SCSI CD-ROM driver hacking, minor bug fixes
+E: kraxel@goldbach.in-berlin.de
+D: SCSI CD-ROM driver hacking, vesafb, v4l, minor bug fixes
 
 N: Harald Koenig
 E: koenig@tat.physik.uni-tuebingen.de
index 2886c6215635001b536ea56f1f550dc7823bec34..777476de4d2bccd2aa4727dd7d5224db40b60ae8 100644 (file)
@@ -226,6 +226,9 @@ will no longer work.  You need to optain "ipchains," available from
 http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html, and use
 that instead of ipfwadm.
 
+   To use port forwarding and auto forwarding you will need 'ipmasqadm'
+tool, available from http://juanjox.home.ml.org. 
+
 Memory
 ======
 
@@ -540,6 +543,11 @@ The 1.3.3 release:
 http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.gz
 http://www.adelaide.net.au/~rustcorp/ipfwchains/ipchains-source-1.3.3.tar.bz2
 
+IP Masq Adm
+===========
+The 0.4.1 release:
+http://juanjox.home.ml.org/ipmasqadm-0.4.1.tar.gz
+
 iBCS
 ====
 
index 37ea34303f8cd0cb075e250039e5b5aa973e1eb8..3a62237a1518f14af7213dea7f1b25bcf475dc43 100644 (file)
@@ -1479,6 +1479,13 @@ CONFIG_VGA_CONSOLE
   display that complies with the generic VGA standard. Virtually
   everyone wants that. Say Y.
 
+Use 64KB of VGA video RAM (aka: Maximum VGA Scrollback)
+CONFIG_VGA_GET_64KB
+  Use 64K rather than 32K of video RAM. This doesn't actually work
+  on all "VGA" controllers. If your vga card can do it, then you 
+  can say Y here to get more scrollback buffer (shift-pgup) on VGA
+  consoles.
+
 Video mode selection support
 CONFIG_VIDEO_SELECT
   This enables support for text mode selection on kernel startup. If
@@ -1500,26 +1507,20 @@ CONFIG_FB
   hardware. It represents the frame buffer of some video hardware and
   allows application software to access the graphics hardware through
   a well-defined interface, so the software doesn't need to know
-  anything about the low-level (hardware register) stuff. 
-
-  Frame buffer devices work identically across the different
-  architectures supported by Linux and make the implementation of
-  application programs easier and more portable; at this point, an X
-  server exists which uses the frame buffer device exclusively.
-  On several non-X86 architectures, the frame buffer device is the
-  only way to use the graphics hardware.
+  anything about the low-level (hardware register) stuff. This works
+  across the different architectures supported by Linux and makes the
+  implementation of application programs easier and more portable; at
+  this point, an X server exists which uses the frame buffer device
+  exclusively.
+
   The device is accessed through special device nodes, usually located
   in the /dev directory, i.e. /dev/fb*.
 
-  You need an utility program called fbset to make full use of frame
-  buffer devices. Please read the file
-  Documentation/fb/framebuffer.txt for more information.
+  Please read the file Documentation/fb/framebuffer.txt for more
+  information.
 
-  If you want to play with it, say Y here and also to the driver for
-  your graphics board, below. If unsure, say N, unless you are
-  compiling a kernel for a non-X86 architecture, in which case you
-  should say Y.
+  If you want to play with it, say Y here and to the driver for your
+  graphics board, below. If unsure, say N.
 
 Acorn VIDC support
 CONFIG_FB_ACORN
@@ -1558,34 +1559,33 @@ CONFIG_FB_AMIGA_AGA
 
 Amiga CyberVision support
 CONFIG_FB_CYBER
-  This enables support for the Cybervision 64 graphics card from
-  Phase5. Please note that its use is not all that intuitive (i.e. if
-  you have any questions, be sure to ask!). Say N unless you have a
-  Cybervision 64 or plan to get one before you next recompile the
-  kernel. Please note that this driver DOES NOT support the
-  Cybervision 64 3D card, as they use incompatible video chips.
+  This enables support for the Cybervision 64 graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64 or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the Cybervision 64 3D
+  card, as they use incompatible video chips.           
 
 Amiga CyberVision3D support (EXPERIMENTAL)
 CONFIG_FB_VIRGE
-  This enables support for the Cybervision 64/3D graphics card from
-  Phase5. Please note that its use is not all that intuitive (i.e. if
-  you have any questions, be sure to ask!). Say N unless you have a
-  Cybervision 64/3D or plan to get one before you next recompile the
-  kernel. Please note that this driver DOES NOT support the older
-  Cybervision 64 card, as they use incompatible video chips.
+  This enables support for the Cybervision 64/3D graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64/3D or plan to get one before you next recompile the kernel.         
+  Please note that this driver DOES NOT support the older Cybervision 64
+  card, as they use incompatible video chips.           
 
 Amiga RetinaZ3 support (EXPERIMENTAL)
 CONFIG_FB_RETINAZ3
-  This enables support for the Retina Z3 graphics card. Say N unless
-  you have a Retina Z3 or plan to get one before you next recompile
-  the kernel.
+  This enables support for the Retina Z3 graphics card. Say N unless you
+  have a Retina Z3 or plan to get one before you next recompile the kernel.
 
 Amiga CLgen driver (EXPERIMENTAL)
 CONFIG_FB_CLGEN
-  This enables support for Cirrus Logic GD542x/543x based boards on
-  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
-  Say N unless you have such a graphics board or plan to get one
-  before you next recompile the kernel.
+  This enables support for Cirrus Logic GD542x/543x based boards on Amiga:
+  SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.  Say N
+  unless you have such a graphics board or plan to get one before you next
+  recompile the kernel.
 
 Atari native chipset support
 CONFIG_FB_ATARI
@@ -1641,17 +1641,15 @@ CONFIG_FB_TGA
 
 VESA VGA graphics console
 CONFIG_FB_VESA
-  This is the frame buffer device driver for generic VESA graphic
-  cards. You will get a boot time penguin logo at no additional cost.
-  Please read Documentation/fb/vesafb.txt. If unsure, say Y.
+  This is the frame buffer device driver for generic VESA graphic cards.
+  Please read Documentation/fb/vesafb.txt.
 
 MDA text console (dual-headed)
 CONFIG_MDA_CONSOLE
   Say Y here if you have an old MDA or monochrome Hercules graphics
-  adapter in your system acting as a second head ( = video card). You
-  will then be able to use two monitors with your Linux system. Do not
-  say Y here if your MDA card is the primary card in your system; the
-  normal VGA driver will handle it.
+  adapter in your system acting as a second head ( = video card).  Do 
+  not enable this driver if your MDA card is the primary card in your
+  system; the normal VGA driver will handle it.
   
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -1688,14 +1686,13 @@ CONFIG_FB_TCX
 
 Virtual Frame Buffer support (ONLY FOR TESTING!)
 CONFIG_FB_VIRTUAL
-  This is a `virtual' frame buffer device. It operates on a chunk of
-  unswapable kernel memory instead of on the memory of a graphics
-  board. This means you cannot see any output sent to this frame
-  buffer device, while it does consume precious memory. The main use
-  of this frame buffer device is testing and debugging the frame
-  buffer subsystem. Do NOT enable it for normal systems! To protect
-  the innocent, it has to be enabled explicitly at boot time using the
-  kernel option `video=vfb:'.
+  This is a `virtual' frame buffer device.  It operates on a chunk of
+  unswapable kernel memory instead of on the memory of a graphics board.
+  This means you cannot see any output sent to this frame buffer device,
+  while it does consume precious memory.  The main use of this frame
+  buffer device is testing and debugging the frame buffer subsystem. Do
+  NOT enable it for normal systems! To protect the innocent, it has to
+  be enabled explicitly on boot time using the kernel option `video=vfb:'.
 
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -1712,12 +1709,12 @@ CONFIG_FBCON_ADVANCED
   drivers. Note that they are used for text console output only; they are
   NOT needed for graphical applications.
 
-  If you say N here, the needed low level drivers are automatically
-  enabled, depending on what frame buffer devices you selected above.
-  This is recommended for most users.
+  If you do not enable this option, the needed low level drivers are
+  automatically enabled, depending on what frame buffer devices you
+  selected. This is recommended for most users.
 
-  If you say Y here, you have more fine-grained control over which low
-  level drivers are enabled. You can e.g. leave out low level drivers
+  If you enable this option, you have more fine-grained control over which
+  low level drivers are enabled. You can e.g. leave out low level drivers
   for color depths you do not intend to use for text consoles.
 
   Low level frame buffer console drivers can be modules ( = code which
@@ -1791,13 +1788,13 @@ CONFIG_FBCON_IPLAN2P8
 Mac variable bpp packed pixels support
 CONFIG_FBCON_MAC
   This is the low level frame buffer console driver for 1/2/4/8/16/32
-  bits per pixel packed pixels on Mac. It supports variable font widths
+  bits per pixel packed pixels on Mac. It supports variable fontwidths
   for low resolution screens.
   
 VGA characters/attributes support
 CONFIG_FBCON_VGA
-  This is the low level frame buffer console driver for VGA text mode;
-  it is used if you said Y to "VGA chipset support (text only)" above.
+  This is the low level frame buffer console driver for VGA text mode, as
+  used by vgafb.
 
 Parallel-port support
 CONFIG_PARPORT
@@ -2250,6 +2247,9 @@ CONFIG_IP_MASQUERADE_IPAUTOFW
   via FTP (user: anonymous) from
   ftp://ftp.netis.com/pub/members/rlynch/
 
+  For 2.1 kernels, you will need "ipmasqadm" tool from
+  http://juanjox.home.ml.org
+
   The ipautofw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
 
@@ -2258,6 +2258,22 @@ CONFIG_IP_MASQUERADE_IPAUTOFW
   The module will be called ip_masq_autofw.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+IP: masquerading special modules support
+CONFIG_IP_MASQUERADE_MOD
+  This provides support for special modules that can modify rewriting
+  rules to achieve, for example, input port forwarding.
+  Beware that this feature adds a little overhead in the input packet
+  processing chain.
+
+  You will need user space program "ipmasqadm" to use these
+  additional modules, you can download it from 
+  http://juanjox.home.ml.org/
+
+  All this additional code is still under development and so is currently
+  marked EXPERIMENTAL. 
+  
+  If you want to try, for example, PORT FORWARDING, say Y.
+
 IP: ipportfw masquerade support
 CONFIG_IP_MASQUERADE_IPPORTFW
   Port Forwarding is an addition to IP Masquerading written by Steven
@@ -2275,7 +2291,10 @@ CONFIG_IP_MASQUERADE_IPPORTFW
   http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to
   browse the WWW, you need to have access to a machine on the Internet
   that has a program like lynx or netscape). You will need the user
-  space program ipportfw which can be downloaded from
+  space program "ipmasqadm" which can be downloaded from
+  http://juanjox.home.ml.org/
+
+  For general info, please see
   ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/
 
   The portfw code is still under development and so is currently
@@ -2286,6 +2305,20 @@ CONFIG_IP_MASQUERADE_IPPORTFW
   The module will be called ip_masq_portfw.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+IP: ipmarkfw masquerade support
+CONFIG_IP_MASQUERADE_IPMARKFW
+  This provides functionally equivalent to port forwarding, the difference
+  is that Mark Forwarding uses "firewalling mark" to select which packets
+  must forward (see ipchains(8), "-m" argument).
+
+  The markfw code is still under development and so is currently
+  marked EXPERIMENTAL. If you want to try it, say Y.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called ip_masq_markfw.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt.
+
 IP: always defragment 
 CONFIG_IP_ALWAYS_DEFRAG
   This option means that all incoming fragments (= parts of IP packets
@@ -8955,6 +8988,15 @@ CONFIG_AMIFB_AGA
   and CD32.  If you intend to run Linux on any of these systems, say Y;
   otherwise say N.
 
+Amiga Cybervision support
+CONFIG_FB_CYBER
+  This enables support for the Cybervision 64 graphics card from Phase5.
+  Please note that its use is not all that intuitive (i.e. if you have
+  any questions, be sure to ask!).  Say N unless you have a Cybervision
+  64 or plan to get one before you next recompile the kernel.
+  Please note that this driver DOES NOT support the Cybervision 64 3D
+  card at present, as they use incompatible video chips.
+
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
   Include support for Amiga graphics cards that use the Texas
index e6f52393d346663e2efe4485e678fad36f0dfb56..0cbd5d1b1ae3f78b9b102a9897eea5c7349fcafa 100644 (file)
@@ -79,17 +79,20 @@ You can pass kernel command line options to vesafb with
 by comma.  Accepted options:
 
 invers - no comment...
-redraw - scroll by redrawing the affected part of the screen
+
+redraw - scroll by redrawing the affected part of the screen.
+         This is the default.
 ypan    - enable display panning using the VESA protected mode
          interface.  This enables the Shift-PgUp scrollback 
          thing and greatly speeds up fullscreen scrolling.
          It is slower than "redraw" when scrolling only a halve
-         screen.  This is the default.
+         screen.  Seems not to work with some BIOSes.
 ywrap  - If your gfx board supports wrap-around, use this one
          instead of ypan. 
-nopal  - Don't use the protected mode interface for palette
-         changes.  vesafb will try the standard vga registers
-         instead.
+
+vgapal - Use the standard vga registers for palette changes.
+         This is the default.
+pmipal - Use the protected mode interface for palette changes.
 
 
 Have fun!
diff --git a/Documentation/networking/ip_masq/ip_masq-API-ex.c b/Documentation/networking/ip_masq/ip_masq-API-ex.c
new file mode 100644 (file)
index 0000000..4b6999d
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+   There is only 1 optname (see setsockopt(2)), IP_FW_MASQ_CTL that
+   must be used.
+   Funcionality depends on your kernel CONFIG options, here is
+   an example you can use to create an ``incoming'' tunnel:
+
+   See "user.c" module under ipmasqadm tree for a generic example
+ */
+#undef __KERNEL__      /* Makefile lazyness ;) */
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+
+#include <asm/types.h>          /* For __uXX types */
+#include <net/if.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <linux/ip_fw.h>        /* For IP_FW_MASQ_CTL */
+#include <linux/ip_masq.h>      /* For specific masq defs */
+
+
+int create_listening_masq(struct ip_masq_ctl *masq, int proto, u_int32_t src_addr, u_int16_t src_port, u_int32_t dst_addr)
+{
+       int sockfd;
+
+       sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+
+       if (sockfd<0) {
+               perror("socket(RAW)");
+               return -1;
+       }
+
+       memset (masq, 0, sizeof (*masq));
+
+       /*
+        *      Want user tunnel control
+        */
+       masq->m_target = IP_MASQ_TARGET_USER;
+
+       /*
+        *      Want to insert new
+        */
+       masq->m_cmd    = IP_MASQ_CMD_INSERT;
+
+       masq->u.user.protocol   = proto;
+       masq->u.user.saddr      = src_addr;
+       masq->u.user.sport      = src_port;
+       masq->u.user.rt_daddr   = inet_addr("192.168.21.239"); 
+
+       if (setsockopt(sockfd, IPPROTO_IP, 
+                               IP_FW_MASQ_CTL, (char *)masq, sizeof(*masq)))    {
+               perror("setsockopt()");
+               return -1;
+       }
+       /* masq struct now contains tunnel details */
+       fprintf(stderr, "PROTO=%d SRC=0x%X:%x - MASQ=0x%X:%x - DST=0x%X:%x\n",
+                       masq->u.user.protocol,
+                       ntohl(masq->u.user.saddr), ntohs(masq->u.user.sport),
+                       ntohl(masq->u.user.maddr), ntohs(masq->u.user.mport),
+                       ntohl(masq->u.user.daddr), ntohs(masq->u.user.dport));
+       return 0;
+}
+
+int main(void) {
+       struct ip_masq_ctl masq_buf;
+
+       return create_listening_masq(&masq_buf,
+                       IPPROTO_TCP, 
+                       inet_addr("192.168.1.4"), 
+                       htons(23),
+                       inet_addr("192.168.21.3"));
+}
+
index a038be2dcfcd436afe46977aa4e4265bb829e62f..b913717e99de02cf5671587e6337a3a671fc4490 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -316,10 +316,11 @@ modules_install:
        if [ -f VIDEO_MODULES ]; then inst_mod VIDEO_MODULES video; fi; \
        if [ -f FC4_MODULES   ]; then inst_mod FC4_MODULES   fc4;   fi; \
        \
-       ls *.o > .allmods; \
-       echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \
-       if [ -s .misc ]; then inst_mod .misc misc; fi; \
-       rm -f .misc .allmods; \
+       rm -f /tmp/.misc.$$$$ /tmp/.allmods.$$$$; \
+       ls *.o > /tmp/.allmods.$$$$; \
+       echo $$MODULES | tr ' ' '\n' | sort | comm -23 /tmp/.allmods.$$$$ - > /tmp/.misc.$$$$; \
+       if [ -s /tmp/.misc.$$$$ ]; then inst_mod /tmp/.misc.$$$$ misc; fi; \
+       rm -f /tmp/.misc.$$$$ /tmp/.allmods.$$$$; \
        )
 
 # modules disabled....
index b82052b8b478068e1defc0a698c5053449616e91..54448e7a3068ce732782cfafda19ba94316d176c 100644 (file)
@@ -135,8 +135,9 @@ if [ "$CONFIG_VT" = "y" ]; then
   mainmenu_option next_comment
   comment 'Console drivers'
   bool 'VGA text console' CONFIG_VGA_CONSOLE
+  bool 'Video mode selection support' CONFIG_VIDEO_SELECT
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool 'Video mode selection support' CONFIG_VIDEO_SELECT
+    tristate 'MDA text console (dual-headed) (EXPERIMENTAL)' CONFIG_MDA_CONSOLE
     bool 'Support for frame buffer devices (EXPERIMENTAL)' CONFIG_FB
   fi
   source drivers/video/Config.in
index 7996c7af7f1b13fb33c8ff4a88f471640ed726e1..1599052ed13f205dc129f2cdd44d87f1f95d897e 100644 (file)
@@ -288,6 +288,7 @@ CONFIG_DEVPTS_FS=y
 # Console drivers
 #
 CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
 
 #
 # Sound
index 373f0770d4a2fff5b56eff433d05bb12e2342130..1bf34e389c8378bac57078970b06f3967270955d 100644 (file)
@@ -290,10 +290,23 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
        return -1;
 }
 
+/*
+ * Unclear documentation on what a "conforming ISA interrupt" means.
+ *
+ * Should we, or should we not, take the ELCR register into account?
+ * It's part of the EISA specification, but maybe it should only be
+ * used if the interrupt is actually marked as EISA?
+ *
+ * Oh, well. Don't do it until somebody tells us what the right thing
+ * to do is..
+ */
+#undef USE_ELCR_TRIGGER_LEVEL
+#ifdef USE_ELCR_TRIGGER_LEVEL
+
 /*
  * ISA Edge/Level control register, ELCR
  */
-static int __init ISA_ELCR(unsigned int irq)
+static int __init EISA_ELCR(unsigned int irq)
 {
        if (irq < 16) {
                unsigned int port = 0x4d0 + (irq >> 3);
@@ -303,41 +316,15 @@ static int __init ISA_ELCR(unsigned int irq)
        return 0;
 }      
 
-/*
- * ISA interrupts can be:
- *  - level triggered, active low (ELCR = 1)
- *  - edge triggered, active high (ELCR = 0)
- *  - edge triggered, active low (magic irq 8)
- */
-static int __init default_ISA_trigger(int idx)
-{
-       unsigned int irq = mp_irqs[idx].mpc_dstirq;
+#define default_ISA_trigger(idx)       (EISA_ELCR(mp_irqs[idx].mpc_dstirq))
+#define default_ISA_polarity(idx)      (0)
 
-       if (irq == 8)
-               return 0;
-       return ISA_ELCR(irq);
-}
+#else
 
-static int __init default_ISA_polarity(int idx)
-{
-#if 0
-       unsigned int irq = mp_irqs[idx].mpc_dstirq;
+#define default_ISA_trigger(idx)       (0)
+#define default_ISA_polarity(idx)      (0)
 
-       if (irq == 8)
-               return 1;
-       return ISA_ELCR(irq);
-#else
-       return 0;
 #endif
-}
-
-/*
- * There are broken mptables which register ISA+high-active+level IRQs,
- * these are illegal and are converted here to ISA+high-active+edge
- * IRQ sources. Careful, ISA+low-active+level is another broken entry
- * type, it represents PCI IRQs 'embedded into an ISA bus', they have
- * to be accepted. Yes, ugh.
- */
 
 static int __init MPBIOS_polarity(int idx)
 {
@@ -457,37 +444,14 @@ static int __init MPBIOS_trigger(int idx)
        return trigger;
 }
 
-static int __init trigger_flag_broken(int idx)
-{
-#if 0
-       int bus = mp_irqs[idx].mpc_srcbus;
-       int polarity = MPBIOS_polarity(idx);
-       int trigger = MPBIOS_trigger(idx);
-
-       if ( (mp_bus_id_to_type[bus] == MP_BUS_ISA) &&
-               (polarity == 0) /* active-high */ &&
-               (trigger == 1) /* level */ )
-
-               return 1; /* broken */
-#endif
-       return 0;
-}
-
 static inline int irq_polarity(int idx)
 {
-       /*
-        * There are no known BIOS bugs wrt polarity.                yet.
-        */
        return MPBIOS_polarity(idx);
 }
 
 static inline int irq_trigger(int idx)
 {
-       int trigger = MPBIOS_trigger(idx);
-
-       if (trigger_flag_broken(idx))
-               trigger = 0;
-       return trigger;
+       return MPBIOS_trigger(idx);
 }
 
 static int __init pin_2_irq(int idx, int pin)
@@ -622,9 +586,6 @@ void __init setup_IO_APIC_irqs(void)
 
                bus = mp_irqs[idx].mpc_srcbus;
 
-               if (trigger_flag_broken (idx))
-                       printk("broken BIOS, changing pin %d to edge\n", pin);
-
                io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
                io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
        }
index ca9a34bdd0df16afe13befc288244160739fcaf4..0bbbfa8738c1a7598b6e802ccf5aede6dc0685d7 100644 (file)
@@ -736,6 +736,7 @@ int __init start_secondary(void *unused)
        /*  Must be done before calibration delay is computed  */
        mtrr_init_secondary_cpu ();
 #endif
+       stts();
        smp_callin();
        while (!smp_commenced)
                barrier();
@@ -1751,8 +1752,8 @@ void __init setup_APIC_clock(void)
 
        static volatile int calibration_lock;
 
-       save_flags(flags);
-       cli();
+       __save_flags(flags);
+       __cli();
 
        SMP_PRINTK(("setup_APIC_clock() called.\n"));
 
@@ -1790,8 +1791,7 @@ void __init setup_APIC_clock(void)
 
        ack_APIC_irq ();
 
-
-       restore_flags(flags);
+       __restore_flags(flags);
 }
 
 /*
index ae2114f7ac68a7d12779bf552b160720bde63c00..01bd41ce4dedd8fe34cfc74f33f18d4d2fcf67bb 100644 (file)
@@ -191,7 +191,7 @@ void die(const char * str, struct pt_regs * regs, long err)
        do_exit(SIGSEGV);
 }
 
-static void die_if_kernel(const char * str, struct pt_regs * regs, long err)
+static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
 {
        if (!(regs->eflags & VM_MASK) && !(3 & regs->xcs))
                die(str, regs, err);
@@ -427,7 +427,7 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
  * Careful.. There are problems with IBM-designed IRQ13 behaviour.
  * Don't touch unless you *really* know how it works.
  */
-asmlinkage void math_state_restore(void)
+asmlinkage void math_state_restore(struct pt_regs regs)
 {
        __asm__ __volatile__("clts");           /* Allow maths ops (or we recurse) */
        if(current->used_math)
index 5a7705af6dfc0e839d7e98d7fd44553e21ca93fb..b1ea955ed4467e61362c575b3312d0cfc2b47608 100644 (file)
@@ -21,6 +21,7 @@
  * applications that require more DP ram, we can expand the boundaries
  * but then we have to be careful of any downloaded microcode.
  */
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index b8840377124246461c2006490be28e6042788957..ad75383d20714dc9a794154b4247a206845ea303 100644 (file)
@@ -25,6 +25,7 @@
  *           /Roman Zippel
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 3df64854647adb639ba6cc3709429f0b7a60781c..b14a59b53e9a1b3379ba52672acc564f8a97724b 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
index faa006815e352d11d13c21bf4e3337be92da091b..e5566dc3225e4d7dd9550f7eb1295e01a9c8fdd5 100644 (file)
@@ -12,6 +12,7 @@
  * I f**ked around for a day trying to figure out how to make EPPC-Bug
  * use SMC1, but gave up and decided to fix it here.
  */
+#include <linux/config.h>
 #include <linux/types.h>
 #ifdef CONFIG_MBX
 #include <asm/mbx.h>
index 08787b33618b7a32d96ae6c334fd808f87080a16..52db9debccb025c8be30899d1246daa23ce20436 100644 (file)
@@ -18,7 +18,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/string.h>
 #include <asm/residual.h>
 #include <asm/pnp.h>
index fa171a7f774361988785bf185e317be1e9dcbe09..45bec8353f9a545a2a5eb67067d03ddb2ab06615 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.36 1998/06/02 00:36:40 davem Exp $
+# $Id: Makefile,v 1.39 1998/09/16 12:31:31 jj Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -15,26 +15,35 @@ SHELL  =/bin/bash
 # Uncomment the first CFLAGS if you are doing kgdb source level
 # debugging of the kernel to get the proper debugging information.
 
+IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+
+ifeq ($(NEW_GAS),y)
+AS              := $(AS) -32
+LD              := $(LD) -m elf32_sparc
+endif
+
 #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
+ifneq ($(IS_EGCS),y)
 CFLAGS := $(CFLAGS) -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+else
+CFLAGS := $(CFLAGS) -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
+endif
 
 #LINKFLAGS = -N -Ttext 0xf0004000
 LINKFLAGS = -T arch/sparc/vmlinux.lds
 
 HEAD := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
 
-# Note arch/sparc/mm has to be the last subdir
 SUBDIRS := $(SUBDIRS) arch/sparc/kernel arch/sparc/lib arch/sparc/prom \
-       arch/sparc/mm
+       arch/sparc/mm arch/sparc/math-emu
 
-CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES)
+CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \
+       arch/sparc/math-emu/math-emu.o
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
        $(TOPDIR)/arch/sparc/lib/lib.a
 
-SUBDIRS += arch/sparc/math-emu
-CORE_FILES += arch/sparc/math-emu/math-emu.o
-
 ifdef CONFIG_AP1000
 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000 mpp
 CORE_FILES := $(TOPDIR)/arch/sparc/ap1000/ap1000lib.o \
@@ -43,8 +52,14 @@ DRIVERS := $(DRIVERS) drivers/ap1000/ap1000.a
 CFLAGS := $(CFLAGS) -D__MPP__=1
 endif
 
+# This one has to come last
+SUBDIRS += arch/sparc/boot
+CORE_FILES_NO_BTFIX := $(CORE_FILES)
+CORE_FILES += arch/sparc/boot/btfix.o
+
 archclean:
-       -$(MAKE) -C arch/sparc/boot archclean
+       rm -f $(TOPDIR)/vmlinux.aout
+       -$(MAKE) -C arch/sparc/boot clean
 
 archmrproper:
        -$(MAKE) -C arch/sparc/math-emu cleansymlinks
@@ -57,19 +72,3 @@ check_asm:
 
 tftpboot.img:
        $(MAKE) -C arch/sparc/boot tftpboot.img
-
-vmlinux.o: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
-       $(LD) -r $(VMLINUX.OBJS) -o vmlinux.o
-
-arch/sparc/boot/btfix.s: arch/sparc/boot/btfixupprep vmlinux.o
-       $(OBJDUMP) -x vmlinux.o | arch/sparc/boot/btfixupprep > arch/sparc/boot/btfix.s
-
-arch/sparc/boot/btfix.o: arch/sparc/boot/btfix.s
-       $(CC) -c -o arch/sparc/boot/btfix.o arch/sparc/boot/btfix.s
-
-arch/sparc/boot/btfixupprep: arch/sparc/boot/btfixupprep.c
-       $(MAKE) -C arch/sparc/boot btfixupprep
-
-vmlinux: arch/sparc/boot/btfix.o
-       $(LD) $(LINKFLAGS) vmlinux.o arch/sparc/boot/btfix.o -o vmlinux
-       $(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
index c9301a79e4d4a94bc0161f5e1c9e3de813589b6d..3aec7808377a895a912ad1661d10b88f2694e17a 100644 (file)
@@ -1,16 +1,13 @@
-# $Id: Makefile,v 1.6 1998/02/23 01:44:39 rth Exp $
+# $Id: Makefile,v 1.8 1998/09/16 12:24:51 jj Exp $
 # Makefile for the Sparc boot stuff.
 #
 # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
-# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+# Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
 
 ROOT_IMG       =/usr/src/root.img
 ELFTOAOUT      =elftoaout
 
-all: boot
-
-boot:
-       @echo "Nothing special to be done for 'boot' on Linux/SPARC."
+all: btfix.o
 
 tftpboot.img: piggyback
        $(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img
@@ -22,8 +19,20 @@ piggyback: piggyback.c
 btfixupprep: btfixupprep.c
        $(HOSTCC) $(HOSTCFLAGS) -o btfixupprep btfixupprep.c
 
-archclean:
-       rm -f btfixupprep piggyback tftpboot.img
+clean:
+       rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s
+
+BTOBJS := $(HEAD) init/main.o init/version.o \
+       $(CORE_FILES_NO_BTFIX) $(FILESYSTEMS) \
+       $(NETWORKS) $(DRIVERS)
+
+vmlinux.o: dummy
+       $(LD) -r $(patsubst %,$(TOPDIR)/%,$(BTOBJS)) $(LIBS) -o vmlinux.o
+
+btfix.s: btfixupprep vmlinux.o
+       $(OBJDUMP) -x vmlinux.o | ./btfixupprep > btfix.s
 
-dep:
+btfix.o: btfix.s
+       $(CC) -c -o btfix.o btfix.s
 
+include $(TOPDIR)/Rules.make
index 1bef965afa971f58ee2e336a4eba7812a0714290..af0a1dc4e7e4270b153a7d617415a3fabfe2f3b9 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: btfixupprep.c,v 1.3 1998/03/09 14:03:10 jj Exp $
+/* $Id: btfixupprep.c,v 1.5 1998/09/16 12:24:55 jj Exp $
    Simple utility to prepare vmlinux image for sparc.
    Resolves all BTFIXUP uses and settings and creates
    a special .s object to link to the image.
 
 #define MAXSYMS 1024
 
+static char *symtab = "SYMBOL TABLE:";
 static char *relrec = "RELOCATION RECORDS FOR [";
 static int rellen;
+static int symlen;
+int mode;
 
 struct _btfixup;
 
@@ -97,6 +100,20 @@ int main(int argc,char **argv)
        unsigned long offset;
        char *initvalstr;
 
+       symlen = strlen(symtab);
+       while (fgets (buffer, 1024, stdin) != NULL)
+               if (!strncmp (buffer, symtab, symlen))
+                       goto main0;
+       fatal();
+main0:
+       if (fgets (buffer, 1024, stdin) == NULL || buffer[0] < '0' || buffer[0] > '9')
+               fatal();
+       for (mode = 0;; mode++)
+               if (buffer[mode] < '0' || buffer[mode] > '9')
+                       break;
+       if (mode != 8 && mode != 16)
+               fatal();
+       
        rellen = strlen(relrec);
        while (fgets (buffer, 1024, stdin) != NULL)
                if (!strncmp (buffer, relrec, rellen))
@@ -112,17 +129,19 @@ main1:
        if (fgets (buffer, 1024, stdin) == NULL)
                fatal();
        while (fgets (buffer, 1024, stdin) != NULL) {
+               int nbase;
                if (!strncmp (buffer, relrec, rellen))
                        goto main1;
                p = strchr (buffer, '\n');
                if (p) *p = 0;
-               if (strlen (buffer) < 30)
+               if (strlen (buffer) < 22+mode)
                        continue;
-               if (strncmp (buffer + 8, " R_SPARC_", 9))
+               if (strncmp (buffer + mode, " R_SPARC_", 9))
                        continue;
-               if (buffer[27] != '_' || buffer[28] != '_' || buffer[29] != '_')
+               nbase = 27 - 8 + mode;
+               if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_')
                        continue;
-               switch (buffer[30]) {
+               switch (buffer[nbase+3]) {
                        case 'f':       /* CALL */
                        case 'b':       /* BLACKBOX */
                        case 's':       /* SIMM13 */
@@ -133,26 +152,26 @@ main1:
                        default:
                                continue;
                }
-               p = strchr (buffer + 32, '+');
+               p = strchr (buffer + nbase+5, '+');
                if (p) *p = 0;
-               shift = 32;
-               if (buffer[31] == 's' && buffer[32] == '_') {
-                       shift = 33;
+               shift = nbase + 5;
+               if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') {
+                       shift = nbase + 6;
                        if (strcmp (sect, ".text.init")) {
                                fprintf(stderr, "Wrong use of '%s' BTFIXUPSET.\nBTFIXUPSET_CALL can be used only in __init sections\n", buffer+shift);
                                exit(1);
                        }
-               } else if (buffer[31] != '_')
+               } else if (buffer[nbase+4] != '_')
                        continue;
-               if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && (strcmp (sect, "__ksymtab") || buffer[30] != 'f')) {
-                       if (buffer[30] == 'f')
-                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init and __ksymtab\n", buffer + shift, sect);
+               if (strcmp (sect, ".text") && strcmp (sect, ".text.init") && strcmp (sect, ".fixup") && (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) {
+                       if (buffer[nbase+3] == 'f')
+                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .text.init, .fixup and __ksymtab\n", buffer + shift, sect);
                        else
-                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text and .text.init\n", buffer + shift, sect);
+                               fprintf(stderr, "Wrong use of '%s' in '%s' section. It can be only used in .text, .fixup and .text.init\n", buffer + shift, sect);
                        exit(1);
                }
                p = strstr (buffer + shift, "__btset_");
-               if (p && buffer[31] == 's') {
+               if (p && buffer[nbase+4] == 's') {
                        fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer);
                        exit(1);
                }
@@ -171,23 +190,23 @@ main1:
                        initvalstr = p + 10;
                        *p = 0;
                }
-               f = find(buffer[30], buffer + shift);
-               if (buffer[31] == 's')
+               f = find(buffer[nbase+3], buffer + shift);
+               if (buffer[nbase+4] == 's')
                        continue;
-               switch (buffer[30]) {
+               switch (buffer[nbase+3]) {
                case 'f':
                        if (initval) {
                                fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer);
                                exit(1);
                        }
                        if (!strcmp (sect, "__ksymtab")) {
-                               if (strncmp (buffer + 17, "32        ", 10)) {
+                               if (strncmp (buffer + mode+9, "32        ", 10)) {
                                        fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer);
                                        exit(1);
                                }
-                       } else if (strncmp (buffer + 17, "WDISP30   ", 10) &&
-                                  strncmp (buffer + 17, "HI22      ", 10) &&
-                                  strncmp (buffer + 17, "LO10      ", 10)) {
+                       } else if (strncmp (buffer + mode+9, "WDISP30   ", 10) &&
+                                  strncmp (buffer + mode+9, "HI22      ", 10) &&
+                                  strncmp (buffer + mode+9, "LO10      ", 10)) {
                                fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer);
                                exit(1);
                        }
@@ -197,7 +216,7 @@ main1:
                                fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer);
                                exit(1);
                        }
-                       if (strncmp (buffer + 17, "HI22      ", 10)) {
+                       if (strncmp (buffer + mode+9, "HI22      ", 10)) {
                                fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer);
                                exit(1);
                        }
@@ -207,7 +226,7 @@ main1:
                                fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer);
                                exit(1);
                        }
-                       if (strncmp (buffer + 17, "13        ", 10)) {
+                       if (strncmp (buffer + mode+9, "13        ", 10)) {
                                fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer);
                                exit(1);
                        }
@@ -217,7 +236,7 @@ main1:
                                fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer);
                                exit(1);
                        }
-                       if (strncmp (buffer + 17, "13        ", 10)) {
+                       if (strncmp (buffer + mode+9, "13        ", 10)) {
                                fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer);
                                exit(1);
                        }
@@ -227,7 +246,7 @@ main1:
                                fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer);
                                exit(1);
                        }
-                       if (strncmp (buffer + 17, "HI22      ", 10)) {
+                       if (strncmp (buffer + mode+9, "HI22      ", 10)) {
                                fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer);
                                exit(1);
                        }
@@ -237,7 +256,7 @@ main1:
                                fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer);
                                exit(1);
                        }
-                       if (strncmp (buffer + 17, "HI22      ", 10) && strncmp (buffer + 17, "LO10      ", 10)) {
+                       if (strncmp (buffer + mode+9, "HI22      ", 10) && strncmp (buffer + mode+9, "LO10      ", 10)) {
                                fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer);
                                exit(1);
                        }
@@ -261,7 +280,7 @@ main1:
                        exit(1);
                }
                offset = strtoul(buffer, &q, 16);
-               if (q != buffer + 8 || (!offset && strncmp (buffer, "00000000 ", 9))) {
+               if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) {
                        fprintf(stderr, "Malformed relocation address in\n%s\n", buffer);
                        exit(1);
                }
@@ -274,7 +293,7 @@ main1:
                if (!*rr) fatal();
                (*rr)->offset = offset;
                (*rr)->f = NULL;
-               if (buffer[30] == 'f') {
+               if (buffer[nbase+3] == 'f') {
                        lastf = f;
                        lastfoffset = offset;
                        lastfrelno = k;
@@ -302,11 +321,13 @@ main1:
                        printf("0\n");
                for (r = f->rel, j--; r != NULL; j--, r = r->next) {
                        if (!strcmp (r->sect, ".text"))
-                               printf ("_stext+0x%08x", r->offset);
+                               printf ("_stext+0x%08lx", r->offset);
                        else if (!strcmp (r->sect, ".text.init"))
-                               printf ("__init_begin+0x%08x", r->offset);
+                               printf ("__init_begin+0x%08lx", r->offset);
                        else if (!strcmp (r->sect, "__ksymtab"))
-                               printf ("__start___ksymtab+0x%08x", r->offset);
+                               printf ("__start___ksymtab+0x%08lx", r->offset);
+                       else if (!strcmp (r->sect, ".fixup"))
+                               printf ("__start___fixup+0x%08lx", r->offset);
                        else
                                fatal();
                        if (f->type == 'f' || !r->f)
index e3aaea31c16888b0db5f72af7a27033b2d1885d9..97c9704815bd21683c1d71934bfb03de6334333d 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.58 1998/07/29 05:06:41 davem Exp $
+# $Id: config.in,v 1.63 1998/09/21 05:05:56 jj Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -35,6 +35,9 @@ if [ "$CONFIG_AP1000" = "y" ]; then
        tristate 'OPIU DDV Driver' CONFIG_DDV
 else
        bool 'Support for SUN4 machines (disables SUN4[CDM] support)' CONFIG_SUN4
+       if [ "$CONFIG_SUN4" != "y" ]; then
+               bool 'Support for PCI and PS/2 keyboard/mouse' CONFIG_PCI
+       fi
 
        mainmenu_option next_comment
        comment 'Console drivers'
@@ -54,9 +57,7 @@ else
        define_bool CONFIG_SUN_CONSOLE y
        define_bool CONFIG_SUN_AUXIO y
        define_bool CONFIG_SUN_IO y
-       if [ "$CONFIG_SUN4" = "y" ]; then
-               bool 'Force early PROM Console' CONFIG_SUN4_FORCECONSOLE
-       else
+       if [ "$CONFIG_SUN4" != "y" ]; then
                source drivers/sbus/char/Config.in
                source drivers/sbus/audio/Config.in
        fi
index 52801ae6827fff67b7c10ea8f468a1e7716f9949..6c89f74c7ba262a061cd213bee350781b22b1612 100644 (file)
@@ -120,8 +120,7 @@ CONFIG_IP_MASQUERADE=y
 #
 # Protocol-specific masquerading support will be built as modules.
 #
-# CONFIG_IP_MASQUERADE_IPAUTOFW is not set
-# CONFIG_IP_MASQUERADE_IPPORTFW is not set
+# CONFIG_IP_MASQUERADE_MOD is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
@@ -136,7 +135,7 @@ CONFIG_IP_ALIAS=y
 CONFIG_INET_RARP=m
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
-CONFIG_IPV6=m
+CONFIG_IPV6=y
 # CONFIG_IPV6_EUI64 is not set
 
 #
@@ -273,7 +272,8 @@ CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_ADFS_FS is not set
-CONFIG_DEVPTS_FS=y
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
index 9606064b3a3a723abdf75b1643629c3674aa435a..18e487d866abd53b73e7825680cda5fee47bef82 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.45 1998/07/28 16:52:42 jj Exp $
+# $Id: Makefile,v 1.48 1998/09/21 05:04:46 jj Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -22,7 +22,7 @@ O_OBJS   := entry.o wof.o wuf.o etrap.o rtrap.o traps.o ${IRQ_OBJS} \
            sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
            sunos_ioctl.o time.o windows.o cpu.o devices.o \
            sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \
-           unaligned.o muldiv.o
+           unaligned.o muldiv.o pcic.o
 
 OX_OBJS  := sparc_ksyms.o
 
@@ -38,6 +38,10 @@ ifdef CONFIG_SUN_AUXIO
 O_OBJS += auxio.o
 endif
 
+ifdef CONFIG_PCI
+O_OBJS += ebus.o
+endif
+
 head.o: head.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
 
index 13d34310f8c36af2dc35efeea5aad7a222c3fdf9..a5e24ac520a77db982c3429ca138591d3c9328e3 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/stddef.h>
 #include <linux/init.h>
+#include <linux/config.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
@@ -32,6 +33,11 @@ __initfunc(void auxio_probe(void))
                node = prom_getchild(node);
                auxio_nd = prom_searchsiblings(node, "auxio");
                if(!auxio_nd) {
+#ifdef CONFIG_PCI
+                       /* There may be auxio on Ebus */
+                       auxio_register = 0;
+                       return;
+#else
                        if(prom_searchsiblings(node, "leds")) {
                                /* VME chassis sun4m machine, no auxio exists. */
                                auxio_register = 0;
@@ -39,6 +45,7 @@ __initfunc(void auxio_probe(void))
                        }
                        prom_printf("Cannot find auxio node, cannot continue...\n");
                        prom_halt();
+#endif
                }
        }
        prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
new file mode 100644 (file)
index 0000000..9ad5498
--- /dev/null
@@ -0,0 +1,328 @@
+/* $Id: ebus.c,v 1.1 1998/09/18 10:43:43 jj Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * Adopted for sparc by V. Roganov and G. Raiko.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+#undef PROM_DEBUG
+#undef DEBUG_FILL_EBUS_DEV
+
+#ifdef PROM_DEBUG
+#define dprintf prom_printf
+#else
+#define dprintf printk
+#endif
+
+struct linux_ebus *ebus_chain = 0;
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+#ifdef CONFIG_OBP_FLASH
+extern int flash_init(void);
+#endif
+#ifdef CONFIG_ENVCTRL
+extern int envctrl_init(void);
+#endif
+
+static inline unsigned long ebus_alloc(size_t size)
+{
+       return (unsigned long)kmalloc(size, GFP_ATOMIC);
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg,
+                               struct linux_ebus_child *dev))
+{
+       int regs[PROMREG_MAX];
+       int irqs[PROMREG_MAX];
+       char lbuf[128];
+       int i, len;
+
+       dev->prom_node = node;
+       prom_getstring(node, "name", lbuf, sizeof(lbuf));
+       strcpy(dev->prom_name, lbuf);
+
+       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+       dev->num_addrs = len / sizeof(regs[0]);
+
+       for (i = 0; i < dev->num_addrs; i++) {
+               if (regs[i] >= dev->parent->num_addrs) {
+                       prom_printf("UGH: property for %s was %d, need < %d\n",
+                                   dev->prom_name, len, dev->parent->num_addrs);
+                       panic(__FUNCTION__);
+               }
+               dev->base_address[i] = dev->parent->base_address[regs[i]];
+       }
+
+       len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+       if ((len == -1) || (len == 0)) {
+               dev->num_irqs = 0;
+               /*
+                * Oh, well, some PROMs don't export interrupts
+                * property to children of EBus devices...
+                *
+                * Be smart about PS/2 keyboard and mouse.
+                */
+               if (!strcmp(dev->parent->prom_name, "8042")) {
+                       dev->num_irqs = 1;
+                       dev->irqs[0] = dev->parent->irqs[0];
+               }
+       } else {
+               dev->num_irqs = len / sizeof(irqs[0]);
+               printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+       }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+       dprintk("child '%s': address%s\n", dev->prom_name,
+              dev->num_addrs > 1 ? "es" : "");
+       for (i = 0; i < dev->num_addrs; i++)
+               dprintk("        %016lx\n", dev->base_address[i]);
+       if (dev->num_irqs) {
+               dprintk("        IRQ%s", dev->num_irqs > 1 ? "s" : "");
+               for (i = 0; i < dev->num_irqs; i++)
+                       dprintk(" %08x", dev->irqs[i]);
+               dprintk("\n");
+       }
+#endif
+}
+
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+{
+       struct linux_prom_registers regs[PROMREG_MAX];
+       struct linux_ebus_child *child;
+       int irqs[PROMINTR_MAX];
+       char lbuf[128];
+       int i, n, len;
+
+       dev->prom_node = node;
+       prom_getstring(node, "name", lbuf, sizeof(lbuf));
+       strcpy(dev->prom_name, lbuf);
+
+       len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+       if (len % sizeof(struct linux_prom_registers)) {
+               prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+                           dev->prom_name, len,
+                           (int)sizeof(struct linux_prom_registers));
+               panic(__FUNCTION__);
+       }
+       dev->num_addrs = len / sizeof(struct linux_prom_registers);
+
+       for (i = 0; i < dev->num_addrs; i++) {
+               n = (regs[i].which_io - 0x10) >> 2;
+
+               dev->base_address[i] = dev->bus->self->base_address[n];
+               dev->base_address[i] += regs[i].phys_addr;
+
+               if (dev->base_address[i]) {
+                   dev->base_address[i] =
+                      (unsigned long)sparc_alloc_io (dev->base_address[i], 0,
+                                                     regs[i].reg_size,
+                                                     dev->prom_name, 0, 0);
+                   if (dev->base_address[i] == 0 ) {
+                       panic("ebus: unable sparc_alloc_io for dev %s",
+                             dev->prom_name);
+                   }
+               }
+       }
+
+       len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+       if ((len == -1) || (len == 0)) {
+               dev->num_irqs = 0;
+       } else {
+               dev->num_irqs = len / sizeof(irqs[0]);
+
+#define IRQ_8042 7
+               if (irqs[0] == 4) dev->irqs[0] = IRQ_8042;
+               printk("FIXME: %s irq(%d)\n", dev->prom_name, irqs[0]);
+       }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+       dprintk("'%s': address%s\n", dev->prom_name,
+              dev->num_addrs > 1 ? "es" : "");
+       for (i = 0; i < dev->num_addrs; i++)
+               dprintk("  %016lx\n", dev->base_address[i]);
+       if (dev->num_irqs) {
+               dprintk("  IRQ%s", dev->num_irqs > 1 ? "s" : "");
+               for (i = 0; i < dev->num_irqs; i++)
+                       dprintk(" %08x", dev->irqs[i]);
+               dprintk("\n");
+       }
+#endif
+       if ((node = prom_getchild(node))) {
+               dev->children = (struct linux_ebus_child *)
+                       ebus_alloc(sizeof(struct linux_ebus_child));
+
+               child = dev->children;
+               child->next = 0;
+               child->parent = dev;
+               child->bus = dev->bus;
+               fill_ebus_child(node, &regs[0], child);
+
+               while ((node = prom_getsibling(node))) {
+                       child->next = (struct linux_ebus_child *)
+                               ebus_alloc(sizeof(struct linux_ebus_child));
+
+                       child = child->next;
+                       child->next = 0;
+                       child->parent = dev;
+                       child->bus = dev->bus;
+                       fill_ebus_child(node, &regs[0], child);
+               }
+       }
+}
+
+__initfunc(void ebus_init(void))
+{
+       struct linux_prom_pci_registers regs[PROMREG_MAX];
+       struct linux_pbm_info *pbm;
+       struct linux_ebus_device *dev;
+       struct linux_ebus *ebus;
+       struct pci_dev *pdev;
+       struct pcidev_cookie *cookie;
+       char lbuf[128];
+       unsigned long addr, *base;
+       unsigned short pci_command;
+       int nd, len, ebusnd;
+       int reg, nreg;
+       int num_ebus = 0;
+
+       if (!pci_present())
+               return;
+
+       pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0);
+       if (!pdev) {
+#ifdef PROM_DEBUG      
+               dprintk("ebus: No EBus's found.\n");
+#endif
+               return;
+       }
+       cookie = pdev->sysdata;
+       ebusnd = cookie->prom_node;
+
+       ebus_chain = ebus = (struct linux_ebus *)
+                       ebus_alloc(sizeof(struct linux_ebus));
+       ebus->next = 0;
+
+       while (ebusnd) {
+#ifdef PROM_DEBUG      
+               dprintk("ebus%d:", num_ebus);
+#endif
+
+               prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+               ebus->prom_node = ebusnd;
+               strcpy(ebus->prom_name, lbuf);
+               ebus->self = pdev;
+               ebus->parent = pbm = cookie->pbm;
+
+               /* Enable BUS Master. */
+               pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+               pci_command |= PCI_COMMAND_MASTER;
+               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+
+               len = prom_getproperty(ebusnd, "reg", (void *)regs,
+                                      sizeof(regs));
+               if (len == 0 || len == -1) {
+                       prom_printf("%s: can't find reg property\n",
+                                   __FUNCTION__);
+                       prom_halt();
+               }
+               nreg = len / sizeof(struct linux_prom_pci_registers);
+
+               base = &ebus->self->base_address[0];
+               for (reg = 0; reg < nreg; reg++) {
+                       if (!(regs[reg].which_io & 0x03000000))
+                               continue;
+
+                       addr = regs[reg].phys_lo;
+                       *base++ = addr;
+#ifdef PROM_DEBUG
+                       dprintk(" %lx[%x]", addr, regs[reg].size_lo);
+#endif
+               }
+#ifdef PROM_DEBUG
+               dprintk("\n");
+#endif
+
+               nd = prom_getchild(ebusnd);
+               if (!nd)
+                       goto next_ebus;
+
+               ebus->devices = (struct linux_ebus_device *)
+                               ebus_alloc(sizeof(struct linux_ebus_device));
+
+               dev = ebus->devices;
+               dev->next = 0;
+               dev->children = 0;
+               dev->bus = ebus;
+               fill_ebus_device(nd, dev);
+
+               while ((nd = prom_getsibling(nd))) {
+                       dev->next = (struct linux_ebus_device *)
+                               ebus_alloc(sizeof(struct linux_ebus_device));
+
+                       dev = dev->next;
+                       dev->next = 0;
+                       dev->children = 0;
+                       dev->bus = ebus;
+                       fill_ebus_device(nd, dev);
+               }
+
+       next_ebus:
+               pdev = pci_find_device(PCI_VENDOR_ID_SUN,
+                                      PCI_DEVICE_ID_SUN_EBUS, pdev);
+               if (!pdev)
+                       break;
+
+               cookie = pdev->sysdata;
+               ebusnd = cookie->prom_node;
+
+               ebus->next = (struct linux_ebus *)
+                       ebus_alloc(sizeof(struct linux_ebus));
+               ebus = ebus->next;
+               ebus->next = 0;
+               ++num_ebus;
+       }
+
+#ifdef CONFIG_SUN_OPENPROMIO
+       openprom_init();
+#endif
+
+#ifdef CONFIG_SPARCAUDIO
+       sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+       bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+       auxio_probe();
+#endif
+#ifdef CONFIG_ENVCTRL
+       envctrl_init();
+#endif
+#ifdef CONFIG_OBP_FLASH
+       flash_init();
+#endif
+}
index d2d27d90a005cad5174a3042244510f5dbde710b..ed3d4de84398c6ccaedd182beb02eb6621ad52b0 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.86 1998/06/04 09:54:49 jj Exp $
+/*  $Id: irq.c,v 1.89 1998/09/21 05:05:12 jj Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -6,7 +6,7 @@
  *
  *  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) 1995 Pete A. Zaitcev (zaitcev@metabyte.com)
  *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
  */
 
@@ -40,6 +40,7 @@
 #include <asm/spinlock.h>
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
+#include <asm/pcic.h>
 
 /*
  * Dave Redman (djhr@tadpole.co.uk)
@@ -669,6 +670,13 @@ __initfunc(void init_IRQ(void))
                break;
 
        case sun4m:
+#ifdef CONFIG_PCI
+               pcic_probe();
+               if (pci_present()) {
+                       sun4m_pci_init_IRQ();
+                       break;
+               }
+#endif
                sun4m_init_IRQ();
                break;
                
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
new file mode 100644 (file)
index 0000000..c6e204c
--- /dev/null
@@ -0,0 +1,762 @@
+/* $Id: pcic.c,v 1.2 1998/09/29 03:21:56 jj Exp $
+ * pcic.c: Sparc/PCI controller support
+ *
+ * Copyright (C) 1998 V. Roganov and G. Raiko
+ *
+ * Code is derived from Ultra/PCI PSYCHO controller support, see that
+ * for author info.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#include <asm/io.h>
+
+#undef PROM_DEBUG
+#undef FIXUP_REGS_DEBUG
+#undef FIXUP_IRQ_DEBUG
+#undef FIXUP_VMA_DEBUG
+
+#ifdef PROM_DEBUG
+#define dprintf        prom_printf
+#else
+#define dprintf printk
+#endif
+
+#include <linux/ctype.h>
+#include <linux/pci.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/oplib.h>
+#include <asm/pcic.h>
+#include <asm/timer.h>
+#include <asm/uaccess.h>
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+       return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+                                 unsigned long dfn,
+                                 unsigned long off,
+                                 unsigned long len,
+                                 unsigned char *buf)
+{
+       return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+                                  unsigned long dfn,
+                                  unsigned long off,
+                                  unsigned long len,
+                                  unsigned char *buf)
+{
+       return 0;
+}
+
+#else
+
+static struct linux_pcic PCIC;
+static struct linux_pcic *pcic = NULL;
+
+static void pci_do_gettimeofday(struct timeval *tv);
+static void pci_do_settimeofday(struct timeval *tv);
+
+__initfunc(void pcic_probe(void))
+{
+       struct linux_prom_registers regs[PROMREG_MAX];
+       struct linux_pbm_info* pbm;
+       char namebuf[64];
+       int node;
+       int err;
+
+       if (pci_present()) {
+               prom_printf("PCIC: called twice!\n");
+               prom_halt();
+       }
+
+       node = prom_getchild (prom_root_node);
+       node = prom_searchsiblings (node, "pci");
+       if (node == 0)
+               return;
+       /*
+        * Map in PCIC register set, config space, and IO base
+        */
+       err = prom_getproperty(node, "reg", (char*)regs, sizeof(regs));
+       if (err == 0 || err == -1) {
+               prom_printf("PCIC: Error, cannot get PCIC registers "
+                           "from PROM.\n");
+               prom_halt();
+       }
+       
+       pcic = &PCIC;
+
+       pcic->pcic_regs = (unsigned long)sparc_alloc_io(regs[0].phys_addr, NULL,
+                                             regs[0].reg_size,
+                                             "PCIC Registers", 0, 0);
+       if (!pcic->pcic_regs) {
+               prom_printf("PCIC: Error, cannot map PCIC registers.\n");
+               prom_halt();
+       }
+
+       pcic->pcic_io_phys = regs[1].phys_addr;
+       pcic->pcic_io = (unsigned long)sparc_alloc_io(regs[1].phys_addr, NULL,
+                                           regs[1].reg_size,
+                                           "PCIC IO Base", 0, 0);
+       if (pcic->pcic_io == 0UL) {
+               prom_printf("PCIC: Error, cannot map PCIC IO Base.\n");
+               prom_halt();
+       }
+
+       pcic->pcic_config_space_addr =
+                       (unsigned long)sparc_alloc_io (regs[2].phys_addr, NULL,
+                                            regs[2].reg_size * 2,
+                                            "PCI Config Space Address", 0, 0);
+       if (pcic->pcic_config_space_addr == 0UL) {
+               prom_printf("PCIC: Error, cannot map" 
+                           "PCI Configuration Space Address.\n");
+               prom_halt();
+       }
+
+       /*
+        * Docs say three least significant bits in address and data
+        * must be the same. Thus, we need adjust size of data.
+        */
+       pcic->pcic_config_space_data =
+                       (unsigned long)sparc_alloc_io (regs[3].phys_addr, NULL,
+                                            regs[3].reg_size * 2,
+                                            "PCI Config Space Data", 0, 0);
+       if (pcic->pcic_config_space_data == 0UL) {
+               prom_printf("PCIC: Error, cannot map" 
+                           "PCI Configuration Space Data.\n");
+               prom_halt();
+       }
+
+       pbm = &pcic->pbm;
+       pbm->prom_node = node;
+       prom_getstring(node, "name", namebuf, sizeof(namebuf));
+       strcpy(pbm->prom_name, namebuf);
+}
+
+__initfunc(void pcibios_init(void))
+{
+       /*
+        * PCIC should be initialized at start of the timer.
+        * So, here we report the presence of PCIC and do some magic passes.
+        */
+       if(!pcic)
+               return;
+
+       printk("PCIC MAP: config addr=0x%lx; config data=0x%lx, "
+              "regs=0x%lx io=0x%lx\n",
+              pcic->pcic_config_space_addr, pcic->pcic_config_space_data,
+              pcic->pcic_regs, pcic->pcic_io);
+
+       /*
+        * FIXME:
+        *      Switch off IOTLB translation.
+        *      It'll be great to use IOMMU to handle HME's rings
+        *      but we couldn't. Thus, we have to flush CPU cache
+        *      in HME.
+        */
+       writeb(PCI_DVMA_CONTROL_IOTLB_DISABLE, 
+              pcic->pcic_regs+PCI_DVMA_CONTROL);
+
+       /*
+        * FIXME:
+        *      Increase mapped size for PCI memory space (DMA access).
+        *      Should be done in that order (size first, address second).
+        *      Why we couldn't set up 4GB and forget about it ?
+        */
+       writel(0xF0000000UL, pcic->pcic_regs+PCI_SIZE_0);
+       writel(0+PCI_BASE_ADDRESS_SPACE_MEMORY, 
+              pcic->pcic_regs+PCI_BASE_ADDRESS_0);
+}
+
+int pcibios_present(void)
+{
+       return pcic != NULL;
+}
+
+__initfunc(static int pdev_to_pnode(struct linux_pbm_info *pbm, 
+                                   struct pci_dev *pdev))
+{
+       struct linux_prom_pci_registers regs[PROMREG_MAX];
+       int err;
+       int node = prom_getchild(pbm->prom_node);
+
+       while(node) {
+               err = prom_getproperty(node, "reg", 
+                                      (char *)&regs[0], sizeof(regs));
+               if(err != 0 && err != -1) {
+                       unsigned long devfn = (regs[0].which_io >> 8) & 0xff;
+                       if(devfn == pdev->devfn)
+                               return node; /* Match */
+               }
+               node = prom_getsibling(node);
+       }
+       return 0;
+}
+
+static inline struct pcidev_cookie *pci_devcookie_alloc(void)
+{
+       return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC);
+}
+
+
+static void pcic_map_pci_device (struct pci_dev *dev) {
+       int node, pcinode;
+       int i, j;
+
+       /* Is any valid address present ? */
+       i = 0;
+       for(j = 0; j < 6; j++)
+               if (dev->base_address[j]) i++;
+       if (!i) return; /* nothing to do */
+
+       /*
+        * find related address and get it's window length
+        */
+       pcinode = prom_getchild(prom_root_node);
+       pcinode = prom_searchsiblings(pcinode, "pci");
+       if (!pcinode)
+               panic("PCIC: failed to locate 'pci' node");
+
+
+       for (node = prom_getchild(pcinode); node;
+            node = prom_getsibling(node)) {
+               struct linux_prom_pci_assigned_addresses addrs[6];
+               int addrlen = prom_getproperty(node,"assigned-addresses",
+                                              (char*)addrs, sizeof(addrs));
+               if (addrlen == -1)
+                       continue;
+
+               addrlen /= sizeof(struct linux_prom_pci_assigned_addresses);
+               for (i = 0; i < addrlen; i++ )
+                   for (j = 0; j < 6; j++) {
+                       if (!dev->base_address[j] || !addrs[i].phys_lo)
+                               continue;
+                       if (addrs[i].phys_lo == dev->base_address[j]) {
+                           unsigned long address = dev->base_address[j];
+                           int length  = addrs[i].size_lo;
+                           char namebuf[128] = { 0, };
+                           unsigned long mapaddr, addrflags;
+           
+                           prom_getstring(node, "name",
+                                          namebuf,  sizeof(namebuf));
+
+                           /* FIXME:
+                            *      failure in allocation too large space
+                            */
+                           if (length > 0x200000) {
+                               length = 0x200000;
+                               prom_printf("PCIC: map window for device '%s' "
+                                           "reduced to 2MB !\n", namebuf);
+                           }
+
+                           /*
+                            *  Be careful with MEM/IO address flags
+                            */
+                           if ((address & PCI_BASE_ADDRESS_SPACE) ==
+                                PCI_BASE_ADDRESS_SPACE_IO) {
+                               mapaddr = address & PCI_BASE_ADDRESS_IO_MASK;
+                           } else {
+                               mapaddr = address & PCI_BASE_ADDRESS_MEM_MASK;
+                           }
+                           addrflags = address ^ mapaddr;
+
+                           dev->base_address[j] =
+                               (unsigned long)sparc_alloc_io(address, 0, 
+                                                             length,
+                                                             namebuf, 0, 0);
+                           if ( dev->base_address[j] == 0 )
+                               panic("PCIC: failed make mapping for "
+                                     "pci device '%s' with address %lx\n",
+                                      namebuf, address);
+
+                           dev->base_address[j] ^= addrflags;
+                           return;
+                       }
+               }
+       }
+
+       panic("PCIC: unable to locate prom node for pci device (%x,%x) \n",
+             dev->device, dev->vendor);
+}
+
+/*
+ * Assign IO space for a device.
+ * This is a chance for devices which have the same IO and Mem Space to
+ * fork access to IO and Mem.
+ *
+ * Now, we assume there is one such device only (IGA 1682) but code below
+ * should work in cases when space of all such devices is less then 16MB.
+ */
+unsigned long pcic_alloc_io( unsigned long* addr )
+{
+       unsigned long paddr = *addr;
+       unsigned long offset;
+
+       if(pcic->pcic_mapped_io == 0) {
+               pcic->pcic_mapped_io = paddr & ~(PCI_SPACE_SIZE-1) ;
+               writeb((pcic->pcic_mapped_io>>24) & 0xff, 
+                      pcic->pcic_regs+PCI_PIBAR);
+               writeb((pcic->pcic_io_phys>>24) & PCI_SIBAR_ADDRESS_MASK,
+                      pcic->pcic_regs+PCI_SIBAR);
+               writeb(PCI_ISIZE_16M, pcic->pcic_regs+PCI_ISIZE);
+       }
+       if(paddr < pcic->pcic_mapped_io ||
+          paddr > pcic->pcic_mapped_io + PCI_SPACE_SIZE)
+               return 0;
+       offset = paddr - pcic->pcic_mapped_io;
+       *addr = pcic->pcic_io_phys + offset;
+       return pcic->pcic_io + offset;
+}
+
+/*
+ * Stolen from both i386 and sparc64 branch 
+ */
+__initfunc(void pcibios_fixup(void))
+{
+  struct pci_dev *dev;
+  int i, has_io, has_mem;
+  unsigned short cmd;
+
+       if(pcic == NULL) {
+               prom_printf("PCI: Error, PCIC not found.\n");
+               prom_halt();
+       }
+
+       for (dev = pci_devices; dev; dev=dev->next) {
+               /*
+                * Comment from i386 branch:
+                *     There are buggy BIOSes that forget to enable I/O and memory
+                *     access to PCI devices. We try to fix this, but we need to
+                *     be sure that the BIOS didn't forget to assign an address
+                *     to the device. [mj]
+                * OBP is a case of such BIOS :-)
+                */
+               has_io = has_mem = 0;
+               for(i=0; i<6; i++) {
+                       unsigned long a = dev->base_address[i];
+                       if (a & PCI_BASE_ADDRESS_SPACE_IO) {
+                               has_io = 1;
+                       } else if (a & PCI_BASE_ADDRESS_MEM_MASK)
+                               has_mem = 1;
+               }
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (has_io && !(cmd & PCI_COMMAND_IO)) {
+                       printk("PCI: Enabling I/O for device %02x:%02x\n",
+                               dev->bus->number, dev->devfn);
+                       cmd |= PCI_COMMAND_IO;
+                       pci_write_config_word(dev, PCI_COMMAND, cmd);
+               }
+               if (has_mem && !(cmd & PCI_COMMAND_MEMORY)) {
+                       printk("PCI: Enabling memory for device %02x:%02x\n",
+                               dev->bus->number, dev->devfn);
+                       cmd |= PCI_COMMAND_MEMORY;
+                       pci_write_config_word(dev, PCI_COMMAND, cmd);
+               }    
+
+               /* cookies */
+               {
+                       struct pcidev_cookie *pcp;
+                       struct linux_pbm_info* pbm = &pcic->pbm;
+                       int node = pdev_to_pnode(pbm, dev);
+
+                       if(node == 0)
+                               node = -1;
+                       pcp = pci_devcookie_alloc();
+                       pcp->pbm = pbm;
+                       pcp->prom_node = node;
+                       dev->sysdata = pcp;
+               }
+
+               /* memory mapping */
+               if (!(dev->vendor == PCI_VENDOR_ID_SUN &&
+                     dev->device == PCI_DEVICE_ID_SUN_EBUS)) {
+                       pcic_map_pci_device(dev);
+               }
+
+               /* irq */
+#define SETIRQ(vend,devid,irqn) \
+       if (dev->vendor==vend && dev->device==devid) dev->irq = irqn;
+
+               SETIRQ(PCI_VENDOR_ID_SUN,PCI_DEVICE_ID_SUN_HAPPYMEAL,3);
+       }
+       ebus_init();
+}
+
+/* Makes compiler happy */
+static volatile int pcic_timer_dummy;
+
+static void pcic_clear_clock_irq(void)
+{
+       pcic_timer_dummy = readl(pcic->pcic_regs+PCI_SYS_LIMIT);
+}
+
+static void pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
+{
+       pcic_clear_clock_irq();
+       do_timer(regs);
+}
+
+#define USECS_PER_JIFFY  10000  /* We have 100HZ "standard" timer for sparc */
+#define TICK_TIMER_LIMIT ((100*1000000/4)/100)
+
+__initfunc(void pci_time_init(void))
+{
+       unsigned long v;
+       int timer_irq, irq;
+
+       do_get_fast_time = pci_do_gettimeofday;
+       /* A hack until do_gettimeofday prototype is moved to arch specific headers
+          and btfixupped. Patch do_gettimeofday with ba pci_do_gettimeofday; nop */
+       ((unsigned int *)do_gettimeofday)[0] = 
+               0x10800000 | (((unsigned long)pci_do_gettimeofday - (unsigned long)do_gettimeofday) & 0x003fffff);
+       ((unsigned int *)do_gettimeofday)[1] =
+               0x01000000;
+       BTFIXUPSET_CALL(bus_do_settimeofday, pci_do_settimeofday, BTFIXUPCALL_NORM);
+       btfixup();
+
+       writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT);
+       /* PROM should set appropriate irq */
+       v = readb(pcic->pcic_regs+PCI_COUNTER_IRQ);
+       timer_irq = PCI_COUNTER_IRQ_SYS(v);
+       writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
+               pcic->pcic_regs+PCI_COUNTER_IRQ);
+       irq = request_irq(timer_irq, pcic_timer_handler,
+                         (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+       if (irq) {
+               prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
+               prom_halt();
+       }
+       __sti();
+}
+
+static __inline__ unsigned long do_gettimeoffset(void)
+{
+       unsigned long offset = 0;
+
+       /* 
+        * We devide all to 100
+        * to have microsecond resolution and to avoid overflow
+        */
+       unsigned long count = 
+           readl(pcic->pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW;
+       count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100);
+
+       if(test_bit(TIMER_BH, &bh_active))
+               offset = 1000000;
+       return offset + count;
+}
+
+extern volatile unsigned long lost_ticks;
+
+static void pci_do_gettimeofday(struct timeval *tv)
+{
+       unsigned long flags;
+
+       save_and_cli(flags);
+       *tv = xtime;
+       tv->tv_usec += do_gettimeoffset();
+
+       /*
+        * xtime is atomically updated in timer_bh. lost_ticks is
+        * nonzero if the timer bottom half hasnt executed yet.
+        */
+       if (lost_ticks)
+               tv->tv_usec += USECS_PER_JIFFY;
+
+       restore_flags(flags);
+
+       if (tv->tv_usec >= 1000000) {
+               tv->tv_usec -= 1000000;
+               tv->tv_sec++;
+       }       
+}
+
+static void pci_do_settimeofday(struct timeval *tv)
+{
+       cli();
+       tv->tv_usec -= do_gettimeoffset();
+       if(tv->tv_usec < 0) {
+               tv->tv_usec += 1000000;
+               tv->tv_sec--;
+       }
+       xtime = *tv;
+       time_state = TIME_BAD;
+       time_maxerror = 0x70000000;
+       time_esterror = 0x70000000;
+       sti();
+}
+
+#if 0
+static void watchdog_reset() {
+       writeb(0, pcic->pcic_regs+PCI_SYS_STATUS);
+}
+#endif
+
+#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char device_fn,
+                            unsigned char where, unsigned char *value)
+{
+       unsigned int v;
+
+       pcibios_read_config_dword (bus, device_fn, where&~3, &v);
+       *value = 0xff & (v >> (8*(where & 3)));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus,
+                             unsigned char device_fn, 
+                             unsigned char where, unsigned short *value)
+{
+       unsigned int v;
+       if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+  
+       pcibios_read_config_dword (bus, device_fn, where&~3, &v);
+       *value = 0xffff & (v >> (8*(where & 3)));
+       return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+                              unsigned char where, unsigned int *value)
+{
+       unsigned long flags;
+       if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+       if (bus != 0 || 
+           (device_fn != 0 && device_fn != 1 && device_fn != 0x80)) {
+               *value = 0xffffffff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       /* FIXME: IGA haven't got high config memory addresses !!! */
+       if (device_fn == 0x80 && where > PCI_INTERRUPT_LINE) {
+               *value = 0xffffffff;
+               return PCIBIOS_SUCCESSFUL;
+       }
+
+       save_and_cli(flags);
+       writel(CONFIG_CMD(bus,device_fn,where), pcic->pcic_config_space_addr);
+       *value = readl(pcic->pcic_config_space_data + (where&4));
+       restore_flags(flags);
+       return PCIBIOS_SUCCESSFUL;
+}
+    
+int pcibios_write_config_byte (unsigned char bus, unsigned char devfn,
+                              unsigned char where, unsigned char value)
+{
+       unsigned int v;
+
+       pcibios_read_config_dword (bus, devfn, where&~3, &v);
+       v = (v & ~(0xff << (8*(where&3)))) | 
+           ((0xff&(unsigned)value) << (8*(where&3)));
+       return pcibios_write_config_dword (bus, devfn, where&~3, v);
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char devfn,
+                              unsigned char where, unsigned short value)
+{
+       unsigned int v;
+       if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       pcibios_read_config_dword (bus, devfn, where&~3, &v);
+       v = (v & ~(0xffff << (8*(where&3)))) | 
+           ((0xffff&(unsigned)value) << (8*(where&3)));
+       return pcibios_write_config_dword (bus, devfn, where&~3, v);
+}
+  
+int pcibios_write_config_dword (unsigned char bus, unsigned char devfn,
+                               unsigned char where, unsigned int value)
+{
+       unsigned long flags;
+       if ((where&3) || bus != 0 || (devfn != 0 && devfn != 1 && devfn != 0x80))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       save_and_cli(flags);
+       writel(CONFIG_CMD(bus,devfn,where),pcic->pcic_config_space_addr);
+       writel(value, pcic->pcic_config_space_data + (where&4));
+       restore_flags(flags);
+       return PCIBIOS_SUCCESSFUL;
+}
+
+__initfunc(char *pcibios_setup(char *str))
+{
+       return str;
+}
+
+/*
+ *  Following code added to handle extra PCI-related system calls 
+ */
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+                                 unsigned long dfn,
+                                 unsigned long off,
+                                 unsigned long len,
+                                 unsigned char *buf)
+{
+       unsigned char ubyte;
+       unsigned short ushort;
+       unsigned int uint;
+       int err = 0;
+
+       if(!suser())
+               return -EPERM;
+
+       lock_kernel();
+       switch(len) {
+       case 1:
+               pcibios_read_config_byte(bus, dfn, off, &ubyte);
+               put_user(ubyte, (unsigned char *)buf);
+               break;
+       case 2:
+               pcibios_read_config_word(bus, dfn, off, &ushort);
+               put_user(ushort, (unsigned short *)buf);
+               break;
+       case 4:
+               pcibios_read_config_dword(bus, dfn, off, &uint);
+               put_user(uint, (unsigned int *)buf);
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+       };
+       unlock_kernel();
+
+       return err;
+}
+   
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+                                  unsigned long dfn,
+                                  unsigned long off,
+                                  unsigned long len,
+                                  unsigned char *buf)
+{
+       unsigned char ubyte;
+       unsigned short ushort;
+       unsigned int uint;
+       int err = 0;
+
+       if(!suser())
+               return -EPERM;
+
+       lock_kernel();
+       switch(len) {
+       case 1:
+               err = get_user(ubyte, (unsigned char *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, ubyte);
+               break;
+
+       case 2:
+               err = get_user(ushort, (unsigned short *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, ushort);
+               break;
+
+       case 4:
+               err = get_user(uint, (unsigned int *)buf);
+               if(err)
+                       break;
+               pcibios_write_config_byte(bus, dfn, off, uint);
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+
+       };
+       unlock_kernel();
+
+       return err;
+}                         
+
+static inline unsigned long get_irqmask(int irq_nr)
+{
+       return 1 << irq_nr;
+}
+
+static inline char *pcic_irq_itoa(unsigned int irq)
+{
+       static char buff[16];
+       sprintf(buff, "%d", irq);
+       return buff;
+}
+
+static void pcic_disable_irq(unsigned int irq_nr)
+{
+       unsigned long mask, flags;
+
+       mask = get_irqmask(irq_nr);
+       save_and_cli(flags);
+       writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+       restore_flags(flags);
+}
+
+static void pcic_enable_irq(unsigned int irq_nr)
+{
+       unsigned long mask, flags;
+
+       mask = get_irqmask(irq_nr);
+       save_and_cli(flags);
+       writel(mask, pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+       restore_flags(flags);
+}
+
+static void pcic_clear_profile_irq(int cpu)
+{
+       printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
+}
+
+static void pcic_load_profile_irq(int cpu, unsigned int limit)
+{
+       printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
+}
+
+/* We assume the caller is local cli()'d when these are called, or else
+ * very bizarre behavior will result.
+ */
+static void pcic_disable_pil_irq(unsigned int pil)
+{
+       writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+}
+
+static void pcic_enable_pil_irq(unsigned int pil)
+{
+       writel(get_irqmask(pil), pcic->pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+}
+
+__initfunc(void sun4m_pci_init_IRQ(void))
+{
+       BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(__irq_itoa, pcic_irq_itoa, BTFIXUPCALL_NORM);
+}
+
+__initfunc(void pcibios_fixup_bus(struct pci_bus *bus))
+{
+}
+
+#endif
index c52674431316fcdea7f3f58a78cf85ddb9a8e47e..3aeee6f6b7b4bf2fb19f4057233b6731bcdc2559 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.118 1998/08/04 20:48:47 davem Exp $
+/*  $Id: process.c,v 1.126 1998/09/21 05:05:18 jj Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -61,8 +61,8 @@ asmlinkage int sys_idle(void)
                goto out;
 
        /* endless idle loop with no priority at all */
-       current->priority = -100;
-       current->counter = -100;
+       current->priority = 0;
+       current->counter = 0;
        for (;;) {
                if (ARCH_SUN4C_SUN4) {
                        static int count = HZ;
@@ -108,16 +108,13 @@ out:
 /* This is being executed in task 0 'user space'. */
 int cpu_idle(void *unused)
 {
-       extern volatile int smp_commenced;
-
-       current->priority = -100;
+       current->priority = 0;
        while(1) {
-               srmmu_check_pgt_cache();
-               run_task_queue(&tq_scheduler);
-               /* endless idle loop with no priority at all */
-               current->counter = -100;
-               if(!smp_commenced || current->need_resched)
-                       schedule();
+               check_pgt_cache();
+               run_task_queue(&tq_scheduler);
+               /* endless idle loop with no priority at all */
+               current->counter = 0;
+               schedule();
        }
 }
 
@@ -176,8 +173,10 @@ void machine_restart(char * cmd)
 
 void machine_power_off(void)
 {
+#ifdef CONFIG_SUN_AUXIO
        if (auxio_power_register)
                *auxio_power_register |= AUXIO_POWER_OFF;
+#endif
        machine_halt();
 }
 
@@ -594,8 +593,44 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
  */
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 {
-       /* Currently we report that we couldn't dump the fpu structure */
-       return 0;
+       if (current->used_math == 0) {
+               memset(fpregs, 0, sizeof(*fpregs));
+               fpregs->pr_q_entrysize = 8;
+               return 1;
+       }
+#ifdef __SMP__
+       if (current->flags & PF_USEDFPU) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+                      &current->tss.fpqueue[0], &current->tss.fpqdepth);
+               regs->psr &= ~(PSR_EF);
+               current->flags &= ~(PF_USEDFPU);
+       }
+#else
+       if (current == last_task_used_math) {
+               put_psr(get_psr() | PSR_EF);
+               fpsave(&current->tss.float_regs[0], &current->tss.fsr,
+                      &current->tss.fpqueue[0], &current->tss.fpqdepth);
+               last_task_used_math = 0;
+               regs->psr &= ~(PSR_EF);
+       }
+#endif
+       memcpy(&fpregs->pr_fr.pr_regs[0],
+              &current->tss.float_regs[0],
+              (sizeof(unsigned long) * 32));
+       fpregs->pr_fsr = current->tss.fsr;
+       fpregs->pr_qcnt = current->tss.fpqdepth;
+       fpregs->pr_q_entrysize = 8;
+       fpregs->pr_en = 1;
+       if(fpregs->pr_qcnt != 0) {
+               memcpy(&fpregs->pr_q[0],
+                      &current->tss.fpqueue[0],
+                      sizeof(struct fpq) * fpregs->pr_qcnt);
+       }
+       /* Zero out the rest. */
+       memset(&fpregs->pr_q[fpregs->pr_qcnt], 0,
+              sizeof(struct fpq) * (32 - fpregs->pr_qcnt));
+       return 1;
 }
 
 /*
index 257b1c08663d9285e95b25d352ffaad7d9bf9c94..84190cf5abe81c567064b474e83b54c4aeb35067 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.99 1998/07/28 16:52:45 jj Exp $
+/*  $Id: setup.c,v 1.103 1998/09/21 05:05:23 jj Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -332,9 +332,6 @@ __initfunc(void setup_arch(char **cmdline_p,
        switch(sparc_cpu_model) {
        case sun4:
                printk("SUN4\n");
-#ifdef CONFIG_SUN4_FORCECONSOLE
-               register_console(&prom_console);
-#endif
                packed = 0;
                break;
        case sun4c:
@@ -443,8 +440,14 @@ __initfunc(void setup_arch(char **cmdline_p,
                                        serial_console = 1;
                                } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
                                        serial_console = 2;
+                               } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
+                                       prom_printf("MrCoffee ttya\n");
+                                       serial_console = 1;
+                               } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
+                                       serial_console = 0;
+                                       prom_printf("MrCoffee keyboard\n");
                                } else {
-                                       prom_printf("Inconsistent console\n");
+                                       prom_printf("Inconsistent or unknown console\n");
                                        prom_halt();
                                }
                        }
index 357d30af58689432399f85ce6924a60227ee9106..eb815ee355edcea6ad875ca47e80d08e0e6591cf 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.82 1998/07/31 05:18:51 jj Exp $
+/*  $Id: signal.c,v 1.86 1998/09/29 09:46:04 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -423,7 +423,7 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
 {
        struct signal_sframe *sframep;
        struct sigcontext *sc;
-       int window = 0;
+       int window = 0, err;
 
        synchronize_user_stack();
        sframep = (struct signal_sframe *)get_sigframe(sa, regs, SF_ALIGNEDSZ);
@@ -443,43 +443,47 @@ setup_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        sc = &sframep->sig_context;
 
        /* We've already made sure frame pointer isn't in kernel space... */
-       __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack);
-       __put_user(oldset->sig[0], &sc->sigc_mask);
-       __copy_to_user(sframep->extramask, &oldset->sig[1],
-                      (_NSIG_WORDS - 1) * sizeof(unsigned int));
-       __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
-       __put_user(pc, &sc->sigc_pc);
-       __put_user(npc, &sc->sigc_npc);
-       __put_user(regs->psr, &sc->sigc_psr);
-       __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
-       __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
-       __put_user(current->tss.w_saved, &sc->sigc_oswins);
+       err  = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
+                        &sc->sigc_onstack);
+       err |= __put_user(oldset->sig[0], &sc->sigc_mask);
+       err |= __copy_to_user(sframep->extramask, &oldset->sig[1],
+                             (_NSIG_WORDS - 1) * sizeof(unsigned int));
+       err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
+       err |= __put_user(pc, &sc->sigc_pc);
+       err |= __put_user(npc, &sc->sigc_npc);
+       err |= __put_user(regs->psr, &sc->sigc_psr);
+       err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
+       err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
+       err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
        if(current->tss.w_saved)
                for(window = 0; window < current->tss.w_saved; window++) {
                        sc->sigc_spbuf[window] =
                                (char *)current->tss.rwbuf_stkptrs[window];
-                       copy_to_user(&sc->sigc_wbuf[window],
-                              &current->tss.reg_window[window],
-                              sizeof(struct reg_window));
+                       err |= copy_to_user(&sc->sigc_wbuf[window],
+                                           &current->tss.reg_window[window],
+                                           sizeof(struct reg_window));
                }
        else
-               copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
-                      sizeof(struct reg_window));
+               err |= copy_to_user(sframep, (char *)regs->u_regs[UREG_FP],
+                                   sizeof(struct reg_window));
 
        current->tss.w_saved = 0; /* So process is allowed to execute. */
-       __put_user(signr, &sframep->sig_num);
+       err |= __put_user(signr, &sframep->sig_num);
        if(signr == SIGSEGV ||
           signr == SIGILL ||
           signr == SIGFPE ||
           signr == SIGBUS ||
           signr == SIGEMT) {
-               __put_user(current->tss.sig_desc, &sframep->sig_code);
-               __put_user(current->tss.sig_address, &sframep->sig_address);
+               err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
+               err |= __put_user(current->tss.sig_address, &sframep->sig_address);
        } else {
-               __put_user(0, &sframep->sig_code);
-               __put_user(0, &sframep->sig_address);
+               err |= __put_user(0, &sframep->sig_code);
+               err |= __put_user(0, &sframep->sig_address);
        }
-       __put_user(sc, &sframep->sig_scptr);
+       err |= __put_user(sc, &sframep->sig_scptr);
+       if (err)
+               goto sigsegv;
+
        regs->u_regs[UREG_FP] = (unsigned long) sframep;
        regs->pc = (unsigned long) sa->sa_handler;
        regs->npc = (regs->pc + 4);
@@ -489,12 +493,16 @@ sigill_and_return:
        /* Ugh, we need to grab master lock in these rare cases ;-( */
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 
-static inline void
+static inline int
 save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
+       int err = 0;
 #ifdef __SMP__
        if (current->flags & PF_USEDFPU) {
                put_psr(get_psr() | PSR_EF);
@@ -512,15 +520,16 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
                regs->psr &= ~(PSR_EF);
        }
 #endif
-       copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
-                    (sizeof(unsigned long) * 32));
-       __put_user(current->tss.fsr, &fpu->si_fsr);
-       __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
+       err |= copy_to_user(&fpu->si_float_regs[0], &current->tss.float_regs[0],
+                           (sizeof(unsigned long) * 32));
+       err |= __put_user(current->tss.fsr, &fpu->si_fsr);
+       err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
        if (current->tss.fpqdepth != 0)
-               copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
-                            ((sizeof(unsigned long) +
-                            (sizeof(unsigned long *)))*16));
+               err |= copy_to_user(&fpu->si_fpqueue[0], &current->tss.fpqueue[0],
+                                   ((sizeof(unsigned long) +
+                                     (sizeof(unsigned long *)))*16));
        current->used_math = 0;
+       return err;
 }
 
 static inline void
@@ -528,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
                int signo, sigset_t *oldset)
 {
        struct new_signal_frame *sf;
-       int sigframe_size;
+       int sigframe_size, err;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
@@ -551,20 +560,22 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 2. Save the current process state */
-       copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
+       err = copy_to_user(&sf->info.si_regs, regs, sizeof (struct pt_regs));
 
        if (current->used_math) {
-               save_fpu_state(regs, &sf->fpu_state);
-               __put_user(&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
 
-       __put_user(oldset->sig[0], &sf->info.si_mask);
-       __copy_to_user(sf->extramask, &oldset->sig[1],
-                      (_NSIG_WORDS - 1) * sizeof(unsigned int));
-       copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-                    sizeof (struct reg_window));
+       err |= __put_user(oldset->sig[0], &sf->info.si_mask);
+       err |= __copy_to_user(sf->extramask, &oldset->sig[1],
+                             (_NSIG_WORDS - 1) * sizeof(unsigned int));
+       err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+                           sizeof (struct reg_window));
+       if (err)
+               goto sigsegv;
        
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -581,8 +592,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        else {
                regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
 
-               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
-               __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+               /* mov __NR_sigreturn, %g1 */
+               err |= __put_user(0x821020d8, &sf->insns[0]);
+
+               /* t 0x10 */
+               err |= __put_user(0x91d02010, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
 
                /* Flush instruction space. */
                flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -592,6 +608,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
 sigill_and_return:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 static inline void
@@ -601,7 +620,7 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        struct rt_signal_frame *sf;
        int sigframe_size;
        unsigned int psr;
-       int i;
+       int i, err;
 
        synchronize_user_stack();
        sigframe_size = RT_ALIGNEDSZ;
@@ -613,30 +632,32 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        if(current->tss.w_saved != 0)
                goto sigill;
 
-       put_user(regs->pc, &sf->regs.pc);
-       __put_user(regs->npc, &sf->regs.npc);
-       __put_user(regs->y, &sf->regs.y);
+       err  = put_user(regs->pc, &sf->regs.pc);
+       err |= __put_user(regs->npc, &sf->regs.npc);
+       err |= __put_user(regs->y, &sf->regs.y);
        psr = regs->psr;
        if(current->used_math)
                psr |= PSR_EF;
-       __put_user(psr, &sf->regs.psr);
+       err |= __put_user(psr, &sf->regs.psr);
        for(i = 0; i < 16; i++)
-               __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+               err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
        if(psr & PSR_EF) {
-               save_fpu_state(regs, &sf->fpu_state);
-               __put_user(&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user(&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
-       __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
+       err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
        
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
-       __put_user(current->sas_ss_size, &sf->stack.ss_size);
+       err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
        
-       copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
-                    sizeof (struct reg_window));       
+       err |= copy_to_user(sf, (char *) regs->u_regs [UREG_FP],
+                           sizeof (struct reg_window));        
+       if (err)
+               goto sigsegv;
 
        regs->u_regs[UREG_FP] = (unsigned long) sf;
        regs->u_regs[UREG_I0] = signo;
@@ -650,8 +671,13 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        else {
                regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2);
 
-               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
-               __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+               /* mov __NR_sigreturn, %g1 */
+               err |= __put_user(0x821020d8, &sf->insns[0]);
+
+               /* t 0x10 */
+               err |= __put_user(0x91d02010, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
 
                /* Flush instruction space. */
                flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
@@ -661,6 +687,9 @@ new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
 sigill:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 /* Setup a Solaris stack frame */
@@ -675,7 +704,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        svr4_gwindows_t *gw;
        svr4_ucontext_t *uc;
        svr4_sigset_t   setv;
-       int window = 0;
+       int window = 0, err;
 
        synchronize_user_stack();
        sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, SVR4_SF_ALIGNED + REGWIN_SZ);
@@ -688,7 +717,7 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        }
 
        /* Start with a clean frame pointer and fill it */
-       clear_user(sfp, sizeof (*sfp));
+       err = clear_user(sfp, sizeof (*sfp));
 
        /* Setup convenience variables */
        si = &sfp->si;
@@ -706,32 +735,32 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        if (_NSIG_WORDS >= 4) {
                setv.sigbits[2] = oldset->sig[2];
                setv.sigbits[3] = oldset->sig[3];
-               __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+               err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
        } else
-               __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+               err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
 
        /* Store registers */
-       __put_user(regs->pc, &((*gr) [SVR4_PC]));
-       __put_user(regs->npc, &((*gr) [SVR4_NPC]));
-       __put_user(regs->psr, &((*gr) [SVR4_PSR]));
-       __put_user(regs->y, &((*gr) [SVR4_Y]));
+       err |= __put_user(regs->pc, &((*gr) [SVR4_PC]));
+       err |= __put_user(regs->npc, &((*gr) [SVR4_NPC]));
+       err |= __put_user(regs->psr, &((*gr) [SVR4_PSR]));
+       err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
        
        /* Copy g [1..7] and o [0..7] registers */
-       copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
-       copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
+       err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+       err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
 
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &uc->stack.sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
-       __put_user(current->sas_ss_size, &uc->stack.size);
+       err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+       err |= __put_user(current->sas_ss_size, &uc->stack.size);
 
        /* Save the currently window file: */
 
        /* 1. Link sfp->uc->gwins to our windows */
-       __put_user(gw, &mc->gwin);
+       err |= __put_user(gw, &mc->gwin);
            
        /* 2. Number of windows to restore at setcontext (): */
-       __put_user(current->tss.w_saved, &gw->count);
+       err |= __put_user(current->tss.w_saved, &gw->count);
 
        /* 3. Save each valid window
         *    Currently, it makes a copy of the windows from the kernel copy.
@@ -745,9 +774,11 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
         *    to flush the user windows.
         */
        for(window = 0; window < current->tss.w_saved; window++) {
-               __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
-               copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
-               __put_user(0, gw->winptr [window]);
+               err |= __put_user((int *) &(gw->win [window]), &gw->winptr [window]);
+               err |= copy_to_user(&gw->win [window],
+                                   &current->tss.reg_window [window],
+                                   sizeof (svr4_rwindow_t));
+               err |= __put_user(0, gw->winptr [window]);
        }
 
        /* 4. We just pay attention to the gw->count field on setcontext */
@@ -758,8 +789,10 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
         * that much currently, should use those that David already
         * is providing with tss.sig_desc
         */
-       __put_user(signr, &si->siginfo.signo);
-       __put_user(SVR4_SINOINFO, &si->siginfo.code);
+       err |= __put_user(signr, &si->siginfo.signo);
+       err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
+       if (err)
+               goto sigsegv;
 
        regs->u_regs[UREG_FP] = (unsigned long) sfp;
        regs->pc = (unsigned long) sa->sa_handler;
@@ -772,10 +805,13 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
        if (regs->u_regs [14]){
                struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
 
-               __put_user(signr, &rw->ins [0]);
-               __put_user(si, &rw->ins [1]);
-               __put_user(uc, &rw->ins [2]);
-               __put_user(sfp, &rw->ins [6]);  /* frame pointer */
+               err |= __put_user(signr, &rw->ins [0]);
+               err |= __put_user(si, &rw->ins [1]);
+               err |= __put_user(uc, &rw->ins [2]);
+               err |= __put_user(sfp, &rw->ins [6]);   /* frame pointer */
+               if (err)
+                       goto sigsegv;
+
                regs->u_regs[UREG_I0] = signr;
                regs->u_regs[UREG_I1] = (uint) si;
                regs->u_regs[UREG_I2] = (uint) uc;
@@ -785,6 +821,9 @@ setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
 sigill_and_return:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
@@ -792,14 +831,14 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
        svr4_gregset_t  *gr;
        svr4_mcontext_t *mc;
        svr4_sigset_t   setv;
+       int err = 0;
 
        synchronize_user_stack();
 
        if (current->tss.w_saved)
                goto sigsegv_and_return;
 
-       if(clear_user(uc, sizeof (*uc)))
-               return -EFAULT;
+       err = clear_user(uc, sizeof (*uc));
 
        /* Setup convenience variables */
        mc = &uc->mcontext;
@@ -810,29 +849,29 @@ asmlinkage int svr4_getcontext (svr4_ucontext_t *uc, struct pt_regs *regs)
        if (_NSIG_WORDS >= 4) {
                setv.sigbits[2] = current->blocked.sig[2];
                setv.sigbits[3] = current->blocked.sig[3];
-               __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+               err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
        } else
-               __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
+               err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int));
 
        /* Store registers */
-       __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
-       __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
-       __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
-        __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
+       err |= __put_user(regs->pc, &uc->mcontext.greg [SVR4_PC]);
+       err |= __put_user(regs->npc, &uc->mcontext.greg [SVR4_NPC]);
+       err |= __put_user(regs->psr, &uc->mcontext.greg [SVR4_PSR]);
+       err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
        
        /* Copy g [1..7] and o [0..7] registers */
-       copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
-       copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+       err |= copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
+       err |= copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
 
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &uc->stack.sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
-       __put_user(current->sas_ss_size, &uc->stack.size);
+       err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+       err |= __put_user(current->sas_ss_size, &uc->stack.size);
 
        /* The register file is not saved
         * we have already stuffed all of it with sync_user_stack
         */
-       return 0;
+       return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
        lock_kernel();
@@ -905,15 +944,17 @@ asmlinkage int svr4_setcontext (svr4_ucontext_t *c, struct pt_regs *regs)
        spin_unlock_irq(&current->sigmask_lock);
        regs->pc = pc;
        regs->npc = npc | 1;
-       __get_user(regs->y, &((*gr) [SVR4_Y]));
-       __get_user(psr, &((*gr) [SVR4_PSR]));
+       err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
+       err |= __get_user(psr, &((*gr) [SVR4_PSR]));
        regs->psr &= ~(PSR_ICC);
        regs->psr |= (psr & PSR_ICC);
 
        /* Restore g[1..7] and o[0..7] registers */
-       copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
-       copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
-       return 0;
+       err |= copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+                             sizeof (long) * 7);
+       err |= copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+                             sizeof (long) * 8);
+       return (err ? -EFAULT : 0);
 
 sigsegv_and_return:
        lock_kernel();
index 0d9c43e9d72a5e87aff9190d288018d85cf6e252..df5208b1acae19245323a6575add7dcbc7b93c98 100644 (file)
@@ -159,7 +159,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
                        local_flush_tlb_mm(mm);
                } else {
                        xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
-                       if(mm->count == 1 && current->mm == mm)
+                       if(atomic_read(&mm->count) == 1 && current->mm == mm)
                                mm->cpu_vm_mask = (1 << smp_processor_id());
                }
        }
@@ -275,3 +275,26 @@ int setup_profiling_timer(unsigned int multiplier)
 
        return 0;
 }
+
+int smp_bogo_info(char *buf)
+{
+       int len = 0, i;
+       
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_present_map & (1 << i))
+                       len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", 
+                                       i,
+                                       cpu_data[i].udelay_val/500000,
+                                       (cpu_data[i].udelay_val/5000)%100);
+       return len;
+}
+
+int smp_info(char *buf)
+{
+       int len = 0, i;
+       
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_present_map & (1 << i))
+                       len += sprintf(buf + len, "CPU%d\t\t: online\n", i);
+       return len;
+}
index e6aad243d2e583d26bbbcad8c625de66ff678726..2e14b5b4b1ad3428bc340406d4eba0c2638519d5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.65 1998/06/04 09:54:50 jj Exp $
+/* $Id: sparc_ksyms.c,v 1.70 1998/09/17 11:04:55 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -85,11 +85,6 @@ __attribute__((section("__ksymtab"))) =                              \
 
 /* used by various drivers */
 EXPORT_SYMBOL(sparc_cpu_model);
-#ifdef __SMP__
-EXPORT_SYMBOL(klock_info);
-#endif
-EXPORT_SYMBOL_PRIVATE(_lock_kernel);
-EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
 EXPORT_SYMBOL_PRIVATE(_spinlock_waitfor);
 #ifdef SPIN_LOCK_DEBUG
 EXPORT_SYMBOL(_spin_lock);
@@ -119,14 +114,10 @@ EXPORT_SYMBOL_PRIVATE(_rw_write_enter);
 EXPORT_SYMBOL(__sparc_bh_counter);
 #ifdef __SMP__
 #ifdef DEBUG_IRQLOCK
-EXPORT_SYMBOL(irq_enter);
-EXPORT_SYMBOL(irq_exit);
 EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_cli);
 #else
-EXPORT_SYMBOL_PRIVATE(_irq_enter);
-EXPORT_SYMBOL_PRIVATE(_irq_exit);
 EXPORT_SYMBOL_PRIVATE(_global_restore_flags);
 EXPORT_SYMBOL_PRIVATE(_global_sti);
 EXPORT_SYMBOL_PRIVATE(_global_cli);
@@ -134,7 +125,10 @@ EXPORT_SYMBOL_PRIVATE(_global_cli);
 #endif
 
 EXPORT_SYMBOL(page_offset);
+
+#ifndef CONFIG_SUN4
 EXPORT_SYMBOL(stack_top);
+#endif
 
 /* Atomic operations. */
 EXPORT_SYMBOL_PRIVATE(_atomic_add);
@@ -227,7 +221,7 @@ EXPORT_SYMBOL(__prom_getsibling);
 
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL_NOVERS(memscan);
 EXPORT_SYMBOL(strlen);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
@@ -235,7 +229,7 @@ EXPORT_SYMBOL(strncpy);
 EXPORT_SYMBOL(strcat);
 EXPORT_SYMBOL(strncat);
 EXPORT_SYMBOL(strcmp);
-EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL_NOVERS(strncmp);
 EXPORT_SYMBOL(strchr);
 EXPORT_SYMBOL(strrchr);
 EXPORT_SYMBOL(strpbrk);
index cda7564dc0c937ab5cffbc3d584e3ef85425931d..cafd619553219bf8209228d70d1ce3c66309076e 100644 (file)
@@ -121,7 +121,7 @@ static void sun4c_clear_clock_irq(void)
 {
        volatile unsigned int clear_intr;
 #ifdef CONFIG_SUN4
-       if( idprom->id_machtype == SM_SUN4 | SM_4_260 
+       if (idprom->id_machtype == (SM_SUN4 | SM_4_260)
          clear_intr = sun4_timer.timer_limit10;
        else
 #endif
@@ -146,7 +146,7 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct
         * the cache chip on the sun4c.
         */
 #ifdef CONFIG_SUN4
-       if (idprom->id_machtype == SM_SUN4 | SM_4_260)
+       if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
                sun4c_timers = &sun4_timer;
        else
 #endif
@@ -171,7 +171,10 @@ __initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct
                prom_halt();
        }
     
+#if 0
+       /* This does not work on 4/330 */
        sun4c_enable_irq(10);
+#endif
        claim_ticker14(NULL, PROFILE_IRQ, 0);
 }
 
index 3a37df0c91198feffa4c0f6cb84cd77a4a03c307..b1a111746b3fe00cabf03a28a983139419c2b0a9 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: sun4d_irq.c,v 1.14 1998/06/04 09:54:47 jj Exp $
+/*  $Id: sun4d_irq.c,v 1.15 1998/09/29 09:46:12 davem Exp $
  *  arch/sparc/kernel/sun4d_irq.c:
  *                     SS1000/SC2000 interrupt handling.
  *
@@ -284,11 +284,12 @@ int sun4d_request_irq(unsigned int irq,
        /* If this is flagged as statically allocated then we use our
         * private struct which is never freed.
         */
-       if (irqflags & SA_STATIC_ALLOC)
+       if (irqflags & SA_STATIC_ALLOC) {
            if (static_irq_count < MAX_STATIC_ALLOC)
                action = &static_irqaction[static_irq_count++];
            else
                printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",irq, devname);
+       }
        
        if (action == NULL)
            action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
index 5563a0cc66eaba4e66f30fe6c0050ae8a889cdda..684b2c2ad5a8ba8b36c1e1b6cff58af73bdd1d9c 100644 (file)
@@ -57,7 +57,6 @@ extern unsigned char boot_cpu_id;
 extern int smp_activated;
 extern volatile int cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
-extern struct klock_info klock_info;
 extern volatile unsigned long ipi_count;
 extern volatile int smp_process_available;
 extern volatile int smp_commenced;
@@ -71,31 +70,6 @@ extern int __smp4d_processor_id(void);
 #define SMP_PRINTK(x)
 #endif
 
-int smp4d_bogo_info(char *buf)
-{
-       int len = 0, i;
-       
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_present_map & (1 << i))
-                       len += sprintf(buf + len, "Cpu%dBogo\t: %lu.%02lu\n", 
-                                       i,
-                                       cpu_data[i].udelay_val/500000,
-                                       (cpu_data[i].udelay_val/5000)%100);
-       return len;
-}
-
-int smp4d_info(char *buf)
-{
-       int len = 0, i;
-       
-       for (i = 0; i < NR_CPUS; i++)
-               if (cpu_present_map & (1 << i))
-                       len += sprintf(buf + len, "CPU%d\t\t: %s\n", 
-                                       i,
-                                       (klock_info.akp == i) ? "akp" : "online");
-       return len;
-}
-
 static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
 {
        __asm__ __volatile__("swap [%1], %0\n\t" :
@@ -216,7 +190,6 @@ __initfunc(void smp4d_boot_cpus(void))
                mid_xlate[i] = i;
        cpu_number_map[boot_cpu_id] = 0;
        __cpu_logical_map[0] = boot_cpu_id;
-       klock_info.akp = boot_cpu_id;
        current->processor = boot_cpu_id;
        smp_store_cpu_info(boot_cpu_id);
        smp_setup_percpu_timer();
@@ -436,6 +409,8 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
 /* Protects counters touched during level14 ticker */
 static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
 
+#ifdef CONFIG_PROFILE
+
 /* 32-bit Sparc specific profiling function. */
 static inline void sparc_do_profile(unsigned long pc)
 {
@@ -454,6 +429,8 @@ static inline void sparc_do_profile(unsigned long pc)
        }
 }
 
+#endif
+
 extern unsigned int prof_multiplier[NR_CPUS];
 extern unsigned int prof_counter[NR_CPUS];
 
@@ -479,9 +456,10 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
                show_leds(cpu);
        }
 
+#ifdef CONFIG_PROFILE
        if(!user_mode(regs))
                sparc_do_profile(regs->pc);
-
+#endif
        if(!--prof_counter[cpu]) {
                int user = user_mode(regs);
                if(current->pid) {
@@ -559,8 +537,6 @@ __initfunc(void sun4d_init_smp(void))
        BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
        BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(smp_bogo_info, smp4d_bogo_info, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(smp_info, smp4d_info, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(__smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
        
        for (i = 0; i < NR_CPUS; i++) {
index 68c04014fbb03d7c4ac7372bc258ec3a4dd1ffcc..bd6fc8e20607216f7c3826e291051603d8c6b106 100644 (file)
@@ -47,10 +47,12 @@ unsigned long *irq_rcvreg = &dummy;
  *
  * take an encoded intr value and lookup if it's valid
  * then get the mask bits that match from irq_mask
+ *
+ * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
  */
 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,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
        0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
 };
 
index 597ee76658b3e8d4b1ee4bdaf7bd3dd0effa3caf..8e0056c3f371f631e6c07c48034892c6337ea817 100644 (file)
@@ -53,7 +53,6 @@ extern unsigned char boot_cpu_id;
 extern int smp_activated;
 extern volatile int cpu_number_map[NR_CPUS];
 extern volatile int __cpu_logical_map[NR_CPUS];
-extern struct klock_info klock_info;
 extern volatile unsigned long ipi_count;
 extern volatile int smp_process_available;
 extern volatile int smp_commenced;
@@ -67,30 +66,6 @@ extern int __smp4m_processor_id(void);
 #define SMP_PRINTK(x)
 #endif
 
-int smp4m_bogo_info(char *buf)
-{
-       return sprintf(buf,
-            "Cpu0Bogo\t: %lu.%02lu\n"
-           "Cpu1Bogo\t: %lu.%02lu\n"
-           "Cpu2Bogo\t: %lu.%02lu\n"
-           "Cpu3Bogo\t: %lu.%02lu\n",
-           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);
-}
-
-int smp4m_info(char *buf)
-{
-       return sprintf(buf,
-"        CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n"
-"State:  %s\t\t%s\t\t%s\t\t%s\n",
-(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline",
-(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline",
-(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline",
-(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline");
-}
-
 static inline unsigned long swap(volatile unsigned long *ptr, unsigned long val)
 {
        __asm__ __volatile__("swap [%1], %0\n\t" :
@@ -186,7 +161,6 @@ __initfunc(void smp4m_boot_cpus(void))
        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;
-       klock_info.akp = boot_cpu_id;
        current->processor = boot_cpu_id;
        smp_store_cpu_info(boot_cpu_id);
        set_irq_udt(mid_xlate[boot_cpu_id]);
@@ -468,6 +442,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 
        if(!--prof_counter[cpu]) {
                int user = user_mode(regs);
+
                if(current->pid) {
                        update_one_process(current, 1, user, !user, cpu);
 
@@ -534,7 +509,5 @@ __initfunc(void sun4m_init_smp(void))
        BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
        BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(smp_bogo_info, smp4m_bogo_info, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(smp_info, smp4m_info, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(__smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
 }
index 7529c679a7edca88ac7432e80e08032b62688f4b..991e651343ed1351381997102c741d6b3251fce6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.46 1998/08/03 23:58:01 davem Exp $
+/* $Id: sys_sparc.c,v 1.48 1998/09/07 09:19:34 davem Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -206,6 +206,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
                }
        }
 
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file, addr, len, prot, flags, off);
 
 out_putf:
@@ -298,6 +299,11 @@ sys_rt_sigaction(int sig, const struct sigaction *act, struct sigaction *oact,
        if (sigsetsize != sizeof(sigset_t))
                return -EINVAL;
 
+       /* All tasks which use RT signals (effectively) use
+        * new style signals.
+        */
+       current->tss.new_signal = 1;
+
        if (act) {
                new_ka.ka_restorer = restorer;
                if (copy_from_user(&new_ka.sa, act, sizeof(*act)))
index d54c9352d80df1a38a8ab2b5c0db57d402899401..69d959afd4ae3bd0689d509c17e47ef6a1fd8eff 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.91 1998/06/16 04:37:04 davem Exp $
+/* $Id: sys_sunos.c,v 1.92 1998/08/31 03:40:53 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -118,6 +118,7 @@ asmlinkage unsigned long sunos_mmap(unsigned long addr, unsigned long len,
                }
        }
 
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file, addr, len, prot, flags, off);
        if(!ret_type)
                retval = ((retval < PAGE_OFFSET) ? 0 : retval);
index 08aae84c9857e1f1d41882b51953de7d40da3567..5508f850ae2d9662b8168157d5d3aa4de861476b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.75 1998/07/28 13:07:48 jj Exp $
+/* $Id: systbls.S,v 1.80 1998/09/21 05:04:59 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  */
 
-#include <asm/cprefix.h>
-
        .data
        .align 4
 
        /* First, the Linux native syscall table. */
 
-       .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)
-/*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_nis_syscall), C_LABEL(sys_mknod)
-/*15*/ .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sparc_brk)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_lseek)
-/*20*/ .long C_LABEL(sys_getpid), C_LABEL(sys_capget), C_LABEL(sys_capset)
-       .long C_LABEL(sys_setuid), C_LABEL(sys_getuid)
-/*25*/ .long C_LABEL(sys_time), C_LABEL(sys_ptrace), C_LABEL(sys_alarm)
-       .long C_LABEL(sys_sigaltstack), C_LABEL(sys_pause)
-/*30*/ .long C_LABEL(sys_utime), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_access), C_LABEL(sys_nice), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_sync), C_LABEL(sys_kill), C_LABEL(sys_newstat)
-       .long C_LABEL(sys_sendfile), C_LABEL(sys_newlstat), C_LABEL(sys_dup)
-       .long C_LABEL(sys_pipe), C_LABEL(sys_times), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_setgid), C_LABEL(sys_getgid)
-       .long C_LABEL(sys_signal), C_LABEL(sys_geteuid)
-/*50*/ .long C_LABEL(sys_getegid), C_LABEL(sys_acct), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_ioctl), C_LABEL(sys_reboot)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_symlink), C_LABEL(sys_readlink)
-       .long C_LABEL(sys_execve), C_LABEL(sys_umask), C_LABEL(sys_chroot)
-       .long C_LABEL(sys_newfstat), C_LABEL(sys_nis_syscall), C_LABEL(sys_getpagesize)
-       .long C_LABEL(sys_msync), C_LABEL(sys_vfork), C_LABEL(sys_pread)
-       .long C_LABEL(sys_pwrite), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_mmap), C_LABEL(sys_nis_syscall), C_LABEL(sys_munmap)
-       .long C_LABEL(sys_mprotect), C_LABEL(sys_nis_syscall), C_LABEL(sys_vhangup)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getgroups)
-       .long C_LABEL(sys_setgroups), C_LABEL(sys_getpgrp), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_setitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_swapon)
-       .long C_LABEL(sys_getitimer), C_LABEL(sys_nis_syscall), C_LABEL(sys_sethostname)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_dup2), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_fcntl), C_LABEL(sys_select), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*100*/        .long C_LABEL(sys_getpriority), C_LABEL(sys_rt_sigreturn)
-       .long C_LABEL(sys_rt_sigaction), C_LABEL(sys_rt_sigprocmask)
-       .long C_LABEL(sys_rt_sigpending), C_LABEL(sys_rt_sigtimedwait)
-       .long C_LABEL(sys_rt_sigqueueinfo), C_LABEL(sys_rt_sigsuspend)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getcwd), C_LABEL(sys_readv)
-       .long C_LABEL(sys_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
-       .long C_LABEL(sys_fchmod), C_LABEL(sys_nis_syscall), C_LABEL(sys_setreuid)
-       .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
-       .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_getrlimit)
-       .long C_LABEL(sys_setrlimit), C_LABEL(sys_nis_syscall), C_LABEL(sys_prctl)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-/*150*/        .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_poll), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_statfs), C_LABEL(sys_fstatfs)
-       .long C_LABEL(sys_umount), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_getdomainname), C_LABEL(sys_setdomainname)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_quotactl), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_mount), C_LABEL(sys_ustat), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_getdents), C_LABEL(sys_setsid)
-       .long C_LABEL(sys_fchdir), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_sigpending), C_LABEL(sys_query_module)
-       .long C_LABEL(sys_setpgid), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
-       .long C_LABEL(sys_personality), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
-/*200*/        .long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
-       .long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_idle), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_waitpid), C_LABEL(sys_swapoff), C_LABEL(sys_sysinfo)
-       .long C_LABEL(sys_ipc), C_LABEL(sys_sigreturn), C_LABEL(sys_clone)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_adjtimex), C_LABEL(sys_sigprocmask)
-       .long C_LABEL(sys_create_module), C_LABEL(sys_delete_module)
-       .long C_LABEL(sys_get_kernel_syms), C_LABEL(sys_getpgid), C_LABEL(sys_bdflush)
-       .long C_LABEL(sys_sysfs), C_LABEL(sys_nis_syscall), C_LABEL(sys_setfsuid)
-       .long C_LABEL(sys_setfsgid), C_LABEL(sys_select), C_LABEL(sys_time)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_stime), C_LABEL(sys_nis_syscall)
-       .long C_LABEL(sys_nis_syscall), C_LABEL(sys_llseek)
-       /* "We are the Knights of the Forest of Ni!!" */
-       .long C_LABEL(sys_mlock)
-       .long C_LABEL(sys_munlock)
-       .long C_LABEL(sys_mlockall)
-/*240*/        .long C_LABEL(sys_munlockall)
-       .long C_LABEL(sys_sched_setparam)
-       .long C_LABEL(sys_sched_getparam)
-       .long C_LABEL(sys_sched_setscheduler)
-       .long C_LABEL(sys_sched_getscheduler)
-/*245*/        .long C_LABEL(sys_sched_yield)
-       .long C_LABEL(sys_sched_get_priority_max)
-       .long C_LABEL(sys_sched_get_priority_min)
-       .long C_LABEL(sys_sched_rr_get_interval)
-       .long C_LABEL(sys_nanosleep)
-/*250*/        .long C_LABEL(sys_mremap)
-       .long C_LABEL(sys_sysctl)
-       .long C_LABEL(sys_getsid)
-       .long C_LABEL(sys_fdatasync)
-       .long C_LABEL(sys_nfsservctl)
-/*255*/        .long C_LABEL(sys_aplib)
-       .long C_LABEL(sys_nis_syscall)
+       .globl sys_call_table
+sys_call_table:
+/*0*/  .long sys_nis_syscall, sys_exit, sys_fork, sys_read, sys_write
+/*5*/  .long sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .long sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
+/*15*/ .long sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
+/*25*/ .long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
+/*30*/ .long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
+/*35*/ .long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
+/*40*/ .long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
+/*45*/ .long sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/ .long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+/*55*/ .long sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/ .long sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+/*65*/ .long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall
+/*70*/ .long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+/*75*/ .long sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/ .long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+/*85*/ .long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/ .long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/        .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
+/*105*/        .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall
+/*110*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*115*/        .long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*120*/        .long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+/*125*/        .long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/        .long sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*135*/        .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall
+/*140*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+/*145*/        .long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
+/*150*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
+/*155*/        .long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/        .long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
+/*165*/        .long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+/*175*/        .long sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/        .long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+/*185*/        .long sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/        .long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*195*/        .long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/        .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
+/*205*/        .long sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/        .long sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+/*215*/        .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/        .long sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+/*225*/        .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/        .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+                                         /* "We are the Knights of the Forest of Ni!!" */
+/*235*/        .long sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/        .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
+/*245*/        .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/        .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*255*/        .long sys_aplib, sys_nis_syscall
 
        /* Now the SunOS syscall table. */
 
        .align 4
-       .globl C_LABEL(sunos_sys_table)
-C_LABEL(sunos_sys_table):
-/*0*/  .long C_LABEL(sunos_indir), C_LABEL(sys_exit), C_LABEL(sys_fork)
-       .long C_LABEL(sunos_read), C_LABEL(sunos_write), C_LABEL(sunos_open)
-       .long C_LABEL(sys_close), C_LABEL(sunos_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(sunos_nosys), C_LABEL(sys_mknod)
-       .long C_LABEL(sys_chmod), C_LABEL(sys_lchown), C_LABEL(sunos_brk)
-       .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 C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace)
-       .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(sunos_nosys)
-       .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 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), 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)
-       .long C_LABEL(sys_mprotect), C_LABEL(sunos_madvise), C_LABEL(sys_vhangup)
-       .long C_LABEL(sunos_nosys), C_LABEL(sunos_mincore), C_LABEL(sys_getgroups)
-       .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 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(sunos_socket)
-       .long C_LABEL(sys_connect), C_LABEL(sunos_accept)
-/*100*/        .long C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv)
-       .long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt)
-       .long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sunos_sigaction)
-       .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(sunos_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv)
-       .long C_LABEL(sunos_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
-       .long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
-       .long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
-       .long C_LABEL(sys_ftruncate), C_LABEL(sys_flock), C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_sendto), C_LABEL(sys_shutdown), C_LABEL(sys_socketpair)
-       .long C_LABEL(sys_mkdir), C_LABEL(sys_rmdir), C_LABEL(sys_utimes)
-       .long C_LABEL(sys_sigreturn), C_LABEL(sunos_nosys), C_LABEL(sys_getpeername)
-       .long C_LABEL(sunos_gethostid), C_LABEL(sunos_nosys), C_LABEL(sys_getrlimit)
-       .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(sys_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(sys_getdomainname), C_LABEL(sys_setdomainname)
-       .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_semsys)
-       .long C_LABEL(sunos_msgsys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit)
-       .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid)
-       .long C_LABEL(sys_fchdir), 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(sys_sigpending), C_LABEL(sunos_nosys)
-       .long C_LABEL(sys_setpgid), C_LABEL(sunos_pathconf), C_LABEL(sunos_fpathconf)
-       .long C_LABEL(sunos_sysconf), C_LABEL(sunos_uname), 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(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-/*200*/        .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(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(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(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(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(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(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(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(sunos_nosys), C_LABEL(sunos_nosys)
-/*250*/        .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
-       .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sys_aplib)
+       .globl sunos_sys_table
+sunos_sys_table:
+/*0*/  .long sunos_indir, sys_exit, sys_fork
+       .long sunos_read, sunos_write, sunos_open
+       .long sys_close, sunos_wait4, sys_creat
+       .long sys_link, sys_unlink, sunos_execv
+       .long sys_chdir, sunos_nosys, sys_mknod
+       .long sys_chmod, sys_lchown, sunos_brk
+       .long sunos_nosys, sys_lseek, sunos_getpid
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_getuid, sunos_nosys, sys_ptrace
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sys_access, sunos_nosys, sunos_nosys
+       .long sys_sync, sys_kill, sys_newstat
+       .long sunos_nosys, sys_newlstat, sys_dup
+       .long sys_pipe, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_getgid
+       .long sunos_nosys, sunos_nosys
+/*50*/ .long sunos_nosys, sys_acct, sunos_nosys
+       .long sunos_mctl, sunos_ioctl, sys_reboot
+       .long sunos_nosys, sys_symlink, sys_readlink
+       .long sys_execve, sys_umask, sys_chroot
+       .long sys_newfstat, sunos_nosys, sys_getpagesize
+       .long sys_msync, sys_vfork, sunos_nosys
+       .long sunos_nosys, sunos_sbrk, sunos_sstk
+       .long sunos_mmap, sunos_vadvise, sys_munmap
+       .long sys_mprotect, sunos_madvise, sys_vhangup
+       .long sunos_nosys, sunos_mincore, sys_getgroups
+       .long sys_setgroups, sys_getpgrp, sunos_setpgrp
+       .long sys_setitimer, sunos_nosys, sys_swapon
+       .long sys_getitimer, sys_gethostname, sys_sethostname
+       .long sunos_getdtablesize, sys_dup2, sunos_nop
+       .long sys_fcntl, sunos_select, sunos_nop
+       .long sys_fsync, sys_setpriority, sunos_socket
+       .long sys_connect, sunos_accept
+/*100*/        .long sys_getpriority, sunos_send, sunos_recv
+       .long sunos_nosys, sys_bind, sunos_setsockopt
+       .long sys_listen, sunos_nosys, sunos_sigaction
+       .long sunos_sigblock, sunos_sigsetmask, sys_sigpause
+       .long sys_sigstack, sys_recvmsg, sys_sendmsg
+       .long sunos_nosys, sys_gettimeofday, sys_getrusage
+       .long sunos_getsockopt, sunos_nosys, sunos_readv
+       .long sunos_writev, sys_settimeofday, sys_fchown
+       .long sys_fchmod, sys_recvfrom, sys_setreuid
+       .long sys_setregid, sys_rename, sys_truncate
+       .long sys_ftruncate, sys_flock, sunos_nosys
+       .long sys_sendto, sys_shutdown, sys_socketpair
+       .long sys_mkdir, sys_rmdir, sys_utimes
+       .long sys_sigreturn, sunos_nosys, sys_getpeername
+       .long sunos_gethostid, sunos_nosys, sys_getrlimit
+       .long sys_setrlimit, sunos_killpg, sunos_nosys
+       .long sunos_nosys, sunos_nosys
+/*150*/        .long sys_getsockname, sunos_nosys, sunos_nosys
+       .long sys_poll, sunos_nosys, sunos_nosys
+       .long sunos_getdirentries, sys_statfs, sys_fstatfs
+       .long sys_umount, sunos_nosys, sunos_nosys
+       .long sys_getdomainname, sys_setdomainname
+       .long sunos_nosys, sys_quotactl, sunos_nosys
+       .long sunos_mount, sys_ustat, sunos_semsys
+       .long sunos_msgsys, sunos_shmsys, sunos_audit
+       .long sunos_nosys, sunos_getdents, sys_setsid
+       .long sys_fchdir, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sys_sigpending, sunos_nosys
+       .long sys_setpgid, sunos_pathconf, sunos_fpathconf
+       .long sunos_sysconf, sunos_uname, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/        .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys
+/*250*/        .long sunos_nosys, sunos_nosys, sunos_nosys
+       .long sunos_nosys, sunos_nosys, sys_aplib
index dba16891c79c2e121365f50d56390eab333561dc..eac95ec9896af79cf12f4cf6ffc7ea54ce5c1089 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.33 1998/07/28 16:52:48 jj Exp $
+/* $Id: time.c,v 1.39 1998/09/29 09:46:15 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -7,6 +7,9 @@
  * Chris Davis (cdavis@cois.on.ca) 03/27/1998
  * Added support for the intersil on the sun4/4200
  *
+ * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998
+ * Support for MicroSPARC-IIep, PCI CPU.
+ *
  * This file handles the Sparc specific time handling details.
  */
 #include <linux/config.h>
@@ -19,6 +22,7 @@
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/init.h>
+#include <linux/pci.h>
 
 #include <asm/oplib.h>
 #include <asm/segment.h>
@@ -36,6 +40,7 @@ enum sparc_clock_type sp_clock_typ;
 struct mostek48t02 *mstk48t02_regs = 0;
 struct mostek48t08 *mstk48t08_regs = 0;
 static int set_rtc_mmss(unsigned long);
+static void sbus_do_settimeofday(struct timeval *tv);
 
 #ifdef CONFIG_SUN4
 struct intersil *intersil_clock;
@@ -71,10 +76,13 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        static long last_rtc_update=0;
 
 #ifdef CONFIG_SUN4
-       int temp;
-        intersil_read_intr(intersil_clock, temp);
-       /* re-enable the irq */
-       enable_pil_irq(10);
+       if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
+   (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
+               int temp;
+               intersil_read_intr(intersil_clock, temp);
+               /* re-enable the irq */
+               enable_pil_irq(10);
+       }
 #endif
        clear_clock_irq();
 
@@ -83,11 +91,12 @@ void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        /* Determine when to update the Mostek clock. */
        if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
            xtime.tv_usec > 500000 - (tick >> 1) &&
-           xtime.tv_usec < 500000 + (tick >> 1))
+           xtime.tv_usec < 500000 + (tick >> 1)) {
          if (set_rtc_mmss(xtime.tv_sec) == 0)
            last_rtc_update = xtime.tv_sec;
          else
            last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+       }
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -316,7 +325,7 @@ static __inline__ void clock_probe(void)
                kick_start_clock();
 }
 
-__initfunc(void time_init(void))
+__initfunc(void sbus_time_init(void))
 {
        unsigned int year, mon, day, hour, min, sec;
        struct mostek48t02 *mregs;
@@ -327,6 +336,8 @@ __initfunc(void time_init(void))
 #endif
 
        do_get_fast_time = do_gettimeofday;
+       BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
+       btfixup();
 
 #if CONFIG_AP1000
        init_timers(timer_interrupt);
@@ -344,7 +355,6 @@ __initfunc(void time_init(void))
 #ifdef CONFIG_SUN4
        if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
 #endif
-
        mregs = mstk48t02_regs;
        if(!mregs) {
                prom_printf("Something wrong, clock regs not mapped yet.\n");
@@ -397,7 +407,19 @@ __initfunc(void time_init(void))
        __sti();
 }
 
-static __inline__ unsigned long do_gettimeoffset(void)
+__initfunc(void time_init(void))
+{
+#ifdef CONFIG_PCI
+       extern void pci_time_init(void);
+       if (pci_present()) {
+               pci_time_init();
+               return;
+       }
+#endif
+       sbus_time_init();
+}
+
+extern __inline__ unsigned long do_gettimeoffset(void)
 {
        unsigned long offset = 0;
        unsigned int count;
@@ -458,6 +480,11 @@ void do_gettimeofday(struct timeval *tv)
 }
 
 void do_settimeofday(struct timeval *tv)
+{
+       bus_do_settimeofday(tv);
+}
+
+static void sbus_do_settimeofday(struct timeval *tv)
 {
        cli();
 #if !CONFIG_AP1000
index 015d05357ef4ab380c436c8c388fe20b95596a57..86d63240933669a3b85b544f278e12b6b9e1580c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.56 1998/04/06 16:08:32 jj Exp $
+/* $Id: traps.c,v 1.57 1998/09/17 11:04:51 jj Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -242,8 +242,8 @@ extern int do_mathemu(struct pt_regs *, struct task_struct *);
 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
                 unsigned long psr)
 {
-       static calls = 0;
-       int ret;
+       static int calls = 0;
+       int ret = 0;
 #ifndef __SMP__
        struct task_struct *fpt = last_task_used_math;
 #else
index fceaf7a4b2dc69611ba0adfd4bbd92c752d6900a..728cbf9bd703292d85d8bc151f2fc5526f8afb89 100644 (file)
@@ -3,7 +3,7 @@
  *  Copyright(C) 1995 Linus Torvalds
  *  Copyright(C) 1996 David S. Miller
  *  Copyright(C) 1996 Eddie C. Dost
- *  Copyright(C) 1996 Jakub Jelinek
+ *  Copyright(C) 1996,1998 Jakub Jelinek
  *
  * derived from:
  *     e-mail between David and Eddie.
 
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
+#include <asm/asmmacro.h>
 
 #define EX(x,y,a,b,z)                          \
 98:    x,y;                                    \
        .section .fixup,z##alloc,z##execinstr;  \
        .align  4;                              \
-99:    retl;                                   \
-        a, b, %o0;                             \
+99:    ba fixupretl;                           \
+        a, b, %g3;                             \
        .section __ex_table,z##alloc;           \
        .align  4;                              \
        .word   98b, 99b;                       \
@@ -31,8 +32,8 @@
        .section .fixup,z##alloc,z##execinstr;  \
        .align  4;                              \
 99:    c, d, e;                                \
-       retl;                                   \
-        a, b, %o0;                             \
+       ba fixupretl;                           \
+        a, b, %g3;                             \
        .section __ex_table,z##alloc;           \
        .align  4;                              \
        .word   98b, 99b;                       \
@@ -340,7 +341,7 @@ short_aligned_end:
         andcc  %o2, 4, %g0
 
        EXO2(ld [%o1 + 0x00], %g2,#)
-       EX(ld   [%o1 + 0x04], %g3, sub %o2, 4,#)
+       EXO2(ld [%o1 + 0x04], %g3,#)
        add     %o1, 8, %o1
        EXO2(st %g2, [%o0 + 0x00],#)
        EX(st   %g3, [%o0 + 0x04], sub %o2, 4,#)
@@ -352,16 +353,32 @@ short_aligned_end:
        .section .fixup,#alloc,#execinstr
        .align  4
 97:
-       retl
-        mov    %o2, %o0
+       mov     %o2, %g3
+fixupretl:
+       GET_PAGE_OFFSET(g1)
+       cmp     %o0, %g1
+       blu     1f
+        cmp    %o1, %g1
+       bgeu    1f
+        nop
+       save    %sp, -64, %sp
+       mov     %i0, %o0
+       call    __bzero
+        mov    %g3, %o1
+       restore
+1:     retl
+        mov    %g3, %o0
+
 /* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
 50:
 /* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
  * happens. This is derived from the amount ldd reads, st stores, etc.
  * x = g2 % 12;
- * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
+ * g3 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? 0 : (x - 4) * 4);
+ * o0 += (g2 / 12) * 32;
  */
        cmp     %g2, 12
+       add     %o0, %g7, %o0
        bcs     1f
         cmp    %g2, 24
        bcs     2f
@@ -370,84 +387,97 @@ short_aligned_end:
         nop
        sub     %g2, 12, %g2
        sub     %g7, 32, %g7
-3:
-       sub     %g2, 12, %g2
+3:     sub     %g2, 12, %g2
        sub     %g7, 32, %g7
-2:
-       sub     %g2, 12, %g2
+2:     sub     %g2, 12, %g2
        sub     %g7, 32, %g7
-1:
-       cmp     %g2, 4
-       bcs,a   1f
-        sll    %g2, 3, %g2
+1:     cmp     %g2, 4
+       bcs,a   60f
+        clr    %g2
        sub     %g2, 4, %g2
        sll     %g2, 2, %g2
-1:
-       and     %g1, 0x7f, %o0
-       add     %o0, %g7, %o0
-       retl
-        sub    %o0, %g2, %o0
+60:    and     %g1, 0x7f, %g3
+       sub     %o0, %g7, %o0
+       add     %g3, %g7, %g3
+       ba      fixupretl
+        sub    %g3, %g2, %g3
 51:
 /* i = 41 - g2; j = i % 6;
- * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;        
+ * g3 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : 16;
+ * o0 -= (i / 6) * 16 + 16;
  */
        neg     %g2
        and     %g1, 0xf, %g1
        add     %g2, 41, %g2
-1:
-       cmp     %g2, 6
+       add     %o0, %g1, %o0
+1:     cmp     %g2, 6
        bcs,a   2f
         cmp    %g2, 4
        add     %g1, 16, %g1
        b       1b
         sub    %g2, 6, %g2
-2:
-       bcs,a   3f
-        inc    %g2
-       sub     %g2, 3, %g2
-       b       2f
-        sll    %g2, 3, %g2
-3:
+2:     bcc,a   2f
+        mov    16, %g2
+       inc     %g2
        sll     %g2, 2, %g2
-2:
-       retl
-        add    %g1, %g2, %o0
+2:     add     %g1, %g2, %g3
+       ba      fixupretl
+        sub    %o0, %g3, %o0
 52:
-/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
-       and     %g2, 0xfffffff8, %g4
+/* g3 = g1 + g7 - (g2 / 8) * 32 + (g2 & 4) ? (g2 & 3) * 8 : 0;
+   o0 += (g2 / 8) * 32 */
+       andn    %g2, 7, %g4
+       add     %o0, %g7, %o0
+       andcc   %g2, 4, %g0
        and     %g2, 3, %g2
        sll     %g4, 2, %g4
        sll     %g2, 3, %g2
-       add     %g2, %g4, %g2
-       b,a     1b
+       bne     60b
+        sub    %g7, %g4, %g7
+       ba      60b
+        clr    %g2
 53:
-/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
+/* g3 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 4) ? (g2 & 3) * 2 : 0;
+   o0 += (g2 & 8) */
        and     %g2, 3, %g4
-       and     %g2, 0xfffffff8, %g2
+       andcc   %g2, 4, %g0
+       and     %g2, 8, %g2
        sll     %g4, 1, %g4
+       be      1f
+        add    %o0, %g2, %o0
        add     %g2, %g4, %g2
-       and     %o2, 0xf, %o0
-       add     %o0, %o3, %o0
-       retl
-        sub    %o0, %g2, %o0
+1:     and     %o2, 0xf, %g3
+       add     %g3, %o3, %g3
+       ba      fixupretl
+        sub    %g3, %g2, %g3
 54:
-/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
+/* g3 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 2) ? (g2 & 1) : 0;
+   o0 += (g2 / 4) * 2 */
        srl     %g2, 2, %o4
-       and     %g2, 1, %o1
-       sll     %o4, 1, %o4
+       and     %g2, 1, %o5
+       srl     %g2, 1, %g2
+       add     %o4, %o4, %o4
+       and     %o5, %g2, %o5
        and     %o2, 0xf, %o2
-       sub     %o3, %o1, %o3
+       add     %o0, %o4, %o0
+       sub     %o3, %o5, %o3
        sub     %o2, %o4, %o2
-       retl
-        add    %o2, %o3, %o0
+       ba      fixupretl
+        add    %o2, %o3, %g3
 55:
-/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
+/* i = 27 - g2;
+   g3 = (o2 & 1) + i / 4 * 2 + !(i & 3);
+   o0 -= i / 4 * 2 + 1 */
        neg     %g2
        and     %o2, 1, %o2
        add     %g2, 27, %g2
-       srl     %g2, 2, %o1
-       and     %g2, 1, %g2
-       sll     %o1, 1, %o1
-       add     %o2, %g2, %o0
-       retl
-        add    %o0, %o1, %o0
+       srl     %g2, 2, %o5
+       andcc   %g2, 3, %g0
+       mov     1, %g2
+       add     %o5, %o5, %o5
+       be,a    1f
+        clr    %g2
+1:     add     %g2, %o5, %g3
+       sub     %o0, %g3, %o0
+       ba      fixupretl
+        add    %g3, %o2, %g3
index 006cba5a8f503493f535efb6bdcc53518ca2260b..ef7d57431e19679b2b85b90a5f9572df9d076951 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: debuglocks.c,v 1.1 1997/05/08 18:13:34 davem Exp $
+/* $Id: debuglocks.c,v 1.3 1998/09/29 09:46:22 davem Exp $
  * debuglocks.c: Debugging versions of SMP locking primitives.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Anton Blanchard (anton@progsoc.uts.edu.au)
  */
 
 #include <linux/kernel.h>
  * number of the owner in the lowest two bits.
  */
 
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
+#define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A));
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _spin_lock(spinlock_t *lock)
+static inline void show(char *str, spinlock_t *lock, unsigned long caller)
 {
-       unsigned long caller;
-       unsigned long val;
        int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-again:
-       __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
-       if(val) {
-               while(lock->lock) {
-                       STUCK;
-                       barrier();
-               }
-               goto again;
-       }
-       lock->owner_pc = (cpu & 3) | (caller & ~3);
+       printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+               lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
 }
 
-int _spin_trylock(spinlock_t *lock)
+static inline void show_read(char *str, rwlock_t *lock, unsigned long caller)
 {
-       unsigned long val;
-       unsigned long caller;
        int cpu = smp_processor_id();
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
-       if(!val) {
-               /* We got it, record our identity for debugging. */
-               lock->owner_pc = (cpu & 3) | (caller & ~3);
-       }
-       return val == 0;
+       printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
+               lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
 }
 
-void _spin_unlock(spinlock_t *lock)
+static inline void show_write(char *str, rwlock_t *lock, unsigned long caller)
 {
-       lock->owner_pc = 0;
-       __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+       int cpu = smp_processor_id();
+
+       printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx) reader[0]=%08lx reader[1]=%08lx reader[2]=%08lx reader[3]=%08lx\n",
+               str, lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3,
+               lock->reader_pc[0],
+               lock->reader_pc[1],
+               lock->reader_pc[2],
+               lock->reader_pc[3]);
 }
 
 #undef INIT_STUCK
 #define INIT_STUCK 100000000
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _spin_lock_irq(spinlock_t *lock)
+void _do_spin_lock(spinlock_t *lock, char *str)
 {
        unsigned long caller;
        unsigned long val;
        int cpu = smp_processor_id();
        int stuck = INIT_STUCK;
 
-       __cli();
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
+       STORE_CALLER(caller);
+
 again:
        __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
        if(val) {
                while(lock->lock) {
-                       STUCK;
+                       if (!--stuck) {
+                               show(str, lock, caller);
+                               stuck = INIT_STUCK;
+                       }
                        barrier();
                }
                goto again;
@@ -98,69 +80,49 @@ again:
        lock->owner_pc = (cpu & 3) | (caller & ~3);
 }
 
-void _spin_unlock_irq(spinlock_t *lock)
-{
-       lock->owner_pc = 0;
-       __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
-       __sti();
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("spin_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller macro does __save_and_cli(flags) for us. */
-void _spin_lock_irqsave(spinlock_t *lock)
+int _spin_trylock(spinlock_t *lock)
 {
-       unsigned long caller;
        unsigned long val;
+       unsigned long caller;
        int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-again:
+       STORE_CALLER(caller);
+
        __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
-       if(val) {
-               while(lock->lock) {
-                       STUCK;
-                       barrier();
-               }
-               goto again;
+       if(!val) {
+               /* We got it, record our identity for debugging. */
+               lock->owner_pc = (cpu & 3) | (caller & ~3);
        }
-       lock->owner_pc = (cpu & 3) | (caller & ~3);
+       return val == 0;
 }
 
-void _spin_unlock_irqrestore(spinlock_t *lock)
+void _do_spin_unlock(spinlock_t *lock)
 {
        lock->owner_pc = 0;
-       __asm__ __volatile__("stb %%g0, [%0]" : : "r" (&(lock->lock)) : "memory");
+       barrier();
+       lock->lock = 0;
 }
 
 #undef INIT_STUCK
 #define INIT_STUCK 100000000
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_lock(rwlock_t *rw)
+void _do_read_lock(rwlock_t *rw, char *str)
 {
-       unsigned long flags;
        unsigned long caller;
        unsigned long val;
        int cpu = smp_processor_id();
        int stuck = INIT_STUCK;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __save_and_cli(flags);
+       STORE_CALLER(caller);
+
 wlock_again:
        __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
                while(rw->lock & 0xff) {
-                       STUCK;
+                       if (!--stuck) {
+                               show(str, (spinlock_t *)rw, caller);
+                               stuck = INIT_STUCK;
+                       }
                        barrier();
                }
                goto wlock_again;
@@ -169,291 +131,85 @@ clock_again:
        __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
                while(rw->lock & 0xff00) {
-                       STUCK;
+                       if (!--stuck) {
+                               show_read(str, rw, caller);
+                               stuck = INIT_STUCK;
+                       }
                        barrier();
                }
                goto clock_again;
        }
        (*((unsigned short *)&rw->lock))++;
+       rw->reader_pc[cpu] = caller;
        barrier();
        (*(((unsigned short *)&rw->lock)+1)) = 0;
-       __restore_flags(flags);
 }
 
 #undef INIT_STUCK
 #define INIT_STUCK 100000000
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_unlock(rwlock_t *rw)
-{
-       unsigned long flags, val, caller;
-       int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
-
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __save_and_cli(flags);
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff00) {
-                       STUCK;
-                       barrier();
-               }
-               goto clock_again;
-       }
-       (*((unsigned short *)&rw->lock))--;
-       barrier();
-       (*(((unsigned char *)&rw->lock)+2))=0;
-       __restore_flags(flags);
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _write_lock(rwlock_t *rw)
-{
-       unsigned long flags, val, caller;
-       int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
-
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __save_and_cli(flags);
-wlock_again:
-       __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff) {
-                       STUCK;
-                       barrier();
-               }
-               goto wlock_again;
-       }
-       rw->owner_pc = (cpu & 3) | (caller & ~3);
-       while(rw->lock & ~0xff) {
-               STUCK;
-               barrier();
-       }
-}
-
-void _write_unlock(rwlock_t *rw)
-{
-       rw->owner_pc = 0;
-       barrier();
-       rw->lock = 0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_lock_irq(rwlock_t *rw)
+void _do_read_unlock(rwlock_t *rw, char *str)
 {
        unsigned long caller;
        unsigned long val;
        int cpu = smp_processor_id();
        int stuck = INIT_STUCK;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __cli();
-wlock_again:
-       __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff) {
-                       STUCK;
-                       barrier();
-               }
-               goto wlock_again;
-       }
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff00) {
-                       STUCK;
-                       barrier();
-               }
-               goto clock_again;
-       }
-       (*((unsigned short *)&rw->lock))++;
-       barrier();
-       (*(((unsigned short *)&rw->lock)+1)) = 0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _read_unlock_irq(rwlock_t *rw)
-{
-       unsigned long val, caller;
-       int stuck = INIT_STUCK;
-       int cpu = smp_processor_id();
+       STORE_CALLER(caller);
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
 clock_again:
        __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
                while(rw->lock & 0xff00) {
-                       STUCK;
+                       if (!--stuck) {
+                               show_read(str, rw, caller);
+                               stuck = INIT_STUCK;
+                       }
                        barrier();
                }
                goto clock_again;
        }
        (*((unsigned short *)&rw->lock))--;
+       rw->reader_pc[cpu] = 0;
        barrier();
        (*(((unsigned char *)&rw->lock)+2))=0;
-       __sti();
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock_irq(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-void _write_lock_irq(rwlock_t *rw)
-{
-       unsigned long val, caller;
-       int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
-
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-       __cli();
-wlock_again:
-       __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff) {
-                       STUCK;
-                       barrier();
-               }
-               goto wlock_again;
-       }
-       rw->owner_pc = (cpu & 3) | (caller & ~3);
-       while(rw->lock & ~0xff) {
-               STUCK;
-               barrier();
-       }
-}
-
-void _write_unlock_irq(rwlock_t *rw)
-{
-       rw->owner_pc = 0;
-       barrier();
-       rw->lock = 0;
-       __sti();
 }
 
 #undef INIT_STUCK
 #define INIT_STUCK 100000000
 
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller does __save_and_cli(flags) for us. */
-void _read_lock_irqsave(rwlock_t *rw)
+void _do_write_lock(rwlock_t *rw, char *str)
 {
        unsigned long caller;
        unsigned long val;
        int cpu = smp_processor_id();
        int stuck = INIT_STUCK;
 
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-wlock_again:
-       __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff) {
-                       STUCK;
-                       barrier();
-               }
-               goto wlock_again;
-       }
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff00) {
-                       STUCK;
-                       barrier();
-               }
-               goto clock_again;
-       }
-       (*((unsigned short *)&rw->lock))++;
-       barrier();
-       (*(((unsigned short *)&rw->lock)+1)) = 0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("read_unlock_irqrestore(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
+       STORE_CALLER(caller);
 
-void _read_unlock_irqrestore(rwlock_t *rw)
-{
-       unsigned long val, caller;
-       int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
-
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
-clock_again:
-       __asm__ __volatile__("ldstub [%1 + 2], %0" : "=r" (val) : "r" (&(rw->lock)));
-       if(val) {
-               while(rw->lock & 0xff00) {
-                       STUCK;
-                       barrier();
-               }
-               goto clock_again;
-       }
-       (*((unsigned short *)&rw->lock))--;
-       barrier();
-       (*(((unsigned char *)&rw->lock)+2))=0;
-}
-
-#undef INIT_STUCK
-#define INIT_STUCK 100000000
-
-#undef STUCK
-#define STUCK \
-if(!--stuck) { printk("write_lock_irqsave(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", rw, cpu, caller, rw->owner_pc & ~3, rw->owner_pc & 3); stuck = INIT_STUCK; }
-
-/* Caller does __save_and_cli(flags) for us. */
-void _write_lock_irqsave(rwlock_t *rw)
-{
-       unsigned long val, caller;
-       int cpu = smp_processor_id();
-       int stuck = INIT_STUCK;
-
-       __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
 wlock_again:
        __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
        if(val) {
                while(rw->lock & 0xff) {
-                       STUCK;
+                       if (!--stuck) {
+                               show_write(str, rw, caller);
+                               stuck = INIT_STUCK;
+                       }
                        barrier();
                }
                goto wlock_again;
        }
        rw->owner_pc = (cpu & 3) | (caller & ~3);
        while(rw->lock & ~0xff) {
-               STUCK;
+               if (!--stuck) {
+                       show_write(str, rw, caller);
+                       stuck = INIT_STUCK;
+               }
                barrier();
        }
 }
 
-void _write_unlock_irqrestore(rwlock_t *rw)
+void _do_write_unlock(rwlock_t *rw)
 {
        rw->owner_pc = 0;
        barrier();
index 929b2a6f0d16d18c591a0bf68a86c0f742328f50..a9e51c67f7512a8298492d9f54fa166ee1ca0e14 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.31 1998/07/26 03:02:45 davem Exp $
+# $Id: Makefile,v 1.32 1998/08/16 16:02:25 ecd Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -12,7 +12,7 @@ O_OBJS   := fault.o init.o loadmmu.o generic.o asyncd.o extable.o btfixup.o
 ifeq ($(CONFIG_SUN4),y)
 O_OBJS  += nosrmmu.o
 else
-O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o turbosparc.o
+O_OBJS  += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o
 endif
 ifdef SMP
 O_OBJS   += nosun4c.o
@@ -25,9 +25,6 @@ include $(TOPDIR)/Rules.make
 hypersparc.o: hypersparc.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o hypersparc.o hypersparc.S
 
-turbosparc.o: turbosparc.S
-       $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o turbosparc.o turbosparc.S
-
 viking.o: viking.S
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c -o viking.o viking.S
 
index 908501dc9d93eb310451610badc80884fb585656..666bf8429f7f3be1a2bbfaafc08a738fb7a81ad8 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.11 1997/12/14 23:24:34 ecd Exp $
+/*  $Id: asyncd.c,v 1.12 1998/09/13 04:30:30 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
index 88d85004c90baf870a49717d11c5dcc736c4db8c..a1324af83778c422f798af712385a003bae86800 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.94 1998/05/01 16:00:27 jj Exp $
+/* $Id: fault.c,v 1.95 1998/09/18 19:50:32 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -149,7 +149,9 @@ static void unhandled_fault(unsigned long address, struct task_struct *tsk,
               (unsigned long) tsk->mm->context);
        printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
               (unsigned long) tsk->mm->pgd);
+       lock_kernel();
        die_if_kernel("Oops", regs);
+       unlock_kernel();
 }
 
 asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
@@ -196,11 +198,11 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        unsigned int fixup;
        unsigned long g2;
        int from_user = !(regs->psr & PSR_PS);
-       lock_kernel();
-       down(&mm->mmap_sem);
+
        if(text_fault)
                address = regs->pc;
 
+       down(&mm->mmap_sem);
        /* The kernel referencing a bad kernel pointer can lock up
         * a sun4c machine completely, so we must attempt recovery.
         */
@@ -231,7 +233,7 @@ good_area:
        }
        handle_mm_fault(current, vma, address, write);
        up(&mm->mmap_sem);
-       goto out;
+       return;
        /*
         * Something tried to access memory that isn't in our memory map..
         * Fix it, but check if it's kernel or user first..
@@ -263,7 +265,7 @@ bad_area:
                        regs->u_regs[UREG_G2] = g2;
                        regs->pc = fixup;
                        regs->npc = regs->pc + 4;
-                       goto out;
+                       return;
                }
        }
        if(from_user) {
@@ -274,11 +276,9 @@ bad_area:
                tsk->tss.sig_address = address;
                tsk->tss.sig_desc = SUBSIG_NOMAPPING;
                force_sig(SIGSEGV, tsk);
-               goto out;
+               return;
        }
        unhandled_fault (address, tsk, regs);
-out:
-       unlock_kernel();
 }
 
 asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
index eef01666de3ba986bc16d6213f912b8efea77a26..391a4dedb1a44e28af70ae3385cbe46ef6d4075d 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.59 1998/03/27 06:59:57 davem Exp $
+/*  $Id: init.c,v 1.60 1998/09/13 04:30:31 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 97bd5be37a986b33dfdbcc366f644726813ae8fc..69d40fa09dbc76948e17108a4c8761d7f4e2685f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.173 1998/08/04 20:48:57 davem Exp $
+/* $Id: srmmu.c,v 1.175 1998/08/28 18:57:31 zaitcev Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -1997,7 +1997,7 @@ static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long ad
 
 static void srmmu_destroy_context(struct mm_struct *mm)
 {
-       if(mm->context != NO_CONTEXT && mm->count == 1) {
+       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                flush_cache_mm(mm);
                ctxd_set(&srmmu_context_table[mm->context], swapper_pg_dir);
                flush_tlb_mm(mm);
@@ -2071,7 +2071,7 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
 
 static void hypersparc_destroy_context(struct mm_struct *mm)
 {
-       if(mm->context != NO_CONTEXT && mm->count == 1) {
+       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                ctxd_t *ctxp;
 
                /* HyperSparc is copy-back, any data for this
@@ -2399,10 +2399,93 @@ __initfunc(static void init_swift(void))
        poke_srmmu = poke_swift;
 }
 
-/* turbosparc.S */
-extern void turbosparc_flush_cache_all(void);
-extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
-extern void turbosparc_flush_page_for_dma(unsigned long page);
+static void turbosparc_flush_cache_all(void)
+{
+       flush_user_windows();
+       turbosparc_idflash_clear();
+}
+
+static void turbosparc_flush_cache_mm(struct mm_struct *mm)
+{
+       FLUSH_BEGIN(mm)
+       flush_user_windows();
+       turbosparc_idflash_clear();
+       FLUSH_END
+}
+
+static void turbosparc_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       FLUSH_BEGIN(mm)
+       flush_user_windows();
+       turbosparc_idflash_clear();
+       FLUSH_END
+}
+
+static void turbosparc_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+       FLUSH_BEGIN(vma->vm_mm)
+       flush_user_windows();
+       if (vma->vm_flags & VM_EXEC)
+               turbosparc_flush_icache();
+       turbosparc_flush_dcache();
+       FLUSH_END
+}
+
+/* TurboSparc is copy-back, if we turn it on, but this does not work. */
+static void turbosparc_flush_page_to_ram(unsigned long page)
+{
+#ifdef TURBOSPARC_WRITEBACK
+       volatile unsigned long clear;
+
+       if (srmmu_hwprobe(page))
+               turbosparc_flush_page_cache(page);
+       clear = srmmu_get_fstatus();
+#endif
+}
+
+static void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+}
+
+static void turbosparc_flush_page_for_dma(unsigned long page)
+{
+       turbosparc_flush_dcache();
+}
+
+static void turbosparc_flush_chunk(unsigned long chunk)
+{
+}
+
+static void turbosparc_flush_tlb_all(void)
+{
+       srmmu_flush_whole_tlb();
+       module_stats.invall++;
+}
+
+static void turbosparc_flush_tlb_mm(struct mm_struct *mm)
+{
+       FLUSH_BEGIN(mm)
+       srmmu_flush_whole_tlb();
+       module_stats.invmm++;
+       FLUSH_END
+}
+
+static void turbosparc_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+       FLUSH_BEGIN(mm)
+       srmmu_flush_whole_tlb();
+       module_stats.invrnge++;
+       FLUSH_END
+}
+
+static void turbosparc_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+       FLUSH_BEGIN(vma->vm_mm)
+       srmmu_flush_whole_tlb();
+       module_stats.invpg++;
+       FLUSH_END
+}
+
 
 __initfunc(static void poke_turbosparc(void))
 {
@@ -2420,7 +2503,7 @@ __initfunc(static void poke_turbosparc(void))
 #ifdef TURBOSPARC_WRITEBACK
        ccreg |= (TURBOSPARC_SNENABLE);         /* Do DVMA snooping in Dcache */
        ccreg &= ~(TURBOSPARC_uS2 | TURBOSPARC_WTENABLE);
-                       /* Write-back D-cache, emulate VLSI 
+                       /* Write-back D-cache, emulate VLSI
                         * abortion number three, not number one */
 #else
        /* For now let's play safe, optimize later */
@@ -2428,7 +2511,8 @@ __initfunc(static void poke_turbosparc(void))
                        /* Do DVMA snooping in Dcache, Write-thru D-cache */
        ccreg &= ~(TURBOSPARC_uS2);
                        /* Emulate VLSI abortion number three, not number one */
-#endif                  
+#endif
+
        switch (ccreg & 7) {
        case 0: /* No SE cache */
        case 7: /* Test mode */
@@ -2449,22 +2533,17 @@ __initfunc(static void init_turbosparc(void))
        srmmu_modtype = TurboSparc;
 
        BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_mm, turbosparc_flush_cache_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_page, turbosparc_flush_cache_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_cache_range, turbosparc_flush_cache_range, BTFIXUPCALL_NORM);
 
-       BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_all, turbosparc_flush_tlb_all, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_mm, turbosparc_flush_tlb_mm, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM);
 
-#ifdef TURBOSPARC_WRITEBACK
-       BTFIXUPSET_CALL(flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(flush_chunk, hypersparc_flush_chunk, BTFIXUPCALL_NORM);
-#else
-       BTFIXUPSET_CALL(flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NOP);
-       BTFIXUPSET_CALL(flush_chunk, swift_flush_chunk, BTFIXUPCALL_NOP);
-#endif
+       BTFIXUPSET_CALL(flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM);
+       BTFIXUPSET_CALL(flush_chunk, turbosparc_flush_chunk, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NOP);
index 448881608018fde4ae1f47ddad5f12fa484d4324..fa8105d576533e8b46e10fc2ee86ad79eeb0728e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.166 1998/08/04 20:49:05 davem Exp $
+/* $Id: sun4c.c,v 1.171 1998/09/21 05:05:41 jj Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -400,7 +400,9 @@ void sun4c_complete_all_stores(void)
 
        _unused = sun4c_get_context();
        sun4c_set_context(_unused);
+#ifdef CONFIG_SUN_AUXIO
        _unused = *AUXREG;
+#endif
 }
 
 /* Bootup utility functions. */
@@ -622,9 +624,8 @@ __initfunc(static void sun4c_probe_mmu(void))
                        break;
 
                case (SM_SUN4|SM_4_470):
-                       prom_printf("No support for 4400 yet\n");
-                       prom_halt();
-                       num_segmaps = 1024;
+                       /* should be 1024 segmaps. when it get fixed */
+                       num_segmaps = 256;
                        num_contexts = 64;
                        break;
                default:
@@ -755,13 +756,15 @@ static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on,
                                      ~bits_off);
 }
 
-/* the 4/260 dies real hard on the prom_putsegment line.
-    not sure why, but it seems to work without it cgd */
 static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
 {
        unsigned long vaddr;
        unsigned char pseg, ctx;
-#ifndef CONFIG_SUN4
+#ifdef CONFIG_SUN4
+       /* sun4/110 and 260 have no kadb. */
+       if((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
+          (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
+#endif
        for(vaddr = KADB_DEBUGGER_BEGVM;
            vaddr < LINUX_OPPROM_ENDVM;
            vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -773,6 +776,8 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
                        fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
                }
        }
+#ifdef CONFIG_SUN4
+       }
 #endif
        for(vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
                pseg = sun4c_get_segmap(vaddr);
@@ -2142,7 +2147,7 @@ static void sun4c_destroy_context_hw(struct mm_struct *mm)
 {
        struct ctx_list *ctx_old;
 
-       if(mm->context != NO_CONTEXT && mm->count == 1) {
+       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
                ctx_old = ctx_list_pool + mm->context;
                remove_from_ctx_list(ctx_old);
@@ -2205,7 +2210,7 @@ static void sun4c_destroy_context_sw(struct mm_struct *mm)
 {
        struct ctx_list *ctx_old;
 
-       if(mm->context != NO_CONTEXT && mm->count == 1) {
+       if(mm->context != NO_CONTEXT && atomic_read(&mm->count) == 1) {
                sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
                ctx_old = ctx_list_pool + mm->context;
                remove_from_ctx_list(ctx_old);
diff --git a/arch/sparc/mm/turbosparc.S b/arch/sparc/mm/turbosparc.S
deleted file mode 100644 (file)
index 731de27..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* $Id: turbosparc.S,v 1.3 1998/02/05 14:19:04 jj Exp $
- * turbosparc.S: High speed TurboSparc mmu/cache operations.
- *
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-#include <asm/asi.h>
-#include <asm/page.h>
-#include <asm/pgtsrmmu.h>
-
-#define WINDOW_FLUSH(tmp1, tmp2)                                       \
-       mov     0, tmp1;                                                \
-98:    ld      [%g6 + AOFF_task_tss + AOFF_thread_uwinmask], tmp2;     \
-       orcc    %g0, tmp2, %g0;                                         \
-       add     tmp1, 1, tmp1;                                          \
-       bne     98b;                                                    \
-        save   %sp, -64, %sp;                                          \
-99:    subcc   tmp1, 1, tmp1;                                          \
-       bne     99b;                                                    \
-        restore %g0, %g0, %g0;
-
-       .text
-       .align  4
-
-       .globl  turbosparc_flush_cache_all
-       .globl  turbosparc_flush_sig_insns
-       .globl  turbosparc_flush_page_for_dma
-
-turbosparc_flush_cache_all:
-       WINDOW_FLUSH(%g4, %g5)
-       sethi   %hi(vac_cache_size), %g4
-       ld      [%g4 + %lo(vac_cache_size)], %g5
-       sethi   %hi(vac_line_size), %g1
-       ld      [%g1 + %lo(vac_line_size)], %g2
-1:     
-       subcc   %g5, %g2, %g5
-       bne     1b
-        sta    %g0, [%g5] ASI_M_DATAC_TAG
-       retl
-        sta    %g0, [%g0] ASI_M_IC_FLCLEAR
-
-turbosparc_flush_sig_insns:
-turbosparc_flush_page_for_dma:
-       retl
-        nop
index 3bbc7ade02a96afd1e8e34983f35cedc6f409b7d..4a1a4230928d3d404f7f7a33d186acb83d4ac168 100644 (file)
@@ -1,8 +1,9 @@
-/* $Id: console.c,v 1.17 1998/03/09 14:04:21 jj Exp $
+/* $Id: console.c,v 1.20 1998/09/21 05:05:50 jj 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)
+ * Copyright (C) 1998 Pete Zaitcev <zaitcev@metabyte.com>
  */
 
 #include <linux/config.h>
@@ -17,6 +18,9 @@
 
 extern void restore_current(void);
 
+static char con_name_jmc[] = "/obio/su@"; /* "/obio/su@0,3002f8"; */
+#define CON_SIZE_JMC   (sizeof(con_name_jmc))
+
 /* Non blocking get character from console input device, returns -1
  * if no input was taken.  This can be used for polling.
  */
@@ -83,7 +87,6 @@ prom_nbputchar(char c)
                  i = 0;
                }
 #endif
-       
                break;
        default:
                i = -1;
@@ -139,9 +142,14 @@ prom_query_input_device()
                restore_flags(flags);
                if(prom_node_has_property(st_p, "keyboard"))
                        return PROMDEV_IKBD;
-               prom_getproperty(st_p, "device_type", propb, sizeof(propb));
+               if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
+                       if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
+                               return PROMDEV_IKBD;
+               }
+               if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
                if(strncmp(propb, "serial", sizeof("serial")))
                        return PROMDEV_I_UNK;
+               }
                prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
                p = propb;
                while(*p) p++; p -= 2;
@@ -154,7 +162,7 @@ prom_query_input_device()
                return PROMDEV_I_UNK;
        case PROM_AP1000:
                return PROMDEV_I_UNK;
-       };
+       }
 }
 
 /* Query for output device type */
@@ -190,9 +198,12 @@ prom_query_output_device()
                        return PROMDEV_OSCREEN;
                }
                if(prom_vers == PROM_V3) {
-                       if(strncmp("serial", propb, sizeof("serial")))
+                       if(propl >= 0 &&
+                           strncmp("serial", propb, sizeof("serial")) != 0)
                                return PROMDEV_O_UNK;
                        prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
+                       if(strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
+                               return PROMDEV_OTTYA;
                        p = propb;
                        while(*p) p++; p -= 2;
                        if(p[0]==':') {
@@ -201,9 +212,7 @@ prom_query_output_device()
                                else if(p[1] == 'b')
                                        return PROMDEV_OTTYB;
                        }
-                       return PROMDEV_O_UNK;
                } else {
-                       /* This works on SS-2 (an early OpenFirmware) still. */
                        switch(*romvec->pv_stdin) {
                        case PROMDEV_TTYA:      return PROMDEV_OTTYA;
                        case PROMDEV_TTYB:      return PROMDEV_OTTYB;
@@ -212,7 +221,6 @@ prom_query_output_device()
                break;
        case PROM_AP1000:
        default:
-               return PROMDEV_I_UNK;
-       };
+       }
        return PROMDEV_O_UNK;
 }
index 1256aacecc37763ae449b03b18ec65ae311ee97f..2e79057d86f6661eaad21f61b346c5dfba742849 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.24 1998/03/09 14:04:29 jj Exp $
+/* $Id: tree.c,v 1.25 1998/09/17 11:04:58 jj Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -11,6 +11,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/ctype.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -257,29 +258,49 @@ char * prom_nextprop(int node, char *oprop, char *buffer)
 
 int prom_finddevice(char *name)
 {
-       int topnd = prom_getchild(prom_root_node);
-       int srch;
-
-       if(name[0] == '/')
-               name++;
-       if(sparc_cpu_model == sun4d) {
-               if(!strcmp(name, "sbus"))
-                       name = "sbi";
-               if((srch = prom_searchsiblings(topnd, "io-unit")) == 0 ||
-                  (srch = prom_getchild(srch)) == 0 ||
-                  (srch = prom_searchsiblings(srch, name)) == 0) {
-                       prom_printf("%s prom node not found.\n", name);
-                       prom_halt();
-               }
-       } else if((srch = prom_searchsiblings(topnd, name)) == 0) {
-               if((srch = prom_searchsiblings(topnd, "iommu")) == 0 ||
-                  (srch = prom_getchild(srch)) == 0 ||
-                  (srch = prom_searchsiblings(srch, name)) == 0) {
-                       prom_printf("Cannot find node %s\n", name);
-                       prom_halt();
+       char nbuf[128];
+       char *s = name, *d;
+       int node = prom_root_node, node2;
+       unsigned int which_io, phys_addr;
+       struct linux_prom_registers reg[PROMREG_MAX];
+
+       while (*s++) {
+               if (!*s) return node; /* path '.../' is legal */
+               node = prom_getchild(node);
+
+               for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
+                       *d++ = *s++;
+               *d = 0;
+               
+               node = prom_searchsiblings(node, nbuf);
+               if (!node)
+                       return 0;
+
+               if (*s == '@') {
+                       if (isxdigit(s[1]) && s[2] == ',') {
+                               which_io = simple_strtoul(s+1, NULL, 16);
+                               phys_addr = simple_strtoul(s+3, &d, 16);
+                               if (d != s + 3 && (!*d || *d == '/')
+                                   && d <= s + 3 + 8) {
+                                       node2 = node;
+                                       while (node2 && node2 != -1) {
+                                               if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
+                                                       if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
+                                                               node = node2;
+                                                               break;
+                                                       }
+                                               }
+                                               node2 = prom_getsibling(node2);
+                                               if (!node2 || node2 == -1)
+                                                       break;
+                                               node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
+                                       }
+                               }
+                       }
+                       while (*s != 0 && *s != '/') s++;
                }
        }
-       return srch;
+       return node;
 }
 
 int prom_node_has_property(int node, char *prop)
index cbfc9fb3c3db10204dc778e2e82d2ecca2983deb..13e4d7202321259a0725f1253a7cd66a94d4de5e 100644 (file)
@@ -22,7 +22,9 @@ SECTIONS
   .data1   : { *(.data1) }
   _edata  =  .;
   PROVIDE (edata = .);
+  __start___fixup = .;
   .fixup   : { *(.fixup) }
+  __stop___fixup = .;
   __start___ex_table = .;
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
index d8cc0f76ee0cb06bdd8acc77960343a214672765..3a60e08af1658a5d9e020e18984c28e0cf45b984 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.27 1998/07/27 07:36:16 davem Exp $
+# $Id: Makefile,v 1.29 1998/09/16 12:25:20 jj Exp $
 # sparc64/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
 SHELL  =/bin/bash
 
 CC             = sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include
+
+IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
+NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi)
+
+ifneq ($(NEW_GAS),y)
 AS             = sparc64-linux-as
 LD             = sparc64-linux-ld
 NM             = sparc64-linux-nm
 AR             = sparc64-linux-ar
 RANLIB         = sparc64-linux-ranlib
+else
+AS             := $(AS) -64
+LD             := $(LD) -m elf64_sparc
+endif
 ELFTOAOUT      = elftoaout
 
-IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi)
 
 #
 # Uncomment the first CFLAGS if you are doing kgdb source level
@@ -30,7 +38,7 @@ ifneq ($(IS_EGCS),y)
   CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \
            -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 else
-  CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mcmodel=medlow \
+  CFLAGS := $(CFLAGS) -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
            -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare
 endif
 
index 2caead01d11526d41529b9d0f3aacab378a6d080..62847fa6f15f93be7499e593b1254fa3faf8ef17 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.55 1998/08/03 15:28:38 davem Exp $
+# $Id: config.in,v 1.57 1998/09/17 11:05:14 jj Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -51,14 +51,15 @@ else
        define_bool CONFIG_SUN_CONSOLE y
        define_bool CONFIG_SUN_AUXIO y
        define_bool CONFIG_SUN_IO y
-       define_bool CONFIG_PCI y
-       define_bool CONFIG_PCI_CONSOLE y
+       bool 'PCI support' CONFIG_PCI
        source drivers/sbus/char/Config.in
        source drivers/sbus/audio/Config.in
 fi
 
 tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS
-bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
+if [ "$CONFIG_PCI" = "y" ]; then
+  bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC
+fi
 bool 'Networking support' CONFIG_NET
 bool 'System V IPC' CONFIG_SYSVIPC
 bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
@@ -246,5 +247,5 @@ mainmenu_option next_comment
 comment 'Kernel hacking'
 
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
-bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
+#bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP
 endmenu
index 35f1219fd9c0f13a5d172435a803819c73295d8e..e971467321238bd4c46289c7d6c5da0d876ccc1f 100644 (file)
@@ -55,7 +55,6 @@ CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
 CONFIG_PCI=y
-CONFIG_PCI_CONSOLE=y
 
 #
 # Misc Linux/SPARC drivers
@@ -73,6 +72,7 @@ CONFIG_OBP_FLASH=m
 # CONFIG_SPARCAUDIO is not set
 # CONFIG_SPARCAUDIO_AMD7930 is not set
 # CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_PCI_OLD_PROC=y
 CONFIG_NET=y
@@ -91,7 +91,7 @@ CONFIG_PARPORT_AX=y
 # CONFIG_PARPORT_OTHER is not set
 CONFIG_PRINTER=y
 CONFIG_PRINTER_READBACK=y
-CONFIG_ENVCTRL=y
+CONFIG_ENVCTRL=m
 
 #
 # Floppy, IDE, and other block devices
@@ -105,7 +105,7 @@ CONFIG_MD_RAID5=m
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_NBD=m
 CONFIG_BLK_DEV_IDE=y
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -292,7 +292,8 @@ CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_ADFS_FS is not set
-# CONFIG_DEVPTS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
 # CONFIG_MAC_PARTITION is not set
 CONFIG_NLS=y
 
@@ -335,4 +336,3 @@ CONFIG_NLS=y
 # Kernel hacking
 #
 # CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_EC_FLUSH_TRAP is not set
index ac61935c879f556247ef18e8bd87084d2cbb8e3b..7a3ee40f8acbad5f2e38132ace35e4d1caa3013a 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.38 1998/07/26 03:02:47 davem Exp $
+# $Id: Makefile,v 1.40 1998/09/17 11:05:03 jj Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -20,9 +20,13 @@ O_OBJS   := process.o setup.o cpu.o idprom.o \
            traps.o devices.o auxio.o ioport.o \
            irq.o ptrace.o time.o sys_sparc.o signal.o \
            unaligned.o sys_sunos32.o sunos_ioctl32.o \
-           central.o psycho.o ebus.o
+           central.o psycho.o
 OX_OBJS  := sparc64_ksyms.o
 
+ifdef CONFIG_PCI
+  O_OBJS += ebus.o
+endif
+
 ifdef SMP
 O_OBJS += smp.o trampoline.o
 endif
@@ -48,6 +52,12 @@ head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \
 #
 binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
 
+ifneq ($(IS_EGCS),y)
+  CMODEL_CFLAG := -mmedlow
+else
+  CMODEL_CFLAG := -mcmodel=medlow
+endif
+
 check_asm: dummy
        @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h
        @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h
@@ -70,7 +80,7 @@ check_asm: dummy
        @rm -f tmp.[ci]
        #$(CC) -o check_asm check_asm.c
        # <hack> Until we can do this natively, a hack has to take place
-       $(CC) -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c
+       $(CC) $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
        $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
        @rm -f check_asm.s
        # </hack>
@@ -94,7 +104,7 @@ check_asm: dummy
        @rm -f tmp.[ci]
        #$(CC) -D__SMP__ -o check_asm check_asm.c
        # <hack> Until we can do this natively, a hack has to take place
-       $(CC) -D__SMP__ -mmedlow -ffixed-g4 -S -o check_asm.s check_asm.c
+       $(CC) -D__SMP__ $(CMODEL_CFLAG) -ffixed-g4 -S -o check_asm.s check_asm.c
        $(HOSTCC) -Wa,-Av9a -o check_asm check_asm.s
        @rm -f check_asm.s
        # </hack>
index b0dd675b05b011d9b4d214abc38e6b7952bb20a8..d749fd5bd66c88d25790b976126308bf58a79a34 100644 (file)
@@ -91,7 +91,7 @@ do_aout32_core_dump(long signr, struct pt_regs * regs)
 #       define START_DATA(u)    (u.u_tsize)
 #       define START_STACK(u)   ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1))
 
-       if (!current->dumpable || current->mm->count != 1)
+       if (!current->dumpable || atomic_read(&current->mm->count) != 1)
                return 0;
        current->dumpable = 0;
 
@@ -201,7 +201,8 @@ aout32_core_dump(long signr, struct pt_regs * regs)
  * memory and creates the pointer tables from them, and puts their
  * addresses on the "stack", returning the new stack pointer value.
  */
-#define A(x) ((unsigned long)x)
+#define A(__x) ((unsigned long)(__x))
+
 static u32 *create_aout32_tables(char * p, struct linux_binprm * bprm)
 {
        u32 *argv, *envp;
index ef41e3f7a7e5076df50a36b9f43f6d0835ca024b..f0c36d1a72d60d1f67b49ebeec6a824924da71e7 100644 (file)
-/* binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
+/*
+ * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra.
  *
+ * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller        (davem@dm.cobaltmicro.com)
+ * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek  (jj@ultra.linux.cz)
  */
 
 #define ELF_ARCH               EM_SPARC
 #define ELF_CLASS              ELFCLASS32
 #define ELF_DATA               ELFDATA2MSB;
 
+/* For the most part we present code dumps in the format
+ * Solaris does.
+ */
+typedef unsigned int elf_greg_t;
+#define ELF_NGREG 38
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Format is:
+ *     G0 --> G7
+ *     O0 --> O7
+ *     L0 --> L7
+ *     I0 --> I7
+ *     PSR, PC, nPC, Y, WIM, TBR
+ */
+#include <asm/psrcompat.h>
+#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs)      \
+do {   unsigned int *dest = &(__elf_regs[0]);          \
+       struct pt_regs *src = (__pt_regs);              \
+       unsigned int *sp;                               \
+       int i;                                          \
+       for(i = 0; i < 16; i++)                         \
+               dest[i] = (unsigned int) src->u_regs[i];\
+       /* Don't try this at home kids... */            \
+       set_fs(USER_DS);                                \
+       sp = (unsigned int *) (src->u_regs[14] &        \
+               0x00000000fffffffc);                    \
+       for(i = 0; i < 16; i++)                         \
+               __get_user(dest[i+16], &sp[i]);         \
+       set_fs(KERNEL_DS);                              \
+       dest[32] = tstate_to_psr(src->tstate);          \
+       dest[33] = (unsigned int) src->tpc;             \
+       dest[34] = (unsigned int) src->tnpc;            \
+       dest[35] = src->y;                              \
+       dest[36] = dest[37] = 0; /* XXX */              \
+} while(0);
+
+typedef struct {
+       union {
+               unsigned int    pr_regs[32];
+               unsigned long   pr_dregs[16];
+       } pr_fr;
+       unsigned int __unused;
+       unsigned int    pr_fsr;
+       unsigned char   pr_qcnt;
+       unsigned char   pr_q_entrysize;
+       unsigned char   pr_en;
+       unsigned int    pr_q[64];
+} elf_fpregset_t;
+
+/* UltraSparc extensions.  Still unused, but will be eventually.  */
+typedef struct {
+       unsigned int pr_type;
+       unsigned int pr_align;
+       union {
+               struct {
+                       union {
+                               unsigned int    pr_regs[32];
+                               unsigned long   pr_dregs[16];
+                               long double     pr_qregs[8];
+                       } pr_xfr;
+               } pr_v8p;
+               unsigned int    pr_xfsr;
+               unsigned int    pr_fprs;
+               unsigned int    pr_xg[8];
+               unsigned int    pr_xo[8];
+               unsigned long   pr_tstate;
+               unsigned int    pr_filler[8];
+       } pr_un;
+} elf_xregset_t;
+
 #define elf_check_arch(x)      (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS))
 
-#define ELF_ET_DYN_BASE         0x60000000
+#define ELF_ET_DYN_BASE         0x08000000
 
 
 #include <asm/processor.h>
 #include <linux/module.h>
 #include <linux/config.h>
+#include <linux/elfcore.h>
+
+struct timeval32
+{
+       int tv_sec, tv_usec;
+};
+
+#define elf_prstatus elf_prstatus32
+struct elf_prstatus32
+{
+       struct elf_siginfo pr_info;     /* Info associated with signal */
+       short   pr_cursig;              /* Current signal */
+       unsigned int pr_sigpend;        /* Set of pending signals */
+       unsigned int pr_sighold;        /* Set of held signals */
+       pid_t   pr_pid;
+       pid_t   pr_ppid;
+       pid_t   pr_pgrp;
+       pid_t   pr_sid;
+       struct timeval32 pr_utime;      /* User time */
+       struct timeval32 pr_stime;      /* System time */
+       struct timeval32 pr_cutime;     /* Cumulative user time */
+       struct timeval32 pr_cstime;     /* Cumulative system time */
+       elf_gregset_t pr_reg;   /* GP registers */
+       int pr_fpvalid;         /* True if math co-processor being used.  */
+};
+
+#define elf_prpsinfo elf_prpsinfo32
+struct elf_prpsinfo32
+{
+       char    pr_state;       /* numeric process state */
+       char    pr_sname;       /* char for pr_state */
+       char    pr_zomb;        /* zombie */
+       char    pr_nice;        /* nice val */
+       unsigned int pr_flag;   /* flags */
+       u16     pr_uid;
+       u16     pr_gid;
+       pid_t   pr_pid, pr_ppid, pr_pgrp, pr_sid;
+       /* Lots missing */
+       char    pr_fname[16];   /* filename of executable */
+       char    pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
 
 #define elf_addr_t     u32
 #define elf_caddr_t    u32
index 2d2fbd224fb7b55f5beab02937d07cf681874a9c..fd56d4e3be3f141c830db1e283ba98deb3f4ee29 100644 (file)
@@ -1,3 +1,4 @@
 #!/bin/sh
 sed -n -e '/struct[    ]*'$1'_struct[  ]*{/,/};/p' < $2 | sed '/struct[        ]*'$1'_struct[  ]*{/d;/:[0-9]*[         ]*;/d;/^[       ]*$/d;/};/d;s/^[        ]*//;s/volatile[        ]*//;s/\(unsigned\|signed\|struct\)[    ]*//;s/\(\[\|__attribute__\).*;[        ]*$//;s/;[      ]*$//;s/^[^     ]*[     ]*//;s/,/\
 /g' | sed 's/^[        *]*//;s/[       ]*$//;s/^.*$/printf ("#define AOFF_'$1'_\0      0x%08x\\n#define ASIZ_'$1'_\0   0x%08x\\n", ((char *)\&_'$1'.\0) - ((char *)\&_'$1'), sizeof(_'$1'.\0));/' >> $3
+echo "printf (\"#define ASIZ_$1\\t0x%08x\\n\", sizeof(_$1));" >> $3
index b3d0a1eb7b108c9ab1e1ce2fc0ae2b36cff85cb0..6207101fd1f9d2f6f9ef93e22bdeab6d7119ed13 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.4 1998/06/15 16:59:34 jj Exp $
+/* $Id: dtlb_backend.S,v 1.6 1998/09/24 03:21:32 davem Exp $
  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
  *                 This is included directly into the trap table.
  *
index 70465afbdb97c03d94ad200884c3c1a5c2cd79f0..e60a5dc6218c6c18d6ee292796d771a8ef2139f0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.29 1998/07/01 15:39:44 jj Exp $
+/* $Id: ebus.c,v 1.33 1998/09/21 05:06:03 jj Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -31,7 +31,6 @@ struct linux_ebus *ebus_chain = 0;
 
 extern void prom_ebus_ranges_init(struct linux_ebus *);
 extern void prom_ebus_intmap_init(struct linux_ebus *);
-extern void pci_console_init(void);
 
 #ifdef CONFIG_SUN_OPENPROMIO
 extern int openprom_init(void);
@@ -227,7 +226,6 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
        }
 }
 
-extern void sun4u_start_timers(void);
 extern void clock_probe(void);
 
 __initfunc(void ebus_init(void))
@@ -367,10 +365,6 @@ __initfunc(void ebus_init(void))
                ++num_ebus;
        }
 
-#ifndef CONFIG_FB
-       pci_console_init();
-#endif
-
 #ifdef CONFIG_SUN_OPENPROMIO
        openprom_init();
 #endif
@@ -389,6 +383,5 @@ __initfunc(void ebus_init(void))
 #ifdef CONFIG_OBP_FLASH
        flash_init();
 #endif
-       sun4u_start_timers();
        clock_probe();
 }
index 774839af6008578502d7e07c0d992e76a388cbd0..cfabbfc57bba84cbcfb97a57fac20e535a9e9219 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.87 1998/07/29 16:32:28 jj Exp $
+/* $Id: entry.S,v 1.90 1998/09/25 01:09:05 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -373,17 +373,112 @@ netbsd_syscall:
        retl
         nop
 
+       /* These next few routines must be sure to clear the
+        * SFSR FaultValid bit so that the fast tlb data protection
+        * handler does not flush the wrong context and lock up the
+        * box.
+        */
+       .globl          __do_data_access_exception
+       .globl          __do_data_access_exception_tl1
+__do_data_access_exception_tl1:
+       rdpr            %pstate, %g4
+       wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
+       rdpr            %tl, %g3
+       cmp             %g3, 1
+       mov             TLB_SFSR, %g3
+       mov             DMMU_SFAR, %g5
+       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
+       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       stxa            %g0, [%g3] ASI_DMMU     ! Clear SFSR.FaultValid bit
+       membar          #Sync
+       bgu,pn          %icc, winfix_dax
+        rdpr           %tpc, %g3
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etraptl1
+        or             %g7, %lo(109f), %g7     ! Merge in below
+__do_data_access_exception:
+       rdpr            %pstate, %g4
+       wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
+       mov             TLB_SFSR, %g3
+       mov             DMMU_SFAR, %g5
+       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
+       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       stxa            %g0, [%g3] ASI_DMMU     ! Clear SFSR.FaultValid bit
+       membar          #Sync
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etrap
+109:    or             %g7, %lo(109b), %g7
+       mov             %l4, %o1
+       mov             %l5, %o2
+       call            data_access_exception
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+
+       .globl          __do_instruction_access_exception
+       .globl          __do_instruction_access_exception_tl1
+__do_instruction_access_exception_tl1:
+       rdpr            %pstate, %g4
+       wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
+       mov             TLB_SFSR, %g3
+       mov             DMMU_SFAR, %g5
+       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
+       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       stxa            %g0, [%g3] ASI_IMMU     ! Clear FaultValid bit
+       membar          #Sync
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etraptl1
+        or             %g7, %lo(109f), %g7     ! Merge in below
+__do_instruction_access_exception:
+       rdpr            %pstate, %g4
+       wrpr            %g4, PSTATE_MG|PSTATE_AG, %pstate
+       mov             TLB_SFSR, %g3
+       mov             DMMU_SFAR, %g5
+       ldxa            [%g3] ASI_DMMU, %g4     ! Get SFSR
+       ldxa            [%g5] ASI_DMMU, %g5     ! Get SFAR
+       stxa            %g0, [%g3] ASI_IMMU     ! Clear FaultValid bit
+       membar          #Sync
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etrap
+109:    or             %g7, %lo(109b), %g7
+       mov             %l4, %o1
+       mov             %l5, %o2
+       call            instruction_access_exception
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+
+       .globl          __do_privact
+__do_privact:
+       mov             TLB_SFSR, %g3
+       stxa            %g0, [%g3] ASI_DMMU     ! Clear FaultValid bit
+       membar          #Sync
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etrap
+109:   or              %g7, %lo(109b), %g7
+       call            do_privact
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+
        .globl          do_mna
 do_mna:
        rdpr            %tl, %g3
        cmp             %g3, 1
-       bgu,a,pn        %icc, winfix_mna
-        rdpr           %tpc, %g3
+
+       /* Setup %g4/%g5 now as they are used in the
+        * winfixup code.
+        */
+       mov             TLB_SFSR, %g3
        mov             DMMU_SFAR, %g4
-       mov             TLB_SFSR, %g5
-       sethi           %hi(109f), %g7
        ldxa            [%g4] ASI_DMMU, %g4
-       ldxa            [%g5] ASI_DMMU, %g5
+       ldxa            [%g3] ASI_DMMU, %g5
+       stxa            %g0, [%g3] ASI_DMMU     ! Clear FaultValid bit
+       membar          #Sync
+       bgu,pn          %icc, winfix_dax
+        rdpr           %tpc, %g3
+
+1:     sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
@@ -395,11 +490,13 @@ do_mna:
 
        .globl          do_lddfmna
 do_lddfmna:
-       mov             DMMU_SFAR, %g4
-       mov             TLB_SFSR, %g5
        sethi           %hi(109f), %g7
+       mov             TLB_SFSR, %g4
+       ldxa            [%g4] ASI_DMMU, %g5
+       stxa            %g0, [%g4] ASI_DMMU     ! Clear FaultValid bit
+       membar          #Sync
+       mov             DMMU_SFAR, %g4
        ldxa            [%g4] ASI_DMMU, %g4
-       ldxa            [%g5] ASI_DMMU, %g5
        ba,pt           %xcc, etrap
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
@@ -411,11 +508,13 @@ do_lddfmna:
 
        .globl          do_stdfmna
 do_stdfmna:
-       mov             DMMU_SFAR, %g4
-       mov             TLB_SFSR, %g5
        sethi           %hi(109f), %g7
+       mov             TLB_SFSR, %g4
+       ldxa            [%g4] ASI_DMMU, %g5
+       stxa            %g0, [%g4] ASI_DMMU     ! Clear FaultValid bit
+       membar          #Sync
+       mov             DMMU_SFAR, %g4
        ldxa            [%g4] ASI_DMMU, %g4
-       ldxa            [%g5] ASI_DMMU, %g5
        ba,pt           %xcc, etrap
 109:    or             %g7, %lo(109b), %g7
        mov             %l4, %o1
index 51fbd6ce5557c1828931498ec5c5b2d61c131a80..d0a0d6c561e9113d70a7d9d22498385db0fa01a2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.48 1998/08/03 23:58:04 davem Exp $
+/* $Id: ioctl32.c,v 1.52 1998/09/25 17:09:22 jj Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -40,6 +40,7 @@
 #undef __KERNEL__
 #include <scsi/scsi_ioctl.h>
 #define __KERNEL__
+#include <scsi/sg.h>
 
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/envctrl.h>
 #include <asm/audioio.h>
 
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to
- * unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x)
- * or instead of just (void *)x, which will produce warnings.
- */
-#define A(x) ((unsigned long)x)
+/* Use this to get at 32-bit user passed pointers. 
+   See sys_sparc32.c for description about these. */
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)                                \
+({     unsigned long __ret;            \
+       __asm__ ("srl   %0, 0, %0"      \
+                : "=r" (__ret)         \
+                : "0" (__x));          \
+       __ret;                          \
+})
 
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
-static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
+static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        int err;
@@ -69,23 +74,23 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
        set_fs (KERNEL_DS);
        err = sys_ioctl(fd, cmd, (unsigned long)&val);
        set_fs (old_fs);
-       if (!err && put_user(val, (u32 *)A(arg)))
+       if (!err && put_user(val, (u32 *)arg))
                return -EFAULT;
        return err;
 }
  
-static int rw_long(unsigned int fd, unsigned int cmd, u32 arg)
+static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        int err;
        unsigned long val;
        
-       if(get_user(val, (u32 *)A(arg)))
+       if(get_user(val, (u32 *)arg))
                return -EFAULT;
        set_fs (KERNEL_DS);
        err = sys_ioctl(fd, cmd, (unsigned long)&val);
        set_fs (old_fs);
-       if (!err && put_user(val, (u32 *)A(arg)))
+       if (!err && put_user(val, (u32 *)arg))
                return -EFAULT;
        return err;
 }
@@ -95,9 +100,9 @@ struct timeval32 {
        int tv_usec;
 };
 
-static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg)
+static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
-       struct timeval32 *up = (struct timeval32 *)A(arg);
+       struct timeval32 *up = (struct timeval32 *)arg;
        struct timeval ktv;
        mm_segment_t old_fs = get_fs();
        int err;
@@ -106,10 +111,8 @@ static int do_siocgstamp(unsigned int fd, unsigned int cmd, u32 arg)
        err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
        set_fs(old_fs);
        if(!err) {
-               if(!access_ok(VERIFY_WRITE, up, sizeof(*up))    ||
-                  __put_user(ktv.tv_sec, &up->tv_sec)          ||
-                  __put_user(ktv.tv_usec, &up->tv_usec))
-                       err = -EFAULT;
+               err = put_user(ktv.tv_sec, &up->tv_sec);
+               err |= __put_user(ktv.tv_usec, &up->tv_usec);
        }
        return err;
 }
@@ -149,7 +152,7 @@ struct ifconf32 {
         __kernel_caddr_t32  ifcbuf;
 };
 
-static inline int dev_ifconf(unsigned int fd, u32 arg)
+static inline int dev_ifconf(unsigned int fd, unsigned long arg)
 {
        struct ifconf32 ifc32;
        struct ifconf ifc;
@@ -159,7 +162,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
        unsigned int i, j;
        int err;
 
-       if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
+       if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32)))
                return -EFAULT;
 
        if(ifc32.ifcbuf == 0) {
@@ -199,7 +202,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
                                ifc32.ifc_len = i;
                        else
                                ifc32.ifc_len = i - sizeof (struct ifreq32);
-                       if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32)))
+                       if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32)))
                                err = -EFAULT;
                }
        }
@@ -208,7 +211,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg)
        return err;
 }
 
-static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
+static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        struct ifreq ifr;
        mm_segment_t old_fs;
@@ -216,26 +219,27 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
        
        switch (cmd) {
        case SIOCSIFMAP:
-               if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) ||
-                   __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
-                   __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
-                   __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
-                   __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
-                   __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
-                   __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
+               err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name));
+               err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+               err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+               err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+               err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+               err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+               err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
+               if (err)
                        return -EFAULT;
                break;
        case SIOCGPPPSTATS:
        case SIOCGPPPCSTATS:
        case SIOCGPPPVER:
-               if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+               if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
                        return -EFAULT;
                ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
                if (!ifr.ifr_data)
                        return -EAGAIN;
                break;
        default:
-               if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+               if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
                        return -EFAULT;
                break;
        }
@@ -255,7 +259,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
                case SIOCGIFBRDADDR:
                case SIOCGIFDSTADDR:
                case SIOCGIFNETMASK:
-                       if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32)))
+                       if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32)))
                                return -EFAULT;
                        break;
                case SIOCGPPPSTATS:
@@ -265,7 +269,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
                        u32 data;
                        int len;
 
-                       __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data));
+                       __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
                        if(cmd == SIOCGPPPVER)
                                len = strlen(PPP_VERSION) + 1;
                        else if(cmd == SIOCGPPPCSTATS)
@@ -278,14 +282,13 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
                        break;
                }
                case SIOCGIFMAP:
-                       if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) ||
-                           __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
-                           __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
-                           __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
-                           __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
-                           __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
-                           __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
-                               return -EFAULT;
+                       err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name));
+                       err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start));
+                       err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end));
+                       err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr));
+                       err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq));
+                       err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma));
+                       err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port));
                        break;
                }
        }
@@ -311,7 +314,7 @@ struct rtentry32 {
 
 };
 
-static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        struct rtentry r;
        char devname[16];
@@ -319,19 +322,20 @@ static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        int ret;
        mm_segment_t old_fs = get_fs();
        
-       if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) ||
-           __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) ||
-           __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) ||
-           __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) ||
-           __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) ||
-           __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) ||
-           __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) ||
-           (rtdev && copy_from_user (devname, (char *)A(rtdev), 15)))
-               return -EFAULT;
+       ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr));
+       ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags));
+       ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric));
+       ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu));
+       ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window));
+       ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt));
+       ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev));
        if (rtdev) {
+               ret |= copy_from_user (devname, (char *)A(rtdev), 15);
                r.rt_dev = devname; devname[15] = 0;
        } else
                r.rt_dev = 0;
+       if (ret)
+               return -EFAULT;
        set_fs (KERNEL_DS);
        ret = sys_ioctl (fd, cmd, (long)&r);
        set_fs (old_fs);
@@ -345,7 +349,7 @@ struct hd_geometry32 {
        u32 start;
 };
                         
-static inline int hdio_getgeo(unsigned int fd, u32 arg)
+static inline int hdio_getgeo(unsigned int fd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        struct hd_geometry geo;
@@ -355,9 +359,8 @@ static inline int hdio_getgeo(unsigned int fd, u32 arg)
        err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
        set_fs (old_fs);
        if (!err) {
-               if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) ||
-                   __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start)))
-                       return -EFAULT;
+               err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4);
+               err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start));
        }
        return err;
 }
@@ -373,7 +376,7 @@ struct  fbcmap32 {
 #define FBIOPUTCMAP32  _IOW('F', 3, struct fbcmap32)
 #define FBIOGETCMAP32  _IOW('F', 4, struct fbcmap32)
 
-static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg)
+static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        struct fbcmap f;
        int ret;
@@ -381,19 +384,21 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg)
        u32 r, g, b;
        mm_segment_t old_fs = get_fs();
        
-       if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) ||
-           __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) ||
-           __get_user(r, &(((struct fbcmap32 *)A(arg))->red)) ||
-           __get_user(g, &(((struct fbcmap32 *)A(arg))->green)) ||
-           __get_user(b, &(((struct fbcmap32 *)A(arg))->blue)))
+       ret = get_user(f.index, &(((struct fbcmap32 *)arg)->index));
+       ret |= __get_user(f.count, &(((struct fbcmap32 *)arg)->count));
+       ret |= __get_user(r, &(((struct fbcmap32 *)arg)->red));
+       ret |= __get_user(g, &(((struct fbcmap32 *)arg)->green));
+       ret |= __get_user(b, &(((struct fbcmap32 *)arg)->blue));
+       if (ret)
                return -EFAULT;
        if ((f.index < 0) || (f.index > 255)) return -EINVAL;
        if (f.index + f.count > 256)
                f.count = 256 - f.index;
        if (cmd == FBIOPUTCMAP32) {
-               if (copy_from_user (red, (char *)A(r), f.count) ||
-                   copy_from_user (green, (char *)A(g), f.count) ||
-                   copy_from_user (blue, (char *)A(b), f.count))
+               ret = copy_from_user (red, (char *)A(r), f.count);
+               ret |= copy_from_user (green, (char *)A(g), f.count);
+               ret |= copy_from_user (blue, (char *)A(b), f.count);
+               if (ret)
                        return -EFAULT;
        }
        f.red = red; f.green = green; f.blue = blue;
@@ -401,10 +406,9 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg)
        ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f);
        set_fs (old_fs);
        if (!ret && cmd == FBIOGETCMAP32) {
-               if (copy_to_user ((char *)A(r), red, f.count) ||
-                   copy_to_user ((char *)A(g), green, f.count) ||
-                   copy_to_user ((char *)A(b), blue, f.count))
-                       return -EFAULT;
+               ret = copy_to_user ((char *)A(r), red, f.count);
+               ret |= copy_to_user ((char *)A(g), green, f.count);
+               ret |= copy_to_user ((char *)A(b), blue, f.count);
        }
        return ret;
 }
@@ -423,7 +427,7 @@ struct fbcursor32 {
 #define FBIOSCURSOR32  _IOW('F', 24, struct fbcursor32)
 #define FBIOGCURSOR32  _IOW('F', 25, struct fbcursor32)
 
-static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
+static inline int fbiogscursor(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        struct fbcursor f;
        int ret;
@@ -433,29 +437,32 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg)
        u32 m, i;
        mm_segment_t old_fs = get_fs();
        
-       if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) ||
-           __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) ||
-           __get_user(f.size.fby, &(((struct fbcursor32 *)A(arg))->size.fby)) ||
-           __get_user(f.cmap.index, &(((struct fbcursor32 *)A(arg))->cmap.index)) ||
-           __get_user(f.cmap.count, &(((struct fbcursor32 *)A(arg))->cmap.count)) ||
-           __get_user(r, &(((struct fbcursor32 *)A(arg))->cmap.red)) ||
-           __get_user(g, &(((struct fbcursor32 *)A(arg))->cmap.green)) ||
-           __get_user(b, &(((struct fbcursor32 *)A(arg))->cmap.blue)) ||
-           __get_user(m, &(((struct fbcursor32 *)A(arg))->mask)) ||
-           __get_user(i, &(((struct fbcursor32 *)A(arg))->image)))
+       ret = copy_from_user (&f, (struct fbcursor32 *)arg, 2 * sizeof (short) + 2 * sizeof(struct fbcurpos));
+       ret |= __get_user(f.size.fbx, &(((struct fbcursor32 *)arg)->size.fbx));
+       ret |= __get_user(f.size.fby, &(((struct fbcursor32 *)arg)->size.fby));
+       ret |= __get_user(f.cmap.index, &(((struct fbcursor32 *)arg)->cmap.index));
+       ret |= __get_user(f.cmap.count, &(((struct fbcursor32 *)arg)->cmap.count));
+       ret |= __get_user(r, &(((struct fbcursor32 *)arg)->cmap.red));
+       ret |= __get_user(g, &(((struct fbcursor32 *)arg)->cmap.green));
+       ret |= __get_user(b, &(((struct fbcursor32 *)arg)->cmap.blue));
+       ret |= __get_user(m, &(((struct fbcursor32 *)arg)->mask));
+       ret |= __get_user(i, &(((struct fbcursor32 *)arg)->image));
+       if (ret)
                return -EFAULT;
        if (f.set & FB_CUR_SETCMAP) {
                if ((uint) f.size.fby > 32)
                        return -EINVAL;
-               if (copy_from_user (mask, (char *)A(m), f.size.fby * 4) ||
-                   copy_from_user (image, (char *)A(i), f.size.fby * 4))
+               ret = copy_from_user (mask, (char *)A(m), f.size.fby * 4);
+               ret |= copy_from_user (image, (char *)A(i), f.size.fby * 4);
+               if (ret)
                        return -EFAULT;
                f.image = image; f.mask = mask;
        }
        if (f.set & FB_CUR_SETCMAP) {
-               if (copy_from_user (red, (char *)A(r), 2) ||
-                   copy_from_user (green, (char *)A(g), 2) ||
-                   copy_from_user (blue, (char *)A(b), 2))
+               ret = copy_from_user (red, (char *)A(r), 2);
+               ret |= copy_from_user (green, (char *)A(g), 2);
+               ret |= copy_from_user (blue, (char *)A(b), 2);
+               if (ret)
                        return -EFAULT;
                f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue;
        }
@@ -491,7 +498,7 @@ struct fb_cmap32 {
        __kernel_caddr_t32      transp;
 };
 
-static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        u32 red = 0, green = 0, blue = 0, transp = 0;
@@ -500,6 +507,7 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        void *karg;
        int err = 0;
 
+       memset(&cmap, 0, sizeof(cmap));
        switch (cmd) {
        case FBIOGET_FSCREENINFO:
                karg = &fix;
@@ -507,120 +515,91 @@ static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        case FBIOGETCMAP:
        case FBIOPUTCMAP:
                karg = &cmap;
-               if (__get_user(cmap.start, &((struct fb_cmap32 *)A(arg))->start) ||
-                   __get_user(cmap.len, &((struct fb_cmap32 *)A(arg))->len) ||
-                   __get_user(red, &((struct fb_cmap32 *)A(arg))->red) ||
-                   __get_user(green, &((struct fb_cmap32 *)A(arg))->green) ||
-                   __get_user(blue, &((struct fb_cmap32 *)A(arg))->blue) ||
-                   __get_user(transp, &((struct fb_cmap32 *)A(arg))->transp))
-                       return -EFAULT;
+               err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start);
+               err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len);
+               err |= __get_user(red, &((struct fb_cmap32 *)arg)->red);
+               err |= __get_user(green, &((struct fb_cmap32 *)arg)->green);
+               err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue);
+               err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp);
+               if (err)
+                       goto out;
+               err = -ENOMEM;
                cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
                if (!cmap.red)
-                       return -ENOMEM;
+                       goto out;
                cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
-               if (!cmap.green) {
-                       kfree(cmap.red);
-                       return -ENOMEM;
-               }
+               if (!cmap.green)
+                       goto out;
                cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
-               if (!cmap.blue) {
-                       kfree(cmap.red);
-                       kfree(cmap.green);
-                       return -ENOMEM;
-               }
+               if (!cmap.blue)
+                       goto out;
                if (transp) {
                        cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL);
-                       if (!cmap.transp) {
-                               kfree(cmap.red);
-                               kfree(cmap.green);
-                               kfree(cmap.blue);
-                               return -ENOMEM;
-                       }
-               } else {
+                       if (!cmap.transp)
+                               goto out;
+               } else
                        cmap.transp = NULL;
-               }
+                       
                if (cmd == FBIOGETCMAP)
                        break;
 
-               if (__copy_from_user(cmap.red, (char *)A(((struct fb_cmap32 *)A(arg))->red),
-                                    cmap.len * sizeof(__u16)) ||
-                   __copy_from_user(cmap.green, (char *)A(((struct fb_cmap32 *)A(arg))->green),
-                                    cmap.len * sizeof(__u16)) ||
-                   __copy_from_user(cmap.blue, (char *)A(((struct fb_cmap32 *)A(arg))->blue),
-                                    cmap.len * sizeof(__u16)) ||
-                   (cmap.transp &&
-                    __copy_from_user(cmap.transp, (char *)A(((struct fb_cmap32 *)A(arg))->transp),
-                                     cmap.len * sizeof(__u16)))) {
-                       kfree(cmap.red);
-                       kfree(cmap.green);
-                       kfree(cmap.blue);
-                       if (cmap.transp)
-                               kfree(cmap.transp);
-                       return -EFAULT;
-               }
+               err = __copy_from_user(cmap.red, (char *)A(red), cmap.len * sizeof(__u16));
+               err |= __copy_from_user(cmap.green, (char *)A(green), cmap.len * sizeof(__u16));
+               err |= __copy_from_user(cmap.blue, (char *)A(blue), cmap.len * sizeof(__u16));
+               if (cmap.transp) err |= __copy_from_user(cmap.transp, (char *)A(transp), cmap.len * sizeof(__u16));
+               if (err)
+                       goto out;
                break;
        default:
-               printk("%s: Unknown fb ioctl cmd fd(%d) cmd(%08x) arg(%08x)\n",
-                      __FUNCTION__, fd, cmd, arg);
+               do {
+                       static int count = 0;
+                       if (++count <= 20)
+                               printk("%s: Unknown fb ioctl cmd fd(%d) "
+                                      "cmd(%08x) arg(%08lx)\n",
+                                      __FUNCTION__, fd, cmd, arg);
+               } while(0);
                return -ENOSYS;
        }
        set_fs(KERNEL_DS);
        err = sys_ioctl(fd, cmd, (unsigned long)karg);
        set_fs(old_fs);
        if (err)
-               return err;
+               goto out;
        switch (cmd) {
        case FBIOGET_FSCREENINFO:
-               if (__copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->id,
-                                  (char *)fix.id, sizeof(fix.id)) ||
-                   __put_user((__u32)(unsigned long)fix.smem_start,
-                              &((struct fb_fix_screeninfo32 *)A(arg))->smem_start) ||
-                   __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)A(arg))->smem_len) ||
-                   __put_user(fix.type, &((struct fb_fix_screeninfo32 *)A(arg))->type) ||
-                   __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)A(arg))->type_aux) ||
-                   __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)A(arg))->visual) ||
-                   __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)A(arg))->xpanstep) ||
-                   __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)A(arg))->ypanstep) ||
-                   __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)A(arg))->ywrapstep) ||
-                   __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)A(arg))->line_length) ||
-                   __put_user((__u32)(unsigned long)fix.mmio_start,
-                              &((struct fb_fix_screeninfo32 *)A(arg))->mmio_start) ||
-                   __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)A(arg))->mmio_len) ||
-                   __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)A(arg))->accel) ||
-                   __copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->reserved,
-                                  (char *)fix.reserved, sizeof(fix.reserved)))
-                       return -EFAULT;
+               err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id));
+               err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start);
+               err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len);
+               err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type);
+               err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux);
+               err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual);
+               err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep);
+               err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep);
+               err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep);
+               err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length);
+               err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start);
+               err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len);
+               err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel);
+               err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved));
                break;
        case FBIOGETCMAP:
-               if (__copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->red), cmap.red,
-                                  cmap.len * sizeof(__u16)) ||
-                   __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->green), cmap.blue,
-                                  cmap.len * sizeof(__u16)) ||
-                   __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->blue), cmap.blue,
-                                  cmap.len * sizeof(__u16)) ||
-                   (cmap.transp &&
-                    __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->transp), cmap.transp,
-                                   cmap.len * sizeof(__u16)))) {
-                       kfree(cmap.red);
-                       kfree(cmap.green);
-                       kfree(cmap.blue);
-                       if (cmap.transp)
-                               kfree(cmap.transp);
-                       return -EFAULT;
-               }
-               /* fall through */
-       case FBIOPUTCMAP:
-               kfree(cmap.red);
-               kfree(cmap.green);
-               kfree(cmap.blue);
+               err = __copy_to_user((char *)A(red), cmap.red, cmap.len * sizeof(__u16));
+               err |= __copy_to_user((char *)A(green), cmap.blue, cmap.len * sizeof(__u16));
+               err |= __copy_to_user((char *)A(blue), cmap.blue, cmap.len * sizeof(__u16));
                if (cmap.transp)
-                       kfree(cmap.transp);
+                       err |= __copy_to_user((char *)A(transp), cmap.transp, cmap.len * sizeof(__u16));
+               break;
+       case FBIOPUTCMAP:
                break;
        }
-       return 0;
+out:   if (cmap.red) kfree(cmap.red);
+       if (cmap.green) kfree(cmap.green);
+       if (cmap.blue) kfree(cmap.blue);
+       if (cmap.transp) kfree(cmap.transp);
+       return err;
 }
 
-static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        unsigned long kval;
@@ -632,7 +611,7 @@ static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        set_fs(old_fs);
 
        if(error == 0) {
-               uvp = (unsigned int *)A(arg);
+               uvp = (unsigned int *)arg;
                if(put_user(kval, uvp))
                        error = -EFAULT;
        }
@@ -744,10 +723,10 @@ static struct {
 
 #define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0]))
 
-static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
-       void *karg;
+       void *karg = NULL;
        unsigned int kcmd = 0;
        int i, err;
 
@@ -771,19 +750,18 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                                return -ENOMEM;
                        if (cmd == FDGETPRM32)
                                break;
-                       if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) ||
-                           __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) ||
-                           __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) ||
-                           __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) ||
-                           __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) ||
-                           __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) ||
-                           __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) ||
-                           __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) ||
-                           __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) ||
-                           __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size);
+                       err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+                       err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head);
+                       err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track);
+                       err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+                       err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+                       err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+                       err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+                       err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+                       err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
+                       if (err)
+                               goto out;
                        break;
                }
                case FDSETDRVPRM32:
@@ -796,28 +774,27 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                                return -ENOMEM;
                        if (cmd == FDGETDRVPRM32)
                                break;
-                       if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) ||
-                           __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) ||
-                           __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) ||
-                           __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) ||
-                           __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) ||
-                           __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) ||
-                           __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) ||
-                           __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) ||
-                           __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) ||
-                           __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) ||
-                           __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) ||
-                           __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) ||
-                           __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) ||
-                           __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) ||
-                           __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) ||
-                           __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) ||
-                           __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) ||
-                           __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) ||
-                           __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+                       err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+                       err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+                       err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+                       err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+                       err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+                       err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+                       err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+                       err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+                       err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+                       err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+                       err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+                       err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+                       err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors));
+                       err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+                       err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+                       err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect));
+                       err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+                       err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
+                       if (err)
+                               goto out;
                        break;
                }
                case FDGETDRVSTAT32:
@@ -842,56 +819,48 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        set_fs (KERNEL_DS);
        err = sys_ioctl (fd, kcmd, (unsigned long)karg);
        set_fs (old_fs);
-       if (err) {
-               kfree(karg);
-               return err;
-       }
+       if (err)
+               goto out;
        switch (cmd) {
                case FDGETPRM32:
                {
                        struct floppy_struct *f = karg;
 
-                       if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) ||
-                           __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) ||
-                           __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) ||
-                           __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) ||
-                           __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) ||
-                           __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) ||
-                           __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) ||
-                           __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) ||
-                           __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) ||
-                           __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size);
+                       err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect);
+                       err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head);
+                       err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track);
+                       err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch);
+                       err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap);
+                       err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate);
+                       err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1);
+                       err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap);
+                       err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name);
                        break;
                }
                case FDGETDRVPRM32:
                {
                        struct floppy_drive_params *f = karg;
 
-                       if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) ||
-                           __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) ||
-                           __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) ||
-                           __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) ||
-                           __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) ||
-                           __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) ||
-                           __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) ||
-                           __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) ||
-                           __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) ||
-                           __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) ||
-                           __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) ||
-                           __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) ||
-                           __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) ||
-                           __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) ||
-                           __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) ||
-                           __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) ||
-                           __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) ||
-                           __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) ||
-                           __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos);
+                       err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr);
+                       err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt);
+                       err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut);
+                       err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt);
+                       err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup);
+                       err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown);
+                       err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset);
+                       err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay);
+                       err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps);
+                       err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks);
+                       err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout);
+                       err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect);
+                       err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors));
+                       err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags);
+                       err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track);
+                       err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect));
+                       err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq);
+                       err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format);
                        break;
                }
                case FDGETDRVSTAT32:
@@ -899,66 +868,57 @@ static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                {
                        struct floppy_drive_struct *f = karg;
 
-                       if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) ||
-                           __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) ||
-                           __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) ||
-                           __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) ||
-                           __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) ||
-                           __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) ||
-                           __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) ||
-                           __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) ||
-                           __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) ||
-                           __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) ||
-                           __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) ||
-                           __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) ||
-                           __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) ||
-                           __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) ||
-                           __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags);
+                       err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date);
+                       err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date);
+                       err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date);
+                       err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format);
+                       err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track);
+                       err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock);
+                       err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack);
+                       err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation);
+                       err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data);
+                       err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref);
+                       err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device);
+                       err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked);
+                       err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf);
+                       err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks);
                        break;
                }
                case FDGETFDCSTAT32:
                {
                        struct floppy_fdc_state *f = karg;
 
-                       if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) ||
-                           __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) ||
-                           __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) ||
-                           __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) ||
-                           __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) ||
-                           __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) ||
-                           __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address
-                                          + sizeof(((struct floppy_fdc_state32 *)A(arg))->address),
-                                          (char *)&f->address + sizeof(f->address), sizeof(int)) ||
-                           __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) ||
-                           __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1);
+                       err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2);
+                       err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr);
+                       err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version);
+                       err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor);
+                       err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address);
+                       err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address
+                                          + sizeof(((struct floppy_fdc_state32 *)arg)->address),
+                                          (char *)&f->address + sizeof(f->address), sizeof(int));
+                       err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version);
+                       err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track));
                        break;
                }
                case FDWERRORGET32:
                {
                        struct floppy_write_errors *f = karg;
 
-                       if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) ||
-                           __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) ||
-                           __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) ||
-                           __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) ||
-                           __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) ||
-                           __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) {
-                               kfree(karg);
-                               return -EFAULT;
-                       }
+                       err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors);
+                       err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector);
+                       err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation);
+                       err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector);
+                       err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation);
+                       err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness);
                        break;
                }
                default:
                        break;
        }
-       kfree(karg);
-       return 0;
+out:   if (karg) kfree(karg);
+       return err;
 }
 
 struct ppp_option_data32 {
@@ -974,7 +934,7 @@ struct ppp_idle32 {
 };
 #define PPPIOCGIDLE32          _IOR('t', 63, struct ppp_idle32)
 
-static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        struct ppp_option_data32 data32;
@@ -991,7 +951,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                karg = &idle;
                break;
        case PPPIOCSCOMPRESS32:
-               if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32)))
+               if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
                        return -EFAULT;
                data.ptr = kmalloc (data32.length, GFP_KERNEL);
                if (!data.ptr)
@@ -1006,8 +966,13 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                karg = &data;
                break;
        default:
-               printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
-                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               do {
+                       static int count = 0;
+                       if (++count <= 20)
+                               printk("ppp_ioctl: Unknown cmd fd(%d) "
+                                      "cmd(%08x) arg(%08x)\n",
+                                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               } while(0);
                return -EINVAL;
        }
        set_fs (KERNEL_DS);
@@ -1019,7 +984,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                        return err;
                idle32.xmit_idle = idle.xmit_idle;
                idle32.recv_idle = idle.recv_idle;
-               if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32)))
+               if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32)))
                        return -EFAULT;
                break;
        case PPPIOCSCOMPRESS32:
@@ -1072,7 +1037,7 @@ struct mtconfiginfo32 {
 #define        MTIOCGETCONFIG32        _IOR('m', 4, struct mtconfiginfo32)
 #define        MTIOCSETCONFIG32        _IOW('m', 5, struct mtconfiginfo32)
 
-static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        struct mtconfiginfo info;
@@ -1098,21 +1063,26 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        case MTIOCSETCONFIG32:
                kcmd = MTIOCSETCONFIG;
                karg = &info;
-               if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) ||
-                   __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) ||
-                   __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) ||
-                   __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) ||
-                   __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) ||
-                   __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) ||
-                   __copy_from_user((char *)&info.debug + sizeof(info.debug),
-                                    (char *)&((struct mtconfiginfo32 *)A(arg))->debug
-                                            + sizeof(((struct mtconfiginfo32 *)A(arg))->debug),
-                                    sizeof(__u32)))
+               err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+               err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+               err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+               err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+               err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+               err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+               err |= __copy_from_user((char *)&info.debug + sizeof(info.debug),
+                                    (char *)&((struct mtconfiginfo32 *)arg)->debug
+                                    + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32));
+               if (err)
                        return -EFAULT;
                break;
        default:
-               printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
-                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               do {
+                       static int count = 0;
+                       if (++count <= 20)
+                               printk("mt_ioctl: Unknown cmd fd(%d) "
+                                      "cmd(%08x) arg(%08x)\n",
+                                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               } while(0);
                return -EINVAL;
        }
        set_fs (KERNEL_DS);
@@ -1122,35 +1092,33 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                return err;
        switch (cmd) {
        case MTIOCPOS32:
-               if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno))
+               if (__put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno))
                        return -EFAULT;
                break;
        case MTIOCGET32:
-               if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) ||
-                   __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) ||
-                   __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) ||
-                   __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) ||
-                   __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) ||
-                   __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) ||
-                   __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno))
-                       return -EFAULT;
+               err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type);
+               err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid);
+               err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg);
+               err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat);
+               err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg);
+               err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno);
+               err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno);
                break;
        case MTIOCGETCONFIG32:
-               if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) ||
-                   __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) ||
-                   __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) ||
-                   __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) ||
-                   __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) ||
-                   __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) ||
-                   __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug
-                                          + sizeof(((struct mtconfiginfo32 *)A(arg))->debug),
-                                          (char *)&info.debug + sizeof(info.debug), sizeof(__u32)))
-                       return -EFAULT;
+               err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type);
+               err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type);
+               err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr);
+               err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr);
+               err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port);
+               err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug);
+               err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug
+                                          + sizeof(((struct mtconfiginfo32 *)arg)->debug),
+                                          (char *)&info.debug + sizeof(info.debug), sizeof(__u32));
                break;
        case MTIOCSETCONFIG32:
                break;
        }
-       return 0;
+       return err;
 }
 
 struct cdrom_read32 {
@@ -1166,7 +1134,7 @@ struct cdrom_read_audio32 {
        __kernel_caddr_t32      buf;
 };
 
-static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
+static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        struct cdrom_read cdread;
@@ -1182,9 +1150,10 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
        case CDROMREADRAW:
        case CDROMREADCOOKED:
                karg = &cdread;
-               if (__get_user(cdread.cdread_lba, &((struct cdrom_read32 *)A(arg))->cdread_lba) ||
-                   __get_user(addr, &((struct cdrom_read32 *)A(arg))->cdread_bufaddr) ||
-                   __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)A(arg))->cdread_buflen))
+               err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba);
+               err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr);
+               err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen);
+               if (err)
                        return -EFAULT;
                data = kmalloc(cdread.cdread_buflen, GFP_KERNEL);
                if (!data)
@@ -1193,10 +1162,11 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                break;
        case CDROMREADAUDIO:
                karg = &cdreadaudio;
-               if (copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)A(arg))->addr, sizeof(cdreadaudio.addr)) ||
-                   __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)A(arg))->addr_format) ||
-                   __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)A(arg))->nframes) || 
-                   __get_user(addr, &((struct cdrom_read_audio32 *)A(arg))->buf))
+               err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr));
+               err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format);
+               err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); 
+               err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
+               if (err)
                        return -EFAULT;
                data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
                if (!data)
@@ -1204,38 +1174,35 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg)
                cdreadaudio.buf = data;
                break;
        default:
-               printk("cdrom_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
-                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               do {
+                       static int count = 0;
+                       if (++count <= 20)
+                               printk("cdrom_ioctl: Unknown cmd fd(%d) "
+                                      "cmd(%08x) arg(%08x)\n",
+                                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               } while(0);
                return -EINVAL;
        }
        set_fs (KERNEL_DS);
        err = sys_ioctl (fd, cmd, (unsigned long)karg);
        set_fs (old_fs);
-       if (err) {
-               if (data) kfree(data);
-               return err;
-       }
+       if (err)
+               goto out;
        switch (cmd) {
        case CDROMREADMODE2:
        case CDROMREADMODE1:
        case CDROMREADRAW:
        case CDROMREADCOOKED:
-               if (copy_to_user((char *)A(addr), data, cdread.cdread_buflen)) {
-                       kfree(data);
-                       return -EFAULT;
-               }
+               err = copy_to_user((char *)A(addr), data, cdread.cdread_buflen);
                break;
        case CDROMREADAUDIO:
-               if (copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352)) {
-                       kfree(data);
-                       return -EFAULT;
-               }
+               err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
                break;
        default:
                break;
        }
-       if (data) kfree(data);
-       return 0;
+out:   if (data) kfree(data);
+       return err;
 }
 
 struct loop_info32 {
@@ -1253,7 +1220,7 @@ struct loop_info32 {
        char                    reserved[4];
 };
 
-static int loop_status(unsigned int fd, unsigned int cmd, u32 arg)
+static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        mm_segment_t old_fs = get_fs();
        struct loop_info l;
@@ -1261,12 +1228,13 @@ static int loop_status(unsigned int fd, unsigned int cmd, u32 arg)
 
        switch(cmd) {
        case LOOP_SET_STATUS:
-               if ((get_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) ||
-                    __get_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) ||
-                    __get_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) ||
-                    __get_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) ||
-                    __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)A(arg))->lo_offset,
-                                          8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset)))
+               err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+               err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+               err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+               err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+               err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
+                                          8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+               if (err)
                        return -EFAULT;
                set_fs (KERNEL_DS);
                err = sys_ioctl (fd, cmd, (unsigned long)&l);
@@ -1276,14 +1244,14 @@ static int loop_status(unsigned int fd, unsigned int cmd, u32 arg)
                set_fs (KERNEL_DS);
                err = sys_ioctl (fd, cmd, (unsigned long)&l);
                set_fs (old_fs);
-               if (!err && 
-                   (put_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) ||
-                    __put_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) ||
-                    __put_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) ||
-                    __put_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) ||
-                    __copy_to_user((char *)&((struct loop_info32 *)A(arg))->lo_offset,
-                                          (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset)))
-                       err = -EFAULT;
+               if (!err) {
+                       err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+                       err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+                       err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+                       err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+                       err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
+                                          (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+               }
                break;
        }
        return err;
@@ -1422,7 +1390,7 @@ static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user
        return 0;
 }
 
-asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        struct file * filp;
        int error = -EBADF;
@@ -1433,7 +1401,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                goto out;
 
        if (!filp->f_op || !filp->f_op->ioctl) {
-               error = sys_ioctl (fd, cmd, (unsigned long)arg);
+               error = sys_ioctl (fd, cmd, arg);
                goto out;
        }
        switch (cmd) {
@@ -1535,7 +1503,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case FDPOLLDRVSTAT32:
        case FDGETFDCSTAT32:
        case FDWERRORGET32:
-               error = fd_ioctl_trans(fd, cmd, (unsigned long)arg);
+               error = fd_ioctl_trans(fd, cmd, arg);
                goto out;
 
        case PPPIOCGIDLE32:
@@ -1570,16 +1538,16 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
                
        case PIO_FONTX:
        case GIO_FONTX:
-               error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)A(arg));
+               error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)arg);
                goto out;
                
        case PIO_UNIMAP:
        case GIO_UNIMAP:
-               error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)A(arg));
+               error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)arg);
                goto out;
 
        case KDFONTOP:
-               error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)A(arg));
+               error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)arg);
                goto out;
                
        /* List here exlicitly which ioctl's are known to have
@@ -1822,6 +1790,13 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case SIOCDRARP:
        case SIOCADDDLCI:
        case SIOCDELDLCI:
+       
+       /* SG stuff */
+       case SG_SET_TIMEOUT:
+       case SG_GET_TIMEOUT:
+       case SG_EMULATED_HOST:
+       case SG_SET_TRANSFORM:
+       case SG_GET_TRANSFORM:
 
        /* PPP stuff */
        case PPPIOCGFLAGS:
@@ -1890,12 +1865,17 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
        case AUTOFS_IOC_PROTOVER:
        case AUTOFS_IOC_EXPIRE:
 
-               error = sys_ioctl (fd, cmd, (unsigned long)arg);
+               error = sys_ioctl (fd, cmd, arg);
                goto out;
 
        default:
-               printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
-                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               do {
+                       static int count = 0;
+                       if (++count <= 20)
+                               printk("sys32_ioctl: Unknown cmd fd(%d) "
+                                      "cmd(%08x) arg(%08x)\n",
+                                      (int)fd, (unsigned int)cmd, (unsigned int)arg);
+               } while(0);
                error = -EINVAL;
                break;
        }
index 373d122c3ddbe5adc59e3351293073c1f3707098..5dced0247a388b973b609c017ead74d395757ba9 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.70 1998/08/04 20:49:15 davem Exp $
+/*  $Id: process.c,v 1.75 1998/09/23 02:05:15 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -407,14 +407,20 @@ void flush_thread(void)
                 * where we grab a new one.
                 */
                spin_lock(&scheduler_lock);
-               get_mmu_context(current);
+               current->mm->cpu_vm_mask = 0;
+               activate_context(current);
+               current->mm->cpu_vm_mask = (1UL<<smp_processor_id());
                spin_unlock(&scheduler_lock);
        }
        if (current->tss.flags & SPARC_FLAG_32BIT)
-               __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r"(TSB_REG), "i"(ASI_DMMU));
+               __asm__ __volatile__("stxa %%g0, [%0] %1"
+                                    : /* no outputs */
+                                    : "r"(TSB_REG), "i"(ASI_DMMU));
+       __cli();
        current->tss.ctx = current->mm->context & 0x3ff;
        spitfire_set_secondary_context (current->tss.ctx);
        __asm__ __volatile__("flush %g6");
+       __sti();
 }
 
 /* It's a bit more tricky when 64-bit tasks are involved... */
@@ -592,7 +598,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-#if 0
+#if 1
+       /* Only should be used for SunOS and ancient a.out
+        * SparcLinux binaries...  Fixme some day when bored.
+        * But for now at least plug the security hole :-)
+        */
+       memset(dump, 0, sizeof(struct user));
+#else
        unsigned long first_stack_page;
        dump->magic = SUNOS_CORE_MAGIC;
        dump->len = sizeof(struct user);
@@ -616,13 +628,69 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
 #endif 
 }
 
+typedef struct {
+       union {
+               unsigned int    pr_regs[32];
+               unsigned long   pr_dregs[16];
+       } pr_fr;
+       unsigned int __unused;
+       unsigned int    pr_fsr;
+       unsigned char   pr_qcnt;
+       unsigned char   pr_q_entrysize;
+       unsigned char   pr_en;
+       unsigned int    pr_q[64];
+} elf_fpregset_t32;
+
 /*
  * fill in the fpu structure for a core dump.
  */
 int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
 {
-       /* Currently we report that we couldn't dump the fpu structure */
-       return 0;
+       unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
+       unsigned long fprs = current->tss.fpsaved[0];
+
+       if ((current->tss.flags & SPARC_FLAG_32BIT) != 0) {
+               elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs;
+
+               if (fprs & FPRS_DL)
+                       memcpy(&fpregs32->pr_fr.pr_regs[0], kfpregs,
+                              sizeof(unsigned int) * 32);
+               else
+                       memset(&fpregs32->pr_fr.pr_regs[0], 0,
+                              sizeof(unsigned int) * 32);
+               fpregs32->pr_qcnt = 0;
+               fpregs32->pr_q_entrysize = 8;
+               memset(&fpregs32->pr_q[0], 0,
+                      (sizeof(unsigned int) * 64));
+               if (fprs & FPRS_FEF) {
+                       fpregs32->pr_fsr = (unsigned int) current->tss.xfsr[0];
+                       fpregs32->pr_en = 1;
+               } else {
+                       fpregs32->pr_fsr = 0;
+                       fpregs32->pr_en = 0;
+               }
+       } else {
+               if(fprs & FPRS_DL)
+                       memcpy(&fpregs->pr_regs[0], kfpregs,
+                              sizeof(unsigned int) * 32);
+               else
+                       memset(&fpregs->pr_regs[0], 0,
+                              sizeof(unsigned int) * 32);
+               if(fprs & FPRS_DU)
+                       memcpy(&fpregs->pr_regs[16], kfpregs+16,
+                              sizeof(unsigned int) * 32);
+               else
+                       memset(&fpregs->pr_regs[16], 0,
+                              sizeof(unsigned int) * 32);
+               if(fprs & FPRS_FEF) {
+                       fpregs->pr_fsr = current->tss.xfsr[0];
+                       fpregs->pr_gsr = current->tss.gsr[0];
+               } else {
+                       fpregs->pr_fsr = fpregs->pr_gsr = 0;
+               }
+               fpregs->pr_fprs = fprs;
+       }
+       return 1;
 }
 
 /*
index 32d9b13c1a43bab0a57982273f0cd2f3a15db913..149c893b0affbe04efffc84aae6c6e3056cfcfd0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: psycho.c,v 1.63 1998/08/02 05:55:42 ecd Exp $
+/* $Id: psycho.c,v 1.64 1998/09/01 07:24:24 jj Exp $
  * psycho.c: Ultra/AX U2P PCI controller support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
@@ -75,7 +75,6 @@ asmlinkage int sys_pciconfig_write(unsigned long bus,
 #include <asm/uaccess.h>
 
 struct linux_psycho *psycho_root = NULL;
-struct linux_psycho **psycho_index_map;
 int linux_num_psycho = 0;
 static struct linux_pbm_info *bus2pbm[256];
 
@@ -534,18 +533,6 @@ __initfunc(void pcibios_init(void))
                if(!node)
                        break;
        }
-
-       /* Last minute sanity check. */
-       if(psycho_root == NULL && SBus_chain == NULL) {
-               prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
-               prom_halt();
-       }
-
-       psycho_index_map = kmalloc(sizeof(struct linux_psycho *) * linux_num_psycho,
-                                  GFP_ATOMIC);
-
-       for (psycho = psycho_root; psycho; psycho = psycho->next)
-               psycho_index_map[psycho->index] = psycho;
 }
 
 int pcibios_present(void)
index 85732960f45d6c9c9f797a3b9cfdbb1d71eeba5c..4784b3c7cb1240d55931c2b364dbffcbe1dfbae7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.39 1998/07/26 03:02:49 davem Exp $
+/* $Id: rtrap.S,v 1.40 1998/09/23 02:05:18 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -144,7 +144,12 @@ check_user_wins:brz,pt                     %o2, 1f
                call                    fault_in_user_windows
                 add                    %sp, STACK_BIAS + REGWIN_SZ, %o0
 
-1:             andcc                   %l1, %l6, %g0
+1:
+#if 0
+               call                    rtrap_check
+                add                    %sp, STACK_BIAS + REGWIN_SZ, %o0
+#endif
+               andcc                   %l1, %l6, %g0
                be,pt                   %xcc, rt_continue
                 stb                    %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only
 
index de0124f520b9712ab74b631c0ec4ed47a0a8fce1..a7274cab51ae081694103d67cdf8d51371c7858b 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.30 1998/07/24 09:50:08 jj Exp $
+/*  $Id: setup.c,v 1.32 1998/09/24 03:21:37 davem Exp $
  *  linux/arch/sparc64/kernel/setup.c
  *
  *  Copyright (C) 1995,1996  David S. Miller (davem@caip.rutgers.edu)
@@ -56,8 +56,6 @@ struct screen_info screen_info = {
        16                      /* orig-video-points */
 };
 
-unsigned int phys_bytes_of_ram, end_of_phys_memory;
-
 /* Typing sync at the prom prompt calls the function pointed to by
  * the sync callback which I set to the following function.
  * This should sync all filesystems and return, for now it just
@@ -235,8 +233,8 @@ extern unsigned long sun_serial_setup(unsigned long);
 extern unsigned short root_flags;
 extern unsigned short root_dev;
 extern unsigned short ram_flags;
-extern unsigned ramdisk_image;
-extern unsigned ramdisk_size;
+extern unsigned int ramdisk_image;
+extern unsigned int ramdisk_size;
 #define RAMDISK_IMAGE_START_MASK       0x07FF
 #define RAMDISK_PROMPT_FLAG            0x8000
 #define RAMDISK_LOAD_FLAG              0x4000
@@ -278,7 +276,7 @@ __initfunc(void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
        extern int serial_console;  /* in console.c, of course */
-       unsigned long lowest_paddr;
+       unsigned long lowest_paddr, end_of_phys_memory = 0;
        int total, i;
 
 #ifdef PROM_DEBUG_CONSOLE
@@ -441,6 +439,8 @@ extern int smp_info(char *);
 extern int smp_bogo(char *);
 extern int mmu_info(char *);
 
+unsigned long dcache_aliases_found = 0;
+
 int get_cpuinfo(char *buffer)
 {
        int cpuid=smp_processor_id();
@@ -454,6 +454,7 @@ int get_cpuinfo(char *buffer)
             "type\t\t: sun4u\n"
            "ncpus probed\t: %d\n"
            "ncpus active\t: %d\n"
+           "d-aliases\t: %lu\n"
 #ifndef __SMP__
             "BogoMips\t: %lu.%02lu\n"
 #endif
@@ -461,7 +462,7 @@ int get_cpuinfo(char *buffer)
             sparc_cpu_type[cpuid],
             sparc_fpu_type[cpuid],
             prom_rev, prom_prev >> 16, (prom_prev >> 8) & 0xff, prom_prev & 0xff,
-           linux_num_cpus, smp_num_cpus
+           linux_num_cpus, smp_num_cpus, dcache_aliases_found
 #ifndef __SMP__
             , loops_per_sec/500000, (loops_per_sec/5000) % 100
 #endif
index 004e0e81e2b7d0a9a1a160b25fc6de6b677b45b8..3fc95ad6224994e97742ff7e6fa204fea7626a4c 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.30 1998/07/30 11:29:34 davem Exp $
+/*  $Id: signal.c,v 1.37 1998/09/25 01:09:22 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -39,6 +39,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
 
 /* This turned off for production... */
 /* #define DEBUG_SIGNALS 1 */
+/* #define DEBUG_SIGNALS_TRACE 1 */
+/* #define DEBUG_SIGNALS_MAPS 1 */
 
 /* {set, get}context() needed for 64-bit SparcLinux userland. */
 asmlinkage void sparc64_set_context(struct pt_regs *regs)
@@ -49,16 +51,17 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        unsigned long pc, npc, tstate;
        unsigned long fp, i7;
        unsigned char fenab;
+       int err;
 
        __asm__ __volatile__("flushw");
        if(tp->w_saved                                          ||
           (((unsigned long)ucp) & (sizeof(unsigned long)-1))   ||
           (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
                goto do_sigsegv;
-       grp = &ucp->uc_mcontext.mc_gregs;
-       __get_user(pc, &((*grp)[MC_PC]));
-       __get_user(npc, &((*grp)[MC_NPC]));
-       if((pc | npc) & 3)
+       grp  = &ucp->uc_mcontext.mc_gregs;
+       err  = __get_user(pc, &((*grp)[MC_PC]));
+       err |= __get_user(npc, &((*grp)[MC_NPC]));
+       if(err || ((pc | npc) & 3))
                goto do_sigsegv;
        if(regs->u_regs[UREG_I1]) {
                sigset_t set;
@@ -78,48 +81,57 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        }
        regs->tpc = pc;
        regs->tnpc = npc;
-       __get_user(regs->y, &((*grp)[MC_Y]));
-       __get_user(tstate, &((*grp)[MC_TSTATE]));
+       err |= __get_user(regs->y, &((*grp)[MC_Y]));
+       err |= __get_user(tstate, &((*grp)[MC_TSTATE]));
        regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC);
        regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC));
-       __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
-       __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2]));
-       __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3]));
-       __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4]));
-       __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5]));
-       __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6]));
-       __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7]));
-       __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0]));
-       __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1]));
-       __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2]));
-       __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3]));
-       __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4]));
-       __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5]));
-       __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6]));
-       __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7]));
-
-       __get_user(fp, &(ucp->uc_mcontext.mc_fp));
-       __get_user(i7, &(ucp->uc_mcontext.mc_i7));
-       __put_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
-       __put_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
-
-       __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
+       err |= __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1]));
+       err |= __get_user(regs->u_regs[UREG_G2], (&(*grp)[MC_G2]));
+       err |= __get_user(regs->u_regs[UREG_G3], (&(*grp)[MC_G3]));
+       err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4]));
+       err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5]));
+       err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6]));
+       err |= __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7]));
+       err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0]));
+       err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1]));
+       err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2]));
+       err |= __get_user(regs->u_regs[UREG_I3], (&(*grp)[MC_O3]));
+       err |= __get_user(regs->u_regs[UREG_I4], (&(*grp)[MC_O4]));
+       err |= __get_user(regs->u_regs[UREG_I5], (&(*grp)[MC_O5]));
+       err |= __get_user(regs->u_regs[UREG_I6], (&(*grp)[MC_O6]));
+       err |= __get_user(regs->u_regs[UREG_I7], (&(*grp)[MC_O7]));
+
+       err |= __get_user(fp, &(ucp->uc_mcontext.mc_fp));
+       err |= __get_user(i7, &(ucp->uc_mcontext.mc_i7));
+       err |= __put_user(fp,
+             (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
+       err |= __put_user(i7,
+             (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
+
+       err |= __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab));
        if(fenab) {
                unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
                unsigned long fprs;
                
                fprs_write(0);
-               __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
+               err |= __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs));
                if (fprs & FPRS_DL)
-                       copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
-                                      (sizeof(unsigned int) * 32));
+                       err |= copy_from_user(fpregs,
+                                             &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs),
+                                             (sizeof(unsigned int) * 32));
                if (fprs & FPRS_DU)
-                       copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
-                                      (sizeof(unsigned int) * 32));
-               __get_user(current->tss.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
-               __get_user(current->tss.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
+                       err |= copy_from_user(fpregs+16,
+                        ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16,
+                        (sizeof(unsigned int) * 32));
+               err |= __get_user(current->tss.xfsr[0],
+                                 &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr));
+               err |= __get_user(current->tss.gsr[0],
+                                 &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
                regs->tstate &= ~TSTATE_PEF;
        }
+       if (err)
+               goto do_sigsegv;
+
        return;
 do_sigsegv:
        lock_kernel();
@@ -134,6 +146,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
        mcontext_t *mcp;
        unsigned long fp, i7;
        unsigned char fenab;
+       int err;
 
        synchronize_user_stack();
        if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
@@ -152,52 +165,61 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
        regs->tpc   = regs->tnpc;
        regs->tnpc += 4;
 
+       err = 0;
        if (_NSIG_WORDS == 1)
-               __put_user(current->blocked.sig[0], (unsigned long *)&ucp->uc_sigmask);
+               err |= __put_user(current->blocked.sig[0],
+                                 (unsigned long *)&ucp->uc_sigmask);
        else
-               __copy_to_user(&ucp->uc_sigmask, &current->blocked, sizeof(sigset_t));
-
-       __put_user(regs->tstate, &((*grp)[MC_TSTATE]));
-       __put_user(regs->tpc, &((*grp)[MC_PC]));
-       __put_user(regs->tnpc, &((*grp)[MC_NPC]));
-       __put_user(regs->y, &((*grp)[MC_Y]));
-       __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1]));
-       __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2]));
-       __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3]));
-       __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4]));
-       __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5]));
-       __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6]));
-       __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7]));
-       __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0]));
-       __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1]));
-       __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2]));
-       __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3]));
-       __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4]));
-       __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5]));
-       __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6]));
-       __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7]));
-
-       __get_user(fp, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
-       __get_user(i7, (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
-       __put_user(fp, &(mcp->mc_fp));
-       __put_user(i7, &(mcp->mc_i7));
-
-       __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
+               err |= __copy_to_user(&ucp->uc_sigmask, &current->blocked,
+                                     sizeof(sigset_t));
+
+       err |= __put_user(regs->tstate, &((*grp)[MC_TSTATE]));
+       err |= __put_user(regs->tpc, &((*grp)[MC_PC]));
+       err |= __put_user(regs->tnpc, &((*grp)[MC_NPC]));
+       err |= __put_user(regs->y, &((*grp)[MC_Y]));
+       err |= __put_user(regs->u_regs[UREG_G1], &((*grp)[MC_G1]));
+       err |= __put_user(regs->u_regs[UREG_G2], &((*grp)[MC_G2]));
+       err |= __put_user(regs->u_regs[UREG_G3], &((*grp)[MC_G3]));
+       err |= __put_user(regs->u_regs[UREG_G4], &((*grp)[MC_G4]));
+       err |= __put_user(regs->u_regs[UREG_G5], &((*grp)[MC_G5]));
+       err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G6]));
+       err |= __put_user(regs->u_regs[UREG_G6], &((*grp)[MC_G7]));
+       err |= __put_user(regs->u_regs[UREG_I0], &((*grp)[MC_O0]));
+       err |= __put_user(regs->u_regs[UREG_I1], &((*grp)[MC_O1]));
+       err |= __put_user(regs->u_regs[UREG_I2], &((*grp)[MC_O2]));
+       err |= __put_user(regs->u_regs[UREG_I3], &((*grp)[MC_O3]));
+       err |= __put_user(regs->u_regs[UREG_I4], &((*grp)[MC_O4]));
+       err |= __put_user(regs->u_regs[UREG_I5], &((*grp)[MC_O5]));
+       err |= __put_user(regs->u_regs[UREG_I6], &((*grp)[MC_O6]));
+       err |= __put_user(regs->u_regs[UREG_I7], &((*grp)[MC_O7]));
+
+       err |= __get_user(fp,
+                (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[6])));
+       err |= __get_user(i7,
+                (&(((struct reg_window *)(STACK_BIAS+regs->u_regs[UREG_I6]))->ins[7])));
+       err |= __put_user(fp, &(mcp->mc_fp));
+       err |= __put_user(i7, &(mcp->mc_i7));
+
+       err |= __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab));
        if(fenab) {
                unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
                unsigned long fprs;
                
                fprs = current->tss.fpsaved[0];
                if (fprs & FPRS_DL)
-                       copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
-                                    (sizeof(unsigned int) * 32));
+                       err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs,
+                                           (sizeof(unsigned int) * 32));
                if (fprs & FPRS_DU)
-                       copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
-                                    (sizeof(unsigned int) * 32));
-               __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
-               __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
-               __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
+                       err |= copy_to_user(
+                          ((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16,
+                         (sizeof(unsigned int) * 32));
+               err |= __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr));
+               err |= __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr));
+               err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs));
        }
+       if (err)
+               goto do_sigsegv;
+
        return;
 do_sigsegv:
        lock_kernel();
@@ -474,22 +496,25 @@ static int invalid_frame_pointer(void *fp, int fplen)
        return 0;
 }
 
-static inline void
+static inline int
 save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
        unsigned long *fpregs = (unsigned long *)(regs+1);
        unsigned long fprs;
+       int err = 0;
        
        fprs = current->tss.fpsaved[0];
        if (fprs & FPRS_DL)
-               copy_to_user(&fpu->si_float_regs[0], fpregs,
-                            (sizeof(unsigned int) * 32));
+               err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+                                   (sizeof(unsigned int) * 32));
        if (fprs & FPRS_DU)
-               copy_to_user(&fpu->si_float_regs[32], fpregs+16,
-                            (sizeof(unsigned int) * 32));
-       __put_user(current->tss.xfsr[0], &fpu->si_fsr);
-       __put_user(current->tss.gsr[0], &fpu->si_gsr);
-       __put_user(fprs, &fpu->si_fprs);
+               err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+                                   (sizeof(unsigned int) * 32));
+       err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
+       err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+       err |= __put_user(fprs, &fpu->si_fprs);
+
+       return err;
 }
 
 static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
@@ -500,7 +525,8 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, u
 
        /* This is the X/Open sanctioned signal stack switching.  */
        if (ka->sa.sa_flags & SA_ONSTACK) {
-               if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
+               if (!on_sig_stack(sp) &&
+                   !((current->sas_ss_sp + current->sas_ss_size) & 7))
                        sp = current->sas_ss_sp + current->sas_ss_size;
        }
        return (void *)(sp - framesize);
@@ -511,7 +537,7 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
                  int signo, sigset_t *oldset)
 {
        struct new_signal_frame *sf;
-       int sigframe_size;
+       int sigframe_size, err;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
@@ -534,22 +560,25 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 2. Save the current process state */
-       copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
+       err = copy_to_user(&sf->info.si_regs, regs, sizeof (*regs));
        
        if (current->tss.fpsaved[0] & FPRS_FEF) {
-               save_fpu_state(regs, &sf->fpu_state);
-               __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
 
-       __put_user(oldset->sig[0], &sf->info.si_mask);
+       err |= __put_user(oldset->sig[0], &sf->info.si_mask);
        if (_NSIG_WORDS > 1)
-               __copy_to_user(sf->extramask, &oldset->sig[1], sizeof(sf->extramask));
+               err |= __copy_to_user(sf->extramask, &oldset->sig[1],
+                                     sizeof(sf->extramask));
 
-       copy_in_user((u64 *)sf,
-                    (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
-                    sizeof(struct reg_window));
+       err |= copy_in_user((u64 *)sf,
+                           (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
+                           sizeof(struct reg_window));
+       if (err)
+               goto sigsegv;
        
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
@@ -572,8 +601,13 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
 
                regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
                
-               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
-               __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */
+               /* mov __NR_sigreturn, %g1 */
+               err |= __put_user(0x821020d8, &sf->insns[0]);
+
+               /* t 0x6d */
+               err |= __put_user(0x91d0206d, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
 
                if(pte_present(*ptep)) {
                        unsigned long page = pte_page(*ptep);
@@ -590,6 +624,9 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
 sigill:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 static inline void
@@ -597,7 +634,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
               int signo, sigset_t *oldset, siginfo_t *info)
 {
        struct rt_signal_frame *sf;
-       int sigframe_size;
+       int sigframe_size, err;
 
        /* 1. Make sure everything is clean */
        synchronize_user_stack();
@@ -619,27 +656,29 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
        }
 
        /* 2. Save the current process state */
-       copy_to_user(&sf->regs, regs, sizeof (*regs));
+       err = copy_to_user(&sf->regs, regs, sizeof (*regs));
 
        if (current->tss.fpsaved[0] & FPRS_FEF) {
-               save_fpu_state(regs, &sf->fpu_state);
-               __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state(regs, &sf->fpu_state);
+               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
        
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
-       __put_user(current->sas_ss_size, &sf->stack.ss_size);
+       err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
 
-       copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
+       err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
 
-       copy_in_user((u64 *)sf,
-                    (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
-                    sizeof(struct reg_window));
+       err |= copy_in_user((u64 *)sf,
+                           (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS),
+                           sizeof(struct reg_window));
 
-       copy_to_user(&sf->info, info, sizeof(siginfo_t));
+       err |= copy_to_user(&sf->info, info, sizeof(siginfo_t));
+       if (err)
+               goto sigsegv;
        
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS;
@@ -662,8 +701,13 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
 
                regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
                
-               __put_user(0x82102065, &sf->insns[0]); /* mov __NR_rt_sigreturn, %g1 */
-               __put_user(0x91d0206d, &sf->insns[1]); /* t 0x6d */
+               /* mov __NR_rt_sigreturn, %g1 */
+               err |= __put_user(0x82102065, &sf->insns[0]);
+
+               /* t 0x6d */
+               err |= __put_user(0x91d0206d, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
 
                if(pte_present(*ptep)) {
                        unsigned long page = pte_page(*ptep);
@@ -680,6 +724,9 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
 sigill:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
@@ -721,6 +768,60 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs,
        }
 }
 
+#ifdef DEBUG_SIGNALS_MAPS
+
+#define MAPS_LINE_FORMAT         "%016lx-%016lx %s %016lx %s %lu "
+
+static inline void read_maps (void)
+{
+       struct vm_area_struct * map, * next;
+       char * buffer;
+       ssize_t i;
+
+       buffer = (char*)__get_free_page(GFP_KERNEL);
+       if (!buffer)
+               return;
+
+       for (map = current->mm->mmap ; map ; map = next ) {
+               /* produce the next line */
+               char *line;
+               char str[5], *cp = str;
+               int flags;
+               kdev_t dev;
+               unsigned long ino;
+
+               /*
+                * Get the next vma now (but it won't be used if we sleep).
+                */
+               next = map->vm_next;
+               flags = map->vm_flags;
+
+               *cp++ = flags & VM_READ ? 'r' : '-';
+               *cp++ = flags & VM_WRITE ? 'w' : '-';
+               *cp++ = flags & VM_EXEC ? 'x' : '-';
+               *cp++ = flags & VM_MAYSHARE ? 's' : 'p';
+               *cp++ = 0;
+
+               dev = 0;
+               ino = 0;
+               if (map->vm_file != NULL) {
+                       dev = map->vm_file->f_dentry->d_inode->i_dev;
+                       ino = map->vm_file->f_dentry->d_inode->i_ino;
+                       line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE);
+               }
+               printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset,
+                             kdevname(dev), ino);
+               if (map->vm_file != NULL)
+                       printk("%s\n", line);
+               else
+                       printk("\n");
+       }
+       free_page((unsigned long)buffer);
+       return;
+}
+
+#endif
+
 /* Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  * mistake.
@@ -824,9 +925,26 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs,
                                        unlock_kernel();
                                }
 #ifdef DEBUG_SIGNALS
-                               /* Very useful to debug dynamic linker problems */
-                               printk ("Sig ILL going...\n");
+                               /* Very useful to debug the dynamic linker */
+                               printk ("Sig %d going...\n", (int)signr);
                                show_regs (regs);
+#ifdef DEBUG_SIGNALS_TRACE
+                               {
+                                       struct reg_window *rw = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
+                                       unsigned long ins[8];
+                                                
+                                       while(rw &&
+                                             !(((unsigned long) rw) & 0x3)) {
+                                               copy_from_user(ins, &rw->ins[0], sizeof(ins));
+                                               printk("Caller[%016lx](%016lx,%016lx,%016lx,%016lx,%016lx,%016lx)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]);
+                                               rw = (struct reg_window *)(unsigned long)(ins[6] + STACK_BIAS);
+                                       }
+                               }
+#endif                 
+#ifdef DEBUG_SIGNALS_MAPS      
+                               printk("Maps:\n");
+                               read_maps();
+#endif
 #endif
                                /* fall through */
                        default:
index b62ab65ff15e31a9b720ca27b9742f8646ff8082..a8f0c2fc68b44cd90cf4b60b4d44438cf9fa4433 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.41 1998/07/30 11:29:32 davem Exp $
+/*  $Id: signal32.c,v 1.44 1998/09/25 01:09:17 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -39,6 +39,7 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs,
 /* #define DEBUG_SIGNALS 1 */
 /* #define DEBUG_SIGNALS_TRACE 1 */
 /* #define DEBUG_SIGNALS_MAPS 1 */
+/* #define DEBUG_SIGNALS_TLB 1 */
 
 /* Signal frames: the original one (compatible with SunOS):
  *
@@ -270,8 +271,10 @@ void do_new_sigreturn32(struct pt_regs *regs)
        recalc_sigpending(current);
        spin_unlock_irq(&current->sigmask_lock);
        return;
+
 segv:
-       send_sig(SIGSEGV, current, 1);
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 asmlinkage void do_sigreturn32(struct pt_regs *regs)
@@ -329,8 +332,10 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs)
        regs->tstate &= ~(TSTATE_ICC);
        regs->tstate |= psr_to_tstate_icc(psr);
        return;
+
 segv:
-       send_sig(SIGSEGV, current, 1);
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
@@ -412,7 +417,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
        spin_unlock_irq(&current->sigmask_lock);
        return;
 segv:
-       send_sig(SIGSEGV, current, 1);
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 /* Checks if the fp is valid */
@@ -445,6 +451,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        struct signal_sframe32 *sframep;
        struct sigcontext32 *sc;
        unsigned seta[_NSIG_WORDS32];
+       int err = 0;
        
 #if 0  
        int window = 0;
@@ -472,7 +479,8 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        sc = &sframep->sig_context;
 
        /* We've already made sure frame pointer isn't in kernel space... */
-       __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack);
+       err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK),
+                        &sc->sigc_onstack);
        
        switch (_NSIG_WORDS) {
        case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -484,67 +492,81 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        case 1: seta[1] = (oldset->sig[0] >> 32);
                seta[0] = oldset->sig[0];
        }
-       __put_user(seta[0], &sc->sigc_mask);
-       __copy_to_user(sframep->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
-       __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
-       __put_user(pc, &sc->sigc_pc);
-       __put_user(npc, &sc->sigc_npc);
+       err |= __put_user(seta[0], &sc->sigc_mask);
+       err |= __copy_to_user(sframep->extramask, seta + 1,
+                             (_NSIG_WORDS32 - 1) * sizeof(unsigned));
+       err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp);
+       err |= __put_user(pc, &sc->sigc_pc);
+       err |= __put_user(npc, &sc->sigc_npc);
        psr = tstate_to_psr (regs->tstate);
        if(current->tss.fpsaved[0] & FPRS_FEF)
                psr |= PSR_EF;
-       __put_user(psr, &sc->sigc_psr);
-       __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
-       __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
-       __put_user(current->tss.w_saved, &sc->sigc_oswins);
+       err |= __put_user(psr, &sc->sigc_psr);
+       err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1);
+       err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0);
+       err |= __put_user(current->tss.w_saved, &sc->sigc_oswins);
 #if 0
 /* w_saved is not currently used... */
        if(current->tss.w_saved)
                for(window = 0; window < current->tss.w_saved; window++) {
                        sc->sigc_spbuf[window] =
                                (char *)current->tss.rwbuf_stkptrs[window];
-                       copy_to_user(&sc->sigc_wbuf[window],
-                              &current->tss.reg_window[window],
-                              sizeof(struct reg_window));
+                       err |= copy_to_user(&sc->sigc_wbuf[window],
+                                           &current->tss.reg_window[window],
+                                           sizeof(struct reg_window));
                }
        else
 #endif 
-               copy_in_user((u32 *)sframep,
-                            (u32 *)(regs->u_regs[UREG_FP]),
-                            sizeof(struct reg_window32));
+               err |= copy_in_user((u32 *)sframep,
+                                   (u32 *)(regs->u_regs[UREG_FP]),
+                                   sizeof(struct reg_window32));
                       
        current->tss.w_saved = 0; /* So process is allowed to execute. */
-       __put_user(signr, &sframep->sig_num);
+       err |= __put_user(signr, &sframep->sig_num);
        if(signr == SIGSEGV ||
           signr == SIGILL ||
           signr == SIGFPE ||
           signr == SIGBUS ||
           signr == SIGEMT) {
-               __put_user(current->tss.sig_desc, &sframep->sig_code);
-               __put_user(current->tss.sig_address, &sframep->sig_address);
+               err |= __put_user(current->tss.sig_desc, &sframep->sig_code);
+               err |= __put_user(current->tss.sig_address, &sframep->sig_address);
        } else {
-               __put_user(0, &sframep->sig_code);
-               __put_user(0, &sframep->sig_address);
+               err |= __put_user(0, &sframep->sig_code);
+               err |= __put_user(0, &sframep->sig_address);
        }
-       __put_user((u64)sc, &sframep->sig_scptr);
+       err |= __put_user((u64)sc, &sframep->sig_scptr);
+       if (err)
+               goto sigsegv;
+
        regs->u_regs[UREG_FP] = (unsigned long) sframep;
        regs->tpc = (unsigned long) sa->sa_handler;
        regs->tnpc = (regs->tpc + 4);
+       return;
+
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 
-static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
+static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu)
 {
        unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs);
        unsigned long fprs;
+       int err = 0;
        
        fprs = current->tss.fpsaved[0];
        if (fprs & FPRS_DL)
-               copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32));
+               err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+                                   (sizeof(unsigned int) * 32));
        if (fprs & FPRS_DU)
-               copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32));
-       __put_user(current->tss.xfsr[0], &fpu->si_fsr);
-       __put_user(current->tss.gsr[0], &fpu->si_gsr);
-       __put_user(fprs, &fpu->si_fprs);
+               err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+                                   (sizeof(unsigned int) * 32));
+       err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr);
+       err |= __put_user(current->tss.gsr[0], &fpu->si_gsr);
+       err |= __put_user(fprs, &fpu->si_fprs);
+
+       return err;
 }
 
 static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
@@ -553,7 +575,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
        struct new_signal_frame32 *sf;
        int sigframe_size;
        u32 psr;
-       int i;
+       int i, err;
        unsigned seta[_NSIG_WORDS32];
 
        /* 1. Make sure everything is clean */
@@ -583,21 +605,21 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
        }
 
        /* 2. Save the current process state */
-       put_user(regs->tpc, &sf->info.si_regs.pc);
-       __put_user(regs->tnpc, &sf->info.si_regs.npc);
-       __put_user(regs->y, &sf->info.si_regs.y);
+       err  = put_user(regs->tpc, &sf->info.si_regs.pc);
+       err |= __put_user(regs->tnpc, &sf->info.si_regs.npc);
+       err |= __put_user(regs->y, &sf->info.si_regs.y);
        psr = tstate_to_psr (regs->tstate);
        if(current->tss.fpsaved[0] & FPRS_FEF)
                psr |= PSR_EF;
-       __put_user(psr, &sf->info.si_regs.psr);
+       err |= __put_user(psr, &sf->info.si_regs.psr);
        for (i = 0; i < 16; i++)
-               __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+               err |= __put_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
 
        if (psr & PSR_EF) {
-               save_fpu_state32(regs, &sf->fpu_state);
-               __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state32(regs, &sf->fpu_state);
+               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
 
        switch (_NSIG_WORDS) {
@@ -610,13 +632,17 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
        case 1: seta[1] = (oldset->sig[0] >> 32);
                seta[0] = oldset->sig[0];
        }
-       __put_user(seta[0], &sf->info.si_mask);
-       __copy_to_user(sf->extramask, seta + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned));
+       err |= __put_user(seta[0], &sf->info.si_mask);
+       err |= __copy_to_user(sf->extramask, seta + 1,
+                             (_NSIG_WORDS32 - 1) * sizeof(unsigned));
 
-       copy_in_user((u32 *)sf,
-                    (u32 *)(regs->u_regs[UREG_FP]),
-                    sizeof(struct reg_window32));
+       err |= copy_in_user((u32 *)sf,
+                           (u32 *)(regs->u_regs[UREG_FP]),
+                           sizeof(struct reg_window32));
        
+       if (err)
+               goto sigsegv;
+
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = (unsigned long) sf;
        regs->u_regs[UREG_I0] = signo;
@@ -638,8 +664,10 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
 
                regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
        
-               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
-               __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+               err  = __put_user(0x821020d8, &sf->insns[0]); /*mov __NR_sigreturn, %g1*/
+               err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
+               if(err)
+                       goto sigsegv;
 
                if(pte_present(*ptep)) {
                        unsigned long page = pte_page(*ptep);
@@ -656,6 +684,9 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg
 sigill:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 /* Setup a Solaris stack frame */
@@ -674,7 +705,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        int window = 0;
 #endif 
        unsigned psr;
-       int i;
+       int i, err;
 
        synchronize_user_stack();
        save_and_clear_fpu();
@@ -691,7 +722,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        }
 
        /* Start with a clean frame pointer and fill it */
-       clear_user(sfp, sizeof (*sfp));
+       err = clear_user(sfp, sizeof (*sfp));
 
        /* Setup convenience variables */
        si = &sfp->si;
@@ -709,37 +740,37 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
        if (_NSIG_WORDS >= 2) {
                setv.sigbits[2] = oldset->sig[1];
                setv.sigbits[3] = (oldset->sig[1] >> 32);
-               __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+               err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
        } else
-               __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
+               err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
        
        /* Store registers */
-       __put_user(regs->tpc, &((*gr) [SVR4_PC]));
-       __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
+       err |= __put_user(regs->tpc, &((*gr) [SVR4_PC]));
+       err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC]));
        psr = tstate_to_psr (regs->tstate);
        if(current->tss.fpsaved[0] & FPRS_FEF)
                psr |= PSR_EF;
-       __put_user(psr, &((*gr) [SVR4_PSR]));
-       __put_user(regs->y, &((*gr) [SVR4_Y]));
+       err |= __put_user(psr, &((*gr) [SVR4_PSR]));
+       err |= __put_user(regs->y, &((*gr) [SVR4_Y]));
        
        /* Copy g [1..7] and o [0..7] registers */
        for (i = 0; i < 7; i++)
-               __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+               err |= __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
        for (i = 0; i < 8; i++)
-               __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+               err |= __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &uc->stack.sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
-       __put_user(current->sas_ss_size, &uc->stack.size);
+       err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+       err |= __put_user(current->sas_ss_size, &uc->stack.size);
 
        /* Save the currently window file: */
 
        /* 1. Link sfp->uc->gwins to our windows */
-       __put_user((u32)(long)gw, &mc->gwin);
+       err |= __put_user((u32)(long)gw, &mc->gwin);
            
        /* 2. Number of windows to restore at setcontext (): */
-       __put_user(current->tss.w_saved, &gw->count);
+       err |= __put_user(current->tss.w_saved, &gw->count);
 
        /* 3. Save each valid window
         *    Currently, it makes a copy of the windows from the kernel copy.
@@ -754,9 +785,12 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
         */
 #if 0   
        for(window = 0; window < current->tss.w_saved; window++) {
-               __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window );
-               copy_to_user(&gw->win [window], &current->tss.reg_window [window], sizeof (svr4_rwindow_t));
-               __put_user(0, (int *)gw->winptr + window);
+               err |= __put_user((int *) &(gw->win [window]),
+                                 (int **)gw->winptr +window );
+               err |= copy_to_user(&gw->win [window],
+                                   &current->tss.reg_window [window],
+                                   sizeof (svr4_rwindow_t));
+               err |= __put_user(0, (int *)gw->winptr + window);
        }
 #endif 
 
@@ -768,8 +802,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
         * that much currently, should use those that David already
         * is providing with tss.sig_desc
         */
-       __put_user(signr, &si->siginfo.signo);
-       __put_user(SVR4_SINOINFO, &si->siginfo.code);
+       err |= __put_user(signr, &si->siginfo.signo);
+       err |= __put_user(SVR4_SINOINFO, &si->siginfo.code);
+       if (err)
+               goto sigsegv;
 
        regs->u_regs[UREG_FP] = (unsigned long) sfp;
        regs->tpc = (unsigned long) sa->sa_handler;
@@ -783,14 +819,22 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc,
                struct reg_window32 *rw = (struct reg_window32 *)
                        (regs->u_regs [14] & 0x00000000ffffffffUL);
 
-               __put_user(signr, &rw->ins [0]);
-               __put_user((u64)si, &rw->ins [1]);
-               __put_user((u64)uc, &rw->ins [2]);
-               __put_user((u64)sfp, &rw->ins [6]);     /* frame pointer */
+               err |= __put_user(signr, &rw->ins [0]);
+               err |= __put_user((u64)si, &rw->ins [1]);
+               err |= __put_user((u64)uc, &rw->ins [2]);
+               err |= __put_user((u64)sfp, &rw->ins [6]);      /* frame pointer */
+               if (err)
+                       goto sigsegv;
+
                regs->u_regs[UREG_I0] = signr;
                regs->u_regs[UREG_I1] = (u32)(u64) si;
                regs->u_regs[UREG_I2] = (u32)(u64) uc;
        }
+       return;
+
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 asmlinkage int
@@ -799,7 +843,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
        svr4_gregset_t  *gr;
        svr4_mcontext_t *mc;
        svr4_sigset_t setv;
-       int i;
+       int i, err;
 
        synchronize_user_stack();
        save_and_clear_fpu();
@@ -809,8 +853,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
                lock_kernel();
                do_exit (SIGSEGV);
        }
-       if(clear_user(uc, sizeof (*uc)))
-               return -EFAULT;
+       err = clear_user(uc, sizeof (*uc));
 
        /* Setup convenience variables */
        mc = &uc->mcontext;
@@ -821,38 +864,38 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs)
        if (_NSIG_WORDS >= 2) {
                setv.sigbits[2] = current->blocked.sig[1];
                setv.sigbits[3] = (current->blocked.sig[1] >> 32);
-               __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
+               err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t));
        } else
-               __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
+               err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned));
 
        /* Store registers */
-       __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
-       __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
+       err |= __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]);
+       err |= __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]);
 #if 1
-       __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
+       err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]);
 #else
        i = tstate_to_psr(regs->tstate) & ~PSR_EF;                 
        if (current->tss.fpsaved[0] & FPRS_FEF)
                i |= PSR_EF;
-       __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
+       err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]);
 #endif
-        __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
+       err |= __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]);
        
        /* Copy g [1..7] and o [0..7] registers */
        for (i = 0; i < 7; i++)
-               __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+               err |= __put_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
        for (i = 0; i < 8; i++)
-               __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+               err |= __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
 
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &uc->stack.sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
-       __put_user(current->sas_ss_size, &uc->stack.size);
+       err |= __put_user(current->sas_ss_sp, &uc->stack.sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags);
+       err |= __put_user(current->sas_ss_size, &uc->stack.size);
 
        /* The register file is not saved
         * we have already stuffed all of it with sync_user_stack
         */
-       return 0;
+       return (err ? -EFAULT : 0);
 }
 
 
@@ -923,8 +966,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
        spin_unlock_irq(&current->sigmask_lock);
        regs->tpc = pc;
        regs->tnpc = npc | 1;
-       __get_user(regs->y, &((*gr) [SVR4_Y]));
-       __get_user(psr, &((*gr) [SVR4_PSR]));
+       err |= __get_user(regs->y, &((*gr) [SVR4_Y]));
+       err |= __get_user(psr, &((*gr) [SVR4_PSR]));
        regs->tstate &= ~(TSTATE_ICC);
        regs->tstate |= psr_to_tstate_icc(psr);
 #if 0  
@@ -933,9 +976,11 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs)
 #endif
        /* Restore g[1..7] and o[0..7] registers */
        for (i = 0; i < 7; i++)
-               __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
+               err |= __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i);
        for (i = 0; i < 8; i++)
-               __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+               err |= __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i);
+       if(err)
+               goto sigsegv;
 
        return -EINTR;
 sigsegv:
@@ -950,7 +995,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
        struct rt_signal_frame32 *sf;
        int sigframe_size;
        u32 psr;
-       int i;
+       int i, err;
        sigset_t32 seta;
 
        /* 1. Make sure everything is clean */
@@ -980,27 +1025,27 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
        }
 
        /* 2. Save the current process state */
-       put_user(regs->tpc, &sf->regs.pc);
-       __put_user(regs->tnpc, &sf->regs.npc);
-       __put_user(regs->y, &sf->regs.y);
+       err  = put_user(regs->tpc, &sf->regs.pc);
+       err |= __put_user(regs->tnpc, &sf->regs.npc);
+       err |= __put_user(regs->y, &sf->regs.y);
        psr = tstate_to_psr (regs->tstate);
        if(current->tss.fpsaved[0] & FPRS_FEF)
                psr |= PSR_EF;
-       __put_user(psr, &sf->regs.psr);
+       err |= __put_user(psr, &sf->regs.psr);
        for (i = 0; i < 16; i++)
-               __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
+               err |= __put_user(regs->u_regs[i], &sf->regs.u_regs[i]);
 
        if (psr & PSR_EF) {
-               save_fpu_state32(regs, &sf->fpu_state);
-               __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+               err |= save_fpu_state32(regs, &sf->fpu_state);
+               err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
        } else {
-               __put_user(0, &sf->fpu_save);
+               err |= __put_user(0, &sf->fpu_save);
        }
        
        /* Setup sigaltstack */
-       __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
-       __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
-       __put_user(current->sas_ss_size, &sf->stack.ss_size);
+       err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
+       err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
+       err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
 
        switch (_NSIG_WORDS) {
        case 4: seta.sig[7] = (oldset->sig[3] >> 32);
@@ -1012,11 +1057,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
        case 1: seta.sig[1] = (oldset->sig[0] >> 32);
                seta.sig[0] = oldset->sig[0];
        }
-       __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
+       err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t));
 
-       copy_in_user((u32 *)sf,
-                    (u32 *)(regs->u_regs[UREG_FP]),
-                    sizeof(struct reg_window32));
+       err |= copy_in_user((u32 *)sf,
+                           (u32 *)(regs->u_regs[UREG_FP]),
+                           sizeof(struct reg_window32));
+       if (err)
+               goto sigsegv;
        
        /* 3. signal handler back-trampoline and parameters */
        regs->u_regs[UREG_FP] = (unsigned long) sf;
@@ -1039,8 +1086,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
 
                regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
        
-               __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */
-               __put_user(0x91d02010, &sf->insns[1]); /* t 0x10 */
+               /* mov __NR_rt_sigreturn, %g1 */
+               err |= __put_user(0x82102065, &sf->insns[0]);
+
+               /* t 0x10 */
+               err |= __put_user(0x91d02010, &sf->insns[1]);
+               if (err)
+                       goto sigsegv;
 
                if(pte_present(*ptep)) {
                        unsigned long page = pte_page(*ptep);
@@ -1057,6 +1109,9 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs
 sigill:
        lock_kernel();
        do_exit(SIGILL);
+sigsegv:
+       lock_kernel();
+       do_exit(SIGSEGV);
 }
 
 static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
@@ -1257,6 +1312,14 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs,
                                /* Very useful to debug dynamic linker problems */
                                printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid);
                                show_regs (regs);
+#ifdef DEBUG_SIGNALS_TLB
+                               do {
+                                       extern void sparc_ultra_dump_itlb(void);
+                                       extern void sparc_ultra_dump_dtlb(void);
+                                       sparc_ultra_dump_dtlb();
+                                       sparc_ultra_dump_itlb();
+                               } while(0);
+#endif
 #ifdef DEBUG_SIGNALS_TRACE
                                {
                                        struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff);
index 3ec32e92bee833277e3486aa12f615a4865acb4e..c9e54956627bf4a9bc418953a7a9ff4fb424f1c8 100644 (file)
@@ -63,7 +63,7 @@ int smp_info(char *buf)
        for (i = 0; i < NR_CPUS; i++)
                if(cpu_present_map & (1UL << i))
                        len += sprintf(buf + len,
-                                       "CPU%d:\t\tonline\n", i
+                                       "CPU%d:\t\tonline\n", i);
        return len;
 }
 
@@ -380,7 +380,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
 {
        u32 ctx = mm->context & 0x3ff;
 
-       if(mm == current->mm && mm->count == 1) {
+       if(mm == current->mm && atomic_read(&mm->count) == 1) {
                if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
                        goto local_flush_and_out;
                return smp_cross_call_avoidance(mm);
@@ -396,7 +396,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 {
        u32 ctx = mm->context & 0x3ff;
 
-       if(mm == current->mm && mm->count == 1) {
+       if(mm == current->mm && atomic_read(&mm->count) == 1) {
                if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
                        goto local_flush_and_out;
                return smp_cross_call_avoidance(mm);
@@ -413,13 +413,13 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
        u32 ctx = mm->context & 0x3ff;
 
-       if(mm == current->mm && mm->count == 1) {
+       if(mm == current->mm && atomic_read(&mm->count) == 1) {
                if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
                        goto local_flush_and_out;
                return smp_cross_call_avoidance(mm);
        }
 #if 0 /* XXX Disabled until further notice... */
-       else if(mm->count == 1) {
+       else if(atomic_read(&mm->count) == 1) {
                /* Try to handle two special cases to avoid cross calls
                 * in common scenerios where we are swapping process
                 * pages out.
index 0bdd42775abfe82e4c09e0e86424e21a4dbc1d59..454b8a0cfa059aca9efe550ff5b17d2a25b3e16c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.39 1998/07/04 12:35:59 ecd Exp $
+/* $Id: sparc64_ksyms.c,v 1.41 1998/10/04 08:44:16 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -103,7 +103,6 @@ __attribute__((section("__ksymtab"))) =                             \
 #ifdef __SMP__
 EXPORT_SYMBOL(scheduler_lock);
 EXPORT_SYMBOL(global_bh_lock);
-EXPORT_SYMBOL(klock_info);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(synchronize_irq);
 EXPORT_SYMBOL(cpu_data);
@@ -184,7 +183,7 @@ EXPORT_SYMBOL(__prom_getsibling);
 
 /* sparc library symbols */
 EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(__strlen);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
index a0bfb47ef45d316636bfc418df65556768d94bc2..d32ea68c2d335de3183a146f3ec7a49e77a12c29 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunos_ioctl32.c,v 1.9 1998/03/29 10:10:53 davem Exp $
+/* $Id: sunos_ioctl32.c,v 1.10 1998/08/15 20:42:46 davem Exp $
  * sunos_ioctl32.c: SunOS ioctl compatability on sparc64.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
 #include <linux/smp_lock.h>
 #include <asm/kbio.h>
 
-#define A(x) ((unsigned long)x)
+/* Use this to get at 32-bit user passed pointers. */
+#define A(__x)                         \
+({     unsigned long __ret;            \
+       __asm__ ("srl   %0, 0, %0"      \
+                : "=r" (__ret)         \
+                : "0" (__x));          \
+       __ret;                          \
+})
 
 #define SUNOS_NR_OPEN  256
 
index ec23e92a0e4db216da69fbc168d3b12d1d891cfc..dcba30496b118f946b66c5f8aef9193ba27524c0 100644 (file)
@@ -1,10 +1,13 @@
-/* $Id: sys32.S,v 1.6 1998/06/28 08:28:22 ecd Exp $
+/* $Id: sys32.S,v 1.7 1998/09/11 10:39:46 jj Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
+/* NOTE: call as jump breaks return stack, we have to avoid that */
+
        .text
 
        .align          32
@@ -15,81 +18,74 @@ sys32_mmap:
        srl             %o1, 0, %o1                     ! IEU0  Group
        or              %g2, %lo(0xffffffff), %g2       ! IEU1
        srl             %o2, 0, %o2                     ! IEU0  Group
-       mov             %o7, %g1                        ! IEU1
+       sethi           %hi(sys_mmap), %g1              ! IEU1
        and             %o3, %g2, %o3                   ! IEU0  Group
        and             %o4, %g2, %o4                   ! IEU1
-       and             %o5, %g2, %o5                   ! IEU0  Group
-       call            sys_mmap                        ! CTI   Group brk forced
-        mov            %g1, %o7                        ! IEU0  Group (regdep)
+       jmpl            %g1 + %lo(sys_mmap), %g0        ! CTI   Group brk forced
+        and            %o5, %g2, %o5                   ! IEU0
 
        .align          32
        .globl          sys32_lseek
        .globl          sys32_chmod, sys32_chown, sys32_lchown, sys32_mknod
 sys32_lseek:
        sra             %o1, 0, %o1
-       mov             %o7, %g1
-       call            sys_lseek
-        mov            %g1, %o7
+       sethi           %hi(sys_lseek), %g1
+       jmpl            %g1 + %lo(sys_lseek), %g0
+        nop
 sys32_chmod:
-       sll             %o1, 16, %o1
-       mov             %o7, %g1
+       sethi           %hi(0xffff), %g2
+       sethi           %hi(sys_chmod), %g1
+       orcc            %g2, %lo(0xffff), %g2
        srl             %o0, 0, %o0
-       srl             %o1, 16, %o1
-       call            sys_chmod
-        mov            %g1, %o7
+       jmpl            %g1 + %lo(sys_chmod), %g0
+        and            %o1, %g2, %o1
 sys32_chown:
-       sll             %o1, 16, %o1
-       mov             %o7, %g1
-       sll             %o2, 16, %o2
+       sethi           %hi(0xffff), %g2
+       sethi           %hi(sys_chown), %g1
+       orcc            %g2, %lo(0xffff), %g2
        srl             %o0, 0, %o0
-       srl             %o1, 16, %o1
-       srl             %o2, 16, %o2
-       call            sys_chown
-        mov            %g1, %o7
+       and             %o1, %g2, %o1
+       jmpl            %g1 + %lo(sys_chown), %g0
+        and            %o2, %g2, %o2
 sys32_lchown:
-       sll             %o1, 16, %o1
-       mov             %o7, %g1
-       sll             %o2, 16, %o2
+       sethi           %hi(0xffff), %g2
+       sethi           %hi(sys_lchown), %g1
+       orcc            %g2, %lo(0xffff), %g2
        srl             %o0, 0, %o0
-       srl             %o1, 16, %o1
-       srl             %o2, 16, %o2
-       call            sys_lchown
-        mov            %g1, %o7
+       and             %o1, %g2, %o1
+       jmpl            %g1 + %lo(sys_lchown), %g0
+        and            %o2, %g2, %o2
 sys32_mknod:
-       sll             %o2, 16, %o2
-       mov             %o7, %g1
+       sethi           %hi(0xffff), %g2
+       sethi           %hi(sys_mknod), %g1
+       orcc            %g2, %lo(0xffff), %g2
        srl             %o0, 0, %o0
-       srl             %o2, 16, %o2
-       call            sys_mknod
-        mov            %g1, %o7
+       jmpl            %g1 + %lo(sys_mknod), %g0
+        and            %o2, %g2, %o2
 
        .align          32
        .globl          sys32_sendto, sys32_recvfrom, sys32_getsockopt
 sys32_sendto:
        srl             %o1, 0, %o1
-       mov             %o7, %g1
+       sethi           %hi(sys_sendto), %g1
        srl             %o2, 0, %o2
-       srl             %o4, 0, %o4
-       call            sys_sendto
-        mov            %g1, %o7
+       jmpl            %g1 + %lo(sys_sendto), %g0
+        srl            %o4, 0, %o4
 sys32_recvfrom:
        srl             %o1, 0, %o1
-       mov             %o7, %g1
+       sethi           %hi(sys_recvfrom), %g1
        srl             %o2, 0, %o2
        srl             %o4, 0, %o4
-       srl             %o5, 0, %o5
-       call            sys_recvfrom
-        mov            %g1, %o7
+       jmpl            %g1 + %lo(sys_recvfrom), %g0
+        srl            %o5, 0, %o5
 sys32_getsockopt:
        srl             %o3, 0, %o3
-       mov             %o7, %g1
-       srl             %o4, 0, %o4
-       call            sys_getsockopt
-        mov            %g1, %o7
+       sethi           %hi(sys_getsockopt), %g1
+       jmpl            %g1 + %lo(sys_getsockopt), %g0
+        srl            %o4, 0, %o4
 
        .globl          sys32_bdflush
 sys32_bdflush:
-       sra             %o1, 0, %o1
-       mov             %o7, %g1
-       call            sys_bdflush
-        mov            %g1, %o7
+       sethi           %hi(sys_bdflush), %g1
+       jmpl            %g1 + %lo(sys_bdflush), %g0
+        sra            %o1, 0, %o1
index 1d9c0457e80004af1244d2e3beb887ec8ce5a136..8e0269de1b20e270fca6f22d8e745fb80a26ada2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.20 1998/08/03 20:03:26 davem Exp $
+/* $Id: sys_sparc.c,v 1.22 1998/09/25 01:09:27 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -181,6 +181,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
                }
        }
 
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file, addr, len, prot, flags, off);
 
 out_putf:
@@ -252,17 +253,20 @@ asmlinkage int sys_aplib(void)
 
 asmlinkage int solaris_syscall(struct pt_regs *regs)
 {
+       static int count = 0;
        lock_kernel();
        regs->tpc = regs->tnpc;
        regs->tnpc += 4;
-       printk ("For Solaris binary emulation you need solaris module loaded\n");
+       if(++count <= 20)
+               printk ("For Solaris binary emulation you need solaris module loaded\n");
        show_regs (regs);
        send_sig(SIGSEGV, current, 1);
        unlock_kernel();
-       return 0;
+       return -ENOSYS;
 }
 
-asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, utrap_handler_t new_d,
+asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p,
+                                utrap_handler_t new_d,
                                 utrap_handler_t *old_p, utrap_handler_t *old_d)
 {
        if (type < UT_INSTRUCTION_EXCEPTION || type > UT_TRAP_INSTRUCTION_31)
index a5043b3ac52e9e3cf51cb69d114d2b3d0fa5a478..7d80404f8e7ed22d9c458e06c5acbfe44af2f205 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $
+/* $Id: sys_sparc32.c,v 1.95 1998/09/07 09:20:50 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 #include <asm/fpumacro.h>
 #include <asm/semaphore.h>
 
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to
- * unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to
- * type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings.
+/* Use this to get at 32-bit user passed pointers. */
+/* Things to consider: the low-level assembly stub does
+   srl x, 0, x for first four arguments, so if you have
+   pointer to something in the first four arguments, just
+   declare it as a pointer, not u32. On the other side, 
+   arguments from 5th onwards should be declared as u32
+   for pointers, and need AA() around each usage.
+   A() macro should be used for places where you e.g.
+   have some internal variable u32 and just want to get
+   rid of a compiler warning. AA() has to be used in
+   places where you want to convert a function argument
+   to 32bit pointer or when you e.g. access pt_regs
+   structure and want to consider 32bit registers only.
+   -jj
  */
-#define A(x) ((unsigned long)x)
+#define A(__x) ((unsigned long)(__x))
+#define AA(__x)                                \
+({     unsigned long __ret;            \
+       __asm__ ("srl   %0, 0, %0"      \
+                : "=r" (__ret)         \
+                : "0" (__x));          \
+       __ret;                          \
+})
+
 static inline char * get_page(void)
 {
        char * res;
@@ -73,12 +89,12 @@ static inline char * get_page(void)
  *
  * POSIX.1 2.4: an empty pathname is invalid (ENOENT).
  */
-static inline int do_getname32(u32 filename, char *page)
+static inline int do_getname32(const char *filename, char *page)
 {
        int retval;
 
        /* 32bit pointer will be always far below TASK_SIZE :)) */
-       retval = strncpy_from_user((char *)page, (char *)A(filename), PAGE_SIZE);
+       retval = strncpy_from_user((char *)page, (char *)filename, PAGE_SIZE);
        if (retval > 0) {
                if (retval < PAGE_SIZE)
                        return 0;
@@ -88,7 +104,7 @@ static inline int do_getname32(u32 filename, char *page)
        return retval;
 }
 
-char * getname32(u32 filename)
+char * getname32(const char *filename)
 {
        char *tmp, *result;
 
@@ -218,6 +234,261 @@ struct shmid_ds32 {
  *
  * This is really horribly ugly.
  */
+#define IPCOP_MASK(__x)        (1UL << (__x))
+static int do_sys32_semctl(int first, int second, int third, void *uptr)
+{
+       union semun fourth;
+       u32 pad;
+       int err = -EINVAL;
+
+       if (!uptr)
+               goto out;
+       err = -EFAULT;
+       if (get_user (pad, (u32 *)uptr))
+               goto out;
+       fourth.__pad = (void *)A(pad);
+       if (IPCOP_MASK (third) &
+           (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SEM_INFO) | IPCOP_MASK (GETVAL) |
+            IPCOP_MASK (GETPID) | IPCOP_MASK (GETNCNT) | IPCOP_MASK (GETZCNT) |
+            IPCOP_MASK (GETALL) | IPCOP_MASK (SETALL) | IPCOP_MASK (IPC_RMID))) {
+               err = sys_semctl (first, second, third, fourth);
+       } else {
+               struct semid_ds s;
+               struct semid_ds32 *usp = (struct semid_ds32 *)A(pad);
+               mm_segment_t old_fs;
+               int need_back_translation;
+
+               if (third == IPC_SET) {
+                       err = get_user (s.sem_perm.uid, &usp->sem_perm.uid);
+                       err |= __get_user (s.sem_perm.gid, &usp->sem_perm.gid);
+                       err |= __get_user (s.sem_perm.mode, &usp->sem_perm.mode);
+                       if (err)
+                               goto out;
+                       fourth.__pad = &s;
+               }
+               need_back_translation =
+                       (IPCOP_MASK (third) &
+                        (IPCOP_MASK (SEM_STAT) | IPCOP_MASK (IPC_STAT))) != 0;
+               if (need_back_translation)
+                       fourth.__pad = &s;
+               old_fs = get_fs ();
+               set_fs (KERNEL_DS);
+               err = sys_semctl (first, second, third, fourth);
+               set_fs (old_fs);
+               if (need_back_translation) {
+                       int err2 = put_user (s.sem_perm.key, &usp->sem_perm.key);
+                       err2 |= __put_user (s.sem_perm.uid, &usp->sem_perm.uid);
+                       err2 |= __put_user (s.sem_perm.gid, &usp->sem_perm.gid);
+                       err2 |= __put_user (s.sem_perm.cuid, &usp->sem_perm.cuid);
+                       err2 |= __put_user (s.sem_perm.cgid, &usp->sem_perm.cgid);
+                       err2 |= __put_user (s.sem_perm.mode, &usp->sem_perm.mode);
+                       err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
+                       err2 |= __put_user (s.sem_otime, &usp->sem_otime);
+                       err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
+                       err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+                       if (err2) err = -EFAULT;
+               }
+       }
+out:
+       return err;
+}
+
+static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
+{
+       struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+       struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+       mm_segment_t old_fs;
+       int err;
+
+       if (!p)
+               return -ENOMEM;
+       err = get_user (p->mtype, &up->mtype);
+       err |= __copy_from_user (p->mtext, &up->mtext, second);
+       if (err)
+               goto out;
+       old_fs = get_fs ();
+       set_fs (KERNEL_DS);
+       err = sys_msgsnd (first, p, second, third);
+       set_fs (old_fs);
+out:
+       kfree (p);
+       return err;
+}
+
+static int do_sys32_msgrcv (int first, int second, int msgtyp, int third,
+                           int version, void *uptr)
+{
+       struct msgbuf32 *up;
+       struct msgbuf *p;
+       mm_segment_t old_fs;
+       int err;
+
+       if (!version) {
+               struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+               struct ipc_kludge ipck;
+
+               err = -EINVAL;
+               if (!uptr)
+                       goto out;
+               err = -EFAULT;
+               if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
+                       goto out;
+               uptr = (void *)A(ipck.msgp);
+               msgtyp = ipck.msgtyp;
+       }
+       err = -ENOMEM;
+       p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+       if (!p)
+               goto out;
+       old_fs = get_fs ();
+       set_fs (KERNEL_DS);
+       err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+       set_fs (old_fs);
+       if (err < 0)
+               goto free_then_out;
+       up = (struct msgbuf32 *)uptr;
+       if (put_user (p->mtype, &up->mtype) ||
+           __copy_to_user (&up->mtext, p->mtext, err))
+               err = -EFAULT;
+free_then_out:
+       kfree (p);
+out:
+       return err;
+}
+
+static int do_sys32_msgctl (int first, int second, void *uptr)
+{
+       int err;
+
+       if (IPCOP_MASK (second) &
+           (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (MSG_INFO) |
+            IPCOP_MASK (IPC_RMID))) {
+               err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+       } else {
+               struct msqid_ds m;
+               struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+               mm_segment_t old_fs;
+
+               if (second == IPC_SET) {
+                       err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
+                       err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
+                       err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
+                       err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+                       if (err)
+                               goto out;
+               }
+               old_fs = get_fs ();
+               set_fs (KERNEL_DS);
+               err = sys_msgctl (first, second, &m);
+               set_fs (old_fs);
+               if (IPCOP_MASK (second) &
+                   (IPCOP_MASK (MSG_STAT) | IPCOP_MASK (IPC_STAT))) {
+                       int err2 = put_user (m.msg_perm.key, &up->msg_perm.key);
+                       err2 |= __put_user (m.msg_perm.uid, &up->msg_perm.uid);
+                       err2 |= __put_user (m.msg_perm.gid, &up->msg_perm.gid);
+                       err2 |= __put_user (m.msg_perm.cuid, &up->msg_perm.cuid);
+                       err2 |= __put_user (m.msg_perm.cgid, &up->msg_perm.cgid);
+                       err2 |= __put_user (m.msg_perm.mode, &up->msg_perm.mode);
+                       err2 |= __put_user (m.msg_perm.seq, &up->msg_perm.seq);
+                       err2 |= __put_user (m.msg_stime, &up->msg_stime);
+                       err2 |= __put_user (m.msg_rtime, &up->msg_rtime);
+                       err2 |= __put_user (m.msg_ctime, &up->msg_ctime);
+                       err2 |= __put_user (m.msg_cbytes, &up->msg_cbytes);
+                       err2 |= __put_user (m.msg_qnum, &up->msg_qnum);
+                       err2 |= __put_user (m.msg_qbytes, &up->msg_qbytes);
+                       err2 |= __put_user (m.msg_lspid, &up->msg_lspid);
+                       err2 |= __put_user (m.msg_lrpid, &up->msg_lrpid);
+                       if (err2)
+                               err = -EFAULT;
+               }
+       }
+
+out:
+       return err;
+}
+
+static int do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+{
+       unsigned long raddr;
+       u32 *uaddr = (u32 *)A((u32)third);
+       int err = -EINVAL;
+
+       if (version == 1)
+               goto out;
+       err = sys_shmat (first, uptr, second, &raddr);
+       if (err)
+               goto out;
+       err = put_user (raddr, uaddr);
+out:
+       return err;
+}
+
+static int do_sys32_shmctl (int first, int second, void *uptr)
+{
+       int err;
+
+       if (IPCOP_MASK (second) &
+           (IPCOP_MASK (IPC_INFO) | IPCOP_MASK (SHM_LOCK) | IPCOP_MASK (SHM_UNLOCK) |
+            IPCOP_MASK (IPC_RMID))) {
+               err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
+       } else {
+               struct shmid_ds s;
+               struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+               mm_segment_t old_fs;
+
+               if (second == IPC_SET) {
+                       err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
+                       err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
+                       err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+                       if (err)
+                               goto out;
+               }
+               old_fs = get_fs ();
+               set_fs (KERNEL_DS);
+               err = sys_shmctl (first, second, &s);
+               set_fs (old_fs);
+               if (err < 0)
+                       goto out;
+
+               /* Mask it even in this case so it becomes a CSE. */
+               if (second == SHM_INFO) {
+                       struct shm_info32 {
+                               int used_ids;
+                               u32 shm_tot, shm_rss, shm_swp;
+                               u32 swap_attempts, swap_successes;
+                       } *uip = (struct shm_info32 *)uptr;
+                       struct shm_info *kp = (struct shm_info *)&s;
+                       int err2 = put_user (kp->used_ids, &uip->used_ids);
+                       err2 |= __put_user (kp->shm_tot, &uip->shm_tot);
+                       err2 |= __put_user (kp->shm_rss, &uip->shm_rss);
+                       err2 |= __put_user (kp->shm_swp, &uip->shm_swp);
+                       err2 |= __put_user (kp->swap_attempts, &uip->swap_attempts);
+                       err2 |= __put_user (kp->swap_successes, &uip->swap_successes);
+                       if (err2)
+                               err = -EFAULT;
+               } else if (IPCOP_MASK (second) &
+                          (IPCOP_MASK (SHM_STAT) | IPCOP_MASK (IPC_STAT))) {
+                       int err2 = put_user (s.shm_perm.key, &up->shm_perm.key);
+                       err2 |= __put_user (s.shm_perm.uid, &up->shm_perm.uid);
+                       err2 |= __put_user (s.shm_perm.gid, &up->shm_perm.gid);
+                       err2 |= __put_user (s.shm_perm.cuid, &up->shm_perm.cuid);
+                       err2 |= __put_user (s.shm_perm.cgid, &up->shm_perm.cgid);
+                       err2 |= __put_user (s.shm_perm.mode, &up->shm_perm.mode);
+                       err2 |= __put_user (s.shm_perm.seq, &up->shm_perm.seq);
+                       err2 |= __put_user (s.shm_atime, &up->shm_atime);
+                       err2 |= __put_user (s.shm_dtime, &up->shm_dtime);
+                       err2 |= __put_user (s.shm_ctime, &up->shm_ctime);
+                       err2 |= __put_user (s.shm_segsz, &up->shm_segsz);
+                       err2 |= __put_user (s.shm_nattch, &up->shm_nattch);
+                       err2 |= __put_user (s.shm_cpid, &up->shm_cpid);
+                       err2 |= __put_user (s.shm_lpid, &up->shm_lpid);
+                       if (err2)
+                               err = -EFAULT;
+               }
+       }
+out:
+       return err;
+}
 
 asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 {
@@ -231,190 +502,32 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
                switch (call) {
                case SEMOP:
                        /* struct sembuf is the same on 32 and 64bit :)) */
-                       err = sys_semop (first, (struct sembuf *)A(ptr), second);
+                       err = sys_semop (first, (struct sembuf *)AA(ptr), second);
                        goto out;
                case SEMGET:
                        err = sys_semget (first, second, third);
                        goto out;
-               case SEMCTL: {
-                       union semun fourth;
-                       void *pad;
-                       mm_segment_t old_fs;
-                       struct semid_ds s;
-                       
-                       err = -EINVAL;
-                       if (!ptr)
-                               goto out;
-                       err = -EFAULT;
-                       if(get_user(pad, (void **)A(ptr)))
-                               goto out;
-                       fourth.__pad = pad;
-                       switch (third) {
-                               case IPC_INFO:
-                               case SEM_INFO:
-                               case GETVAL:
-                               case GETPID:
-                               case GETNCNT:
-                               case GETZCNT:
-                               case GETALL:
-                               case SETALL:
-                               case IPC_RMID:
-                                       err = sys_semctl (first, second, third, fourth);
-                                       goto out;
-                               case IPC_SET:
-                                       if (get_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
-                                           __get_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
-                                           __get_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode))) {
-                                               err = -EFAULT;
-                                               goto out;
-                                       }
-                                       /* Fall through */
-                               case SEM_STAT:
-                               case IPC_STAT:
-                                       fourth.__pad = &s;
-                                       break;
-                       }
-                       old_fs = get_fs();
-                       set_fs (KERNEL_DS);
-                       err = sys_semctl (first, second, third, fourth);
-                       set_fs (old_fs);
-                       switch (third) {
-                               case SEM_STAT:
-                               case IPC_STAT:
-                                       if (put_user (s.sem_perm.key, &(((struct semid_ds32 *)A(pad))->sem_perm.key)) ||
-                                           __put_user (s.sem_perm.uid, &(((struct semid_ds32 *)A(pad))->sem_perm.uid)) ||
-                                           __put_user (s.sem_perm.gid, &(((struct semid_ds32 *)A(pad))->sem_perm.gid)) ||
-                                           __put_user (s.sem_perm.cuid, &(((struct semid_ds32 *)A(pad))->sem_perm.cuid)) ||
-                                           __put_user (s.sem_perm.cgid, &(((struct semid_ds32 *)A(pad))->sem_perm.cgid)) ||
-                                           __put_user (s.sem_perm.mode, &(((struct semid_ds32 *)A(pad))->sem_perm.mode)) ||
-                                           __put_user (s.sem_perm.seq, &(((struct semid_ds32 *)A(pad))->sem_perm.seq)) ||
-                                           __put_user (s.sem_otime, &(((struct semid_ds32 *)A(pad))->sem_otime)) ||
-                                           __put_user (s.sem_ctime, &(((struct semid_ds32 *)A(pad))->sem_ctime)) ||
-                                           __put_user (s.sem_nsems, &(((struct semid_ds32 *)A(pad))->sem_nsems)))
-                                               err = -EFAULT;
-                       }
+               case SEMCTL:
+                       err = do_sys32_semctl (first, second, third, (void *)AA(ptr));
                        goto out;
-                       }
                default:
                        err = -EINVAL;
                        goto out;
-               }
+               };
        if (call <= MSGCTL) 
                switch (call) {
                case MSGSND:
-                       {
-                               struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
-                               
-                               if (!p) err = -ENOMEM;
-                               else {
-                                       err = 0;
-                                       if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                           __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second))
-                                               err = -EFAULT;
-                                       if (!err) {
-                                               mm_segment_t old_fs = get_fs();
-                                               set_fs (KERNEL_DS);
-                                               err = sys_msgsnd (first, p, second, third);
-                                               set_fs (old_fs);
-                                       }
-                                       kfree (p);
-                               }
-                       }
+                       err = do_sys32_msgsnd (first, second, third, (void *)AA(ptr));
                        goto out;
                case MSGRCV:
-                       {
-                               struct msgbuf *p;
-                               mm_segment_t old_fs;
-                               long msgtyp = fifth;
-                               
-                               if (!version) {
-                                       struct ipc_kludge tmp;
-                                       err = -EINVAL;
-                                       if (!ptr)
-                                               goto out;
-                                       err = -EFAULT;
-                                       if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp)))
-                                               goto out;
-                                       ptr = tmp.msgp;
-                                       msgtyp = tmp.msgtyp;
-                               }
-
-                               p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL);
-                               if (!p) {
-                                       err = -EFAULT;
-                                       goto out;
-                               }
-
-                               old_fs = get_fs();
-                               set_fs (KERNEL_DS);
-                               err = sys_msgrcv (first, p, second + 4, msgtyp, third);
-                               set_fs (old_fs);
-
-                               if (err < 0)
-                                       goto out;
-
-                               if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) ||
-                                   __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err))
-                                       err = -EFAULT;
-                               kfree (p);
-                               goto out;
-                       }
+                       err = do_sys32_msgrcv (first, second, fifth, third,
+                                              version, (void *)AA(ptr));
+                       goto out;
                case MSGGET:
                        err = sys_msgget ((key_t) first, second);
                        goto out;
                case MSGCTL:
-                       {
-                               struct msqid_ds m;
-                               mm_segment_t old_fs;
-                               
-                               switch (second) {
-                                       case IPC_INFO:
-                                       case MSG_INFO:
-                                               /* struct msginfo is the same */
-                                       case IPC_RMID:
-                                               /* and this doesn't care about ptr */
-                                               err = sys_msgctl (first, second, (struct msqid_ds *)A(ptr));
-                                               goto out;
-                                               
-                                       case IPC_SET:
-                                               if (get_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
-                                                   __get_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
-                                                   __get_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
-                                                   __get_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes))) {
-                                                       err = -EFAULT;  
-                                                       goto out;
-                                               }
-                                       default:
-                                               break;
-                               }
-                               old_fs = get_fs();
-                               set_fs (KERNEL_DS);
-                               err = sys_msgctl (first, second, &m);
-                               set_fs (old_fs);
-                               switch (second) {
-                                       case MSG_STAT:
-                                       case IPC_STAT:
-                                               if (put_user (m.msg_perm.key, &(((struct msqid_ds32 *)A(ptr))->msg_perm.key)) ||
-                                                   __put_user (m.msg_perm.uid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.uid)) ||
-                                                   __put_user (m.msg_perm.gid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.gid)) ||
-                                                   __put_user (m.msg_perm.cuid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cuid)) ||
-                                                   __put_user (m.msg_perm.cgid, &(((struct msqid_ds32 *)A(ptr))->msg_perm.cgid)) ||
-                                                   __put_user (m.msg_perm.mode, &(((struct msqid_ds32 *)A(ptr))->msg_perm.mode)) ||
-                                                   __put_user (m.msg_perm.seq, &(((struct msqid_ds32 *)A(ptr))->msg_perm.seq)) ||
-                                                   __put_user (m.msg_stime, &(((struct msqid_ds32 *)A(ptr))->msg_stime)) ||
-                                                   __put_user (m.msg_rtime, &(((struct msqid_ds32 *)A(ptr))->msg_rtime)) ||
-                                                   __put_user (m.msg_ctime, &(((struct msqid_ds32 *)A(ptr))->msg_ctime)) ||
-                                                   __put_user (m.msg_cbytes, &(((struct msqid_ds32 *)A(ptr))->msg_cbytes)) ||
-                                                   __put_user (m.msg_qnum, &(((struct msqid_ds32 *)A(ptr))->msg_qnum)) ||
-                                                   __put_user (m.msg_qbytes, &(((struct msqid_ds32 *)A(ptr))->msg_qbytes)) ||
-                                                   __put_user (m.msg_lspid, &(((struct msqid_ds32 *)A(ptr))->msg_lspid)) ||
-                                                   __put_user (m.msg_lrpid, &(((struct msqid_ds32 *)A(ptr))->msg_lrpid)))
-                                                       err = -EFAULT;
-                                               break;
-                                       default:
-                                               break;
-                               }
-                       }
+                       err = do_sys32_msgctl (first, second, (void *)AA(ptr));
                        goto out;
                default:
                        err = -EINVAL;
@@ -423,95 +536,17 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u
        if (call <= SHMCTL) 
                switch (call) {
                case SHMAT:
-                       switch (version) {
-                       case 0: default: {
-                               unsigned long raddr;
-                               u32 *uptr = (u32 *) A(((u32)third));
-                               err = sys_shmat (first, (char *)A(ptr), second, &raddr);
-                               if (err)
-                                       goto out;
-                               err = -EFAULT;
-                               if(put_user (raddr, uptr))
-                                       goto out;
-                               err = 0;
-                               goto out;
-                               }
-                       case 1: /* If iBCS2 should ever run, then for sure in 64bit mode, not 32bit... */
-                               err = -EINVAL;
-                               goto out;
-                       }
+                       err = do_sys32_shmat (first, second, third,
+                                             version, (void *)AA(ptr));
+                       goto out;
                case SHMDT: 
-                       err = sys_shmdt ((char *)A(ptr));
+                       err = sys_shmdt ((char *)AA(ptr));
                        goto out;
                case SHMGET:
                        err = sys_shmget (first, second, third);
                        goto out;
                case SHMCTL:
-                       {
-                               struct shmid_ds s;
-                               mm_segment_t old_fs;
-                               
-                               switch (second) {
-                                       case IPC_INFO:
-                                               /* struct shminfo is the same */
-                                       case SHM_LOCK:
-                                       case SHM_UNLOCK:
-                                       case IPC_RMID:
-                                               /* and these three aren't using ptr at all */
-                                               err = sys_shmctl (first, second, (struct shmid_ds *)A(ptr));
-                                               goto out;
-                                               
-                                       case IPC_SET:
-                                               if (get_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
-                                                   __get_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
-                                                   __get_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode))) {
-                                                       err = -EFAULT; 
-                                                       goto out;
-                                               }
-                                       default:
-                                               break;
-                               }
-                               old_fs = get_fs();
-                               set_fs (KERNEL_DS);
-                               err = sys_shmctl (first, second, &s);
-                               set_fs (old_fs);
-                               switch (second) {
-                                       case SHM_INFO:
-                                               {
-                                                       struct shm_info32 { int used_ids; u32 shm_tot; u32 shm_rss; u32 shm_swp; u32 swap_attempts; u32 swap_successes; };
-                                                       struct shm_info *si = (struct shm_info *)&s;
-
-                                                       if (put_user (si->used_ids, &(((struct shm_info32 *)A(ptr))->used_ids)) ||
-                                                           __put_user (si->shm_tot, &(((struct shm_info32 *)A(ptr))->shm_tot)) ||
-                                                           __put_user (si->shm_rss, &(((struct shm_info32 *)A(ptr))->shm_rss)) ||
-                                                           __put_user (si->shm_swp, &(((struct shm_info32 *)A(ptr))->shm_swp)) ||
-                                                           __put_user (si->swap_attempts, &(((struct shm_info32 *)A(ptr))->swap_attempts)) ||
-                                                           __put_user (si->swap_successes, &(((struct shm_info32 *)A(ptr))->swap_successes)))
-                                                               err = -EFAULT;
-                                               }
-                                               break;
-                                       case SHM_STAT:
-                                       case IPC_STAT:
-                                               if (put_user (s.shm_perm.key, &(((struct shmid_ds32 *)A(ptr))->shm_perm.key)) ||
-                                                   __put_user (s.shm_perm.uid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.uid)) ||
-                                                   __put_user (s.shm_perm.gid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.gid)) ||
-                                                   __put_user (s.shm_perm.cuid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cuid)) ||
-                                                   __put_user (s.shm_perm.cgid, &(((struct shmid_ds32 *)A(ptr))->shm_perm.cgid)) ||
-                                                   __put_user (s.shm_perm.mode, &(((struct shmid_ds32 *)A(ptr))->shm_perm.mode)) ||
-                                                   __put_user (s.shm_perm.seq, &(((struct shmid_ds32 *)A(ptr))->shm_perm.seq)) ||
-                                                   __put_user (s.shm_atime, &(((struct shmid_ds32 *)A(ptr))->shm_atime)) ||
-                                                   __put_user (s.shm_dtime, &(((struct shmid_ds32 *)A(ptr))->shm_dtime)) ||
-                                                   __put_user (s.shm_ctime, &(((struct shmid_ds32 *)A(ptr))->shm_ctime)) ||
-                                                   __put_user (s.shm_segsz, &(((struct shmid_ds32 *)A(ptr))->shm_segsz)) ||
-                                                   __put_user (s.shm_nattch, &(((struct shmid_ds32 *)A(ptr))->shm_nattch)) ||
-                                                   __put_user (s.shm_lpid, &(((struct shmid_ds32 *)A(ptr))->shm_cpid)) ||
-                                                   __put_user (s.shm_cpid, &(((struct shmid_ds32 *)A(ptr))->shm_lpid)))
-                                                       err = -EFAULT;
-                                               break;
-                                       default:
-                                               break;
-                               }
-                       }
+                       err = do_sys32_shmctl (first, second, (void *)AA(ptr));
                        goto out;
                default:
                        err = -EINVAL;
@@ -527,29 +562,31 @@ out:
 
 static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
 {
-       if(get_user(kfl->l_type, &ufl->l_type)          ||
-          __get_user(kfl->l_whence, &ufl->l_whence)    ||
-          __get_user(kfl->l_start, &ufl->l_start)      ||
-          __get_user(kfl->l_len, &ufl->l_len)          ||
-          __get_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
+       int err;
+       
+       err = get_user(kfl->l_type, &ufl->l_type);
+       err |= __get_user(kfl->l_whence, &ufl->l_whence);
+       err |= __get_user(kfl->l_start, &ufl->l_start);
+       err |= __get_user(kfl->l_len, &ufl->l_len);
+       err |= __get_user(kfl->l_pid, &ufl->l_pid);
+       return err;
 }
 
 static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
 {
-       if(__put_user(kfl->l_type, &ufl->l_type)        ||
-          __put_user(kfl->l_whence, &ufl->l_whence)    ||
-          __put_user(kfl->l_start, &ufl->l_start)      ||
-          __put_user(kfl->l_len, &ufl->l_len)          ||
-          __put_user(kfl->l_pid, &ufl->l_pid))
-               return -EFAULT;
-       return 0;
+       int err;
+       
+       err = __put_user(kfl->l_type, &ufl->l_type);
+       err |= __put_user(kfl->l_whence, &ufl->l_whence);
+       err |= __put_user(kfl->l_start, &ufl->l_start);
+       err |= __put_user(kfl->l_len, &ufl->l_len);
+       err |= __put_user(kfl->l_pid, &ufl->l_pid);
+       return err;
 }
 
 extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
-asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
+asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
        switch (cmd) {
        case F_GETLK:
@@ -560,12 +597,12 @@ asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
                        mm_segment_t old_fs;
                        long ret;
                        
-                       if(get_flock(&f, (struct flock32 *)A(arg)))
+                       if(get_flock(&f, (struct flock32 *)arg))
                                return -EFAULT;
                        old_fs = get_fs(); set_fs (KERNEL_DS);
                        ret = sys_fcntl(fd, cmd, (unsigned long)&f);
                        set_fs (old_fs);
-                       if(put_flock(&f, (struct flock32 *)A(arg)))
+                       if(put_flock(&f, (struct flock32 *)arg))
                                return -EFAULT;
                        return ret;
                }
@@ -587,7 +624,7 @@ struct dqblk32 {
                                 
 extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
 
-asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
+asmlinkage int sys32_quotactl(int cmd, const char *special, int id, unsigned long addr)
 {
        int cmds = cmd >> SUBCMDSHIFT;
        int err;
@@ -601,29 +638,29 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
        case Q_SETQUOTA:
        case Q_SETUSE:
        case Q_SETQLIM:
-               if (copy_from_user (&d, (struct dqblk32 *)A(addr),
+               if (copy_from_user (&d, (struct dqblk32 *)addr,
                                    sizeof (struct dqblk32)))
                        return -EFAULT;
                d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
                d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
                break;
        default:
-               return sys_quotactl(cmd, (const char *)A(special),
-                                   id, (caddr_t)A(addr));
+               return sys_quotactl(cmd, special,
+                                   id, (caddr_t)addr);
        }
        spec = getname32 (special);
        err = PTR_ERR(spec);
        if (IS_ERR(spec)) return err;
        old_fs = get_fs ();
        set_fs (KERNEL_DS);
-       err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
+       err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)&d);
        set_fs (old_fs);
        putname32 (spec);
        if (cmds == Q_GETQUOTA) {
                __kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
                ((struct dqblk32 *)&d)->dqb_itime = i;
                ((struct dqblk32 *)&d)->dqb_btime = b;
-               if (copy_to_user ((struct dqblk32 *)A(addr), &d,
+               if (copy_to_user ((struct dqblk32 *)addr, &d,
                                  sizeof (struct dqblk32)))
                        return -EFAULT;
        }
@@ -632,23 +669,24 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
 
 static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
-       if (put_user (kbuf->f_type, &ubuf->f_type)                      ||
-           __put_user (kbuf->f_bsize, &ubuf->f_bsize)                  ||
-           __put_user (kbuf->f_blocks, &ubuf->f_blocks)                ||
-           __put_user (kbuf->f_bfree, &ubuf->f_bfree)                  ||
-           __put_user (kbuf->f_bavail, &ubuf->f_bavail)                ||
-           __put_user (kbuf->f_files, &ubuf->f_files)                  ||
-           __put_user (kbuf->f_ffree, &ubuf->f_ffree)                  ||
-           __put_user (kbuf->f_namelen, &ubuf->f_namelen)              ||
-           __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0])      ||
-           __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]))
-               return -EFAULT;
-       return 0;
+       int err;
+       
+       err = put_user (kbuf->f_type, &ubuf->f_type);
+       err |= __put_user (kbuf->f_bsize, &ubuf->f_bsize);
+       err |= __put_user (kbuf->f_blocks, &ubuf->f_blocks);
+       err |= __put_user (kbuf->f_bfree, &ubuf->f_bfree);
+       err |= __put_user (kbuf->f_bavail, &ubuf->f_bavail);
+       err |= __put_user (kbuf->f_files, &ubuf->f_files);
+       err |= __put_user (kbuf->f_ffree, &ubuf->f_ffree);
+       err |= __put_user (kbuf->f_namelen, &ubuf->f_namelen);
+       err |= __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0]);
+       err |= __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]);
+       return err;
 }
 
 extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
 
-asmlinkage int sys32_statfs(u32 path, u32 buf)
+asmlinkage int sys32_statfs(const char * path, struct statfs32 *buf)
 {
        int ret;
        struct statfs s;
@@ -662,7 +700,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf)
                ret = sys_statfs((const char *)pth, &s);
                set_fs (old_fs);
                putname32 (pth);
-               if (put_statfs((struct statfs32 *)A(buf), &s))
+               if (put_statfs(buf, &s))
                        return -EFAULT;
        }
        return ret;
@@ -670,7 +708,7 @@ asmlinkage int sys32_statfs(u32 path, u32 buf)
 
 extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
 
-asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
+asmlinkage int sys32_fstatfs(unsigned int fd, struct statfs32 *buf)
 {
        int ret;
        struct statfs s;
@@ -679,25 +717,28 @@ asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
        set_fs (KERNEL_DS);
        ret = sys_fstatfs(fd, &s);
        set_fs (old_fs);
-       if (put_statfs((struct statfs32 *)A(buf), &s))
+       if (put_statfs(buf, &s))
                return -EFAULT;
        return ret;
 }
 
 extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
 
-asmlinkage int sys32_utime(u32 filename, u32 times)
+struct utimbuf32 {
+       __kernel_time_t32 actime, modtime;
+};
+
+asmlinkage int sys32_utime(char * filename, struct utimbuf32 *times)
 {
-       struct utimbuf32 { __kernel_time_t32 actime, modtime; };
        struct utimbuf t;
        mm_segment_t old_fs;
        int ret;
        char *filenam;
        
        if (!times)
-               return sys_utime((char *)A(filename), NULL);
-       if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) ||
-           __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime)))
+               return sys_utime(filename, NULL);
+       if (get_user (t.actime, &times->actime) ||
+           __get_user (t.modtime, &times->modtime))
                return -EFAULT;
        filenam = getname32 (filename);
        ret = PTR_ERR(filenam);
@@ -813,7 +854,7 @@ static long do_readv_writev32(int type, struct file *file,
        return retval;
 }
 
-asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
+asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count)
 {
        struct file *file;
        long ret = -EBADF;
@@ -827,7 +868,7 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
                goto out;
 
        ret = do_readv_writev32(VERIFY_WRITE, file,
-                               (struct iovec32 *)A(vector), count);
+                               vector, count);
 out:
        fput(file);
 bad_file:
@@ -835,7 +876,7 @@ bad_file:
        return ret;
 }
 
-asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
+asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count)
 {
        struct file *file;
        int ret = -EBADF;
@@ -850,7 +891,7 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
 
        down(&file->f_dentry->d_inode->i_sem);
        ret = do_readv_writev32(VERIFY_READ, file,
-                               (struct iovec32 *)A(vector), count);
+                               vector, count);
        up(&file->f_dentry->d_inode->i_sem);
 out:
        fput(file);
@@ -894,7 +935,7 @@ static int fillonedir(void * __buf, const char * name, int namlen,
        return 0;
 }
 
-asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
+asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 *dirent, unsigned int count)
 {
        int error = -EBADF;
        struct file * file;
@@ -907,7 +948,7 @@ asmlinkage int old32_readdir(unsigned int fd, u32 dirent, unsigned int count)
                goto out;
 
        buf.count = 0;
-       buf.dirent = (struct old_linux_dirent32 *)A(dirent);
+       buf.dirent = dirent;
 
        error = -ENOTDIR;
        if (!file->f_op || !file->f_op->readdir)
@@ -966,7 +1007,7 @@ static int filldir(void * __buf, const char * name, int namlen, off_t offset, in
        return 0;
 }
 
-asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
+asmlinkage int sys32_getdents(unsigned int fd, struct linux_dirent32 *dirent, unsigned int count)
 {
        struct file * file;
        struct inode * inode;
@@ -979,7 +1020,7 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count)
        if (!file)
                goto out;
 
-       buf.current_dir = (struct linux_dirent32 *) A(dirent);
+       buf.current_dir = dirent;
        buf.previous = NULL;
        buf.count = count;
        buf.error = 0;
@@ -1015,10 +1056,8 @@ out:
  */
 
 static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x)
+get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
 {
-       u32 *ufdset = (u32 *)A(ufdset_x);
-
        if (ufdset) {
                unsigned long odd;
 
@@ -1048,10 +1087,9 @@ get_fd_set32(unsigned long n, unsigned long *fdset, u32 ufdset_x)
 }
 
 static inline void
-set_fd_set32(unsigned long n, u32 ufdset_x, unsigned long *fdset)
+set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
 {
        unsigned long odd;
-       u32 *ufdset = (u32 *)A(ufdset_x);
 
        if (!ufdset)
                return;
@@ -1071,10 +1109,10 @@ set_fd_set32(unsigned long n, u32 ufdset_x, unsigned long *fdset)
                __put_user(*fdset, ufdset);
 }
 
-asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x)
+asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
 {
        fd_set_buffer *fds;
-       struct timeval32 *tvp = (struct timeval32 *)A(tvp_x);
+       struct timeval32 *tvp = (struct timeval32 *)AA(tvp_x);
        unsigned long timeout, nn;
        int ret;
 
@@ -1148,26 +1186,27 @@ out_nofds:
 
 static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
 {
-       if (put_user (kbuf->st_dev, &ubuf->st_dev)              ||
-           __put_user (kbuf->st_ino, &ubuf->st_ino)            ||
-           __put_user (kbuf->st_mode, &ubuf->st_mode)          ||
-           __put_user (kbuf->st_nlink, &ubuf->st_nlink)        ||
-           __put_user (kbuf->st_uid, &ubuf->st_uid)            ||
-           __put_user (kbuf->st_gid, &ubuf->st_gid)            ||
-           __put_user (kbuf->st_rdev, &ubuf->st_rdev)          ||
-           __put_user (kbuf->st_size, &ubuf->st_size)          ||
-           __put_user (kbuf->st_atime, &ubuf->st_atime)        ||
-           __put_user (kbuf->st_mtime, &ubuf->st_mtime)        ||
-           __put_user (kbuf->st_ctime, &ubuf->st_ctime)        ||
-           __put_user (kbuf->st_blksize, &ubuf->st_blksize)    ||
-           __put_user (kbuf->st_blocks, &ubuf->st_blocks))
-               return -EFAULT;
-       return 0;
+       int err;
+       
+       err = put_user (kbuf->st_dev, &ubuf->st_dev);
+       err |= __put_user (kbuf->st_ino, &ubuf->st_ino);
+       err |= __put_user (kbuf->st_mode, &ubuf->st_mode);
+       err |= __put_user (kbuf->st_nlink, &ubuf->st_nlink);
+       err |= __put_user (kbuf->st_uid, &ubuf->st_uid);
+       err |= __put_user (kbuf->st_gid, &ubuf->st_gid);
+       err |= __put_user (kbuf->st_rdev, &ubuf->st_rdev);
+       err |= __put_user (kbuf->st_size, &ubuf->st_size);
+       err |= __put_user (kbuf->st_atime, &ubuf->st_atime);
+       err |= __put_user (kbuf->st_mtime, &ubuf->st_mtime);
+       err |= __put_user (kbuf->st_ctime, &ubuf->st_ctime);
+       err |= __put_user (kbuf->st_blksize, &ubuf->st_blksize);
+       err |= __put_user (kbuf->st_blocks, &ubuf->st_blocks);
+       return err;
 }
 
 extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
 
-asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
+asmlinkage int sys32_newstat(char * filename, struct stat32 *statbuf)
 {
        int ret;
        struct stat s;
@@ -1181,7 +1220,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
                ret = sys_newstat(filenam, &s);
                set_fs (old_fs);
                putname32 (filenam);
-               if (putstat ((struct stat32 *)A(statbuf), &s))
+               if (putstat (statbuf, &s))
                        return -EFAULT;
        }
        return ret;
@@ -1189,7 +1228,7 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
 
 extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
 
-asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
+asmlinkage int sys32_newlstat(char * filename, struct stat32 *statbuf)
 {
        int ret;
        struct stat s;
@@ -1203,7 +1242,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
                ret = sys_newlstat(filenam, &s);
                set_fs (old_fs);
                putname32 (filenam);
-               if (putstat ((struct stat32 *)A(statbuf), &s))
+               if (putstat (statbuf, &s))
                        return -EFAULT;
        }
        return ret;
@@ -1211,7 +1250,7 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
 
 extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
 
-asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
+asmlinkage int sys32_newfstat(unsigned int fd, struct stat32 *statbuf)
 {
        int ret;
        struct stat s;
@@ -1220,7 +1259,7 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
        set_fs (KERNEL_DS);
        ret = sys_newfstat(fd, &s);
        set_fs (old_fs);
-       if (putstat ((struct stat32 *)A(statbuf), &s))
+       if (putstat (statbuf, &s))
                return -EFAULT;
        return ret;
 }
@@ -1318,7 +1357,7 @@ extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
 #define SMBFS_NAME     "smbfs"
 #define NCPFS_NAME     "ncpfs"
 
-asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data)
+asmlinkage int sys32_mount(char *dev_name, char *dir_name, char *type, unsigned long new_flags, u32 data)
 {
        unsigned long type_page;
        int err, is_smb, is_ncp;
@@ -1326,7 +1365,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
        if(!capable(CAP_SYS_ADMIN))
                return -EPERM;
        is_smb = is_ncp = 0;
-       err = copy_mount_stuff_to_kernel((const void *)A(type), &type_page);
+       err = copy_mount_stuff_to_kernel((const void *)type, &type_page);
        if(err)
                return err;
        if(type_page) {
@@ -1336,20 +1375,18 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
        if(!is_smb && !is_ncp) {
                if(type_page)
                        free_page(type_page);
-               return sys_mount((char *)A(dev_name), (char *)A(dir_name),
-                                (char *)A(type), (unsigned long)new_flags,
-                                (void *)A(data));
+               return sys_mount(dev_name, dir_name, type, new_flags, (void *)AA(data));
        } else {
                unsigned long dev_page, dir_page, data_page;
                mm_segment_t old_fs;
 
-               err = copy_mount_stuff_to_kernel((const void *)A(dev_name), &dev_page);
+               err = copy_mount_stuff_to_kernel((const void *)dev_name, &dev_page);
                if(err)
                        goto out;
-               err = copy_mount_stuff_to_kernel((const void *)A(dir_name), &dir_page);
+               err = copy_mount_stuff_to_kernel((const void *)dir_name, &dir_page);
                if(err)
                        goto dev_out;
-               err = copy_mount_stuff_to_kernel((const void *)A(data), &data_page);
+               err = copy_mount_stuff_to_kernel((const void *)AA(data), &data_page);
                if(err)
                        goto dir_out;
                if(is_ncp)
@@ -1361,7 +1398,7 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags,
                old_fs = get_fs();
                set_fs(KERNEL_DS);
                err = sys_mount((char *)dev_page, (char *)dir_page,
-                               (char *)type_page, (unsigned long)new_flags,
+                               (char *)type_page, new_flags,
                                (void *)data_page);
                set_fs(old_fs);
 
@@ -1399,37 +1436,38 @@ struct rusage32 {
         s32    ru_nivcsw;
 };
 
-static int put_rusage (u32 ru, struct rusage *r)
-{
-       if (put_user (r->ru_utime.tv_sec, &(((struct rusage32 *)A(ru))->ru_utime.tv_sec)) ||
-           __put_user (r->ru_utime.tv_usec, &(((struct rusage32 *)A(ru))->ru_utime.tv_usec)) ||
-           __put_user (r->ru_stime.tv_sec, &(((struct rusage32 *)A(ru))->ru_stime.tv_sec)) ||
-           __put_user (r->ru_stime.tv_usec, &(((struct rusage32 *)A(ru))->ru_stime.tv_usec)) ||
-           __put_user (r->ru_maxrss, &(((struct rusage32 *)A(ru))->ru_maxrss)) ||
-           __put_user (r->ru_ixrss, &(((struct rusage32 *)A(ru))->ru_ixrss)) ||
-           __put_user (r->ru_idrss, &(((struct rusage32 *)A(ru))->ru_idrss)) ||
-           __put_user (r->ru_isrss, &(((struct rusage32 *)A(ru))->ru_isrss)) ||
-           __put_user (r->ru_minflt, &(((struct rusage32 *)A(ru))->ru_minflt)) ||
-           __put_user (r->ru_majflt, &(((struct rusage32 *)A(ru))->ru_majflt)) ||
-           __put_user (r->ru_nswap, &(((struct rusage32 *)A(ru))->ru_nswap)) ||
-           __put_user (r->ru_inblock, &(((struct rusage32 *)A(ru))->ru_inblock)) ||
-           __put_user (r->ru_oublock, &(((struct rusage32 *)A(ru))->ru_oublock)) ||
-           __put_user (r->ru_msgsnd, &(((struct rusage32 *)A(ru))->ru_msgsnd)) ||
-           __put_user (r->ru_msgrcv, &(((struct rusage32 *)A(ru))->ru_msgrcv)) ||
-           __put_user (r->ru_nsignals, &(((struct rusage32 *)A(ru))->ru_nsignals)) ||
-           __put_user (r->ru_nvcsw, &(((struct rusage32 *)A(ru))->ru_nvcsw)) ||
-           __put_user (r->ru_nivcsw, &(((struct rusage32 *)A(ru))->ru_nivcsw)))
-               return -EFAULT;
-       return 0;
+static int put_rusage (struct rusage32 *ru, struct rusage *r)
+{
+       int err;
+       
+       err = put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
+       err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
+       err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
+       err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
+       err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
+       err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
+       err |= __put_user (r->ru_idrss, &ru->ru_idrss);
+       err |= __put_user (r->ru_isrss, &ru->ru_isrss);
+       err |= __put_user (r->ru_minflt, &ru->ru_minflt);
+       err |= __put_user (r->ru_majflt, &ru->ru_majflt);
+       err |= __put_user (r->ru_nswap, &ru->ru_nswap);
+       err |= __put_user (r->ru_inblock, &ru->ru_inblock);
+       err |= __put_user (r->ru_oublock, &ru->ru_oublock);
+       err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
+       err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
+       err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
+       err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
+       err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
+       return err;
 }
 
 extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
                                int options, struct rusage * ru);
 
-asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
+asmlinkage int sys32_wait4(__kernel_pid_t32 pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
 {
        if (!ru)
-               return sys_wait4(pid, (unsigned int *)A(stat_addr), options, NULL);
+               return sys_wait4(pid, stat_addr, options, NULL);
        else {
                struct rusage r;
                int ret;
@@ -1440,7 +1478,7 @@ asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32
                ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
                set_fs (old_fs);
                if (put_rusage (ru, &r)) return -EFAULT;
-               if (stat_addr && put_user (status, (unsigned int *)A(stat_addr)))
+               if (stat_addr && put_user (status, stat_addr))
                        return -EFAULT;
                return ret;
        }
@@ -1461,26 +1499,27 @@ struct sysinfo32 {
 
 extern asmlinkage int sys_sysinfo(struct sysinfo *info);
 
-asmlinkage int sys32_sysinfo(u32 info)
+asmlinkage int sys32_sysinfo(struct sysinfo32 *info)
 {
        struct sysinfo s;
-       int ret;
+       int ret, err;
        mm_segment_t old_fs = get_fs ();
        
        set_fs (KERNEL_DS);
        ret = sys_sysinfo(&s);
        set_fs (old_fs);
-       if (put_user (s.uptime, &(((struct sysinfo32 *)A(info))->uptime)) ||
-           __put_user (s.loads[0], &(((struct sysinfo32 *)A(info))->loads[0])) ||
-           __put_user (s.loads[1], &(((struct sysinfo32 *)A(info))->loads[1])) ||
-           __put_user (s.loads[2], &(((struct sysinfo32 *)A(info))->loads[2])) ||
-           __put_user (s.totalram, &(((struct sysinfo32 *)A(info))->totalram)) ||
-           __put_user (s.freeram, &(((struct sysinfo32 *)A(info))->freeram)) ||
-           __put_user (s.sharedram, &(((struct sysinfo32 *)A(info))->sharedram)) ||
-           __put_user (s.bufferram, &(((struct sysinfo32 *)A(info))->bufferram)) ||
-           __put_user (s.totalswap, &(((struct sysinfo32 *)A(info))->totalswap)) ||
-           __put_user (s.freeswap, &(((struct sysinfo32 *)A(info))->freeswap)) ||
-           __put_user (s.procs, &(((struct sysinfo32 *)A(info))->procs)))
+       err = put_user (s.uptime, &info->uptime);
+       err |= __put_user (s.loads[0], &info->loads[0]);
+       err |= __put_user (s.loads[1], &info->loads[1]);
+       err |= __put_user (s.loads[2], &info->loads[2]);
+       err |= __put_user (s.totalram, &info->totalram);
+       err |= __put_user (s.freeram, &info->freeram);
+       err |= __put_user (s.sharedram, &info->sharedram);
+       err |= __put_user (s.bufferram, &info->bufferram);
+       err |= __put_user (s.totalswap, &info->totalswap);
+       err |= __put_user (s.freeswap, &info->freeswap);
+       err |= __put_user (s.procs, &info->procs);
+       if (err)
                return -EFAULT;
        return ret;
 }
@@ -1492,7 +1531,7 @@ struct timespec32 {
                 
 extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
 
-asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
+asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, struct timespec32 *interval)
 {
        struct timespec t;
        int ret;
@@ -1501,29 +1540,29 @@ asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
        set_fs (KERNEL_DS);
        ret = sys_sched_rr_get_interval(pid, &t);
        set_fs (old_fs);
-       if (put_user (t.tv_sec, &(((struct timespec32 *)A(interval))->tv_sec)) ||
-           __put_user (t.tv_nsec, &(((struct timespec32 *)A(interval))->tv_nsec)))
+       if (put_user (t.tv_sec, &interval->tv_sec) ||
+           __put_user (t.tv_nsec, &interval->tv_nsec))
                return -EFAULT;
        return ret;
 }
 
 extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
 
-asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
+asmlinkage int sys32_nanosleep(struct timespec32 *rqtp, struct timespec32 *rmtp)
 {
        struct timespec t;
        int ret;
        mm_segment_t old_fs = get_fs ();
        
-       if (get_user (t.tv_sec, &(((struct timespec32 *)A(rqtp))->tv_sec)) ||
-           __get_user (t.tv_nsec, &(((struct timespec32 *)A(rqtp))->tv_nsec)))
+       if (get_user (t.tv_sec, &rqtp->tv_sec) ||
+           __get_user (t.tv_nsec, &rqtp->tv_nsec))
                return -EFAULT;
        set_fs (KERNEL_DS);
        ret = sys_nanosleep(&t, rmtp ? &t : NULL);
        set_fs (old_fs);
        if (rmtp && ret == -EINTR) {
-               if (__put_user (t.tv_sec, &(((struct timespec32 *)A(rmtp))->tv_sec)) ||
-                   __put_user (t.tv_nsec, &(((struct timespec32 *)A(rmtp))->tv_nsec)))
+               if (__put_user (t.tv_sec, &rmtp->tv_sec) ||
+                   __put_user (t.tv_nsec, &rmtp->tv_nsec))
                        return -EFAULT;
        }
        return ret;
@@ -1531,24 +1570,24 @@ asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
 
 extern asmlinkage int sys_sigprocmask(int how, old_sigset_t *set, old_sigset_t *oset);
 
-asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
+asmlinkage int sys32_sigprocmask(int how, old_sigset_t32 *set, old_sigset_t32 *oset)
 {
        old_sigset_t s;
        int ret;
        mm_segment_t old_fs = get_fs();
        
-       if (set && get_user (s, (old_sigset_t32 *)A(set))) return -EFAULT;
+       if (set && get_user (s, set)) return -EFAULT;
        set_fs (KERNEL_DS);
        ret = sys_sigprocmask(how, set ? &s : NULL, oset ? &s : NULL);
        set_fs (old_fs);
        if (ret) return ret;
-       if (oset && put_user (s, (old_sigset_t32 *)A(oset))) return -EFAULT;
+       if (oset && put_user (s, oset)) return -EFAULT;
        return 0;
 }
 
 extern asmlinkage int sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, size_t sigsetsize);
 
-asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t32 sigsetsize)
+asmlinkage int sys32_rt_sigprocmask(int how, sigset_t32 *set, sigset_t32 *oset, __kernel_size_t32 sigsetsize)
 {
        sigset_t s;
        sigset_t32 s32;
@@ -1556,7 +1595,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3
        mm_segment_t old_fs = get_fs();
        
        if (set) {
-               if (copy_from_user (&s32, (sigset_t32 *)A(set), sizeof(sigset_t32)))
+               if (copy_from_user (&s32, set, sizeof(sigset_t32)))
                        return -EFAULT;
                switch (_NSIG_WORDS) {
                case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
@@ -1576,7 +1615,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3
                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
                }
-               if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32)))
+               if (copy_to_user (oset, &s32, sizeof(sigset_t32)))
                        return -EFAULT;
        }
        return 0;
@@ -1584,7 +1623,7 @@ asmlinkage int sys32_rt_sigprocmask(int how, u32 set, u32 oset, __kernel_size_t3
 
 extern asmlinkage int sys_sigpending(old_sigset_t *set);
 
-asmlinkage int sys32_sigpending(u32 set)
+asmlinkage int sys32_sigpending(old_sigset_t32 *set)
 {
        old_sigset_t s;
        int ret;
@@ -1593,13 +1632,13 @@ asmlinkage int sys32_sigpending(u32 set)
        set_fs (KERNEL_DS);
        ret = sys_sigpending(&s);
        set_fs (old_fs);
-       if (put_user (s, (old_sigset_t32 *)A(set))) return -EFAULT;
+       if (put_user (s, set)) return -EFAULT;
        return ret;
 }
 
 extern asmlinkage int sys_rt_sigpending(sigset_t *set, size_t sigsetsize);
 
-asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize)
+asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize)
 {
        sigset_t s;
        sigset_t32 s32;
@@ -1616,7 +1655,7 @@ asmlinkage int sys32_rt_sigpending(u32 set, __kernel_size_t32 sigsetsize)
                case 2: s32.sig[3] = (s.sig[1] >> 32); s32.sig[2] = s.sig[1];
                case 1: s32.sig[1] = (s.sig[0] >> 32); s32.sig[0] = s.sig[0];
                }
-               if (copy_to_user ((sigset_t32 *)A(set), &s32, sizeof(sigset_t32)))
+               if (copy_to_user (set, &s32, sizeof(sigset_t32)))
                        return -EFAULT;
        }
        return ret;
@@ -1706,8 +1745,8 @@ sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo,
                    const struct timespec *uts, size_t sigsetsize);
 
 asmlinkage int
-sys32_rt_sigtimedwait(u32 uthese, u32 uinfo,
-                     u32 uts, __kernel_size_t32 sigsetsize)
+sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
+                     struct timespec32 *uts, __kernel_size_t32 sigsetsize)
 {
        sigset_t s;
        sigset_t32 s32;
@@ -1717,7 +1756,7 @@ sys32_rt_sigtimedwait(u32 uthese, u32 uinfo,
        siginfo_t info;
        siginfo_t32 info32;
                
-       if (copy_from_user (&s32, (sigset_t32 *)A(uthese), sizeof(sigset_t32)))
+       if (copy_from_user (&s32, uthese, sizeof(sigset_t32)))
                return -EFAULT;
        switch (_NSIG_WORDS) {
        case 4: s.sig[3] = s32.sig[6] | (((long)s32.sig[7]) << 32);
@@ -1726,15 +1765,16 @@ sys32_rt_sigtimedwait(u32 uthese, u32 uinfo,
        case 1: s.sig[0] = s32.sig[0] | (((long)s32.sig[1]) << 32);
        }
        if (uts) {
-               if (get_user (t.tv_sec, &(((struct timespec32 *)A(uts))->tv_sec)) ||
-                   __get_user (t.tv_nsec, &(((struct timespec32 *)A(uts))->tv_nsec)))
+               ret = get_user (t.tv_sec, &uts->tv_sec);
+               ret |= __get_user (t.tv_nsec, &uts->tv_nsec);
+               if (ret)
                        return -EFAULT;
        }
        set_fs (KERNEL_DS);
        ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize);
        set_fs (old_fs);
        if (ret >= 0 && uinfo) {
-               if (copy_to_user ((siginfo_t32 *)A(uinfo), siginfo64to32(&info32, &info), sizeof(siginfo_t32)))
+               if (copy_to_user (uinfo, siginfo64to32(&info32, &info), sizeof(siginfo_t32)))
                        return -EFAULT;
        }
        return ret;
@@ -1744,14 +1784,14 @@ extern asmlinkage int
 sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo);
 
 asmlinkage int
-sys32_rt_sigqueueinfo(int pid, int sig, u32 uinfo)
+sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo)
 {
        siginfo_t info;
        siginfo_t32 info32;
        int ret;
        mm_segment_t old_fs = get_fs();
        
-       if (copy_from_user (&info32, (siginfo_t32 *)A(uinfo), sizeof(siginfo_t32)))
+       if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32)))
                return -EFAULT;
        /* XXX: Is this correct? */
        siginfo32to64(&info, &info32);
@@ -1788,7 +1828,7 @@ asmlinkage int sys32_setresuid(__kernel_uid_t32 ruid,
 
 extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
 
-asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
+asmlinkage int sys32_getresuid(__kernel_uid_t32 *ruid, __kernel_uid_t32 *euid, __kernel_uid_t32 *suid)
 {
        uid_t a, b, c;
        int ret;
@@ -1797,9 +1837,7 @@ asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
        set_fs (KERNEL_DS);
        ret = sys_getresuid(&a, &b, &c);
        set_fs (old_fs);
-       if (put_user (a, (__kernel_uid_t32 *)A(ruid)) ||
-           put_user (b, (__kernel_uid_t32 *)A(euid)) ||
-           put_user (c, (__kernel_uid_t32 *)A(suid)))
+       if (put_user (a, ruid) || put_user (b, euid) || put_user (c, suid))
                return -EFAULT;
        return ret;
 }
@@ -1831,7 +1869,7 @@ asmlinkage int sys32_setresgid(__kernel_gid_t32 rgid,
 
 extern asmlinkage int sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
 
-asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid)
+asmlinkage int sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, __kernel_gid_t32 *sgid)
 {
        gid_t a, b, c;
        int ret;
@@ -1840,10 +1878,11 @@ asmlinkage int sys32_getresgid(u32 rgid, u32 egid, u32 sgid)
        set_fs (KERNEL_DS);
        ret = sys_getresgid(&a, &b, &c);
        set_fs (old_fs);
-       if (put_user (a, (__kernel_gid_t32 *)A(rgid)) ||
-           put_user (b, (__kernel_gid_t32 *)A(egid)) ||
-           put_user (c, (__kernel_gid_t32 *)A(sgid)))
-               return -EFAULT;
+       if (!ret) {
+               ret = put_user (a, rgid);
+               ret |= put_user (b, egid);
+               ret |= put_user (c, sgid);
+       }
        return ret;
 }
 
@@ -1856,27 +1895,30 @@ struct tms32 {
                                 
 extern asmlinkage long sys_times(struct tms * tbuf);
 
-asmlinkage long sys32_times(u32 tbuf)
+asmlinkage long sys32_times(struct tms32 *tbuf)
 {
        struct tms t;
        long ret;
        mm_segment_t old_fs = get_fs ();
+       int err;
        
        set_fs (KERNEL_DS);
        ret = sys_times(tbuf ? &t : NULL);
        set_fs (old_fs);
-       if (tbuf && (
-           put_user (t.tms_utime, &(((struct tms32 *)A(tbuf))->tms_utime)) ||
-           __put_user (t.tms_stime, &(((struct tms32 *)A(tbuf))->tms_stime)) ||
-           __put_user (t.tms_cutime, &(((struct tms32 *)A(tbuf))->tms_cutime)) ||
-           __put_user (t.tms_cstime, &(((struct tms32 *)A(tbuf))->tms_cstime))))
-               return -EFAULT;
+       if (tbuf) {
+               err = put_user (t.tms_utime, &tbuf->tms_utime);
+               err |= __put_user (t.tms_stime, &tbuf->tms_stime);
+               err |= __put_user (t.tms_cutime, &tbuf->tms_cutime);
+               err |= __put_user (t.tms_cstime, &tbuf->tms_cstime);
+               if (err)
+                       ret = -EFAULT;
+       }
        return ret;
 }
 
 extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
 
-asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
+asmlinkage int sys32_getgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
 {
        gid_t gl[NGROUPS];
        int ret, i;
@@ -1886,15 +1928,15 @@ asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
        ret = sys_getgroups(gidsetsize, gl);
        set_fs (old_fs);
        if (gidsetsize && ret > 0 && ret <= NGROUPS)
-               for (i = 0; i < ret; i++, grouplist += sizeof(__kernel_gid_t32))
-                       if (__put_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+               for (i = 0; i < ret; i++, grouplist++)
+                       if (__put_user (gl[i], grouplist))
                                return -EFAULT;
        return ret;
 }
 
 extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
 
-asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
+asmlinkage int sys32_setgroups(int gidsetsize, __kernel_gid_t32 *grouplist)
 {
        gid_t gl[NGROUPS];
        int ret, i;
@@ -1902,8 +1944,8 @@ asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
        
        if ((unsigned) gidsetsize > NGROUPS)
                return -EINVAL;
-       for (i = 0; i < gidsetsize; i++, grouplist += sizeof(__kernel_gid_t32))
-               if (__get_user (gl[i], (__kernel_gid_t32 *)A(grouplist)))
+       for (i = 0; i < gidsetsize; i++, grouplist++)
+               if (__get_user (gl[i], grouplist))
                        return -EFAULT;
         set_fs (KERNEL_DS);
        ret = sys_setgroups(gidsetsize, gl);
@@ -1921,7 +1963,7 @@ struct rlimit32 {
 
 extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
 
-asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
+asmlinkage int sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
 {
        struct rlimit r;
        int ret;
@@ -1930,24 +1972,24 @@ asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
        set_fs (KERNEL_DS);
        ret = sys_getrlimit(resource, &r);
        set_fs (old_fs);
-       if (!ret && (
-           put_user (RESOURCE32(r.rlim_cur), &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
-           __put_user (RESOURCE32(r.rlim_max), &(((struct rlimit32 *)A(rlim))->rlim_max))))
-               return -EFAULT;
+       if (!ret) {
+               ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
+               ret |= __put_user (RESOURCE32(r.rlim_max), &rlim->rlim_max);
+       }
        return ret;
 }
 
 extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
 
-asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
+asmlinkage int sys32_setrlimit(unsigned int resource, struct rlimit32 *rlim)
 {
        struct rlimit r;
        int ret;
        mm_segment_t old_fs = get_fs ();
 
        if (resource >= RLIM_NLIMITS) return -EINVAL;   
-       if (get_user (r.rlim_cur, &(((struct rlimit32 *)A(rlim))->rlim_cur)) ||
-           __get_user (r.rlim_max, &(((struct rlimit32 *)A(rlim))->rlim_max)))
+       if (get_user (r.rlim_cur, &rlim->rlim_cur) ||
+           __get_user (r.rlim_max, &rlim->rlim_max))
                return -EFAULT;
        if (r.rlim_cur == RLIM_INFINITY32)
                r.rlim_cur = RLIM_INFINITY;
@@ -1961,7 +2003,7 @@ asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
 
 extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
 
-asmlinkage int sys32_getrusage(int who, u32 ru)
+asmlinkage int sys32_getrusage(int who, struct rusage32 *ru)
 {
        struct rusage r;
        int ret;
@@ -1999,49 +2041,46 @@ struct timex32 {
        int  :32; int  :32; int  :32; int  :32;
 };
 
-extern asmlinkage int sys_adjtimex(struct timex *txc_p);
+extern int do_adjtimex(struct timex *);
 
-asmlinkage int sys32_adjtimex(u32 txc_p)
+asmlinkage int sys32_adjtimex(struct timex32 *txc_p)
 {
        struct timex t;
        int ret;
-       mm_segment_t old_fs = get_fs ();
 
-       if (get_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
-           __get_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
-           __get_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
-           __get_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
-           __get_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
-           __get_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
-           __get_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
-           __get_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
-           __get_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)))
-               return -EFAULT;
-       set_fs (KERNEL_DS);
-       ret = sys_adjtimex(&t);
-       set_fs (old_fs);
-       if ((unsigned)ret >= 0 && (
-           __put_user (t.modes, &(((struct timex32 *)A(txc_p))->modes)) ||
-           __put_user (t.offset, &(((struct timex32 *)A(txc_p))->offset)) ||
-           __put_user (t.freq, &(((struct timex32 *)A(txc_p))->freq)) ||
-           __put_user (t.maxerror, &(((struct timex32 *)A(txc_p))->maxerror)) ||
-           __put_user (t.esterror, &(((struct timex32 *)A(txc_p))->esterror)) ||
-           __put_user (t.status, &(((struct timex32 *)A(txc_p))->status)) ||
-           __put_user (t.constant, &(((struct timex32 *)A(txc_p))->constant)) ||
-           __put_user (t.precision, &(((struct timex32 *)A(txc_p))->precision)) ||
-           __put_user (t.tolerance, &(((struct timex32 *)A(txc_p))->tolerance)) ||
-           __put_user (t.time.tv_sec, &(((struct timex32 *)A(txc_p))->time.tv_sec)) ||
-           __put_user (t.time.tv_usec, &(((struct timex32 *)A(txc_p))->time.tv_usec)) ||
-           __put_user (t.tick, &(((struct timex32 *)A(txc_p))->tick)) ||
-           __put_user (t.ppsfreq, &(((struct timex32 *)A(txc_p))->ppsfreq)) ||
-           __put_user (t.jitter, &(((struct timex32 *)A(txc_p))->jitter)) ||
-           __put_user (t.shift, &(((struct timex32 *)A(txc_p))->shift)) ||
-           __put_user (t.stabil, &(((struct timex32 *)A(txc_p))->stabil)) ||
-           __put_user (t.jitcnt, &(((struct timex32 *)A(txc_p))->jitcnt)) ||
-           __put_user (t.calcnt, &(((struct timex32 *)A(txc_p))->calcnt)) ||
-           __put_user (t.errcnt, &(((struct timex32 *)A(txc_p))->errcnt)) ||
-           __put_user (t.stbcnt, &(((struct timex32 *)A(txc_p))->stbcnt))))
-               return -EFAULT;
+       ret = get_user (t.modes, &txc_p->modes);
+       ret |= __get_user (t.offset, &txc_p->offset);
+       ret |= __get_user (t.freq, &txc_p->freq);
+       ret |= __get_user (t.maxerror, &txc_p->maxerror);
+       ret |= __get_user (t.esterror, &txc_p->esterror);
+       ret |= __get_user (t.status, &txc_p->status);
+       ret |= __get_user (t.constant, &txc_p->constant);
+       ret |= __get_user (t.tick, &txc_p->tick);
+       ret |= __get_user (t.shift, &txc_p->shift);
+       if (ret || (ret = do_adjtimex(&t)))
+               return ret;
+       ret = __put_user (t.modes, &txc_p->modes);
+       ret |= __put_user (t.offset, &txc_p->offset);
+       ret |= __put_user (t.freq, &txc_p->freq);
+       ret |= __put_user (t.maxerror, &txc_p->maxerror);
+       ret |= __put_user (t.esterror, &txc_p->esterror);
+       ret |= __put_user (t.status, &txc_p->status);
+       ret |= __put_user (t.constant, &txc_p->constant);
+       ret |= __put_user (t.precision, &txc_p->precision);
+       ret |= __put_user (t.tolerance, &txc_p->tolerance);
+       ret |= __put_user (t.time.tv_sec, &txc_p->time.tv_sec);
+       ret |= __put_user (t.time.tv_usec, &txc_p->time.tv_usec);
+       ret |= __put_user (t.tick, &txc_p->tick);
+       ret |= __put_user (t.ppsfreq, &txc_p->ppsfreq);
+       ret |= __put_user (t.jitter, &txc_p->jitter);
+       ret |= __put_user (t.shift, &txc_p->shift);
+       ret |= __put_user (t.stabil, &txc_p->stabil);
+       ret |= __put_user (t.jitcnt, &txc_p->jitcnt);
+       ret |= __put_user (t.calcnt, &txc_p->calcnt);
+       ret |= __put_user (t.errcnt, &txc_p->errcnt);
+       ret |= __put_user (t.stbcnt, &txc_p->stbcnt);
+       if (!ret)
+               ret = time_state;
        return ret;
 }
 
@@ -2129,22 +2168,23 @@ static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
                                             struct msghdr32 *umsg)
 {
        u32 tmp1, tmp2, tmp3;
+       int err;
 
-       if(get_user(tmp1, &umsg->msg_name)      ||
-          get_user(tmp2, &umsg->msg_iov)       ||
-          get_user(tmp3, &umsg->msg_control))
+       err = get_user(tmp1, &umsg->msg_name);
+       err |= __get_user(tmp2, &umsg->msg_iov);
+       err |= __get_user(tmp3, &umsg->msg_control);
+       if (err)
                return -EFAULT;
 
        kmsg->msg_name = (void *)A(tmp1);
        kmsg->msg_iov = (struct iovec *)A(tmp2);
        kmsg->msg_control = (void *)A(tmp3);
 
-       if(get_user(kmsg->msg_namelen, &umsg->msg_namelen)              ||
-          get_user(kmsg->msg_controllen, &umsg->msg_controllen)        ||
-          get_user(kmsg->msg_flags, &umsg->msg_flags))
-               return -EFAULT;
-
-       return 0;
+       err = get_user(kmsg->msg_namelen, &umsg->msg_namelen);
+       err |= get_user(kmsg->msg_controllen, &umsg->msg_controllen);
+       err |= get_user(kmsg->msg_flags, &umsg->msg_flags);
+       
+       return err;
 }
 
 /* I've named the args so it is easy to tell whose space the pointers are in. */
@@ -2183,7 +2223,7 @@ static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
        return tot_len;
 }
 
-asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
+asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
        struct socket *sock;
        char address[MAX_SOCK_ADDR];
@@ -2193,7 +2233,7 @@ asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
        struct msghdr kern_msg;
        int err, total_len;
 
-       if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
                return -EFAULT;
        if(kern_msg.msg_iovlen > UIO_MAXIOV)
                return -EINVAL;
@@ -2246,7 +2286,7 @@ out:
        return err;
 }
 
-asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
+asmlinkage int sys32_recvmsg(int fd, struct msghdr32 *user_msg, unsigned int user_flags)
 {
        struct iovec iovstack[UIO_FASTIOV];
        struct msghdr kern_msg;
@@ -2258,13 +2298,13 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
        unsigned long cmsg_ptr;
        int err, total_len, len = 0;
 
-       if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
+       if(msghdr_from_user32_to_kern(&kern_msg, user_msg))
                return -EFAULT;
        if(kern_msg.msg_iovlen > UIO_MAXIOV)
                return -EINVAL;
 
        uaddr = kern_msg.msg_name;
-       uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen;
+       uaddr_len = &user_msg->msg_namelen;
        err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
        if (err < 0)
                goto out;
@@ -2288,12 +2328,11 @@ asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
        if(uaddr != NULL && err >= 0)
                err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
        if(err >= 0) {
-               err = __put_user(kern_msg.msg_flags,
-                                &((struct msghdr32 *)A(user_msg))->msg_flags);
+               err = __put_user(kern_msg.msg_flags, &user_msg->msg_flags);
                if(!err) {
                        /* XXX Convert cmsg back into userspace 32-bit format... */
                        err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
-                                        &((struct msghdr32 *)A(user_msg))->msg_controllen);
+                                        &user_msg->msg_controllen);
                }
        }
 
@@ -2334,14 +2373,14 @@ extern asmlinkage int sys_socketpair(int family, int type, int protocol,
 extern asmlinkage int sys_shutdown(int fd, int how);
 extern asmlinkage int sys_listen(int fd, int backlog);
 
-asmlinkage int sys32_socketcall(int call, u32 args)
+asmlinkage int sys32_socketcall(int call, u32 *args)
 {
        u32 a[6];
        u32 a0,a1;
                                 
        if (call<SYS_SOCKET||call>SYS_RECVMSG)
                return -EINVAL;
-       if (copy_from_user(a, (u32 *)A(args), nargs[call]))
+       if (copy_from_user(a, args, nargs[call]))
                return -EFAULT;
        a0=a[0];
        a1=a[1];
@@ -2379,16 +2418,16 @@ asmlinkage int sys32_socketcall(int call, u32 args)
                case SYS_GETSOCKOPT:
                        return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
                case SYS_SENDMSG:
-                       return sys32_sendmsg(a0, a1, a[2]);
+                       return sys32_sendmsg(a0, (struct msghdr32 *)A(a1), a[2]);
                case SYS_RECVMSG:
-                       return sys32_recvmsg(a0, a1, a[2]);
+                       return sys32_recvmsg(a0, (struct msghdr32 *)A(a1), a[2]);
        }
        return -EINVAL;
 }
 
 extern void check_pending(int signum);
 
-asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact)
+asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
 {
         struct k_sigaction new_ka, old_ka;
         int ret;
@@ -2401,31 +2440,31 @@ asmlinkage int sys32_sigaction (int sig, u32 act, u32 oact)
         if (act) {
                old_sigset_t32 mask;
                
-               if (get_user((long)new_ka.sa.sa_handler, &((struct old_sigaction32 *)A(act))->sa_handler) ||
-                   __get_user((long)new_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(act))->sa_restorer))
-                       return -EFAULT;
-               __get_user(new_ka.sa.sa_flags, &((struct old_sigaction32 *)A(act))->sa_flags);
-               __get_user(mask, &((struct old_sigaction32 *)A(act))->sa_mask);
-                new_ka.ka_restorer = NULL;
-                siginitset(&new_ka.sa.sa_mask, mask);
+               ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+               ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+               ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               ret |= __get_user(mask, &act->sa_mask);
+               if (ret)
+                       return ret;
+               new_ka.ka_restorer = NULL;
+               siginitset(&new_ka.sa.sa_mask, mask);
         }
 
         ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
-        if (!ret && oact) {
-               if (put_user((long)old_ka.sa.sa_handler, &((struct old_sigaction32 *)A(oact))->sa_handler) ||
-                   __put_user((long)old_ka.sa.sa_restorer, &((struct old_sigaction32 *)A(oact))->sa_restorer))
-                        return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &((struct old_sigaction32 *)A(oact))->sa_flags);
-               __put_user(old_ka.sa.sa_mask.sig[0], &((struct old_sigaction32 *)A(oact))->sa_mask);
+       if (!ret && oact) {
+               ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
+               ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer);
+               ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               ret |= __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
         }
 
        return ret;
 }
 
 asmlinkage int
-sys32_rt_sigaction(int sig, u32 act, u32 oact,
-                 u32 restorer, __kernel_size_t32 sigsetsize)
+sys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact,
+                  void *restorer, __kernel_size_t32 sigsetsize)
 {
         struct k_sigaction new_ka, old_ka;
         int ret;
@@ -2435,35 +2474,40 @@ sys32_rt_sigaction(int sig, u32 act, u32 oact,
         if (sigsetsize != sizeof(sigset_t32))
                 return -EINVAL;
 
+       /* All tasks which use RT signals (effectively) use
+        * new style signals.
+        */
+       current->tss.new_signal = 1;
+
         if (act) {
-               if (get_user((long)new_ka.sa.sa_handler, &((struct sigaction32 *)A(act))->sa_handler) ||
-                   __copy_from_user(&set32, &((struct sigaction32 *)A(act))->sa_mask, sizeof(sigset_t32)))
-                        return -EFAULT;
+               new_ka.ka_restorer = restorer;
+               ret = get_user((long)new_ka.sa.sa_handler, &act->sa_handler);
+               ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(sigset_t32));
                switch (_NSIG_WORDS) {
                case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
                case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
                case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
                case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
                }
-               __get_user(new_ka.sa.sa_flags, &((struct sigaction32 *)A(act))->sa_flags);
-               __get_user((long)new_ka.sa.sa_restorer, &((struct sigaction32 *)A(act))->sa_restorer);
-                new_ka.ka_restorer = (void *)(long)restorer;
-        }
+               ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               ret |= __get_user((long)new_ka.sa.sa_restorer, &act->sa_restorer);
+                if (ret)
+                       return -EFAULT;
+       }
 
-        ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+       ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
 
-        if (!ret && oact) {
+       if (!ret && oact) {
                switch (_NSIG_WORDS) {
                case 4: set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); set32.sig[6] = old_ka.sa.sa_mask.sig[3];
                case 3: set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); set32.sig[4] = old_ka.sa.sa_mask.sig[2];
                case 2: set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); set32.sig[2] = old_ka.sa.sa_mask.sig[1];
                case 1: set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); set32.sig[0] = old_ka.sa.sa_mask.sig[0];
                }
-               if (put_user((long)old_ka.sa.sa_handler, &((struct sigaction32 *)A(oact))->sa_handler) ||
-                   __copy_to_user(&((struct sigaction32 *)A(oact))->sa_mask, &set32, sizeof(sigset_t32)))
-                        return -EFAULT;
-               __put_user(old_ka.sa.sa_flags, &((struct sigaction32 *)A(oact))->sa_flags);
-               __put_user((long)old_ka.sa.sa_restorer, &((struct sigaction32 *)A(oact))->sa_restorer);
+               ret = put_user((long)old_ka.sa.sa_handler, &oact->sa_handler);
+               ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(sigset_t32));
+               ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               ret |= __put_user((long)old_ka.sa.sa_restorer, &oact->sa_restorer);
         }
 
         return ret;
@@ -2608,14 +2652,14 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
                 base = 1;
 
        lock_kernel();
-        filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
+        filename = getname32((char *)AA(regs->u_regs[base + UREG_I0]));
        error = PTR_ERR(filename);
         if(IS_ERR(filename))
                 goto out;
         error = do_execve32(filename,
-               (u32 *)A((u32)regs->u_regs[base + UREG_I1]),
-               (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs);
-        putname(filename);
+               (u32 *)AA((u32)regs->u_regs[base + UREG_I1]),
+               (u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs);
+        putname32(filename);
 
        if(!error) {
                fprs_write(0);
@@ -2632,9 +2676,9 @@ out:
 
 extern asmlinkage unsigned long sys_create_module(const char *name_user, size_t size);
 
-asmlinkage unsigned long sys32_create_module(u32 name_user, __kernel_size_t32 size)
+asmlinkage unsigned long sys32_create_module(const char *name_user, __kernel_size_t32 size)
 {
-       return sys_create_module((const char *)A(name_user), (size_t)size);
+       return sys_create_module(name_user, (size_t)size);
 }
 
 extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_user);
@@ -2642,16 +2686,16 @@ extern asmlinkage int sys_init_module(const char *name_user, struct module *mod_
 /* Hey, when you're trying to init module, take time and prepare us a nice 64bit
  * module structure, even if from 32bit modutils... Why to pollute kernel... :))
  */
-asmlinkage int sys32_init_module(u32 nameuser, u32 mod_user)
+asmlinkage int sys32_init_module(const char *name_user, struct module *mod_user)
 {
-       return sys_init_module((const char *)A(nameuser), (struct module *)A(mod_user));
+       return sys_init_module(name_user, mod_user);
 }
 
 extern asmlinkage int sys_delete_module(const char *name_user);
 
-asmlinkage int sys32_delete_module(u32 name_user)
+asmlinkage int sys32_delete_module(const char *name_user)
 {
-       return sys_delete_module((const char *)A(name_user));
+       return sys_delete_module(name_user);
 }
 
 struct module_info32 {
@@ -2876,7 +2920,7 @@ qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret)
        return error;
 }
 
-asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret)
+asmlinkage int sys32_query_module(char *name_user, int which, char *buf, __kernel_size_t32 bufsize, u32 ret)
 {
        struct module *mod;
        int err;
@@ -2888,7 +2932,7 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si
                long namelen;
                char *name;
 
-               if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) {
+               if ((namelen = get_mod_name(name_user, &name)) < 0) {
                        err = namelen;
                        goto out;
                }
@@ -2908,19 +2952,19 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si
                err = 0;
                break;
        case QM_MODULES:
-               err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+               err = qm_modules(buf, bufsize, (__kernel_size_t32 *)AA(ret));
                break;
        case QM_DEPS:
-               err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+               err = qm_deps(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
                break;
        case QM_REFS:
-               err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+               err = qm_refs(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
                break;
        case QM_SYMBOLS:
-               err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+               err = qm_symbols(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
                break;
        case QM_INFO:
-               err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret));
+               err = qm_info(mod, buf, bufsize, (__kernel_size_t32 *)AA(ret));
                break;
        default:
                err = -EINVAL;
@@ -2938,7 +2982,7 @@ struct kernel_sym32 {
                 
 extern asmlinkage int sys_get_kernel_syms(struct kernel_sym *table);
 
-asmlinkage int sys32_get_kernel_syms(u32 table)
+asmlinkage int sys32_get_kernel_syms(struct kernel_sym32 *table)
 {
        int len, i;
        struct kernel_sym *tbl;
@@ -2953,8 +2997,8 @@ asmlinkage int sys32_get_kernel_syms(u32 table)
        sys_get_kernel_syms(tbl);
        set_fs (old_fs);
        for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
-               if (put_user (tbl[i].value, &(((struct kernel_sym32 *)A(table))->value)) ||
-                   copy_to_user (((struct kernel_sym32 *)A(table))->name, tbl[i].name, 60))
+               if (put_user (tbl[i].value, &table->value) ||
+                   copy_to_user (table->name, tbl[i].name, 60))
                        break;
        }
        kfree (tbl);
@@ -3069,61 +3113,65 @@ union nfsctl_res32 {
 
 static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
-       if(__get_user(karg->ca_version, &arg32->ca32_version)                   ||
-          __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port)       ||
-          __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads))
-               return -EFAULT;
-       return 0;
+       int err;
+       
+       err = __get_user(karg->ca_version, &arg32->ca32_version);
+       err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
+       err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
+       return err;
 }
 
 static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
-       if(__get_user(karg->ca_version, &arg32->ca32_version)                   ||
-          copy_from_user(&karg->ca_client.cl_ident[0],
+       int err;
+       
+       err = __get_user(karg->ca_version, &arg32->ca32_version);
+       err |= copy_from_user(&karg->ca_client.cl_ident[0],
                          &arg32->ca32_client.cl32_ident[0],
-                         NFSCLNT_IDMAX)                                        ||
-          __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr) ||
-          copy_from_user(&karg->ca_client.cl_addrlist[0],
+                         NFSCLNT_IDMAX);
+       err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
+       err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
                          &arg32->ca32_client.cl32_addrlist[0],
-                         (sizeof(struct in_addr) * NFSCLNT_ADDRMAX))           ||
-          __get_user(karg->ca_client.cl_fhkeytype,
-                     &arg32->ca32_client.cl32_fhkeytype)                       ||
-          __get_user(karg->ca_client.cl_fhkeylen,
-                     &arg32->ca32_client.cl32_fhkeylen)                        ||
-          copy_from_user(&karg->ca_client.cl_fhkey[0],
+                         (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
+       err |= __get_user(karg->ca_client.cl_fhkeytype,
+                     &arg32->ca32_client.cl32_fhkeytype);
+       err |= __get_user(karg->ca_client.cl_fhkeylen,
+                     &arg32->ca32_client.cl32_fhkeylen);
+       err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
                          &arg32->ca32_client.cl32_fhkey[0],
-                         NFSCLNT_KEYMAX))
-               return -EFAULT;
-       return 0;
+                         NFSCLNT_KEYMAX);
+       return err;
 }
 
 static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
-       if(__get_user(karg->ca_version, &arg32->ca32_version)                   ||
-          copy_from_user(&karg->ca_export.ex_client[0],
+       int err;
+       
+       err = __get_user(karg->ca_version, &arg32->ca32_version);
+       err |= copy_from_user(&karg->ca_export.ex_client[0],
                          &arg32->ca32_export.ex32_client[0],
-                         NFSCLNT_IDMAX)                                        ||
-          copy_from_user(&karg->ca_export.ex_path[0],
+                         NFSCLNT_IDMAX);
+       err |= copy_from_user(&karg->ca_export.ex_path[0],
                          &arg32->ca32_export.ex32_path[0],
-                         NFS_MAXPATHLEN)                                       ||
-          __get_user(karg->ca_export.ex_dev,
-                     &arg32->ca32_export.ex32_dev)                             ||
-          __get_user(karg->ca_export.ex_ino,
-                     &arg32->ca32_export.ex32_ino)                             ||
-          __get_user(karg->ca_export.ex_flags,
-                     &arg32->ca32_export.ex32_flags)                           ||
-          __get_user(karg->ca_export.ex_anon_uid,
-                     &arg32->ca32_export.ex32_anon_uid)                        ||
-          __get_user(karg->ca_export.ex_anon_gid,
-                     &arg32->ca32_export.ex32_anon_gid))
-               return -EFAULT;
-       return 0;
+                         NFS_MAXPATHLEN);
+       err |= __get_user(karg->ca_export.ex_dev,
+                     &arg32->ca32_export.ex32_dev);
+       err |= __get_user(karg->ca_export.ex_ino,
+                     &arg32->ca32_export.ex32_ino);
+       err |= __get_user(karg->ca_export.ex_flags,
+                     &arg32->ca32_export.ex32_flags);
+       err |= __get_user(karg->ca_export.ex_anon_uid,
+                     &arg32->ca32_export.ex32_anon_uid);
+       err |= __get_user(karg->ca_export.ex_anon_gid,
+                     &arg32->ca32_export.ex32_anon_gid);
+       return err;
 }
 
 static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
        u32 uaddr;
        int i;
+       int err;
 
        memset(karg, 0, sizeof(*karg));
        if(__get_user(karg->ca_version, &arg32->ca32_version))
@@ -3131,76 +3179,74 @@ static int nfs_uud32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
        karg->ca_umap.ug_ident = (char *)get_free_page(GFP_USER);
        if(!karg->ca_umap.ug_ident)
                return -ENOMEM;
-       if(__get_user(uaddr, &arg32->ca32_umap.ug32_ident))
-               return -EFAULT;
+       err = __get_user(uaddr, &arg32->ca32_umap.ug32_ident);
        if(strncpy_from_user(karg->ca_umap.ug_ident,
                             (char *)A(uaddr), PAGE_SIZE) <= 0)
                return -EFAULT;
-       if(__get_user(karg->ca_umap.ug_uidbase,
-                     &arg32->ca32_umap.ug32_uidbase)           ||
-          __get_user(karg->ca_umap.ug_uidlen,
-                     &arg32->ca32_umap.ug32_uidlen)            ||
-          __get_user(uaddr, &arg32->ca32_umap.ug32_udimap))
+       err |= __get_user(karg->ca_umap.ug_uidbase,
+                     &arg32->ca32_umap.ug32_uidbase);
+       err |= __get_user(karg->ca_umap.ug_uidlen,
+                     &arg32->ca32_umap.ug32_uidlen);
+       err |= __get_user(uaddr, &arg32->ca32_umap.ug32_udimap);
+       if (err)
                return -EFAULT;
        karg->ca_umap.ug_udimap = kmalloc((sizeof(uid_t) * karg->ca_umap.ug_uidlen),
                                          GFP_USER);
        if(!karg->ca_umap.ug_udimap)
-               return -EFAULT;
+               return -ENOMEM;
        for(i = 0; i < karg->ca_umap.ug_uidlen; i++)
-               if(__get_user(karg->ca_umap.ug_udimap[i],
-                             &(((__kernel_uid_t32 *)A(uaddr))[i])))
-                       return -EFAULT;
-       if(__get_user(karg->ca_umap.ug_gidbase,
-                     &arg32->ca32_umap.ug32_gidbase)           ||
-          __get_user(karg->ca_umap.ug_uidlen,
-                     &arg32->ca32_umap.ug32_gidlen)            ||
-          __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap))
+               err |= __get_user(karg->ca_umap.ug_udimap[i],
+                             &(((__kernel_uid_t32 *)A(uaddr))[i]));
+       err |= __get_user(karg->ca_umap.ug_gidbase,
+                     &arg32->ca32_umap.ug32_gidbase);
+       err |= __get_user(karg->ca_umap.ug_uidlen,
+                     &arg32->ca32_umap.ug32_gidlen);
+       err |= __get_user(uaddr, &arg32->ca32_umap.ug32_gdimap);
+       if (err)
                return -EFAULT;
        karg->ca_umap.ug_gdimap = kmalloc((sizeof(gid_t) * karg->ca_umap.ug_uidlen),
                                          GFP_USER);
        if(!karg->ca_umap.ug_gdimap)
-               return -EFAULT;
+               return -ENOMEM;
        for(i = 0; i < karg->ca_umap.ug_gidlen; i++)
-               if(__get_user(karg->ca_umap.ug_gdimap[i],
-                             &(((__kernel_gid_t32 *)A(uaddr))[i])))
-                       return -EFAULT;
+               err |= __get_user(karg->ca_umap.ug_gdimap[i],
+                             &(((__kernel_gid_t32 *)A(uaddr))[i]));
 
-       /* Success! */
-       return 0;
+       return err;
 }
 
 static int nfs_getfh32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
 {
-       if(__get_user(karg->ca_version, &arg32->ca32_version)   ||
-          copy_from_user(&karg->ca_getfh.gf_addr,
+       int err;
+       
+       err = __get_user(karg->ca_version, &arg32->ca32_version);
+       err |= copy_from_user(&karg->ca_getfh.gf_addr,
                          &arg32->ca32_getfh.gf32_addr,
-                         (sizeof(struct sockaddr)))            ||
-          __get_user(karg->ca_getfh.gf_dev,
-                     &arg32->ca32_getfh.gf32_dev)              ||
-          __get_user(karg->ca_getfh.gf_ino,
-                     &arg32->ca32_getfh.gf32_ino)              ||
-          __get_user(karg->ca_getfh.gf_version,
-                     &arg32->ca32_getfh.gf32_version))
-               return -EFAULT;
-       return 0;
+                         (sizeof(struct sockaddr)));
+       err |= __get_user(karg->ca_getfh.gf_dev,
+                     &arg32->ca32_getfh.gf32_dev);
+       err |= __get_user(karg->ca_getfh.gf_ino,
+                     &arg32->ca32_getfh.gf32_ino);
+       err |= __get_user(karg->ca_getfh.gf_version,
+                     &arg32->ca32_getfh.gf32_version);
+       return err;
 }
 
 static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
 {
-       if(copy_to_user(&res32->cr32_getfh,
+       int err;
+       
+       err = copy_to_user(&res32->cr32_getfh,
                        &kres->cr_getfh,
-                       sizeof(res32->cr32_getfh))              ||
-          __put_user(kres->cr_debug, &res32->cr32_debug))
-               return -EFAULT;
-       return 0;
+                       sizeof(res32->cr32_getfh));
+       err |= __put_user(kres->cr_debug, &res32->cr32_debug);
+       return err;
 }
 
 extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
 
-int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
+int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
 {
-       struct nfsctl_arg32 *arg32 = (struct nfsctl_arg32 *)A(u_argp);
-       union nfsctl_res32 *res32 = (union nfsctl_res32 *)A(u_resp);
        struct nfsctl_arg *karg = NULL;
        union nfsctl_res *kres = NULL;
        mm_segment_t oldfs;
@@ -3273,32 +3319,32 @@ done:
 extern struct timezone sys_tz;
 extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
 
-asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
+asmlinkage int sys32_gettimeofday(struct timeval32 *tv, struct timezone *tz)
 {
        if (tv) {
                struct timeval ktv;
                do_gettimeofday(&ktv);
-               if (put_tv32((struct timeval32 *)A(tv), &ktv))
+               if (put_tv32(tv, &ktv))
                        return -EFAULT;
        }
        if (tz) {
-               if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz)))
+               if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
                        return -EFAULT;
        }
        return 0;
 }
 
-asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
+asmlinkage int sys32_settimeofday(struct timeval32 *tv, struct timezone *tz)
 {
        struct timeval ktv;
        struct timezone ktz;
 
        if (tv) {
-               if (get_tv32(&ktv, (struct timeval32 *)A(tv)))
+               if (get_tv32(&ktv, tv))
                        return -EFAULT;
        }
        if (tz) {
-               if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz)))
+               if (copy_from_user(&ktz, tz, sizeof(ktz)))
                        return -EFAULT;
        }
 
@@ -3307,13 +3353,13 @@ asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
 
 extern int do_getitimer(int which, struct itimerval *value);
 
-asmlinkage int sys32_getitimer(int which, u32 it)
+asmlinkage int sys32_getitimer(int which, struct itimerval32 *it)
 {
        struct itimerval kit;
        int error;
 
        error = do_getitimer(which, &kit);
-       if (!error && put_it32((struct itimerval32 *)A(it), &kit))
+       if (!error && put_it32(it, &kit))
                error = -EFAULT;
 
        return error;
@@ -3321,13 +3367,13 @@ asmlinkage int sys32_getitimer(int which, u32 it)
 
 extern int do_setitimer(int which, struct itimerval *, struct itimerval *);
 
-asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
+asmlinkage int sys32_setitimer(int which, struct itimerval32 *in, struct itimerval32 *out)
 {
        struct itimerval kin, kout;
        int error;
 
        if (in) {
-               if (get_it32(&kin, (struct itimerval32 *)A(in)))
+               if (get_it32(&kin, in))
                        return -EFAULT;
        } else
                memset(&kin, 0, sizeof(kin));
@@ -3335,7 +3381,7 @@ asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
        error = do_setitimer(which, &kin, out ? &kout : NULL);
        if (error || !out)
                return error;
-       if (put_it32((struct itimerval32 *)A(out), &kout))
+       if (put_it32(out, &kout))
                return -EFAULT;
 
        return 0;
@@ -3344,7 +3390,7 @@ asmlinkage int sys32_setitimer(int which, u32 in, u32 out)
 
 asmlinkage int sys_utimes(char *, struct timeval *);
 
-asmlinkage int sys32_utimes(u32 filename, u32 tvs)
+asmlinkage int sys32_utimes(char *filename, struct timeval32 *tvs)
 {
        char *kfilename;
        struct timeval ktvs[2];
@@ -3355,8 +3401,8 @@ asmlinkage int sys32_utimes(u32 filename, u32 tvs)
        ret = PTR_ERR(kfilename);
        if (!IS_ERR(kfilename)) {
                if (tvs) {
-                       if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) ||
-                           get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs)))
+                       if (get_tv32(&ktvs[0], tvs) ||
+                           get_tv32(&ktvs[1], 1+tvs))
                                return -EFAULT;
                }
 
@@ -3397,7 +3443,7 @@ asmlinkage int sys32_pciconfig_read(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf
                                  (unsigned long) dfn,
                                  (unsigned long) off,
                                  (unsigned long) len,
-                                 (unsigned char *)A(ubuf));
+                                 (unsigned char *)AA(ubuf));
 }
 
 asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
@@ -3406,7 +3452,7 @@ asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubu
                                   (unsigned long) dfn,
                                   (unsigned long) off,
                                   (unsigned long) len,
-                                  (unsigned char *)A(ubuf));
+                                  (unsigned char *)AA(ubuf));
 }
 
 extern asmlinkage int sys_prctl(int option, unsigned long arg2, unsigned long arg3,
@@ -3442,16 +3488,16 @@ extern asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
 
 typedef __kernel_ssize_t32 ssize_t32;
 
-asmlinkage ssize_t32 sys32_pread(unsigned int fd, u32 ubuf,
+asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
                                 __kernel_size_t32 count, u32 pos)
 {
-       return sys_pread(fd, (char *) A(ubuf), count, pos);
+       return sys_pread(fd, ubuf, count, pos);
 }
 
-asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, u32 ubuf,
+asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
                                  __kernel_size_t32 count, u32 pos)
 {
-       return sys_pwrite(fd, (char *) A(ubuf), count, pos);
+       return sys_pwrite(fd, ubuf, count, pos);
 }
 
 
@@ -3472,20 +3518,20 @@ asmlinkage int sys32_personality(unsigned long personality)
 
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count)
+asmlinkage int sys32_sendfile(int out_fd, int in_fd, __kernel_off_t32 *offset, s32 count)
 {
        mm_segment_t old_fs = get_fs();
        int ret;
        off_t of;
        
-       if (offset && get_user(of, (__kernel_off_t32 *)A(offset)))
+       if (offset && get_user(of, offset))
                return -EFAULT;
                
        set_fs(KERNEL_DS);
        ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count);
        set_fs(old_fs);
        
-       if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset)))
+       if (!ret && offset && put_user(of, offset))
                return -EFAULT;
                
        return ret;
index ec965972fe9200760ed896681bb9554590ad1910..c0cc42cb9316ca73135f1bebdbbcf726d3f7dfe0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.16 1998/06/16 04:37:06 davem Exp $
+/* $Id: sys_sunos32.c,v 1.18 1998/08/31 03:41:01 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
 #include <linux/time.h>
 #include <linux/personality.h>
 
-#define A(x) ((unsigned long)x)
+/* Use this to get at 32-bit user passed pointers. */
+#define A(__x)                         \
+({     unsigned long __ret;            \
+       __asm__ ("srl   %0, 0, %0"      \
+                : "=r" (__ret)         \
+                : "0" (__x));          \
+       __ret;                          \
+})
 
 #define SUNOS_NR_OPEN  256
 
@@ -98,6 +105,7 @@ asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 of
        ret_type = flags & _MAP_NEW;
        flags &= ~_MAP_NEW;
 
+       flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        retval = do_mmap(file,
                         (unsigned long) addr, (unsigned long) len,
                         (unsigned long) prot, (unsigned long) flags,
index beed61bd722c5258580fc5cda24bd1bf1e212d12..55b41b36e3dfd22f6141cf8a9be461b5b993ad6d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.47 1998/07/28 13:07:55 jj Exp $
+/* $Id: systbls.S,v 1.49 1998/09/13 04:30:32 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -17,9 +17,9 @@
 
        .globl sys_call_table32
 sys_call_table32:
-/*0*/  .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write
+/*0*/  .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
 /*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
@@ -76,9 +76,9 @@ sys_call_table32:
        .globl sys_call_table64, sys_call_table
 sys_call_table64:
 sys_call_table:
-/*0*/  .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write
+/*0*/  .word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
 /*5*/  .word sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown, sys_mknod
 /*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall
index 364f2b4a188bf74f362d27e5edf58fba8bff02dd..e95bf0727d971c45ffbb07fcba0b1090eab49c55 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.15 1998/05/12 22:38:29 ecd Exp $
+/* $Id: time.c,v 1.16 1998/09/05 17:25:28 jj Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -32,8 +32,8 @@
 #include <asm/ebus.h>
 
 struct mostek48t02 *mstk48t02_regs = 0;
-struct mostek48t08 *mstk48t08_regs = 0;
-struct mostek48t59 *mstk48t59_regs = 0;
+static struct mostek48t08 *mstk48t08_regs = 0;
+static struct mostek48t59 *mstk48t59_regs = 0;
 
 static int set_rtc_mmss(unsigned long);
 
@@ -133,7 +133,7 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon,
 }
 
 /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void kick_start_clock(void)
+static void __init kick_start_clock(void)
 {
        register struct mostek48t02 *regs = mstk48t02_regs;
        unsigned char sec;
@@ -182,7 +182,7 @@ static void kick_start_clock(void)
 }
 
 /* Return nonzero if the clock chip battery is low. */
-static int has_low_battery(void)
+static int __init has_low_battery(void)
 {
        register struct mostek48t02 *regs = mstk48t02_regs;
        unsigned char data1, data2;
@@ -197,7 +197,7 @@ static int has_low_battery(void)
 
 
 /* Probe for the real time clock chip. */
-__initfunc(static void set_system_time(void))
+static void __init set_system_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        struct mostek48t02 *mregs;
@@ -222,15 +222,18 @@ __initfunc(static void set_system_time(void))
        mregs->creg &= ~MSTK_CREG_READ;
 }
 
-__initfunc(void clock_probe(void))
+void __init clock_probe(void)
 {
        struct linux_prom_registers clk_reg[2];
        char model[128];
        int node, busnd = -1, err;
+       unsigned long flags;
 #ifdef CONFIG_PCI
        struct linux_ebus *ebus = 0;
 #endif
 
+       __save_and_cli(flags);
+
        if(central_bus != NULL) {
                busnd = central_bus->child->prom_node;
        }
@@ -349,6 +352,8 @@ __initfunc(void clock_probe(void))
                kick_start_clock();
 
        set_system_time();
+       
+       __restore_flags(flags);
 }
 
 #ifndef BCD_TO_BIN
@@ -359,19 +364,15 @@ __initfunc(void clock_probe(void))
 #define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
 #endif
 
-__initfunc(void time_init(void))
-{
-       /* clock_probe() is now done at end of sbus_init on sparc64
-        * so that both sbus and fhc bus information is probed and
-        * available.
-        */
-}
-
 extern void init_timers(void (*func)(int, void *, struct pt_regs *),
                        unsigned long *);
 
-__initfunc(void sun4u_start_timers(void))
+void __init time_init(void)
 {
+       /* clock_probe() is now done at end of [se]bus_init on sparc64
+        * so that sbus, fhc and ebus bus information is probed and
+        * available.
+        */
        unsigned long clock;
 
        init_timers(timer_interrupt, &clock);
index e1d6528417b94a2b89adf15feff6baae03b5b122..4c7b931da4c23f051c16d9d1f3ed9275be71573b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.51 1998/06/12 14:54:20 jj Exp $
+/* $Id: traps.c,v 1.54 1998/09/25 01:09:02 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -178,6 +178,79 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
 }
 #endif /* SYSCALL_TRACING */
 
+#if 0
+void rtrap_check(struct pt_regs *regs)
+{
+       register unsigned long pgd_phys asm("o1");
+       register unsigned long pgd_cache asm("o2");
+       register unsigned long g1_or_g3 asm("o3");
+       register unsigned long g2 asm("o4");
+       unsigned long ctx;
+
+#if 0
+       do {
+               unsigned long test;
+               __asm__ __volatile__("rdpr      %%pstate, %0"
+                                    : "=r" (test));
+               if((test & PSTATE_MG) != 0 ||
+                  (test & PSTATE_IE) == 0) {
+                       printk("rtrap_check: Bogus pstate[%016lx]\n", test);
+                       return;
+               }
+       } while(0);
+#endif
+
+       __asm__ __volatile__("
+       rdpr    %%pstate, %%o5
+       wrpr    %%o5, %4, %%pstate
+       or      %%g1, %%g3, %2
+       mov     %%g2, %3
+       mov     %%g7, %0
+       mov     %5, %1
+       ldxa    [%1] %6, %1
+       wrpr    %%o5, 0x0, %%pstate"
+       : "=r" (pgd_phys), "=r" (pgd_cache),
+         "=r" (g1_or_g3), "=r" (g2)
+       : "i" (PSTATE_IE | PSTATE_MG), "i" (TSB_REG),
+         "i" (ASI_DMMU)
+       : "o5");
+
+       ctx = spitfire_get_secondary_context();
+
+       if((pgd_phys != __pa(current->mm->pgd)) ||
+          ((pgd_cache != 0) &&
+           (pgd_cache != pgd_val(current->mm->pgd[0]))) ||
+          (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) ||
+#define KERN_HIGHBITS          ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
+#define KERN_LOWBITS           (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
+          (g2 != (KERN_HIGHBITS | KERN_LOWBITS)) ||
+#undef KERN_HIGHBITS
+#undef KERN_LOWBITS
+          ((ctx != (current->mm->context & 0x3ff)) ||
+           (ctx == 0) ||
+           (current->tss.ctx != ctx))) {
+               printk("SHIT[%s:%d]: "
+                      "(PP[%016lx] CACH[%016lx] CTX[%x] g1g3[%016lx] g2[%016lx]) ",
+                      current->comm, current->pid,
+                      pgd_phys, pgd_cache, ctx, g1_or_g3, g2);
+               printk("SHIT[%s:%d]: "
+                      "[PP[%016lx] CACH[%016lx] CTX[%x:%x]] PC[%016lx:%016lx]\n",
+                      current->comm, current->pid,
+                      __pa(current->mm->pgd),
+                      pgd_val(current->mm->pgd[0]),
+                      current->mm->context & 0x3ff,
+                      current->tss.ctx,
+                      regs->tpc, regs->tnpc);
+               show_regs(regs);
+#if 1
+               __sti();
+               while(1)
+                       barrier();
+#endif
+       }
+}
+#endif
+
 void bad_trap (struct pt_regs *regs, long lvl)
 {
        lock_kernel ();
@@ -205,7 +278,20 @@ void bad_trap_tl1 (struct pt_regs *regs, long lvl)
        unlock_kernel();
 }
 
-void data_access_exception (struct pt_regs *regs)
+void instruction_access_exception (struct pt_regs *regs,
+                                  unsigned long sfsr, unsigned long sfar)
+{
+       lock_kernel();
+#if 1
+       printk("instruction_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
+              sfsr, sfar);
+#endif
+       die_if_kernel("Iax", regs);
+       unlock_kernel();
+}
+
+void data_access_exception (struct pt_regs *regs,
+                           unsigned long sfsr, unsigned long sfar)
 {
        if (regs->tstate & TSTATE_PRIV) {
                /* Test if this comes from uaccess places. */
@@ -224,7 +310,17 @@ void data_access_exception (struct pt_regs *regs)
                        regs->u_regs[UREG_G2] = g2;
                        return;
                }
+               /* Shit... */
+#if 1
+               printk("data_access_exception: Shit SFSR[%016lx] SFAR[%016lx], going.\n",
+                      sfsr, sfar);
+#endif
+               die_if_kernel("Dax", regs);
        }
+#if 0
+       else
+               rtrap_check(regs);
+#endif
        lock_kernel();
        force_sig(SIGSEGV, current);
        unlock_kernel();
@@ -286,7 +382,7 @@ void do_dae(struct pt_regs *regs)
        unlock_kernel();
 }
 
-void instruction_access_exception (struct pt_regs *regs)
+void do_iae(struct pt_regs *regs)
 {
        clean_and_reenable_l1_caches();
 
@@ -295,13 +391,6 @@ void instruction_access_exception (struct pt_regs *regs)
        unlock_kernel();
 }
 
-void do_iae(struct pt_regs *regs)
-{
-       lock_kernel();
-       force_sig(SIGSEGV, current);
-       unlock_kernel();
-}
-
 void do_fpe_common(struct pt_regs *regs)
 {
        if(regs->tstate & TSTATE_PRIV) {
index 87f282fa144dcf895cc00fd664ba92e293487e8c..656d294546516ffb7247c57fb505f85902d77e0b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.25 1998/05/23 18:24:53 jj Exp $
+/* $Id: ttable.S,v 1.27 1998/09/25 01:09:10 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -11,7 +11,7 @@
 sparc64_ttable_tl0:
 tl0_resv000:   BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3)
 tl0_resv004:   BTRAP(0x4)  BTRAP(0x5) BTRAP(0x6) BTRAP(0x7)
-tl0_iax:       ACCESS_EXCEPTION_TRAP(instruction_access_exception)
+tl0_iax:       TRAP_NOSAVE(__do_instruction_access_exception)
 tl0_resv009:   BTRAP(0x9)
 tl0_iae:       TRAP(do_iae)
 tl0_resv00b:   BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf)
@@ -28,14 +28,14 @@ tl0_cwin:   CLEAN_WINDOW
 tl0_div0:      TRAP(do_div0)
 tl0_resv029:   BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e)
 tl0_resv02f:   BTRAP(0x2f)
-tl0_dax:       ACCESS_EXCEPTION_TRAP(data_access_exception)
+tl0_dax:       TRAP_NOSAVE(__do_data_access_exception)
 tl0_resv031:   BTRAP(0x31)
 tl0_dae:       TRAP(do_dae)
 tl0_resv033:   BTRAP(0x33)
 tl0_mna:       TRAP_NOSAVE(do_mna)
 tl0_lddfmna:   TRAP_NOSAVE(do_lddfmna)
 tl0_stdfmna:   TRAP_NOSAVE(do_stdfmna)
-tl0_privact:   TRAP(do_privact)
+tl0_privact:   TRAP_NOSAVE(__do_privact)
 tl0_resv038:   BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d)
 tl0_resv03e:   BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40)
 tl0_irq1:      TRAP_IRQ(handler_irq, 1)  TRAP_IRQ(handler_irq, 2)
@@ -160,7 +160,7 @@ tl0_resv1f0:        BTRAPS(0x1f0) BTRAPS(0x1f8)
 sparc64_ttable_tl1:
 tl1_resv000:   BOOT_KERNEL    BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3)
 tl1_resv004:   BTRAPTL1(0x4)  BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7)
-tl1_iax:       ACCESS_EXCEPTION_TRAPTL1(instruction_access_exception)
+tl1_iax:       TRAP_NOSAVE(__do_instruction_access_exception_tl1)
 tl1_resv009:   BTRAPTL1(0x9)
 tl1_iae:       TRAPTL1(do_iae_tl1)
 tl1_resv00b:   BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf)
@@ -178,7 +178,7 @@ tl1_cwin:   CLEAN_WINDOW
 tl1_div0:      TRAPTL1(do_div0_tl1)
 tl1_resv029:   BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c)
 tl1_resv02d:   BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f)
-tl1_dax:       ACCESS_EXCEPTION_TRAPTL1(data_access_exception)
+tl1_dax:       TRAP_NOSAVE(__do_data_access_exception_tl1)
 tl1_resv031:   BTRAPTL1(0x31)
 tl1_dae:       TRAPTL1(do_dae_tl1)
 tl1_resv033:   BTRAPTL1(0x33)
index 50de6cfd5dd85fdf465195a34a555ac336407a6b..40494cabaebf3392fe98e75e1fa2f3b0b16a88f7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unaligned.c,v 1.10 1998/06/19 13:00:32 jj Exp $
+/* $Id: unaligned.c,v 1.11 1998/09/22 03:24:52 davem Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
@@ -91,10 +91,13 @@ static inline int decode_signedness(unsigned int insn)
 }
 
 static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
-                                      unsigned int rd)
+                                      unsigned int rd, int from_kernel)
 {
        if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
-               flushw_user();
+               if(from_kernel != 0)
+                       __asm__ __volatile__("flushw");
+               else
+                       flushw_user();
        }
 }
 
@@ -149,12 +152,13 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs,
 {
        unsigned int rs1 = (insn >> 14) & 0x1f;
        unsigned int rs2 = insn & 0x1f;
+       int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
 
        if(insn & 0x2000) {
-               maybe_flush_windows(rs1, 0, rd);
+               maybe_flush_windows(rs1, 0, rd, from_kernel);
                return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
        } else {
-               maybe_flush_windows(rs1, rs2, rd);
+               maybe_flush_windows(rs1, rs2, rd, from_kernel);
                return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
        }
 }
@@ -430,12 +434,13 @@ int handle_popc(u32 insn, struct pt_regs *regs)
 {
        u64 value;
        int ret, i, rd = ((insn >> 25) & 0x1f);
+       int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
                                
        if (insn & 0x2000) {
-               maybe_flush_windows(0, 0, rd);
+               maybe_flush_windows(0, 0, rd, from_kernel);
                value = sign_extend_imm13(insn);
        } else {
-               maybe_flush_windows(0, insn & 0x1f, rd);
+               maybe_flush_windows(0, insn & 0x1f, rd, from_kernel);
                value = fetch_reg(insn & 0x1f, regs);
        }
        for (ret = 0, i = 0; i < 16; i++) {
@@ -583,7 +588,8 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
                pc = (u32)pc;
        if (get_user(insn, (u32 *)pc) != -EFAULT) {
                asi = sfsr >> 16;
-               if (asi > ASI_SNFL)
+               if ((asi > ASI_SNFL) ||
+                   (asi < ASI_P))
                        goto daex;
                if (get_user(first, (u32 *)sfar) ||
                     get_user(second, (u32 *)(sfar + 4))) {
@@ -637,7 +643,8 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr
                asi = sfsr >> 16;
                value = 0;
                flag = (freg < 32) ? FPRS_DL : FPRS_DU;
-               if (asi > ASI_SNFL)
+               if ((asi > ASI_SNFL) ||
+                   (asi < ASI_P))
                        goto daex;
                save_and_clear_fpu();
                if (current->tss.fpsaved[0] & flag)
index fd75011fd1e33ead85dcccb5c264b6dc206aecc2..5bf82db59cf4c3ed7c1183b2226e2873874da9d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.24 1998/06/12 14:54:19 jj Exp $
+/* $Id: winfixup.S,v 1.27 1998/09/25 01:09:14 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -27,7 +27,7 @@
         * These are layed out in a special way for cache reasons,
         * don't touch...
         */
-       .globl  winfix_trampoline, fill_fixup, spill_fixup
+       .globl  fill_fixup, spill_fixup
 fill_fixup:
        rdpr            %tstate, %g1
        andcc           %g1, TSTATE_PRIV, %g0
@@ -192,8 +192,8 @@ fill_fixup_mna:
        stxa            %g0, [%g1] ASI_DMMU             ! Back into the nucleus.
        flush           %g6                             ! Flush instruction buffers
        rdpr            %pstate, %l1                    ! Prepare to change globals.
-       mov             %g4, %o5                        ! Setup args for
-       mov             %g5, %o4                        ! final call to do_sparc64_fault.
+       mov             %g4, %o2                        ! Setup args for
+       mov             %g5, %o1                        ! final call to mem_address_unaligned.
        andn            %l1, PSTATE_MM, %l1             ! We want to be in RMO
 
        mov             %g6, %o7                        ! Stash away current.
@@ -261,8 +261,117 @@ window_mna_from_user_common:
        sethi           %hi(109f), %g7
        ba,pt           %xcc, etrap
 109:    or             %g7, %lo(109b), %g7
+       mov             %l4, %o2
+       mov             %l5, %o1
        call            mem_address_unaligned
         add            %sp, STACK_BIAS + REGWIN_SZ, %o0
        ba,pt           %xcc, rtrap
         clr            %l6
        
+       /* These are only needed for 64-bit mode processes which
+        * put their stack pointer into the VPTE area and there
+        * happens to be a VPTE tlb entry mapped there during
+        * a spill/fill trap to that stack frame.
+        */
+       .globl          winfix_dax, fill_fixup_dax, spill_fixup_dax
+winfix_dax:
+       andn            %g3, 0x7f, %g3
+       add             %g3, 0x74, %g3
+       wrpr            %g3, %tnpc
+       done
+fill_fixup_dax:
+       rdpr            %tstate, %g1
+       andcc           %g1, TSTATE_PRIV, %g0
+       be,pt           %xcc, window_dax_from_user_common
+        and            %g1, TSTATE_CWP, %g1
+
+       /* Please, see fill_fixup commentary about why we must preserve
+        * %l5 and %l6 to preserve absolute correct semantics.
+        */
+       rdpr            %wstate, %g2                    ! Grab user mode wstate.
+       wrpr            %g1, %cwp                       ! Get into the right window.
+       sll             %g2, 3, %g2                     ! NORMAL-->OTHER
+       wrpr            %g0, 0x0, %canrestore           ! Standard etrap stuff.
+
+       wrpr            %g2, 0x0, %wstate               ! This must be consistant.
+       wrpr            %g0, 0x0, %otherwin             ! We know this.
+       mov             PRIMARY_CONTEXT, %g1            ! Change contexts...
+       stxa            %g0, [%g1] ASI_DMMU             ! Back into the nucleus.
+       flush           %g6                             ! Flush instruction buffers
+       rdpr            %pstate, %l1                    ! Prepare to change globals.
+       mov             %g4, %o1                        ! Setup args for
+       mov             %g5, %o2                        ! final call to data_access_exception.
+       andn            %l1, PSTATE_MM, %l1             ! We want to be in RMO
+
+       mov             %g6, %o7                        ! Stash away current.
+       wrpr            %g0, 0x0, %tl                   ! Out of trap levels.
+       wrpr            %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate
+       sethi           %uhi(PAGE_OFFSET), %g4          ! Set page_offset global reg.
+       mov             %o7, %g6                        ! Get current back.
+       sllx            %g4, 32, %g4                    ! Finish it.
+       call            data_access_exception
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+
+       b,pt            %xcc, rtrap
+        nop                                            ! yes, the nop is correct
+spill_fixup_dax:
+       lduh            [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1
+       andcc           %g1, SPARC_FLAG_32BIT, %g0
+       lduh            [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1
+       sll             %g1, 3, %g3
+       add             %g6, %g3, %g3
+       stx             %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+
+       sll             %g1, 7, %g3
+       bne,pt          %xcc, 1f
+        add            %g6, %g3, %g3
+       stx             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+       stx             %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+       stx             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+       stx             %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+       stx             %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+
+       stx             %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+       stx             %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+       stx             %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+       stx             %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+       stx             %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+       stx             %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+       stx             %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+       stx             %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+
+       stx             %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+       stx             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+       stx             %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+       b,pt            %xcc, 2f
+        add            %g1, 1, %g1
+1:     std             %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+       std             %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+       std             %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+
+       std             %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+       std             %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+       std             %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+       std             %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+       std             %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+       add             %g1, 1, %g1
+2:     sth             %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved]
+       rdpr            %tstate, %g1
+
+       andcc           %g1, TSTATE_PRIV, %g0
+       saved
+       be,pn           %xcc, window_dax_from_user_common
+        and            %g1, TSTATE_CWP, %g1
+       retry
+window_dax_from_user_common:
+       wrpr            %g1, %cwp
+       sethi           %hi(109f), %g7
+       ba,pt           %xcc, etrap
+109:    or             %g7, %lo(109b), %g7
+       mov             %l4, %o1
+       mov             %l5, %o2
+       call            data_access_exception
+        add            %sp, STACK_BIAS + REGWIN_SZ, %o0
+       ba,pt           %xcc, rtrap
+        clr            %l6
+       
index 2e22ec2d89bdc02e63bf49fcb75a0a942599dad2..ea732b367fa5df1ee981ec21acd1990a754742a3 100644 (file)
@@ -180,7 +180,7 @@ ccfold:     sllx            %sum, 32, %o0           ! IEU0  Group
        bcs,a,pn        %xcc, 1f                ! CTI
         add            %o0, 1, %o0             ! IEU1  4 clocks (mispredict)
 1:     retl                                    ! CTI   Group brk forced
-        sllx           %g4, 32,%g4             ! IEU0  Group
+        sllx           %g4, 32, %g4            ! IEU0  Group
 
 ccslow:        mov     0, %g5
        brlez,pn %len, 4f
@@ -268,8 +268,9 @@ cpc_handler:
        sub     %g0, EFAULT, %g2
        brnz,a,pt %g1, 1f
         st     %g2, [%g1]
-1:     retl
-        nop
+1:     sethi   %uhi(PAGE_OFFSET), %g4
+       retl
+        sllx   %g4, 32, %g4
 
        .section __ex_table
        .align  4
index 5f2ec6bb4346bac191d8f252dcb0de0c619215c5..61207dd91ac316b7a981862c45943d13858bbc2f 100644 (file)
@@ -8,9 +8,9 @@
 #define LO_MAGIC 0x01010101
 #define HI_MAGIC 0x80808080
 
-       .align 4
-       .global strlen
-strlen:
+       .align  32
+       .global __strlen
+__strlen:
        mov     %o0, %o1
        andcc   %o0, 3, %g0
        be,pt   %icc, 9f
index 6dfaca524f9b65c527ed6b3c27c0af889d2051c4..a0d1c8144d67728ed54cbd615813bfa421451add 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: asyncd.c,v 1.4 1998/05/24 02:53:58 davem Exp $
+/*  $Id: asyncd.c,v 1.5 1998/09/13 04:30:33 davem Exp $
  *  The asyncd kernel daemon. This handles paging on behalf of 
  *  processes that receive page faults due to remote (async) memory
  *  accesses. 
index 21389e397351cd90b832b6fd31fde9005f1a4b64..851a8566bad8415035e299b67ea6aa47393d0c77 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.21 1998/03/25 10:43:20 jj Exp $
+/* $Id: fault.c,v 1.24 1998/09/22 03:27:33 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -100,49 +100,38 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk,
               (unsigned long) tsk->mm->context);
        printk(KERN_ALERT "tsk->mm->pgd = %016lx\n",
               (unsigned long) tsk->mm->pgd);
+       lock_kernel();
        die_if_kernel("Oops", regs);
-}
-
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
-                           unsigned long address)
-{
-       unsigned long g2;
-       int i;
-       unsigned insn;
-       struct pt_regs regs;
-       
-       i = search_exception_table (ret_pc, &g2);
-       switch (i) {
-       /* load & store will be handled by fixup */
-       case 3: return 3;
-       /* store will be handled by fixup, load will bump out */
-       /* for _to_ macros */
-       case 1: insn = *(unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
-       /* load will be handled by fixup, store will bump out */
-       /* for _from_ macros */
-       case 2: insn = *(unsigned *)pc; 
-               if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2; 
-               break; 
-       default: break;
-       }
-       memset (&regs, 0, sizeof (regs));
-       regs.tpc = pc;
-       regs.tnpc = pc + 4;
-       /* FIXME: Should set up regs->tstate? */
-       unhandled_fault (address, current, &regs);
-       /* Not reached */
-       return 0;
+       unlock_kernel();
 }
 
 /* #define DEBUG_EXCEPTIONS */
+/* #define DEBUG_LOCKUPS */
 
 asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, int write)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
+#ifdef DEBUG_LOCKUPS
+       static unsigned long lastaddr, lastpc;
+       static int lastwrite, lockcnt;
+#endif
 
-       lock_kernel();
        down(&mm->mmap_sem);
+#ifdef DEBUG_LOCKUPS
+       if (regs->tpc == lastpc && address == lastaddr && write == lastwrite) {
+               lockcnt++;
+               if (lockcnt == 100000) {
+                       printk("do_sparc64_fault: possible fault loop for %016lx %s\n", address, write ? "write" : "read");
+                       show_regs(regs);
+               }
+       } else {
+               lastpc = regs->tpc;
+               lastaddr = address;
+               lastwrite = write;
+               lockcnt = 0;
+       }
+#endif
        vma = find_vma(mm, address);
        if(!vma)
                goto bad_area;
@@ -167,7 +156,7 @@ good_area:
        }
        handle_mm_fault(current, vma, address, write);
        up(&mm->mmap_sem);
-       goto out;
+       return;
        /*
         * Something tried to access memory that isn't in our memory map..
         * Fix it, but check if it's kernel or user first..
@@ -204,16 +193,14 @@ bad_area:
                                regs->tpc = fixup;
                                regs->tnpc = regs->tpc + 4;
                                regs->u_regs[UREG_G2] = g2;
-                               goto out;
+                               return;
                        }
                } else {
                        current->tss.sig_address = address;
                        current->tss.sig_desc = SUBSIG_NOMAPPING;
                        force_sig(SIGSEGV, current);
-                       goto out;
+                       return;
                }
                unhandled_fault (address, current, regs);
        }
-out:
-       unlock_kernel();
 }
index 035b023fc064fa7f0b74b351636ca9f0383a58e0..27908c2141da467eced28bb29deca67bbbe78c33 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.93 1998/08/04 20:49:25 davem Exp $
+/*  $Id: init.c,v 1.98 1998/09/28 06:18:39 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -37,7 +37,8 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
 /* Ugly, but necessary... -DaveM */
 unsigned long phys_base;
 
-unsigned long tlb_context_cache = CTX_FIRST_VERSION;
+/* get_new_mmu_context() uses "cache + 1".  */
+unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1;
 
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
@@ -565,9 +566,9 @@ static void __flush_nucleus_vptes(void)
        unsigned long prom_reserved_base = 0xfffffffc00000000UL;
        int i;
 
-       __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
-                            "wrpr      %0, %1, %%pstate\n\t"
-                            "flushw"
+       __asm__ __volatile__("flushw\n\t"
+                            "rdpr      %%pstate, %0\n\t"
+                            "wrpr      %0, %1, %%pstate"
                             : "=r" (pstate)
                             : "i" (PSTATE_IE));
 
@@ -720,6 +721,18 @@ void prom_reload_locked(void)
        membar("#Sync");
 }
 
+void __flush_dcache_range(unsigned long start, unsigned long end)
+{
+       unsigned long va;
+       int n = 0;
+
+       for (va = start; va < end; va += 32) {
+               spitfire_put_dcache_tag(va & 0x3fe0, 0x0);
+               if (++n >= 512)
+                       break;
+       }
+}
+
 void __flush_cache_all(void)
 {
        unsigned long va;
@@ -735,9 +748,9 @@ void __flush_tlb_all(void)
        unsigned long pstate;
        int i;
 
-       __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
-                            "wrpr      %0, %1, %%pstate\n\t"
-                            "flushw"
+       __asm__ __volatile__("flushw\n\t"
+                            "rdpr      %%pstate, %0\n\t"
+                            "wrpr      %0, %1, %%pstate"
                             : "=r" (pstate)
                             : "i" (PSTATE_IE));
        for(i = 0; i < 64; i++) {
@@ -913,7 +926,6 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr)
        pte_clear(ptep);
 }
 
-#ifdef NOTUSED
 void sparc_ultra_dump_itlb(void)
 {
         int slot;
@@ -933,17 +945,17 @@ void sparc_ultra_dump_dtlb(void)
 {
         int slot;
 
-        prom_printf ("Contents of dtlb: ");
+        printk ("Contents of dtlb: ");
        for (slot = 0; slot < 14; slot++) printk ("    ");
-       prom_printf ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0));
+       printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0),
+               spitfire_get_dtlb_data(0));
         for (slot = 1; slot < 64; slot+=3) {
-               prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
+               printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", 
                        slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot),
                        slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1),
                        slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2));
         }
 }
-#endif
 
 /* paging_init() sets up the page tables */
 
index 683f4bcb1719d39169e89913c954ce3819e4c4b1..fcf458fdc8552be9a7aac5f1afa3ba7a0130fbfd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.24 1998/05/22 11:02:56 davem Exp $
+/* $Id: ultra.S,v 1.27 1998/09/28 06:18:42 davem Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -56,6 +56,7 @@ __flush_tlb_range_page_by_page:
 __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
 /*IC5*/        rdpr            %pstate, %g1
        wrpr            %g1, PSTATE_IE, %pstate
+       mov             TLB_TAG_ACCESS, %g3
        mov             (62 << 3), %g2
 1:     ldxa            [%g2] ASI_ITLB_TAG_READ, %o4
        and             %o4, 0x3ff, %o5
@@ -80,10 +81,12 @@ __flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */
         sub            %g2, (1 << 3), %g2
 /*IC8*/        retl
         wrpr           %g1, 0x0, %pstate
-4:     stxa            %g0, [%g2] ASI_ITLB_DATA_ACCESS
+4:     stxa            %g0, [%g3] ASI_IMMU
+       stxa            %g0, [%g2] ASI_ITLB_DATA_ACCESS
        ba,pt           %xcc, 2b
         flush          %g6
-5:     stxa            %g0, [%g2] ASI_DTLB_DATA_ACCESS
+5:     stxa            %g0, [%g3] ASI_DMMU
+       stxa            %g0, [%g2] ASI_DTLB_DATA_ACCESS
        ba,pt           %xcc, 3b
         flush          %g6
 __flush_tlb_mm_slow:
@@ -122,6 +125,35 @@ __flush_tlb_range_pbp_slow:
        retl
         wrpr           %g1, 0x0, %pstate
 
+       /* Unfortunately, it is necessary. */
+       .globl          flush_page_to_ram
+flush_page_to_ram:     /* %o0 = page */
+       rdpr            %pstate, %g5
+       wrpr            %g5, PSTATE_IE, %pstate
+       sethi           %hi(dcache_aliases_found), %g1
+       ldx             [%g1 + %lo(dcache_aliases_found)], %g2
+       sub             %o0, %g4, %o0           ! Get phys_page
+       clr             %o2                     ! This dcache area begin
+       sethi           %hi(1<<14), %o1         ! This dcache area end
+1:     ldxa            [%o2] ASI_DCACHE_TAG, %o3
+       andcc           %o3, 0x3, %g0           ! Valid bits set?
+       be,pn           %xcc, 2f                ! Nope, skip this one
+        andn           %o3, 0x3, %o3           ! Mask out valid bits
+       sllx            %o3, (13 - 2), %o3      ! Shift into physaddr
+       cmp             %o3, %o0                ! Match?
+       bne,pt          %xcc, 2f                ! Nope, skip to next
+        nop
+       stxa            %g0, [%o2] ASI_DCACHE_TAG
+       membar          #Sync
+       add             %g2, 1, %g2             ! Increment alias counter
+2:     add             %o2, (1<<5), %o2        ! 32-bytes per full line
+       cmp             %o2, %o1
+       bne,pt          %xcc, 1b
+        nop
+       stx             %g2, [%g1 + %lo(dcache_aliases_found)]
+       retl
+        wrpr           %g5, 0x0, %pstate
+
 #ifdef __SMP__
        /* These are all called by the slaves of a cross call, at
         * trap level 1, with interrupts fully disabled.
index fa716f595e741c3e0d82756d7a06d6d1125632b0..1cb3c90188e1bdbcbabee25a620369f10d4e96d0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: conv.h,v 1.3 1998/03/26 08:46:13 jj Exp $
+/* $Id: conv.h,v 1.4 1998/08/15 20:42:51 davem Exp $
  * conv.h: Utility macros for Solaris emulation
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
 
 #include <asm/unistd.h>
 
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to
- * unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to
- * type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings.
- */
-#define A(x) ((unsigned long)x)
+/* Use this to get at 32-bit user passed pointers. */
+#define A(__x)                         \
+({     unsigned long __ret;            \
+       __asm__ ("srl   %0, 0, %0"      \
+                : "=r" (__ret)         \
+                : "0" (__x));          \
+       __ret;                          \
+})
 
 extern unsigned sys_call_table[];
 extern unsigned sys_call_table32[];
index dce7927d863436e32af2354c50f1d58039526b67..dbdbcd1a2364a8ea7e5afa0181efa97c756e7e8e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: socksys.c,v 1.7 1998/03/29 10:11:04 davem Exp $
+/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $
  * socksys.c: /dev/inet/ stuff for Solaris emulation.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
index d065606c7ea605ed5789074706e16bac5fd6ede7..62319220be50f750e1364f1ca0f815024ea951f8 100644 (file)
@@ -74,8 +74,8 @@ static int ns87415_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
                case ide_dma_end: /* returns 1 on error, 0 otherwise */
                        drive->waiting_for_dma = 0;
                        dma_stat = inb(hwif->dma_base+2);
-                       outb(7, hwif->dma_base);                /* from errata: stop DMA, clear INTR & ERROR */
-                       outb(dma_stat|6, hwif->dma_base+2);     /* clear the INTR & ERROR bits */
+                       outb(inb(hwif->dma_base)&~1, hwif->dma_base);   /* stop DMA */
+                       outb(inb(hwif->dma_base)|6, hwif->dma_base);    /* from ERRATA: clear the INTR & ERROR bits */
                        return (dma_stat & 7) != 4;             /* verify good DMA status */
                case ide_dma_write:
                case ide_dma_read:
index ac9462c9a355be29063fa386ac255aa968ad13e9..af39d573c983c57e5c26324068f5dd85b280c856 100644 (file)
@@ -29,12 +29,14 @@ LX_OBJS += console.o selection.o
 endif
 
 ifeq ($(CONFIG_SERIAL),y)
-  ifndef CONFIG_SUN_SERIAL
+  ifeq ($(CONFIG_SUN_SERIAL),)
   LX_OBJS += serial.o
   endif
 else
   ifeq ($(CONFIG_SERIAL),m)
-  MX_OBJS += serial.o
+    ifeq ($(CONFIG_SUN_SERIAL),)
+    MX_OBJS += serial.o
+    endif
   endif
 endif
 
index b579e6d6e0a46d7592756e393c86b6e92f1aef31..bd5c3ee7c3b06d24ad6a5bf7ddf8c99cdf9030c0 100644 (file)
@@ -130,7 +130,9 @@ static struct termios *console_termios[MAX_NR_CONSOLES];
 static struct termios *console_termios_locked[MAX_NR_CONSOLES];
 struct vc vc_cons [MAX_NR_CONSOLES];
 
+#ifndef VT_SINGLE_DRIVER
 static struct consw *con_driver_map[MAX_NR_CONSOLES];
+#endif
 
 static int con_open(struct tty_struct *, struct file *);
 static void vc_init(unsigned int console, unsigned int rows,
@@ -192,6 +194,12 @@ static int scrollback_delta = 0;
 #define IS_FG (currcons == fg_console)
 #define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
 
+#ifdef VT_BUF_VRAM_ONLY
+#define DO_UPDATE 0
+#else
+#define DO_UPDATE IS_VISIBLE
+#endif
+
 static inline unsigned short *screenpos(int currcons, int offset, int viewed)
 {
        unsigned short *p = (unsigned short *)(visible_origin + offset);
@@ -240,6 +248,7 @@ scrdown(int currcons, unsigned int t, unsigned int b, int nr)
 
 static void do_update_region(int currcons, unsigned long start, int count)
 {
+#ifndef VT_BUF_VRAM_ONLY
        unsigned int xx, yy, offset;
        u16 *p;
 
@@ -276,11 +285,12 @@ static void do_update_region(int currcons, unsigned long start, int count)
                xx = 0;
                yy++;
        }
+#endif
 }
 
 void update_region(int currcons, unsigned long start, int count)
 {
-       if (IS_VISIBLE) {
+       if (DO_UPDATE) {
                hide_cursor(currcons);
                do_update_region(currcons, start, count);
                set_cursor(currcons);
@@ -294,6 +304,7 @@ static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _unde
        if (sw->con_build_attr)
                return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
 
+#ifndef VT_BUF_VRAM_ONLY
 /*
  * ++roman: I completely changed the attribute format for monochrome
  * mode (!can_do_color). The formerly used MDA (monochrome display
@@ -325,6 +336,9 @@ static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _unde
                a <<= 1;
        return a;
        }
+#else
+       return 0;
+#endif
 }
 
 static void update_attr(int currcons)
@@ -343,6 +357,7 @@ void invert_screen(int currcons, int offset, int count, int viewed)
        p = screenpos(currcons, offset, viewed);
        if (sw->con_invert_region)
                sw->con_invert_region(vc_cons[currcons].d, p, count);
+#ifndef VT_BUF_VRAM_ONLY
        else {
                u16 *q = p;
                int cnt = count;
@@ -363,7 +378,8 @@ void invert_screen(int currcons, int offset, int count, int viewed)
                        }
                }
        }
-       if (IS_VISIBLE)
+#endif
+       if (DO_UPDATE)
                do_update_region(currcons, (unsigned long) p, count);
 }
 
@@ -376,7 +392,7 @@ void complement_pos(int currcons, int offset)
 
        if (p) {
                scr_writew(old, p);
-               if (IS_VISIBLE)
+               if (DO_UPDATE)
                        sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
        }
        if (offset == -1)
@@ -387,7 +403,7 @@ void complement_pos(int currcons, int offset)
                old = scr_readw(p);
                new = old ^ complement_mask;
                scr_writew(new, p);
-               if (IS_VISIBLE) {
+               if (DO_UPDATE) {
                        oldx = (offset >> 1) % video_num_columns;
                        oldy = (offset >> 1) / video_num_columns;
                        sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
@@ -404,7 +420,7 @@ static void insert_char(int currcons, unsigned int nr)
                scr_writew(scr_readw(p), p + nr);
        scr_memsetw(q, video_erase_char, nr*2);
        need_wrap = 0;
-       if (IS_VISIBLE) {
+       if (DO_UPDATE) {
                unsigned short oldattr = attr;
                sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
                              video_num_columns-x-nr);
@@ -427,7 +443,7 @@ static void delete_char(int currcons, unsigned int nr)
        }
        scr_memsetw(p, video_erase_char, nr*2);
        need_wrap = 0;
-       if (IS_VISIBLE) {
+       if (DO_UPDATE) {
                unsigned short oldattr = attr;
                sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
                              video_num_columns-x-nr);
@@ -455,7 +471,7 @@ static void add_softcursor(int currcons)
        if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
        if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
        scr_writew(i, (u16 *) pos);
-       if (IS_VISIBLE)
+       if (DO_UPDATE)
                sw->con_putc(vc_cons[currcons].d, i, y, x);
 }
 
@@ -465,7 +481,7 @@ static void hide_cursor(int currcons)
                clear_selection();
        if (softcursor_original != -1) {
                scr_writew(softcursor_original,(u16 *) pos);
-               if (IS_VISIBLE)
+               if (DO_UPDATE)
                        sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
                softcursor_original = -1;
        }
@@ -572,8 +588,10 @@ static void visual_init(int currcons, int init)
 {
     /* ++Geert: sw->con_init determines console size */
     sw = conswitchp;
+#ifndef VT_SINGLE_DRIVER
     if (con_driver_map[currcons])
        sw = con_driver_map[currcons];
+#endif
     cons_num = currcons;
     display_fg = &master_display_fg;
     vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
@@ -887,7 +905,7 @@ static void csi_J(int currcons, int vpar)
                case 0: /* erase from cursor to end of display */
                        count = (scr_end-pos)>>1;
                        start = (unsigned short *) pos;
-                       if (IS_VISIBLE) {
+                       if (DO_UPDATE) {
                                /* do in two stages */
                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
                                              video_num_columns-x);
@@ -899,7 +917,7 @@ static void csi_J(int currcons, int vpar)
                case 1: /* erase from start to cursor */
                        count = ((pos-origin)>>1)+1;
                        start = (unsigned short *) origin;
-                       if (IS_VISIBLE) {
+                       if (DO_UPDATE) {
                                /* do in two stages */
                                sw->con_clear(vc_cons[currcons].d, 0, 0, y,
                                              video_num_columns);
@@ -910,7 +928,7 @@ static void csi_J(int currcons, int vpar)
                case 2: /* erase whole display */
                        count = video_num_columns * video_num_lines;
                        start = (unsigned short *) origin;
-                       if (IS_VISIBLE)
+                       if (DO_UPDATE)
                                sw->con_clear(vc_cons[currcons].d, 0, 0,
                                              video_num_lines,
                                              video_num_columns);
@@ -931,21 +949,21 @@ static void csi_K(int currcons, int vpar)
                case 0: /* erase from cursor to end of line */
                        count = video_num_columns-x;
                        start = (unsigned short *) pos;
-                       if (IS_VISIBLE)
+                       if (DO_UPDATE)
                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
                                              video_num_columns-x);
                        break;
                case 1: /* erase from start of line to cursor */
                        start = (unsigned short *) (pos - (x<<1));
                        count = x+1;
-                       if (IS_VISIBLE)
+                       if (DO_UPDATE)
                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
                                              x + 1);
                        break;
                case 2: /* erase whole line */
                        start = (unsigned short *) (pos - (x<<1));
                        count = video_num_columns;
-                       if (IS_VISIBLE)
+                       if (DO_UPDATE)
                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
                                              video_num_columns);
                        break;
@@ -965,7 +983,7 @@ static void csi_X(int currcons, int vpar) /* erase the following vpar positions
        count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
 
        scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
-       if (IS_VISIBLE)
+       if (DO_UPDATE)
                sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
        need_wrap = 0;
 }
@@ -1743,10 +1761,14 @@ static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
 static int do_con_write(struct tty_struct * tty, int from_user,
                        const unsigned char *buf, int count)
 {
+#ifdef VT_BUF_VRAM_ONLY
+#define FLUSH do { } while(0);
+#else
 #define FLUSH if (draw_x >= 0) { \
        sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
        draw_x = -1; \
        }
+#endif
 
        int c, tc, ok, n = 0, draw_x = -1;
        unsigned int currcons;
@@ -1874,7 +1896,7 @@ static int do_con_write(struct tty_struct * tty, int from_user,
                                     ((attr & ~himask) << 8) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
                                     (attr << 8) + tc,
                                   (u16 *) pos);
-                       if (IS_VISIBLE && draw_x < 0) {
+                       if (DO_UPDATE && draw_x < 0) {
                                draw_x = x;
                                draw_from = pos;
                        }
@@ -1958,6 +1980,9 @@ void vt_console_print(struct console *co, const char * b, unsigned count)
                goto quit;
        }
 
+       if (vcmode != KD_TEXT)
+               return;
+
        /* undraw cursor first */
        if (IS_FG)
                hide_cursor(currcons);
@@ -2329,6 +2354,8 @@ __initfunc(unsigned long con_init(unsigned long kmem_start))
        return kmem_start;
 }
 
+#ifndef VT_SINGLE_DRIVER
+
 static void clear_buffer_attributes(int currcons)
 {
        unsigned short *p = (unsigned short *) origin;
@@ -2403,6 +2430,8 @@ void give_up_console(struct consw *csw)
                        con_driver_map[i] = NULL;
 }
 
+#endif
+
 /*
  *     Screen blanking
  */
@@ -2766,5 +2795,7 @@ EXPORT_SYMBOL(video_font_height);
 EXPORT_SYMBOL(video_scan_lines);
 EXPORT_SYMBOL(vc_resize);
 
+#ifndef VT_SINGLE_DRIVER
 EXPORT_SYMBOL(take_over_console);
 EXPORT_SYMBOL(give_up_console);
+#endif
index 5f4ee8b3da92e9ec8d2f925c0dc12d09f7509d74..ba5f82539548ef14d590c580f78fc38f9874b2b0 100644 (file)
@@ -44,6 +44,12 @@ extern int videodev_init(void);
 #ifdef CONFIG_FB
 extern void fbmem_init(void);
 #endif
+#ifdef CONFIG_PROM_CONSOLE
+extern void prom_con_init(void);
+#endif
+#ifdef CONFIG_MDA_CONSOLE
+extern void mda_console_init(void);
+#endif
 
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
                            const char * buf, size_t count, loff_t *ppos)
@@ -544,6 +550,12 @@ __initfunc(int chr_dev_init(void))
        rand_initialize();
 #if defined (CONFIG_FB)
        fbmem_init();
+#endif
+#if defined (CONFIG_PROM_CONSOLE)
+       prom_con_init();
+#endif
+#if defined (CONFIG_MDA_CONSOLE)
+       mda_console_init();
 #endif
        tty_init();
 #ifdef CONFIG_PRINTER
index 4418fb28da9a5c3bc027e3fe0f839cb0c56042ba..52d4e9c9ba90bf6506a89c2712ab19a7675c7d5d 100644 (file)
@@ -178,6 +178,7 @@ struct ei_device {
   /* The new statistics table. */
   struct net_device_stats stat;
   unsigned char *reg_offset;    /* Register mapping table */
+  unsigned long priv;          /* Private field to store bus IDs etc. */
 };
 
 /* The maximum number of 8390 interrupt service routines called per IRQ. */
@@ -207,11 +208,11 @@ struct ei_device {
 #define E8390_PAGE1    0x40    /* using the two high-order bits */
 #define E8390_PAGE2    0x80    /* Page 3 is invalid. */
 
-
-#ifndef CONFIG_MAC
-#define EI_SHIFT(x)    (x)
-#else
+#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
+    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE)
 #define EI_SHIFT(x)    (ei_local->reg_offset[x])
+#else
+#define EI_SHIFT(x)    (x)
 #endif
 
 #define E8390_CMD      EI_SHIFT(0x00)  /* The command register (for all pages) */
index b51140858776eed00cc4486cf4337eab807a7b9d..db75330ac4015b8da05bba382cb6d549791c0b29 100644 (file)
@@ -37,6 +37,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
   fi
   if [ "$CONFIG_ZORRO" = "y" ]; then
     tristate 'Ariadne support' CONFIG_ARIADNE
+    tristate 'Ariadne II support' CONFIG_ARIADNE2
     tristate 'A2065 support' CONFIG_A2065
     tristate 'Hydra support' CONFIG_HYDRA
   fi
index 256b374ad455084fc0753db42a20026d31a0ce9c..b99ac4668d22f2a6a1d02d097a6a0fc9538ef87a 100644 (file)
@@ -752,6 +752,16 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_ARIADNE2),y)
+L_OBJS += ariadne2.o
+CONFIG_8390_BUILTIN = y
+else
+  ifeq ($(CONFIG_ARIADNE2),m)
+  M_OBJS += ariadne2.o
+  CONFIG_8390_MODULE = y
+  endif
+endif
+
 # If anything built-in uses the 8390, then build it into the kernel also.
 # If not, but a module uses it, build as a module.
 ifdef CONFIG_8390_BUILTIN
index faaa7a843c1e65debf70e5405020f9d13853a711..479830e9743c84dec607055a9b344fbb5fe14e28 100644 (file)
@@ -90,6 +90,7 @@ extern int sgiseeq_probe(struct device *);
 extern int atarilance_probe(struct device *);
 extern int a2065_probe(struct device *);
 extern int ariadne_probe(struct device *);
+extern int ariadne2_probe(struct device *);
 extern int hydra_probe(struct device *);
 extern int apne_probe(struct device *);
 extern int bionet_probe(struct device *);
@@ -364,6 +365,9 @@ struct devprobe m68k_probes[] __initdata = {
 #ifdef CONFIG_ARIADNE          /* Village Tronic Ariadne Ethernet Board */
        {ariadne_probe, 0},
 #endif
+#ifdef CONFIG_ARIADNE2         /* Village Tronic Ariadne II Ethernet Board */
+       {ariadne2_probe, 0},
+#endif
 #ifdef CONFIG_HYDRA            /* Hydra Systems Amiganet Ethernet board */
        {hydra_probe, 0},
 #endif
index c9d2d5eca3f6bb42e44111e78a5027ce68b261ec..898369fb37c550b9c97e20ce6bed9ec536e83cbf 100644 (file)
@@ -570,6 +570,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        int entry, skblen, len;
        int status = 0;
        static int outs;
+       unsigned long flags;
 
        /* Transmitter timeout, serious problems */
        if (dev->tbusy) {
@@ -586,18 +587,20 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
        }
 
        /* Block a timer-based transmit from overlapping. */
-#ifdef OLD_METHOD
-       dev->tbusy = 1;
-#else
        if (test_and_set_bit (0, (void *) &dev->tbusy) != 0) {
                printk ("Transmitter access conflict.\n");
                return -1;
        }
-#endif
+
        skblen = skb->len;
 
-       if (!TX_BUFFS_AVAIL)
+       save_flags(flags);
+       cli();
+
+       if (!TX_BUFFS_AVAIL){
+               restore_flags(flags);
                return -1;
+       }
 
 #ifdef DEBUG_DRIVER
        /* dump the packet */
@@ -634,6 +637,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct device *dev)
     
        if (TX_BUFFS_AVAIL)
                dev->tbusy = 0;
+       restore_flags(flags);
 
        return status;
 }
index 005cc3195d76bb085cc68ff61155170351331306..d3578f5daa712b2d944d731f50fad507943a9d0f 100644 (file)
@@ -577,14 +577,14 @@ int init_module(void)
 
 void cleanup_module(void)
 {
-       unregister_netdev(&apne_dev);
-
        pcmcia_disable_irq();
 
        free_irq(IRQ_AMIGA_PORTS, &apne_dev);
 
        pcmcia_reset();
 
+       unregister_netdev(&apne_dev);
+
        unlock_8390_module();
 }
 
diff --git a/drivers/net/ariadne2.c b/drivers/net/ariadne2.c
new file mode 100644 (file)
index 0000000..5e6fb21
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ *  Amiga Linux/m68k Ariadne II Ethernet Driver
+ *
+ *  (C) Copyright 1998 by some Elitist 680x0 Users(TM)
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This program is based on all the other NE2000 drivers for Linux
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of the Linux
+ *  distribution for more details.
+ *
+ *  ---------------------------------------------------------------------------
+ *
+ *  The Ariadne II is a Zorro-II board made by Village Tronic. It contains a
+ *  Realtek RTL8019AS Ethernet Controller.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/zorro.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+
+#include "8390.h"
+
+
+#define ARIADNE2_BASE          0x0300
+#define ARIADNE2_BOOTROM       0xc000
+
+
+#define NE_BASE                (dev->base_addr)
+#define NE_CMD         (0x00*2)
+#define NE_DATAPORT    (0x10*2)        /* NatSemi-defined port window offset. */
+#define NE_RESET       (0x1f*2)        /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT   (0x20*2)
+
+#define NE_EN0_ISR     (0x07*2)
+#define NE_EN0_DCFG    (0x0e*2)
+
+#define NE_EN0_RSARLO  (0x08*2)
+#define NE_EN0_RSARHI  (0x09*2)
+#define NE_EN0_RCNTLO  (0x0a*2)
+#define NE_EN0_RXCR    (0x0c*2)
+#define NE_EN0_TXCR    (0x0d*2)
+#define NE_EN0_RCNTHI  (0x0b*2)
+#define NE_EN0_IMR     (0x0f*2)
+
+#define NESM_START_PG  0x40    /* First page of TX buffer */
+#define NESM_STOP_PG   0x80    /* Last page +1 of RX ring */
+
+
+#define WORDSWAP(a)    ((((a)>>8)&0xff) | ((a)<<8))
+
+int ariadne2_probe(struct device *dev);
+static int ariadne2_init(struct device *dev, unsigned int key,
+                        unsigned long board);
+
+static int ariadne2_open(struct device *dev);
+static int ariadne2_close(struct device *dev);
+
+static void ariadne2_reset_8390(struct device *dev);
+static void ariadne2_get_8390_hdr(struct device *dev,
+                                 struct e8390_pkt_hdr *hdr, int ring_page);
+static void ariadne2_block_input(struct device *dev, int count,
+                                struct sk_buff *skb, int ring_offset);
+static void ariadne2_block_output(struct device *dev, const int count,
+                                 const unsigned char *buf,
+                                 const int start_page);
+
+
+__initfunc(int ariadne2_probe(struct device *dev))
+{
+    unsigned int key;
+    const struct ConfigDev *cd;
+    u_long board;
+    int err;
+
+    if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, 0, 0))) {
+       cd = zorro_get_board(key);
+       if ((board = (u_long)cd->cd_BoardAddr)) {
+           if ((err = ariadne2_init(dev, key, ZTWO_VADDR(board))))
+               return err;
+           zorro_config_board(key, 0);
+           return 0;
+       }
+    }
+    return ENODEV;
+}
+
+__initfunc(static int ariadne2_init(struct device *dev, unsigned int key,
+                                   unsigned long board))
+{
+    int i;
+    unsigned char SA_prom[32];
+    const char *name = NULL;
+    int start_page, stop_page;
+    static int ariadne2_offsets[16] = {
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+       0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+    };
+    int ioaddr = board+ARIADNE2_BASE*2;
+
+    if (load_8390_module("ariadne2.c"))
+       return -ENOSYS;
+
+    /* We should have a "dev" from Space.c or the static module table. */
+    if (dev == NULL) {
+       printk(KERN_ERR "ariadne2.c: Passed a NULL device.\n");
+       dev = init_etherdev(0, 0);
+    }
+
+    /* Reset card. Who knows what dain-bramaged state it was left in. */
+    {
+       unsigned long reset_start_time = jiffies;
+
+       writeb(readb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+       while ((readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0)
+           if (jiffies - reset_start_time > 2*HZ/100) {
+               printk(" not found (no reset ack).\n");
+               return ENODEV;
+           }
+
+       writeb(0xff, ioaddr + NE_EN0_ISR);              /* Ack all intr. */
+    }
+
+    /* Read the 16 bytes of station address PROM.
+       We must first initialize registers, similar to NS8390_init(eifdev, 0).
+       We can't reliably read the SAPROM address without this.
+       (I learned the hard way!). */
+    {
+       struct {
+           u32 value;
+           u32 offset;
+       } program_seq[] = {
+           {E8390_NODMA+E8390_PAGE0+E8390_STOP, NE_CMD}, /* Select page 0*/
+           {0x48,      NE_EN0_DCFG},   /* Set byte-wide (0x48) access. */
+           {0x00,      NE_EN0_RCNTLO}, /* Clear the count regs. */
+           {0x00,      NE_EN0_RCNTHI},
+           {0x00,      NE_EN0_IMR},    /* Mask completion irq. */
+           {0xFF,      NE_EN0_ISR},
+           {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20  Set to monitor */
+           {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02  and loopback mode. */
+           {32,        NE_EN0_RCNTLO},
+           {0x00,      NE_EN0_RCNTHI},
+           {0x00,      NE_EN0_RSARLO}, /* DMA starting at 0x0000. */
+           {0x00,      NE_EN0_RSARHI},
+           {E8390_RREAD+E8390_START, NE_CMD},
+       };
+       for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+           writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
+       }
+    }
+    for (i = 0; i < 16; i++) {
+       SA_prom[i] = readb(ioaddr + NE_DATAPORT);
+       (void)readb(ioaddr + NE_DATAPORT);
+    }
+
+    /* We must set the 8390 for word mode. */
+    writeb(0x49, ioaddr + NE_EN0_DCFG);
+    start_page = NESM_START_PG;
+    stop_page = NESM_STOP_PG;
+
+    name = "NE2000";
+
+    dev->base_addr = ioaddr;
+
+    /* Install the Interrupt handler */
+    if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, 0, "AriadNE2 Ethernet",
+                   dev))
+       return -EAGAIN;
+
+    /* Allocate dev->priv and fill in 8390 specific dev fields. */
+    if (ethdev_init(dev)) {
+       printk("Unable to get memory for dev->priv.\n");
+       return -ENOMEM;
+    }
+    ((struct ei_device *)dev->priv)->priv = key;
+
+    for(i = 0; i < ETHER_ADDR_LEN; i++) {
+       printk(" %2.2x", SA_prom[i]);
+       dev->dev_addr[i] = SA_prom[i];
+    }
+
+    printk("%s: AriadNE2 at 0x%08lx, Ethernet Address "
+          "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
+          dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+          dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+    ei_status.name = name;
+    ei_status.tx_start_page = start_page;
+    ei_status.stop_page = stop_page;
+    ei_status.word16 = 1;
+
+    ei_status.rx_start_page = start_page + TX_PAGES;
+
+    ei_status.reset_8390 = &ariadne2_reset_8390;
+    ei_status.block_input = &ariadne2_block_input;
+    ei_status.block_output = &ariadne2_block_output;
+    ei_status.get_8390_hdr = &ariadne2_get_8390_hdr;
+    ei_status.reg_offset = ariadne2_offsets;
+    dev->open = &ariadne2_open;
+    dev->stop = &ariadne2_close;
+    NS8390_init(dev, 0);
+    return 0;
+}
+
+static int ariadne2_open(struct device *dev)
+{
+    ei_open(dev);
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static int ariadne2_close(struct device *dev)
+{
+    if (ei_debug > 1)
+       printk("%s: Shutting down ethercard.\n", dev->name);
+    ei_close(dev);
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+static void ariadne2_reset_8390(struct device *dev)
+{
+    unsigned long reset_start_time = jiffies;
+
+    if (ei_debug > 1)
+       printk("resetting the 8390 t=%ld...", jiffies);
+
+    writeb(readb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+    ei_status.txing = 0;
+    ei_status.dmaing = 0;
+
+    /* This check _should_not_ be necessary, omit eventually. */
+    while ((readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0)
+       if (jiffies - reset_start_time > 2*HZ/100) {
+           printk("%s: ne_reset_8390() did not complete.\n", dev->name);
+           break;
+       }
+    writeb(ENISR_RESET, NE_BASE + NE_EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ariadne2_get_8390_hdr(struct device *dev,
+                                 struct e8390_pkt_hdr *hdr, int ring_page)
+{
+    int nic_base = dev->base_addr;
+    int cnt;
+    short *ptrs;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+       printk("%s: DMAing conflict in ne_get_8390_hdr "
+          "[DMAstat:%d][irqlock:%d][intr:%ld].\n", dev->name, ei_status.dmaing,
+          ei_status.irqlock, dev->interrupt);
+       return;
+    }
+
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(sizeof(struct e8390_pkt_hdr), nic_base + NE_EN0_RCNTLO);
+    writeb(0, nic_base + NE_EN0_RCNTHI);
+    writeb(0, nic_base + NE_EN0_RSARLO);               /* On page boundary */
+    writeb(ring_page, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+    ptrs = (short*)hdr;
+    for (cnt = 0; cnt < (sizeof(struct e8390_pkt_hdr)>>1); cnt++)
+       *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);  /* Ack intr. */
+
+    hdr->count = WORDSWAP(hdr->count);
+
+    ei_status.dmaing &= ~0x01;
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using writeb. */
+
+static void ariadne2_block_input(struct device *dev, int count,
+                                struct sk_buff *skb, int ring_offset)
+{
+    int nic_base = dev->base_addr;
+    char *buf = skb->data;
+    short *ptrs;
+    int cnt;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+       printk("%s: DMAing conflict in ne_block_input "
+          "[DMAstat:%d][irqlock:%d][intr:%ld].\n",
+          dev->name, ei_status.dmaing, ei_status.irqlock,
+          dev->interrupt);
+       return;
+    }
+    ei_status.dmaing |= 0x01;
+    writeb(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8, nic_base + NE_EN0_RCNTHI);
+    writeb(ring_offset & 0xff, nic_base + NE_EN0_RSARLO);
+    writeb(ring_offset >> 8, nic_base + NE_EN0_RSARHI);
+    writeb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < (count>>1); cnt++)
+       *ptrs++ = readw(NE_BASE + NE_DATAPORT);
+    if (count & 0x01)
+       buf[count-1] = readb(NE_BASE + NE_DATAPORT);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);  /* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+static void ariadne2_block_output(struct device *dev, int count,
+                                 const unsigned char *buf,
+                                 const int start_page)
+{
+    int nic_base = NE_BASE;
+    unsigned long dma_start;
+    short *ptrs;
+    int cnt;
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+       count++;
+
+    /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+    if (ei_status.dmaing) {
+       printk("%s: DMAing conflict in ne_block_output."
+          "[DMAstat:%d][irqlock:%d][intr:%ld]\n", dev->name, ei_status.dmaing,
+          ei_status.irqlock, dev->interrupt);
+       return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    writeb(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);
+
+   /* Now the normal output. */
+    writeb(count & 0xff, nic_base + NE_EN0_RCNTLO);
+    writeb(count >> 8,   nic_base + NE_EN0_RCNTHI);
+    writeb(0x00, nic_base + NE_EN0_RSARLO);
+    writeb(start_page, nic_base + NE_EN0_RSARHI);
+
+    writeb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+    ptrs = (short*)buf;
+    for (cnt = 0; cnt < count>>1; cnt++)
+       writew(*ptrs++, NE_BASE+NE_DATAPORT);
+
+    dma_start = jiffies;
+
+    while ((readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0)
+       if (jiffies - dma_start > 2*HZ/100) {           /* 20ms */
+               printk("%s: timeout waiting for Tx RDC.\n", dev->name);
+               ariadne2_reset_8390(dev);
+               NS8390_init(dev,1);
+               break;
+       }
+
+    writeb(ENISR_RDC, nic_base + NE_EN0_ISR);  /* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+    return;
+}
+
+#ifdef MODULE
+static char devicename[9] = { 0, };
+
+static struct device ariadne2_dev =
+{
+    devicename,
+    0, 0, 0, 0,
+    0, 0,
+    0, 0, 0, NULL, ariadne2_probe,
+};
+
+int init_module(void)
+{
+    int err;
+    if ((err = register_netdev(&ariadne2_dev))) {
+       if (err == -EIO)
+           printk("No AriadNE2 ethernet card found.\n");
+       return err;
+    }
+    lock_8390_module();
+    return 0;
+}
+
+void cleanup_module(void)
+{
+    unsigned int key = ((struct ei_device *)ariadne2_dev.priv)->priv;
+    free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev);
+    unregister_netdev(&ariadne2_dev);
+    zorro_config_board(key, 0);
+    unlock_8390_module();
+}
+
+#endif /* MODULE */
index 4367f476fa3c4d614b7e54c2658f352d08752057..8d4ea3b056771fbea88beb10e26636069c9cdb8b 100644 (file)
@@ -99,7 +99,7 @@ __initfunc(int dummy_init(struct device *dev))
        ether_setup(dev);
        dev->tx_queue_len = 0;
        dev->flags |= IFF_NOARP;
-       dev->flags &= ~(IFF_BROADCAST|IFF_MULTICAST);
+       dev->flags &= ~IFF_MULTICAST;
 #ifdef CONFIG_NET_FASTROUTE
        dev->accept_fastpath = dummy_accept_fastpath;
 #endif
index 392354f5a758ff3376de4b4861572bad3142acd3..ed653ce167b14b9357d4961fccbca9d81634c946 100644 (file)
@@ -120,6 +120,7 @@ mace_probe(struct device *dev)
                if (dev->priv == 0)
                        return -ENOMEM;
        }
+       memset(dev->priv, 0, PRIV_BYTES);
 
        mp = (struct mace_data *) dev->priv;
        dev->base_addr = mace->addrs[0].address;
@@ -127,21 +128,6 @@ mace_probe(struct device *dev)
                ioremap(mace->addrs[0].address, 0x1000);
        dev->irq = mace->intrs[0].line;
 
-       if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
-               printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
-               return -EAGAIN;
-       }
-       if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
-                       dev)) {
-               printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
-               return -EAGAIN;
-       }
-       if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
-                       dev)) {
-               printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
-               return -EAGAIN;
-       }
-
        addr = get_property(mace, "mac-address", NULL);
        if (addr == NULL) {
                addr = get_property(mace, "local-mac-address", NULL);
@@ -187,6 +173,23 @@ mace_probe(struct device *dev)
 
        ether_setup(dev);
 
+       mace_reset(dev);
+
+       if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+               printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+               return -EAGAIN;
+       }
+       if (request_irq(mace->intrs[1].line, mace_txdma_intr, 0, "MACE-txdma",
+                       dev)) {
+               printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
+               return -EAGAIN;
+       }
+       if (request_irq(mace->intrs[2].line, mace_rxdma_intr, 0, "MACE-rxdma",
+                       dev)) {
+               printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
+               return -EAGAIN;
+       }
+
        return 0;
 }
 
@@ -197,36 +200,49 @@ static void mace_reset(struct device *dev)
     int i;
 
     /* soft-reset the chip */
-    mb->biucc = SWRST; eieio();
-    udelay(100);
+    i = 200;
+    while (--i) {
+       out_8(&mb->biucc, SWRST);
+       if (mb->biucc & SWRST) {
+           udelay(20);
+           continue;
+       }
+       break;
+    }
+    if (!i) {
+       printk("mace: cannot reset chip!\n");
+       return;
+    }
+
+    out_8(&mb->imr, 0xff);     /* disable all intrs for now */
+    i = in_8(&mb->ir);
+    out_8(&mb->maccc, 0);      /* turn off tx, rx */
 
     mb->biucc = XMTSP_64;
-    mb->imr = 0xff;            /* disable all intrs for now */
-    i = mb->ir;
-    mb->maccc = 0;             /* turn off tx, rx */
     mb->utr = RTRD;
-    mb->fifocc = RCVFW_64;
+    mb->fifocc = RCVFW_32 | XMTFW_16 | XMTFWU | RCVFWU | XMTBRST;
     mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+    mb->rcvfc = 0;
 
     /* load up the hardware address */
-    mb->iac = ADDRCHG | PHYADDR; eieio();
-    while ((mb->iac & ADDRCHG) != 0)
-       eieio();
+    out_8(&mb->iac, ADDRCHG | PHYADDR);
+    while ((in_8(&mb->iac) & ADDRCHG) != 0)
+       ;
     for (i = 0; i < 6; ++i) {
-       mb->padr = dev->dev_addr[i];
-       eieio();
+       out_8(&mb->padr, dev->dev_addr[i]);
     }
 
     /* clear the multicast filter */
-    mb->iac = ADDRCHG | LOGADDR; eieio();
-    while ((mb->iac & ADDRCHG) != 0)
-       eieio();
+    out_8(&mb->iac, ADDRCHG | LOGADDR);
+    while ((in_8(&mb->iac) & ADDRCHG) != 0)
+       ;
     for (i = 0; i < 8; ++i) {
-       mb->ladrf = 0;
-       eieio();
+       out_8(&mb->ladrf, 0);
     }
+    /* done changing address */
+    out_8(&mb->iac, 0);
 
-    mb->plscc = PORTSEL_GPSI + ENPLSIO;
+    out_8(&mb->plscc, PORTSEL_GPSI + ENPLSIO);
 }
 
 static int mace_set_address(struct device *dev, void *addr)
@@ -240,15 +256,15 @@ static int mace_set_address(struct device *dev, void *addr)
     save_flags(flags); cli();
 
     /* load up the hardware address */
-    mb->iac = ADDRCHG | PHYADDR; eieio();
-    while ((mb->iac & ADDRCHG) != 0)
-       eieio();
+    out_8(&mb->iac, ADDRCHG | PHYADDR);
+    while ((in_8(&mb->iac) & ADDRCHG) != 0)
+       ;
     for (i = 0; i < 6; ++i) {
-       mb->padr = dev->dev_addr[i] = p[i];
-       eieio();
+       out_8(&mb->padr, dev->dev_addr[i] = p[i]);
     }
+    out_8(&mb->iac, 0);
     /* note: setting ADDRCHG clears ENRCV */
-    mb->maccc = mp->maccc; eieio();
+    out_8(&mb->maccc, mp->maccc);
 
     restore_flags(flags);
     return 0;
@@ -316,9 +332,9 @@ static int mace_open(struct device *dev)
     mp->tx_bad_runt = 0;
 
     /* turn it on! */
-    mb->maccc = mp->maccc; eieio();
+    out_8(&mb->maccc, mp->maccc);
     /* enable all interrupts except receive interrupts */
-    mb->imr = RCVINT; eieio();
+    out_8(&mb->imr, RCVINT);
     return 0;
 }
 
@@ -389,7 +405,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct device *dev)
        dev->tbusy = 1;
        mp->tx_fullup = 1;
        restore_flags(flags);
-       return -1;              /* can't take it at the moment */
+       return 1;               /* can't take it at the moment */
     }
     restore_flags(flags);
 
@@ -483,16 +499,15 @@ static void mace_set_multicast(struct device *dev)
        printk("\n");
 #endif
 
-       mb->iac = ADDRCHG | LOGADDR; eieio();
-       while ((mb->iac & ADDRCHG) != 0)
-           eieio();
+       out_8(&mb->iac, ADDRCHG | LOGADDR);
+       while ((in_8(&mb->iac) & ADDRCHG) != 0)
+           ;
        for (i = 0; i < 8; ++i) {
-           mb->ladrf = multicast_filter[i];
-           eieio();
+           out_8(&mb->ladrf, multicast_filter[i]);
        }
     }
     /* reset maccc */
-    mb->maccc = mp->maccc; eieio();
+    out_8(&mb->maccc, mp->maccc);
 }
 
 static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
@@ -525,9 +540,10 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     volatile struct dbdma_cmd *cp;
     int intr, fs, i, stat, x;
     int xcount, dstat;
-    static int mace_last_fs, mace_last_xcount;
+    /* static int mace_last_fs, mace_last_xcount; */
 
-    intr = mb->ir;             /* read interrupt register */
+    intr = in_8(&mb->ir);              /* read interrupt register */
+    in_8(&mb->xmtrc);                  /* get retries */
     mace_handle_misc_intrs(mp, intr);
 
     i = mp->tx_empty;
@@ -543,10 +559,9 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        if (intr != 0)
            mace_handle_misc_intrs(mp, intr);
        if (mp->tx_bad_runt) {
-           fs = mb->xmtfs;
-           eieio();
+           fs = in_8(&mb->xmtfs);
            mp->tx_bad_runt = 0;
-           mb->xmtfc = AUTO_PAD_XMIT;
+           mb->xmtfc = AUTO_PAD_XMIT; 
            continue;
        }
        dstat = ld_le32(&td->status);
@@ -569,8 +584,7 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
             * so the two bytes will only be a runt packet which should
             * be ignored by other stations.
             */
-           mb->xmtfc = DXMTFCS;
-           eieio();
+           out_8(&mb->xmtfc, DXMTFCS);
        }
        fs = mb->xmtfs;
        if ((fs & XMTSV) == 0) {
@@ -618,14 +632,16 @@ static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                ++mp->stats.tx_carrier_errors;
            if (fs & (UFLO|LCOL|RTRY))
                ++mp->stats.tx_aborted_errors;
-       } else
+       } else 
            ++mp->stats.tx_packets;
        dev_kfree_skb(mp->tx_bufs[i]);
        --mp->tx_active;
        if (++i >= N_TX_RING)
            i = 0;
+#if 0
        mace_last_fs = fs;
        mace_last_xcount = xcount;
+#endif
     }
 
     if (i != mp->tx_empty) {
@@ -675,7 +691,7 @@ static void mace_tx_timeout(unsigned long data)
     cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
 
     /* turn off both tx and rx and reset the chip */
-    mb->maccc = 0;
+    out_8(&mb->maccc, 0);
     out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
     printk(KERN_ERR "mace: transmit timeout - resetting\n");
     mace_reset(dev);
index 53bafee5548f10673470b1762d26a7bbf42551e4..23a54356d28cebace7582db8c8f9037d846a5c3f 100644 (file)
@@ -1676,9 +1676,14 @@ static inline void pci_happy_meal_tx(struct happy_meal *hp)
 
                TXD(("[%d]", elem));
                this = &txbase[elem];
+#ifdef  __sparc_v9__
                __asm__ __volatile__("lduwa [%1] %2, %0"
                                     : "=r" (flags)
                                     : "r" (&this->tx_flags), "i" (ASI_PL));
+#else
+               flush_cache_all();
+               flags = flip_dword(this->tx_flags);
+#endif
                if(flags & TXFLAG_OWN)
                        break;
                skb = hp->tx_skbs[elem];
@@ -1813,7 +1818,7 @@ static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
                }
 
                /* This card is _fucking_ hot... */
-               if(!~(csum))
+               if(!(csum ^ 0xffff))
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
                        skb->ip_summed = CHECKSUM_NONE;
@@ -1845,9 +1850,14 @@ static inline void pci_happy_meal_rx(struct happy_meal *hp, struct device *dev,
 
        RXD(("RX<"));
        this = &rxbase[elem];
+#ifdef  __sparc_v9__
        __asm__ __volatile__("lduwa [%1] %2, %0"
                             : "=r" (flags)
                             : "r" (&this->rx_flags), "i" (ASI_PL));
+#else
+       flush_cache_all();
+       flags = flip_dword(this->rx_flags); /* FIXME */
+#endif
        while(!(flags & RXFLAG_OWN)) {
                struct sk_buff *skb;
                int len;
@@ -1934,9 +1944,14 @@ static inline void pci_happy_meal_rx(struct happy_meal *hp, struct device *dev,
        next:
                elem = NEXT_RX(elem);
                this = &rxbase[elem];
+#ifdef __sparc_v9__ 
                __asm__ __volatile__("lduwa [%1] %2, %0"
                                     : "=r" (flags)
                                     : "r" (&this->rx_flags), "i" (ASI_PL));
+#else
+               flush_cache_all();
+               flags = flip_dword(this->rx_flags); /* FIXME */
+#endif
        }
        hp->rx_new = elem;
        if(drops)
@@ -2159,7 +2174,7 @@ static int happy_meal_open(struct device *dev)
                        return -EAGAIN;
                }
        } else
-#else
+#endif
 #ifdef CONFIG_PCI
        if(hp->happy_flags & HFLAG_PCI) {
                if(request_irq(dev->irq, &pci_happy_meal_interrupt,
@@ -2170,7 +2185,6 @@ static int happy_meal_open(struct device *dev)
                        return -EAGAIN;
                }
        } else
-#endif
 #endif
        if(request_irq(dev->irq, &happy_meal_interrupt,
                       SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
index 15b408ece61d481bc97427b93234c9e5dee14d0c..e938e21bc90829d8439894bf78e3aa39804d5f53 100644 (file)
@@ -632,6 +632,7 @@ extern inline void hme_write32(struct happy_meal *hp,
 }
 
 #ifdef CONFIG_PCI
+#ifdef __sparc_v9__
 extern inline void pcihme_write_rxd(struct happy_meal_rxd *rp,
                                    unsigned int flags,
                                    unsigned int addr)
@@ -655,6 +656,27 @@ extern inline void pcihme_write_txd(struct happy_meal_txd *tp,
        : "r" (&tp->tx_addr), "r" (&tp->tx_flags),
          "i" (ASI_PL), "r" (addr), "r" (flags));
 }
-#endif
+#else
+
+extern inline void pcihme_write_rxd(struct happy_meal_rxd *rp,
+                                   unsigned int flags,
+                                   unsigned int addr)
+{
+       rp->rx_addr = flip_dword(addr);
+       rp->rx_flags = flip_dword(flags);
+        flush_cache_all();
+}
+       
+extern inline void pcihme_write_txd(struct happy_meal_txd *tp,
+                                   unsigned int flags,
+                                   unsigned int addr)
+{
+       tp->tx_addr = flip_dword(addr);
+       tp->tx_flags = flip_dword(flags);
+        flush_cache_all();
+}
+       
+#endif  /* def __sparc_v9__ */
+#endif  /* def CONFIG_PCI */
 
 #endif /* !(_SUNHME_H) */
index 71a75c7634f7cc1e6776b30dd937d1c4929671f3..fba86a6a58ab6a9b4bf36d5df31791d2cc3a4698 100644 (file)
@@ -9,4 +9,5 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Audio support (EXPERIMENTAL)' CONFIG_SPARCAUDIO
   dep_tristate '  AMD7930 Lowlevel Driver' CONFIG_SPARCAUDIO_AMD7930 $CONFIG_SPARCAUDIO
   dep_tristate '  CS4231 Lowlevel Driver' CONFIG_SPARCAUDIO_CS4231 $CONFIG_SPARCAUDIO
+  dep_tristate '  DBRI Lowlevel Driver' CONFIG_SPARCAUDIO_DBRI $CONFIG_SPARCAUDIO
 fi
index 3dcb06f826fc19794a7288e76569c1df565c51bb..ed15e083ae2fcb07a206f8796b0df242e9fe4cff 100644 (file)
@@ -43,6 +43,16 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SPARCAUDIO_DBRI),y)
+SBUS_AUDIO=y
+O_OBJS += dbri.o
+else
+  ifeq ($(CONFIG_SPARCAUDIO_DBRI),m)
+  SBUS_AUDIO_MODULE=y
+  M_OBJS += dbri.o
+  endif
+endif
+
 ifdef SBUS_AUDIO
 OX_OBJS += audio.o
 else
index fb87bbe6fca887d9f5ebc1a83e84db4a41324af9..07893896be1553d3cc25e20587551af2a29805e7 100644 (file)
@@ -1334,10 +1334,7 @@ static int amd7930_attach(struct sparcaudio_driver *drv, int node,
        /* Point at the information structure and initialize it. */
        drv->ops = &amd7930_ops;
        info = (struct amd7930_info *)drv->private;
-       info->Bb.output_ptr = info->Bb.input_ptr = NULL;
-       info->Bb.output_count = info->Bb.input_count = 0;
-       info->Bc.output_ptr = info->Bc.input_ptr = NULL;
-       info->Bc.output_count = info->Bc.input_count = 0;
+       memset(info, 0, sizeof(*info));
        info->ints_on = 1; /* force disable below */
 
        drv->dev = sdev;
index c98923da439ef96a884f0ad7e741d451e8e632b2..f708fb77f3c913aa5c0518801dcbc72422d9656c 100644 (file)
@@ -1035,6 +1035,10 @@ __initfunc(int sparcaudio_init(void))
        cs4231_init();
 #endif
 
+#ifdef CONFIG_SPARCAUDIO_DBRI
+       dbri_init();
+#endif
+
        return 0;
 }
 
index ec8de8fad4c460915888736acec17cd659267e40..105dad4da9f6c592d0f4e45b51487689b0631413 100644 (file)
@@ -41,22 +41,22 @@ static struct {
        unsigned char  xtal;
        unsigned char  csval;
 } CS4215_FREQ[] = {
-       {        8000,  1,      (0<<3)  },
-       {       16000,  1,      (1<<3)  },
-       {       27429,  1,      (2<<3)  },      /* Actually 24428.57 */
-       {       32000,  1,      (3<<3)  },
-       /* {     NA,    1,      (4<<3)  }, */
-       /* {     NA,    1,      (5<<3)  }, */
-       {       48000,  1,      (6<<3)  },
-       {        9600,  1,      (7<<3)  },
-       {        5513,  2,      (0<<3)  },      /* Actually 5512.5 */
-       {       11025,  2,      (1<<3)  },
-       {       18900,  2,      (2<<3)  },
-       {       22050,  2,      (3<<3)  },
-       {       37800,  2,      (4<<3)  },
-       {       44100,  2,      (5<<3)  },
-       {       33075,  2,      (6<<3)  },
-       {        6615,  2,      (7<<3)  },
+       {        8000,  (1<<4), (0<<3)  },
+       {       16000,  (1<<4), (1<<3)  },
+       {       27429,  (1<<4), (2<<3)  },      /* Actually 24428.57 */
+       {       32000,  (1<<4), (3<<3)  },
+       /* {     NA,    (1<<4), (4<<3)  }, */
+       /* {     NA,    (1<<4), (5<<3)  }, */
+       {       48000,  (1<<4), (6<<3)  },
+       {        9600,  (1<<4), (7<<3)  },
+       {        5513,  (2<<4), (0<<3)  },      /* Actually 5512.5 */
+       {       11025,  (2<<4), (1<<3)  },
+       {       18900,  (2<<4), (2<<3)  },
+       {       22050,  (2<<4), (3<<3)  },
+       {       37800,  (2<<4), (4<<3)  },
+       {       44100,  (2<<4), (5<<3)  },
+       {       33075,  (2<<4), (6<<3)  },
+       {        6615,  (2<<4), (7<<3)  },
        {           0,  0,      0       }
 };
 #define CS4215_HPF     (1<<7)  /* High Pass Filter, 1: Enabled */
index 0456282efe84cc79a30f63f53c0725269a5d7211..d65a2e964294707ba38ba86c6b4cd05e51e9c981 100644 (file)
@@ -59,7 +59,7 @@
 #include <asm/delay.h>
 #include <asm/sbus.h>
 
-#include "audio.h"
+#include <asm/audioio.h>
 #include "dbri.h"
 
 
@@ -84,10 +84,13 @@ static char *cmds[] = {
 /* Bit hunting */
 #define dumpcmd {int i; for(i=0; i<n; i++) printk("DBRI: %x\n", dbri->cmd[i]); }
 
+#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (1 << 27) | value)
+
 #else
 
 #define dprintk(a, x)
 #define dumpcmd
+#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value)
 
 #endif /* DBRI_DEBUG */
 
@@ -103,6 +106,7 @@ static char drv_name[] = "DBRI/audio";
 static int num_drivers;
 static int dbri_cmdlocked = 0;
 
+static void * output_callback_arg;
 
 /*
  * Make sure, that we can send a command to the dbri
@@ -130,21 +134,6 @@ static int dbri_cmdlock(struct dbri *dbri)
        return 0;
 }
 
-static void dummy()
-{
-}
-
-static struct sparcaudio_operations dbri_ops = {
-       dummy, /* dbri_open, */
-       dummy, /* dbri_release, */
-       dummy, /* dbri_ioctl, */
-       dummy, /* dbri_start_output, */
-       dummy, /* dbri_stop_output, */
-       dummy, /* dbri_start_input, */
-        dummy, /* dbri_stop_input, */
-       dummy, /* dbri_audio_getdev, */
-};
-
 static void dbri_reset(struct sparcaudio_driver *drv)
 {
        struct dbri *dbri = (struct dbri *)drv->private;
@@ -171,7 +160,7 @@ static void dbri_detach(struct sparcaudio_driver *drv)
 }
 
 
-static void dbri_init(struct sparcaudio_driver *drv)
+static void dbri_initialize(struct sparcaudio_driver *drv)
 {
        struct dbri *dbri = (struct dbri *)drv->private;
        int n;
@@ -191,7 +180,13 @@ static void dbri_init(struct sparcaudio_driver *drv)
        dbri->intr[n * DBRI_INT_BLK] = (int)(dbri->intr);
        dbri->dbri_irqp = 1;
 
+#ifdef USE_SBUS_BURSTS
+        /* Enable 4-word, 8-word, and 16-word SBus Bursts */
        dbri->regs->reg0 |= (D_G|D_S|D_E);
+#else
+        /* Disable 4-word, 8-word, and 16-word SBus Bursts */
+        dbri->regs->reg0 &= ~(D_G|D_S|D_E);
+#endif
 
        /*
         * Set up the interrupt queue
@@ -236,7 +231,7 @@ static void mmcodec_default(struct cs4215 *mm)
         */
        mm->data[0] = CS4215_LO(0x20) | CS4215_HE|CS4215_LE;
        mm->data[1] = CS4215_RO(0x20) | CS4215_SE;
-       mm->data[2] = CS4215_LG( 0x8) | CS4215_IS;
+       mm->data[2] = CS4215_LG( 0x8) | CS4215_IS | CS4215_PIO0 | CS4215_PIO1;
        mm->data[3] = CS4215_RG( 0x8) | CS4215_MA(0xf);
 
        /*
@@ -248,7 +243,7 @@ static void mmcodec_default(struct cs4215 *mm)
         */
        mm->ctrl[0] = CS4215_RSRVD_1;
        mm->ctrl[1] = CS4215_DFR_ULAW | CS4215_FREQ[0].csval;
-       mm->ctrl[2] = CS4215_XEN | CS4215_XCLK |
+       mm->ctrl[2] = CS4215_XCLK |
                        CS4215_BSEL_128 | CS4215_FREQ[0].xtal;
        mm->ctrl[3] = 0;
 }
@@ -264,69 +259,86 @@ static void mmcodec_init_data(struct dbri *dbri)
         * Pipe  4: Send timeslots 1-4 (audio data)
         * Pipe 17: Send timeslots 5-8 (part of ctrl data)
         * Pipe  6: Receive timeslots 1-4 (audio data)
-        * Pipe 19: Receive timeslots 6-7. We can only receive 20 bits via
+        * Pipe 20: Receive timeslots 6-7. We can only receive 20 bits via
         *          interrupt, and the rest of the data (slot 5 and 8) is
         *          not relevant for us (only for doublechecking).
+         *
+         * Just like in control mode, the time slots are all offset by eight
+         * bits.  The CS4215, it seems, observes TSIN (the delayed signal)
+         * even if it's the CHI master.  Don't ask me...
         */
        
-       /* Transmit & Receive Memory setup */
-       dbri->mm.td.flags = DBRI_TD_F|DBRI_TD_D|DBRI_TD_CNT(0);
-       dbri->mm.td.ba = 0;
-       dbri->mm.td.nda = (__u32)&dbri->mm.td;
-       dbri->mm.td.status = 0;
-
-       dbri->mm.td.flags = DBRI_RD_BCNT(0);
-       dbri->mm.td.ba = 0;
-       dbri->mm.td.nda = (__u32)&dbri->mm.rd;
-       dbri->mm.td.status = 0;
-
-       /* Pipe 4: SDP + DTS */
-       val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_C|D_SDP_MSB|D_PIPE(D_P_4);
-       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
-       dbri->cmd[n++] = (__u32)&dbri->mm.td;
 
-       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_4);
-       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       /* Pipe 4: SDP */
+       val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;
-       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_16);
 
 
-       /* Pipe 17: SDP + DTS + SSP */
+       /* Pipe 17: SDP */
        val = D_SDP_FIXED|D_SDP_TO_SER|D_SDP_C|D_PIPE(D_P_17);
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;                             /* Fixed data */
 
-       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_4) | D_PIPE(D_P_17);
-       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-       dbri->cmd[n++] = 0;
-       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(32) | D_TS_NONCONTIG |
-                        D_TS_MON(D_P_4) | D_TS_NEXT(D_P_16);
-
+        /* Pipe 17: SSP */
        dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
        dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.data, 4);
 
 
-       /* Pipe 6: SDP + DTS */
-       val=D_SDP_MEM|D_SDP_FROM_SER|D_SDP_C|D_SDP_MSB|D_PIPE(D_P_6);
+       /* Pipe 6: SDP */
+       val=D_SDP_MEM|D_SDP_FROM_SER|D_SDP_C|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_6);
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
-       dbri->cmd[n++] = (__u32)&dbri->mm.rd;
-
-       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_6);
-       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(0)| D_TS_NEXT(D_P_16);
        dbri->cmd[n++] = 0;
 
 
-       /* Pipe 19: SDP + DTS */
-       val = D_SDP_FIXED|D_SDP_FROM_SER|D_SDP_P|D_SDP_C|D_PIPE(D_P_19);
+       /* Pipe 20: SDP */
+       val = D_SDP_FIXED|D_SDP_FROM_SER|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_20);
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;                             /* Fixed data */
 
-       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_6) | D_PIPE(D_P_19);
+
+
+       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+
+
+        /* Pipe 4: DTS */
+       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_4);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = 0;
+#if 0
+        /* Full blown, four time slots, 16 bit stereo */
+       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
+#else
+        /* Single time slot, 8 bit mono */
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
+#endif
+
+        /* Pipe 17: DTS */
+       val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_4) | D_PIPE(D_P_17);
        dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-       dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(40) | D_TS_NONCONTIG |
-                        D_TS_MON(D_P_6) | D_TS_NEXT(D_P_16); 
        dbri->cmd[n++] = 0;
+       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(40) | D_TS_NEXT(D_P_16);
+
+        /* Pipe 6: DTS */
+       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_6);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+#if 0
+        /* Full blown, four time slots, 16 bit stereo */
+       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
+#else
+        /* Single time slot, 8 bit mono */
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(8)| D_TS_NEXT(D_P_16);
+#endif
+       dbri->cmd[n++] = 0;
+
+        /* Pipe 20: DTS */
+       val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_6) | D_PIPE(D_P_20);
+       dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
+       dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(48) | D_TS_NEXT(D_P_16); 
+       dbri->cmd[n++] = 0;
+
+        /* CHI: Slave mode; enable interrupts */
+       dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN);
 
        dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
 
@@ -342,12 +354,31 @@ static void mmcodec_setctrl(struct dbri *dbri)
        int n = 0, val;
 
        /*
-        * Enable Command mode: Set PIO3 to 0, then wait
+        * Enable Control mode: Set DBRI's PIO3 (4215's D/~C) to 0, then wait
         * 12 cycles <= 12/(5512.5*64) sec = 34.01 usec
         */
        val = D_ENPIO | D_PIO1 | (dbri->mm.onboard ? D_PIO0 : D_PIO2);
        dbri->regs->reg2 = val;
-       udelay(34);     
+       udelay(34);
+
+        /* In Control mode, the CS4215 is a slave device, so the DBRI must
+         * operate as CHI master, supplying clocking and frame synchronization.
+         *
+         * In Data mode, however, the CS4215 must be CHI master to insure
+         * that its data stream is synchronous with its codec.
+         *
+         * The upshot of all this?  We start by putting the DBRI into master
+         * mode, program the CS4215 in Control mode, then switch the CS4215
+         * into Data mode and put the DBRI into slave mode.  Various timing
+         * requirements must be observed along the way.
+         *
+         * Oh, and one more thing - when the DBRI is master (and only when
+         * the DBRI is master), the addressing of the CS4215's time slots
+         * is offset by eight bits, so we add eight to all the "cycle"
+         * values in the Define Time Slot (DTS) commands.  This is done in
+         * hardware by a TI 248 that delays the DBRI->4215 frame sync signal
+         * by eight clock cycles.  Anybody know why?
+         */
 
        dbri_cmdlock(dbri);
 
@@ -371,11 +402,11 @@ static void mmcodec_setctrl(struct dbri *dbri)
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;
 
-       val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_P|D_SDP_C|D_PIPE(D_P_18);
+       val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_18);
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;
 
-       val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_P|D_SDP_C|D_PIPE(D_P_19);
+       val = D_SDP_FIXED|D_SDP_CHANGE|D_SDP_C|D_PIPE(D_P_19);
        dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
        dbri->cmd[n++] = 0;
 
@@ -389,76 +420,103 @@ static void mmcodec_setctrl(struct dbri *dbri)
 
 
        /* Link the timeslots */
+
+        /* Pipe 17 - CS4215 Status, Data Format, Serial Control, Test - output
+         *           time slots 1, 2, 3 and 4 - 32 bits
+         */
+
        val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_17);
        dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
        dbri->cmd[n++] = 0;
-       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(256) | D_TS_NEXT(D_P_16);
+       dbri->cmd[n++] = D_TS_LEN(32) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16);
+
+        /* Pipe 18 - CS4215 Status and Data Format - input
+         *           time slots 1 & 2 - 16 bits
+         */
 
        val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_16) | D_PIPE(D_P_18);
        dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-       dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(0) | D_TS_NEXT(D_P_16);
+       dbri->cmd[n++] = D_TS_LEN(16) | D_TS_CYCLE(8) | D_TS_NEXT(D_P_16);
        dbri->cmd[n++] = 0;
 
+        /* Pipe 19 - CS4215 Revision - time slot 7, eight bits - input
+         */
+
        val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(D_P_18) | D_PIPE(D_P_19);
        dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
-       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(48) | D_TS_NEXT(D_P_16);
-       /*
-        * According to the manual we should also specify 
-        * D_TS_NONCONTIG | D_TS_MON(D_P_18), but the machine freezes
-        * if we do that. Can somebody explain me why?
-        */
+       dbri->cmd[n++] = D_TS_LEN(8) | D_TS_CYCLE(56) | D_TS_NEXT(D_P_16);
        dbri->cmd[n++] = 0;
 
 
-       /* Setup DBRI for CHI Master */
-       dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_REN);
-       dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(6) | D_CHI_FD |
-                                       D_CHI_IR | D_CHI_EN);
-       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
+       /* Setup DBRI for CHI Master
+         *
+         * BPF   =  128 (128 bits per 8 kHz frame = 1.024 MHz clock rate)
+         * CHICM =  12 (12.288 MHz / 24 = 1.024 MHz clock rate)
+         * FD    =  1 - drive CHIFS on rising edge of CHICK
+         *
+         * RCE   =  0 - receive on falling edge of CHICK
+         * XCE   =  1 - transmit on rising edge of CHICK
+         */
+       dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(12) | D_CHI_FD |
+                                       D_CHI_IR | D_CHI_EN | D_CHI_BPF(128));
        dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0);
 
-       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, 0);
+       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
        dbri->regs->reg8 = (int)dbri->cmd;
 
+
        /* Wait for the data from the CS4215 */
-       interruptible_sleep_on(&dbri->int_wait);
-printk("Woke up (1) reg2: %x\n", dbri->regs->reg2);
+        interruptible_sleep_on(&dbri->int_wait);
 
+        /* Switch CS4215 to data mode - data sheet says
+         * "Set CLB=1 and send two more frames of valid control info"
+         */
+       dbri_cmdlock(dbri);
+
+        n = 0;
+       dbri->mm.ctrl[0] |= CS4215_CLB;
+       dbri->cmd[n++] = DBRI_CMD(D_SSP, 0, D_PIPE(D_P_17));
+       dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4);
+
+       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
+       dbri->regs->reg8 = (int)dbri->cmd;
+
+        dbri_cmdlock(dbri);
+
+        /* Two frames of control info @ 8kHz frame rate = 250 us delay */
+        udelay(250);
 
-       /* Now switch back to data mode */
        n = 0;
-       /* CHI Anchor: Stop Send/Receive */
+
+       /* Now switch back to data mode */
+       /* Reset CHI Anchor: Stop Send/Receive */
        val = D_DTS_VI | D_DTS_VO | D_DTS_INS |
              D_DTS_PRVIN(D_P_16) | D_DTS_PRVOUT(D_P_16) | D_PIPE(D_P_16);
        dbri->cmd[n++] = DBRI_CMD(D_DTS, 0, val);
        dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
        dbri->cmd[n++] = D_TS_ANCHOR | D_TS_NEXT(D_P_16);
 
-       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, 0x17);
-       dbri->regs->reg8 = (int)dbri->cmd;
-
-#if 0      
-       dbri->mm.ctrl[0] |= CS4215_CLB;
-       dbri->cmd[n++] = DBRI_CMD(D_SSP, 1, D_PIPE(D_P_17));
-       dbri->cmd[n++] = reverse_bytes(*(int *)dbri->mm.ctrl, 4);
 
        /* Setup DBRI for CHI Slave */
-       dbri->cmd[n++] = DBRI_CMD(D_CDM, 1, D_CDM_XCE|D_CDM_REN);
-       dbri->cmd[n++] = DBRI_CMD(D_CHI, 1, D_CHI_CHICM(1) | D_CHI_FD |
-                                       D_CHI_IR | D_CHI_EN);
-       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 1, 0x16);
-       dbri->cmd[n++] = DBRI_CMD(D_CDM, 0, D_CDM_XCE|D_CDM_XEN|D_CDM_REN);
+       dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0));
+       /* dbri->cmd[n++] = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(0) | D_CHI_IR | D_CHI_EN); */
+       dbri->cmd[n++] = DBRI_CMD(D_PAUSE, 0, 0x16);
+
 
-       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, 0x17);
+       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
+       dbri->regs->reg8 = (int)dbri->cmd;
+
+        /* Wait for command to complete */
+        dbri_cmdlock(dbri);
+        n = 0;
+       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 1, WAIT_INTR1);
        dbri->regs->reg8 = (int)dbri->cmd;
 
-       dbri->regs->reg2 = D_ENPIO | D_PIO3 |
-                               (dbri->mm.onboard ? D_PIO0 : D_PIO2);
-#endif
 
-       /* We are ready */
-       dbri_cmdlocked = 0;
-       wake_up(&dbri->wait);
+        /* Switch CS4215 to data mode - set PIO3 to 1 */
+       dbri->regs->reg2 = D_ENPIO | D_PIO1 | D_PIO3 |
+                               (dbri->mm.onboard ? D_PIO0 : D_PIO2);
 }
 
 static int mmcodec_init(struct sparcaudio_driver *drv)
@@ -500,9 +558,7 @@ static int mmcodec_init(struct sparcaudio_driver *drv)
        if(dbri->mm.version == 0xff) 
                return -EIO;
 
-       /*
-       mmcodec_init_data(dbri, &n);
-       */
+       mmcodec_init_data(dbri);
 
        return 0;
 }
@@ -518,11 +574,13 @@ void dbri_intr(int irq, void *dev_id, struct pt_regs *regs)
         * Read it, so the interrupt goes away.
         */
        x = dbri->regs->reg1;
+#if 0
        if(numint++ > 20) {
            dbri->regs->reg0 = D_R; /* Soft Reset */
            numint = 0;
            printk("Soft reset\n");
        }
+#endif
 
        if ( x & (D_MRR|D_MLE|D_LBG|D_MBE) ) {
                /*
@@ -562,6 +620,12 @@ void dbri_intr(int irq, void *dev_id, struct pt_regs *regs)
                                        if(val == WAIT_INTR2)
                                                wake_up(&dbri->int_wait);
                                break;
+                       case D_P_4:
+                               if (D_INTR_GETCODE(x) == D_INTR_XCMP) {
+                                       sparcaudio_output_done(output_callback_arg, 1);
+                               }
+                               break;
+
                        case D_P_18:
                                if(val != 0) {
                                        x = reverse_bytes(val,2)&CS4215_12_MASK;
@@ -591,8 +655,124 @@ printk("Comp ok\n");
 }
 
 
+/*
+****************************************************************************
+******************** Interface with sparcaudio midlevel ********************
+****************************************************************************
+*/
 
 
+static void dummy()
+{
+}
+
+static int dbri_open(struct inode * inode, struct file * file,
+                     struct sparcaudio_driver *drv)
+{
+       struct dbri *dbri = (struct dbri *)drv->private;
+
+#if 0
+       /* Set the default audio parameters. */
+       info->rgain = 128;
+       info->pgain = 200;
+       info->mgain = 0;
+#endif
+
+       MOD_INC_USE_COUNT;
+
+       return 0;
+}
+
+static void dbri_release(struct inode * inode, struct file * file,
+                         struct sparcaudio_driver *drv)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static void dbri_start_output(struct sparcaudio_driver *drv,
+                              __u8 * buffer, unsigned long count)
+{
+       struct dbri *dbri = (struct dbri *)drv->private;
+        int val, n = 0;
+
+        /* XXX - This routine can be called via interrupt.  If DBRI
+         * was cmdlocked, that would cause a sleep, which would be
+         * scheduling in an interrupt, and that's not allowed
+         *
+         * Fortunately, there's nothing else talking to our DBRI (yet),
+         * so this isn't a problem (yet)
+         */
+
+        dbri_cmdlock(dbri);
+
+        dbri->mm.td.flags = DBRI_TD_F | DBRI_TD_B | DBRI_TD_D | DBRI_TD_CNT(count);
+        dbri->mm.td.ba = (__u32) buffer;
+        dbri->mm.td.nda = 0;
+        dbri->mm.td.status = 0;
+
+        /* Pipe 4 is audio transmit */
+       val = D_SDP_MEM|D_SDP_TO_SER|D_SDP_P|D_SDP_MSB|D_PIPE(D_P_4);
+       dbri->cmd[n++] = DBRI_CMD(D_SDP, 0, val);
+       dbri->cmd[n++] = (__u32)&dbri->mm.td;
+
+       dbri->cmd[n++] = DBRI_CMD(D_WAIT, 0, WAIT_INTR1);
+
+       dbri->regs->reg8 = (int)dbri->cmd;
+
+        output_callback_arg = drv;
+}
+
+static void dbri_stop_output(struct sparcaudio_driver *drv)
+{
+       struct dbri *dbri = (struct dbri *)drv->private;
+}
+
+static struct sparcaudio_operations dbri_ops = {
+       dbri_open,
+       dbri_release,
+       dummy, /* dbri_ioctl, */
+       dbri_start_output,
+       dbri_stop_output,
+       dummy, /* dbri_start_input, */
+        dummy, /* dbri_stop_input, */
+       dummy, /* dbri_audio_getdev, */
+       dummy, /* dbri_set_output_volume, */
+       dummy, /* dbri_get_output_volume, */
+       dummy, /* dbri_set_input_volume, */
+       dummy, /* dbri_get_input_volume, */
+       dummy, /* dbri_set_monitor_volume, */
+       dummy, /* dbri_get_monitor_volume, */
+       dummy, /* dbri_set_output_balance */
+       dummy, /* dbri_get_output_balance, */
+       dummy, /* dbri_set_input_balance */
+       dummy, /* dbri_get_input_balance, */
+       dummy, /* dbri_set_output_channels */
+       dummy, /* dbri_get_output_channels, */
+       dummy, /* dbri_set_input_channels */
+       dummy, /* dbri_get_input_channels, */
+       dummy, /* dbri_set_output_precision */
+       dummy, /* dbri_get_output_precision, */
+       dummy, /* dbri_set_input_precision */
+       dummy, /* dbri_get_input_precision, */
+       dummy, /* dbri_set_output_port */
+       dummy, /* dbri_get_output_port, */
+       dummy, /* dbri_set_input_port */
+       dummy, /* dbri_get_input_port, */
+       dummy, /* dbri_set_output_encoding */
+       dummy, /* dbri_get_output_encoding, */
+       dummy, /* dbri_set_input_encoding */
+       dummy, /* dbri_get_input_encoding, */
+       dummy, /* dbri_set_output_rate */
+       dummy, /* dbri_get_output_rate, */
+       dummy, /* dbri_set_input_rate */
+       dummy, /* dbri_get_input_rate, */
+       dummy, /* dbri_sunaudio_getdev_sunos, */
+       dummy, /* dbri_get_output_ports, */
+       dummy, /* dbri_get_input_ports, */
+       dummy, /* dbri_set_output_muted */
+       dummy, /* dbri_get_output_muted, */
+};
+
 
 static int dbri_attach(struct sparcaudio_driver *drv, 
                         struct linux_sbus_device *sdev)
@@ -651,7 +831,7 @@ static int dbri_attach(struct sparcaudio_driver *drv,
                return err;
        }
 
-       dbri_init(drv);
+       dbri_initialize(drv);
        err = mmcodec_init(drv);
        if(err) {
                dbri_detach(drv);
@@ -713,3 +893,22 @@ void cleanup_module(void)
         }
 }
 #endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 098616ac815e6ab8d49e9c8b1c273654e0e6c957..0bb9d67b0dc858b70cbe02cf65de8e863f6bf68c 100644 (file)
@@ -106,7 +106,6 @@ struct dbri {
 #define D_TEST         0xd     /* No comment */
 #define D_CDM          0xe     /* CHI Data mode command */
 
-#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | (intr << 27) | value)
 
 
 /* Special bits for some commands */
@@ -268,7 +267,7 @@ struct dbri {
 
 /* Transmit descriptor defines */
 #define DBRI_TD_F      (1<<31) /* End of Frame */
-#define DBRI_TD_D      (1<<31) /* Do not append CRC */
+#define DBRI_TD_D      (1<<30) /* Do not append CRC */
 #define DBRI_TD_CNT(v) (v<<16) /* Number of valid bytes in the buffer */
 #define DBRI_TD_B      (1<<15) /* Final interrupt */
 #define DBRI_TD_M      (1<<14) /* Marker interrupt */
index 6312709e1968a1ad31d6cd2ddcedb7ab40c122f1..6faee52219cc1bd8a0f63800a480c5b3dc58c317 100644 (file)
@@ -2,7 +2,9 @@ comment 'Misc Linux/SPARC drivers'
 tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
 tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
 if [ "$ARCH" = "sparc64" ]; then
-       tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532
+       if [ "$CONFIG_PCI" = "y" ]; then
+               tristate 'Siemens SAB82532 serial support' CONFIG_SAB82532
+       fi
        tristate 'OBP Flash Device support' CONFIG_OBP_FLASH
 fi
 
index 9ad88d1575e2b4a71c9a4b9833aef677b2ab2e1f..ec75114fed2d9fb8ac8482969aa90251f0d7d579 100644 (file)
@@ -47,7 +47,13 @@ else
   endif
 endif
 
-endif # eq($(ARCH),sparc64)
+else # !eq($(ARCH),sparc64)
+
+ifeq ($(CONFIG_PCI),y)
+O_OBJS += su32.o pcikbd.o
+endif
+
+endif # !eq($(ARCH),sparc64)
 
 ifeq ($(CONFIG_SUN_OPENPROMIO),y)
 O_OBJS += openprom.o
index 846f7cd7bb7800aa6e0a8b17c8b2f54527f6c5c5..f445a14b2efc8e0037989ac63c2e921adb07ff0a 100644 (file)
@@ -314,13 +314,6 @@ static inline void bpp_snap(const char *msg, unsigned minor)
 
 #endif /* __sparc__ */
 
-/*
- * This is TRUE if the module_init successfully loaded the module.
- */
-#if 0
-static int loaded_flag = 0;
-#endif
-
 static void bpp_wake_up(unsigned long val)
 { wake_up(&instances[val].wait_queue); }
 
@@ -946,25 +939,22 @@ static volatile struct bpp_regs *map_bpp(struct linux_sbus_device *dev, int idx)
 {
       volatile struct bpp_regs *regs;
 
-      /* Apply ranges to here, do not pollute Sbus devices list. */
-      struct linux_prom_registers areg;
-
       /*
        * PROM reports different numbers on Zebra and on DMA2.
        * We need to figure out when to apply parent ranges.
        * printk will show this on different machines.
        */
 
-      areg = dev->reg_addrs[0];
-      printk("bpp%d.map_bpp: 0x%x.%p[0x%x] i=%d\n", idx,
-            areg.which_io, areg.phys_addr, areg.reg_size,
-            dev->irqs[0]);
       /* IPC Zebra   1.fa200000[1c] i=2  */
-      /** prom_apply_sbus_ranges (&areg, 1); **/
+      prom_apply_sbus_ranges(dev->my_bus, &dev->reg_addrs[0],
+                            dev->num_registers, dev);
 
-      regs = sparc_alloc_io (areg.phys_addr, 0,
-                                   sizeof(struct bpp_regs), "bpp",
-                                   areg.which_io, 0x0);
+      regs = sparc_alloc_io(dev->reg_addrs[0].phys_addr, 0,
+                           dev->reg_addrs[0].reg_size, "bpp",
+                           dev->reg_addrs[0].which_io, 0x0);
+      printk("bpp%d.map_bpp: 0x%x.%p[0x%x] i=%d\n", idx,
+            dev->reg_addrs[0].which_io, dev->reg_addrs[0].phys_addr,
+            dev->reg_addrs[0].reg_size, dev->irqs[0]);
 
       return regs;
 }
index af8f6ce789603c1125ed229e4e892f112ad3f573..fb5088b4e045c8574e1b7c9e0d385244f4dae371 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: envctrl.c,v 1.7 1998/06/10 07:25:28 davem Exp $
+/* $Id: envctrl.c,v 1.8 1998/08/26 10:29:40 davem Exp $
  * envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
index fd91eeefdd566caa2af72337bc62ddd9fb3ee433..cea0c5131aac7bc012fd45485c6e78ff933bf902 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: flash.c,v 1.9 1998/05/17 06:33:39 ecd Exp $
+/* $Id: flash.c,v 1.10 1998/08/26 10:29:41 davem Exp $
  * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
index d6be1fca078823f57efba5443ddea4cfc14930db..5f1576d4de5aae1d3217d39f4d538c066a2236a5 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: pcikbd.c,v 1.18 1998/05/29 06:00:23 ecd Exp $
+/* $Id: pcikbd.c,v 1.22 1998/09/21 05:06:45 jj Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * JavaStation(MrCoffee) support by Pete A. Zaitcev.
  *
  * This code is mainly put together from various places in
  * drivers/char, please refer to these sources for credits
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
+#ifdef __sparc_v9__
+#define        PCI_KB_NAME     "kb_ps2"
+#define PCI_MS_NAME    "kdmouse"
+#else
+#define PCI_KB_NAME    "keyboard"
+#define PCI_MS_NAME    "mouse"
+/*
+ * XXX.
+ * Gleb defines check_region and request_region here.
+ * This looks suspicios because he neglects to call
+ * sparc_alloc_io, but the conflict with sparc_alloc_io is what
+ * causes problems.
+ */
+#endif
+
 #include "pcikbd.h"
 #include "sunserial.h"
 
-static int kbd_node;
-static int beep_node;
+#ifndef __sparc_v9__
+static int pcikbd_mrcoffee = 0;
+#else
+#define pcikbd_mrcoffee 0
+#endif
 
 static unsigned long pcikbd_iobase = 0;
-static unsigned long pcibeep_iobase = 0;
-static unsigned int pcikbd_irq;
+static unsigned int pcikbd_irq = 0;
 
 /* used only by send_data - set by keyboard_interrupt */
 static volatile unsigned char reply_expected = 0;
@@ -53,6 +71,8 @@ extern int pci_getkeycode(unsigned int);
 extern void pci_setledstate(struct kbd_struct *, unsigned int);
 extern unsigned char pci_getledstate(void);
 
+#ifdef __sparc_v9__
+
 static __inline__ unsigned char pcikbd_inb(unsigned long port)
 {
        return inb(port);
@@ -63,6 +83,20 @@ static __inline__ void pcikbd_outb(unsigned char val, unsigned long port)
        outb(val, port);
 }
 
+#else
+
+static __inline__ unsigned char pcikbd_inb(unsigned long port)
+{
+       return *(volatile unsigned char *)port;
+}
+
+static __inline__ void pcikbd_outb(unsigned char val, unsigned long port)
+{
+       *(volatile unsigned char *)port = val;
+}
+
+#endif
+
 static inline void kb_wait(void)
 {
        unsigned long start = jiffies;
@@ -372,6 +406,10 @@ __initfunc(static void pcikbd_write(int address, int data))
        pcikbd_outb(data, pcikbd_iobase + address);
 }
 
+#ifdef __sparc_v9__
+
+static unsigned long pcibeep_iobase = 0;
+
 /* Timer routine to turn off the beep after the interval expires. */
 static void pcikbd_kd_nosound(unsigned long __unused)
 {
@@ -402,6 +440,7 @@ static void pcikbd_kd_mksound(unsigned int hz, unsigned int ticks)
                outl(0, pcibeep_iobase);
        restore_flags(flags);
 }
+#endif
 
 static void nop_kd_mksound(unsigned int hz, unsigned int ticks)
 {
@@ -411,6 +450,7 @@ extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
 
 __initfunc(static char *do_pcikbd_init_hw(void))
 {
+
        while(pcikbd_wait_for_input() != -1)
                ;
 
@@ -458,40 +498,58 @@ __initfunc(void pcikbd_init_hw(void))
        struct linux_ebus_child *child;
        char *msg;
 
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if(!strcmp(edev->prom_name, "8042")) {
-                               for_each_edevchild(edev, child) {
-                                       if (!strcmp(child->prom_name, "kb_ps2"))
-                                               goto found;
+       if (pcikbd_mrcoffee) {
+               if ((pcikbd_iobase = (unsigned long) sparc_alloc_io(0x71300060,
+                   0, 8, "ps2kbd-regs", 0x0, 0)) == 0) {
+                       prom_printf("pcikbd_init_hw: cannot map\n");
+                       return;
+               }
+               pcikbd_irq = 13 | 0x20;
+               if (request_irq(pcikbd_irq, &pcikbd_interrupt,
+                               SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) {
+                       printk("8042: cannot register IRQ %x\n", pcikbd_irq);
+                       return;
+               }
+               printk("8042(kbd): iobase[%08x] irq[%x]\n",
+                   (unsigned)pcikbd_iobase, pcikbd_irq);
+       } else {
+               for_each_ebus(ebus) {
+                       for_each_ebusdev(edev, ebus) {
+                               if(!strcmp(edev->prom_name, "8042")) {
+                                       for_each_edevchild(edev, child) {
+                                               if (!strcmp(child->prom_name, "kb_ps2"))
+                                                       goto found;
+                                       }
                                }
                        }
                }
-       }
-       printk("pcikbd_probe: no 8042 found\n");
-       return;
+               printk("pcikbd_init_hw: no 8042 found\n");
+               return;
 
 found:
-       pcikbd_iobase = child->base_address[0];
-       if (check_region(pcikbd_iobase, sizeof(unsigned long))) {
-               printk("8042: can't get region %lx, %d\n",
-                      pcikbd_iobase, (int)sizeof(unsigned long));
-               return;
-       }
-       request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller");
+               pcikbd_iobase = child->base_address[0];
+               if (check_region(pcikbd_iobase, sizeof(unsigned long))) {
+                       printk("8042: can't get region %lx, %d\n",
+                              pcikbd_iobase, (int)sizeof(unsigned long));
+                       return;
+               }
+               request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller");
+
+               pcikbd_irq = child->irqs[0];
+               if (request_irq(pcikbd_irq, &pcikbd_interrupt,
+                               SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) {
+                       printk("8042: cannot register IRQ %s\n",
+                              __irq_itoa(pcikbd_irq));
+                       return;
+               }
 
-       pcikbd_irq = child->irqs[0];
-       if (request_irq(pcikbd_irq, &pcikbd_interrupt,
-                       SA_SHIRQ, "keyboard", (void *)pcikbd_iobase)) {
-               printk("8042: cannot register IRQ %s\n",
+               printk("8042(kbd) at 0x%lx (irq %s)\n", pcikbd_iobase,
                       __irq_itoa(pcikbd_irq));
-               return;
        }
 
-       printk("8042(kbd) at 0x%lx (irq %s)\n", pcikbd_iobase,
-              __irq_itoa(pcikbd_irq));
-
        kd_mksound = nop_kd_mksound;
+
+#ifdef __sparc_v9__
        edev = 0;
        for_each_ebus(ebus) {
                for_each_ebusdev(edev, ebus) {
@@ -504,6 +562,8 @@ ebus_done:
        /*
         * XXX: my 3.1.3 PROM does not give me the beeper node for the audio
         *      auxio register, though I know it is there... (ecd)
+        *
+        * Both JE1 & MrCoffe have no beeper. How about Krups? --zaitcev
         */
        if (!edev)
                pcibeep_iobase = (pcikbd_iobase & ~(0xffffff)) | 0x722000;
@@ -519,6 +579,7 @@ ebus_done:
                printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase,
                       edev ? "" : " (forced)");
        }
+#endif
 
        disable_irq(pcikbd_irq);
        msg = do_pcikbd_init_hw();
@@ -534,8 +595,6 @@ ebus_done:
  * Here begins the Mouse Driver.
  */
 
-static int ms_node;
-
 static unsigned long pcimouse_iobase = 0;
 static unsigned int pcimouse_irq;
 
@@ -554,6 +613,8 @@ static int aux_ready = 0;
 static int aux_count = 0;
 static int aux_present = 0;
 
+#ifdef __sparc_v9__
+
 static __inline__ unsigned char pcimouse_inb(unsigned long port)
 {
        return inb(port);
@@ -564,6 +625,20 @@ static __inline__ void pcimouse_outb(unsigned char val, unsigned long port)
        outb(val, port);
 }
 
+#else
+
+static __inline__ unsigned char pcimouse_inb(unsigned long port)
+{
+       return *(volatile unsigned char *)port;
+}
+
+static __inline__ void pcimouse_outb(unsigned char val, unsigned long port)
+{
+       *(volatile unsigned char *)port = val;
+}
+
+#endif
+
 /*
  *     Shared subroutines
  */
@@ -587,11 +662,11 @@ static inline int queue_empty(void)
        return queue->head == queue->tail;
 }
 
-static int aux_fasync(struct file *filp, int on)
+static int aux_fasync(int fd, struct file *filp, int on)
 {
        int retval;
 
-       retval = fasync_helper(filp, on, &queue->fasync);
+       retval = fasync_helper(fd, filp, on, &queue->fasync);
        if (retval < 0)
                return retval;
        return 0;
@@ -721,7 +796,7 @@ void pcimouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 static int aux_release(struct inode * inode, struct file * file)
 {
-       aux_fasync(file, 0);
+       aux_fasync(-1, file, 0);
        if (--aux_count)
                return 0;
        aux_start_atomic();
@@ -885,29 +960,43 @@ __initfunc(int pcimouse_init(void))
        struct linux_ebus_device *edev;
        struct linux_ebus_child *child;
 
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if(!strcmp(edev->prom_name, "8042")) {
-                               for_each_edevchild(edev, child) {
-                                       if (!strcmp(child->prom_name,"kdmouse"))
-                                               goto found;
+       if (pcikbd_mrcoffee) {
+               if ((pcimouse_iobase = pcikbd_iobase) == 0) {
+                       printk("pcimouse_init: no 8042 given\n");
+                       return -ENODEV;
+               }
+               pcimouse_irq = pcikbd_irq;
+       } else {
+               for_each_ebus(ebus) {
+                       for_each_ebusdev(edev, ebus) {
+                               if(!strcmp(edev->prom_name, "8042")) {
+                                       for_each_edevchild(edev, child) {
+                                                       if (!strcmp(child->prom_name, PCI_MS_NAME))
+                                                       goto found;
+                                       }
                                }
                        }
                }
-       }
-       printk("pcimouse_init: no 8042 found\n");
-       return -ENODEV;
+               printk("pcimouse_init: no 8042 found\n");
+               return -ENODEV;
 
 found:
-       pcimouse_iobase = child->base_address[0];
-       /*
-        * Just in case the iobases for kbd/mouse ever differ...
-        */
-       if (!check_region(pcimouse_iobase, sizeof(unsigned long)))
-               request_region(pcimouse_iobase, sizeof(unsigned long),
-                              "8042 controller");
+               pcimouse_iobase = child->base_address[0];
+               /*
+                * Just in case the iobases for kbd/mouse ever differ...
+                */
+               if (!check_region(pcimouse_iobase, sizeof(unsigned long)))
+                       request_region(pcimouse_iobase, sizeof(unsigned long),
+                                      "8042 controller");
+
+               pcimouse_irq = child->irqs[0];
+       }
+
+       queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+       memset(queue, 0, sizeof(*queue));
+       queue->head = queue->tail = 0;
+       queue->proc_list = NULL;
 
-       pcimouse_irq = child->irqs[0];
        if (request_irq(pcimouse_irq, &pcimouse_interrupt,
                        SA_SHIRQ, "mouse", (void *)pcimouse_iobase)) {
                printk("8042: Cannot register IRQ %s\n",
@@ -923,10 +1012,6 @@ found:
        pckbd_read_mask = AUX_STAT_OBF;
 
        misc_register(&psaux_mouse);
-       queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
-       memset(queue, 0, sizeof(*queue));
-       queue->head = queue->tail = 0;
-       queue->proc_list = NULL;
        aux_start_atomic();
        pcimouse_outb(KBD_CCMD_MOUSE_ENABLE, pcimouse_iobase + KBD_CNTL_REG);
        aux_write_ack(AUX_RESET);
@@ -956,8 +1041,22 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
        char prop[128];
        int len;
 
+#ifndef __sparc_v9__
+       /*
+        * MrCoffee has hardware but has no PROM nodes whatsoever.
+        */
+       len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
+       if (len < 0) {
+               printk("ps2kbd_probe: no name of root node\n");
+               return -ENODEV;
+       }
+       if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
+               pcikbd_mrcoffee = 1;    /* Brain damage detected */
+               goto found;
+       }
+#endif
        /*
-        * Get the nodes for keyboard and mouse from 'aliases'...
+        * Get the nodes for keyboard and mouse from aliases on normal systems.
         */
         node = prom_getchild(prom_root_node);
        node = prom_searchsiblings(node, "aliases");
@@ -1020,17 +1119,14 @@ __initfunc(int ps2kbd_probe(unsigned long *memory_start))
                                 * Does it match?
                                 */
                                dnode = prom_getchild(node);
-                               dnode = prom_searchsiblings(dnode, "kb_ps2");
+                               dnode = prom_searchsiblings(dnode, PCI_KB_NAME);
                                if (dnode == kbnode) {
-                                       kbd_node = kbnode;
-                                       beep_node = bnode;
                                        ++devices;
                                }
 
                                dnode = prom_getchild(node);
-                               dnode = prom_searchsiblings(dnode, "kdmouse");
+                               dnode = prom_searchsiblings(dnode, PCI_MS_NAME);
                                if (dnode == msnode) {
-                                       ms_node = msnode;
                                        ++devices;
                                }
 
index 8e001c0bdf23207488dbc28e1afcbbaf40bdbe7e..1576a4a0b167e87e4ff0eaeeb9b8117b41e0fc25 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: rtc.c,v 1.12 1998/05/08 21:04:35 davem Exp $
+/* $Id: rtc.c,v 1.13 1998/08/26 10:29:44 davem Exp $
  *
  * Linux/SPARC Real Time Clock Driver
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
index 8f3d2a90a271a5388cf01aed81506067ad954696..4073e0e5e7554f12e87340d473c0ed5699b5c996 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.20 1998/05/29 06:00:24 ecd Exp $
+/* $Id: sab82532.c,v 1.23 1998/09/16 03:20:25 ecd Exp $
  * sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -52,6 +52,13 @@ static int sab82532_refcount;
 #undef SERIAL_DEBUG_SEND_BREAK
 #undef SERIAL_DEBUG_INTR
 
+/* Trace things on serial device, useful for console debugging: */
+#undef SERIAL_LOG_DEVICE
+
+#ifdef SERIAL_LOG_DEVICE
+static void dprint_init(int tty);
+#endif
+
 static void change_speed(struct sab82532 *info);
 static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout);
 
@@ -1330,57 +1337,34 @@ static int set_modem_info(struct sab82532 * info, unsigned int cmd,
 /*
  * This routine sends a break character out the serial port.
  */
-static void send_break(        struct sab82532 * info, int duration)
+static void sab82532_break(struct tty_struct *tty, int break_state)
 {
-       if (!info->regs)
-               return;
-       current->state = TASK_INTERRUPTIBLE;
-       current->timeout = jiffies + duration;
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("sab82532_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
-       cli();
-       info->regs->rw.dafo |= SAB82532_DAFO_XBRK;
-       schedule();
-       info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK);
-       sti();
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("done jiffies=%lu\n", jiffies);
-#endif
-}
+       struct sab82532 * info = (struct sab82532 *)tty->driver_data;
+       unsigned long flags;
 
-/*
- * This routine sets the break condition on the serial port.
- */
-static void begin_break(struct sab82532 * info)
-{
-       if (!info->regs)
+       if (serial_paranoia_check(info, tty->device, "sab82532_break"))
                return;
-       info->regs->rw.dafo |= SAB82532_DAFO_XBRK;
-#ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("begin_break: jiffies=%lu\n", jiffies);
-#endif
-}
 
-/*
- * This routine clears the break condition on the serial port.
- */
-static void end_break(struct sab82532 * info)
-{
        if (!info->regs)
                return;
-       info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK);
+
 #ifdef SERIAL_DEBUG_SEND_BREAK
-       printk("end_break: jiffies=%lu\n", jiffies);
+       printk("sab82532_break(%d) jiff=%lu...", break_state, jiffies);
 #endif
+       save_flags(flags); cli();
+       if (break_state == -1)
+               info->regs->rw.dafo |= SAB82532_DAFO_XBRK;
+       else
+               info->regs->rw.dafo &= ~(SAB82532_DAFO_XBRK);
+       restore_flags(flags);
 }
 
+
 static int sab82532_ioctl(struct tty_struct *tty, struct file * file,
                    unsigned int cmd, unsigned long arg)
 {
        int error;
        struct sab82532 * info = (struct sab82532 *)tty->driver_data;
-       int retval;
        struct async_icount cprev, cnow;        /* kernel counter temps */
        struct serial_icounter_struct *p_cuser; /* user space */
 
@@ -1396,43 +1380,6 @@ static int sab82532_ioctl(struct tty_struct *tty, struct file * file,
        }
        
        switch (cmd) {
-               case TCSBRK:    /* SVID version: non-zero arg --> no break */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       if (!arg) {
-                               send_break(info, HZ/4); /* 1/4 second */
-                               if (signal_pending(current))
-                                       return -EINTR;
-                       }
-                       return 0;
-               case TCSBRKP:   /* support for POSIX tcsendbreak() */
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       send_break(info, arg ? arg*(HZ/10) : HZ/4);
-                       if (signal_pending(current))
-                               return -EINTR;
-                       return 0;
-               case TIOCSBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       tty_wait_until_sent(tty, 0);
-                       begin_break(info);
-                       return 0;
-               case TIOCCBRK:
-                       retval = tty_check_change(tty);
-                       if (retval)
-                               return retval;
-                       end_break(info);
-                       return 0;
                case TIOCGSOFTCAR:
                        return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
                case TIOCSSOFTCAR:
@@ -2047,7 +1994,7 @@ int sab82532_read_proc(char *page, char **start, off_t off, int count,
        int i, len = 0;
        off_t   begin = 0;
 
-       len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.20 $");
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", "$Revision: 1.23 $");
        for (i = 0; i < NR_PORTS && len < 4000; i++) {
                len += line_info(page + len, sab82532_table[i]);
                if (len+begin > off+count)
@@ -2142,7 +2089,7 @@ sab82532_kgdb_hook(int line))
 
 __initfunc(static inline void show_serial_version(void))
 {
-       char *revision = "$Revision: 1.20 $";
+       char *revision = "$Revision: 1.23 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
@@ -2203,6 +2150,7 @@ __initfunc(int sab82532_init(void))
        serial_driver.stop = sab82532_stop;
        serial_driver.start = sab82532_start;
        serial_driver.hangup = sab82532_hangup;
+       serial_driver.break_ctl = sab82532_break;
        serial_driver.wait_until_sent = sab82532_wait_until_sent;
        serial_driver.read_proc = sab82532_read_proc;
 
@@ -2274,6 +2222,10 @@ __initfunc(int sab82532_init(void))
                       info->line, (unsigned long)info->regs,
                       __irq_itoa(info->irq), sab82532_version[info->type]);
        }
+
+#ifdef SERIAL_LOG_DEVICE
+       dprint_init(SERIAL_LOG_DEVICE);
+#endif
        return 0;
 }
 
@@ -2388,7 +2340,12 @@ sab82532_console_write(struct console *con, const char *s, unsigned n)
        struct sab82532 *info;
        int i;
 
-       info = sab82532_chain + con->index;
+       info = sab82532_chain;
+       for (i = con->index; i; i--) {
+               info = info->next;
+               if (!info)
+                       return;
+       }
 
        for (i = 0; i < n; i++) {
                if (*s == '\n')
@@ -2421,7 +2378,12 @@ sab82532_console_setup(struct console *con, char *options)
        int             i, bits;
        unsigned long   flags;
 
-       info = sab82532_chain + con->index;
+       info = sab82532_chain;
+       for (i = con->index; i; i--) {
+               info = info->next;
+               if (!info)
+                       return -ENODEV;
+       }
        info->is_console = 1;
 
        /*
@@ -2487,7 +2449,7 @@ sab82532_console_setup(struct console *con, char *options)
        if (i & CBAUDEX) {
                i &= ~(CBAUDEX);
                if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
-                       info->tty->termios->c_cflag &= ~CBAUDEX;
+                       cflag &= ~CBAUDEX;
                else
                        i += 15;
        }
@@ -2565,4 +2527,36 @@ __initfunc(int sab82532_console_init(void))
        return 0;
 }
 
+#ifdef SERIAL_LOG_DEVICE
+
+static int serial_log_device = 0;
+
+static void
+dprint_init(int tty)
+{
+       serial_console = tty + 1;
+       sab82532_console.index = tty;
+       sab82532_console_setup(&sab82532_console, "");
+       serial_console = 0;
+       serial_log_device = tty + 1;
+}
+
+int
+dprintf(const char *fmt, ...)
+{
+       static char buffer[4096];
+       va_list args;
+       int i;
+
+       if (!serial_log_device)
+               return 0;
+
+       va_start(args, fmt);
+       i = vsprintf(buffer, fmt, args);
+       va_end(args);
+       sab82532_console.write(&sab82532_console, buffer, i);
+       return i;
+}
+#endif /* SERIAL_LOG_DEVICE */
 #endif /* CONFIG_SERIAL_CONSOLE */
+
diff --git a/drivers/sbus/char/su32.c b/drivers/sbus/char/su32.c
new file mode 100644 (file)
index 0000000..537c90d
--- /dev/null
@@ -0,0 +1,3565 @@
+/* $Id: su32.c,v 1.1 1998/09/18 10:45:32 jj Exp $
+ * su.c: Small serial driver for keyboard/mouse interface on sparc32/PCI
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ * Coypright (C) 1998  Pete Zaitcev   (zaitcev@metabyte.com)
+ *
+ * This is mainly a variation of drivers/char/serial.c,
+ * credits go to authors mentioned therein.
+ */
+
+/*
+ * Configuration section.
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO       /* Unused on sparc */
+#define SERIAL_DO_RESTART
+
+#if 1
+/* Normally these defines are controlled by the autoconf.h */
+
+#undef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_SHARE_IRQ                /* Must be enabled for MrCoffee. */
+#undef CONFIG_SERIAL_DETECT_IRQ                /* code is removed from su.c */
+#undef CONFIG_SERIAL_MULTIPORT
+#endif
+
+/* Sanity checks */
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_THROTTLE
+
+/* */
+
+#define RS_STROBE_TIME (10*HZ)
+#define RS_ISR_PASS_LIMIT 256
+
+#ifdef __sparc_v9__
+#define IRQ_4M(n)      (n)
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+#else
+/* 0x20 is sun4m thing, Dave Redman heritage. See arch/sparc/kernel/irq.c. */
+#define IRQ_4M(n)      ((n)|0x20)
+/* Interrupts must be shared on MrCoffee. */
+#define IRQ_T(info)    SA_SHIRQ
+#endif
+
+#define SERIAL_INLINE
+  
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
+#endif
+
+/*
+ * End of serial driver configuration section.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
+#include <linux/console.h>
+#include <linux/major.h>
+#endif
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/ebus.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#if 0 /* P3: Needed if we to support /sbin/setserial. */
+#include <asm/serial.h>
+#endif
+
+#include "sunserial.h"
+#include "sunkbd.h"
+#include "sunmouse.h"
+
+/* We are on a NS PC87303 clocked with 24.0 MHz, which results
+ * in a UART clock of 1.8462 MHz.
+ */
+#define BAUD_BASE      (1846200 / 16)
+
+#ifdef CONFIG_SERIAL_CONSOLE
+extern int serial_console;
+static struct console sercons;
+int su_serial_console_init(void);
+#endif
+
+/*
+ * serial.c saves memory when it allocates async_info upon first open.
+ * We have parts of state structure together because we do call startup
+ * for keyboard and mouse.
+ */
+struct su_struct {
+       int              magic;
+       unsigned long    port;
+       int              baud_base;
+       int             type;                   /* Hardware type: e.g. 16550 */
+       int              irq;
+       int              flags;
+       int              line;
+       int              cflag;
+
+       /* XXX Unify. */
+       int              kbd_node;
+       int              ms_node;
+       int              port_node;
+
+       char             name[16];
+
+       int             xmit_fifo_size;
+       int             custom_divisor;
+       unsigned short  close_delay;
+       unsigned short  closing_wait; /* time to wait before closing */
+       unsigned short  closing_wait2; /* no longer used... */
+
+       struct tty_struct       *tty;
+       int                     read_status_mask;
+       int                     ignore_status_mask;
+       int                     timeout;
+       int                     quot;
+       int                     x_char; /* xon/xoff character */
+       int                     IER;    /* Interrupt Enable Register */
+       int                     MCR;    /* Modem control register */
+       unsigned long           event;
+       int                     blocked_open; /* # of blocked opens */
+       long                    session; /* Session of opening process */
+       long                    pgrp; /* pgrp of opening process */
+       unsigned char           *xmit_buf;
+       int                     xmit_head;
+       int                     xmit_tail;
+       int                     xmit_cnt;
+       struct tq_struct        tqueue;
+       struct wait_queue       *open_wait;
+       struct wait_queue       *close_wait;
+       struct wait_queue       *delta_msr_wait;
+
+       struct su_struct        *next_port;
+       struct su_struct        *prev_port;
+
+       int                     count;
+       struct async_icount     icount;
+       struct termios          normal_termios, callout_termios;
+       unsigned long           last_active;    /* For async_struct, to be */
+};
+
+#if 0 /* P3: became unused after surgery. */
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+       0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+       9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+#endif
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+static char *serial_name = "Serial driver";
+static char *serial_version = "4.25.s1";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/*
+ * IRQ_timeout         - How long the timeout should be for each IRQ
+ *                             should be after the IRQ has been active.
+ */
+static struct su_struct *IRQ_ports[NR_IRQS];
+#ifdef CONFIG_SERIAL_MULTIPORT
+static struct rs_multiport_struct rs_multiport[NR_IRQS];
+#endif
+static int IRQ_timeout[NR_IRQS];
+
+static void autoconfig(struct su_struct *info);
+static void change_speed(struct su_struct *info);
+static void su_wait_until_sent(struct tty_struct *tty, int timeout);
+
+/*
+ * Here we define the default xmit fifo size used for each type of
+ * UART
+ */
+static struct serial_uart_config uart_config[] = {
+       { "unknown", 1, 0 }, 
+       { "8250", 1, 0 }, 
+       { "16450", 1, 0 }, 
+       { "16550", 1, 0 }, 
+       { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
+       { "cirrus", 1, 0 }, 
+       { "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, 
+       { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
+                 UART_STARTECH }, 
+       { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+       { 0, 0}
+};
+
+
+#define NR_PORTS       4
+
+static struct su_struct su_table[NR_PORTS];
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+#ifndef MIN
+#define MIN(a,b)       ((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char *tmp_buf;
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct su_struct *info,
+                                       kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+       static const char *badmagic =
+               "Warning: bad magic number for serial struct (%s) in %s\n";
+       static const char *badinfo =
+               "Warning: null su_struct for (%s) in %s\n";
+
+       if (!info) {
+               printk(badinfo, kdevname(device), routine);
+               return 1;
+       }
+       if (info->magic != SERIAL_MAGIC) {
+               printk(badmagic, kdevname(device), routine);
+               return 1;
+       }
+#endif
+       return 0;
+}
+
+#ifdef __sparc_v9__
+
+static inline
+unsigned int su_inb(struct su_struct *info, unsigned long offset)
+{
+       return inb(info->port + offset);
+}
+
+static inline void
+su_outb(struct su_struct *info, unsigned long offset, int value)
+{
+       outb(value, info->port + offset);
+}
+
+#else
+
+static inline
+unsigned int su_inb(struct su_struct *info, unsigned long offset)
+{
+       return (unsigned int)(*(volatile unsigned char *)(info->port + offset));
+}
+
+static inline void
+su_outb(struct su_struct *info, unsigned long offset, int value)
+{
+       /*
+        * MrCoffee has weird schematics: IRQ4 & P10(?) pins of SuperIO are
+        * connected with a gate then go to SlavIO. When IRQ4 goes tristated
+        * gate gives logical one. Since we use level triggered interrupts
+        * we have lockup and watchdog reset. We cannot mask IRQ because
+        * keyboard shares IRQ with us (Bob Smelik: I would not hire you).
+        * P3: Assure that OUT2 never goes down.
+        */
+       if (offset == UART_MCR) value |= UART_MCR_OUT2;
+       *(volatile unsigned char *)(info->port + offset) = value;
+}
+
+#endif
+
+#define serial_in(info, off)   su_inb(info, off)
+#define serial_inp(info, off)  su_inb(info, off)
+#define serial_out(info, off, val)     su_outb(info, off, val)
+#define serial_outp(info, off, val)    su_outb(info, off, val)
+
+/*
+ * ------------------------------------------------------------
+ * su_stop() and su_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void su_stop(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "su_stop"))
+               return;
+
+       save_flags(flags); cli();
+       if (info->IER & UART_IER_THRI) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       restore_flags(flags);
+}
+
+static void su_start(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "su_start"))
+               return;
+
+       save_flags(flags); cli();
+       if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       restore_flags(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * su_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ *                             - Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void su_sched_event(struct su_struct *info, int event)
+{
+       info->event |= 1 << event;
+       queue_task(&info->tqueue, &tq_serial);
+       mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(struct su_struct *info, int *status,
+               struct pt_regs *regs)
+{
+       struct tty_struct *tty = info->tty;
+       unsigned char ch;
+       int ignored = 0;
+       struct  async_icount *icount;
+
+       icount = &info->icount;
+       do {
+               ch = serial_inp(info, UART_RX);
+               if (info->kbd_node) {
+                       if(ch == SUNKBD_RESET) {
+                               l1a_state.kbd_id = 1;
+                               l1a_state.l1_down = 0;
+                       } else if(l1a_state.kbd_id) {
+                               l1a_state.kbd_id = 0;
+                       } else if(ch == SUNKBD_L1) {
+                               l1a_state.l1_down = 1;
+                       } else if(ch == (SUNKBD_L1|SUNKBD_UP)) {
+                               l1a_state.l1_down = 0;
+                       } else if(ch == SUNKBD_A && l1a_state.l1_down) {
+                               /* whee... */
+                               batten_down_hatches();
+                               /* Continue execution... */
+                               l1a_state.l1_down = 0;
+                               l1a_state.kbd_id = 0;
+                               return;
+                       }
+                       sunkbd_inchar(ch, regs);
+               } else {
+                       sun_mouse_inbyte(ch);
+               }
+               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+                       break;
+               *tty->flip.char_buf_ptr = ch;
+               icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+               printk("DR%02x:%02x...", ch, *status);
+#endif
+               *tty->flip.flag_buf_ptr = 0;
+               if (*status & (UART_LSR_BI | UART_LSR_PE |
+                              UART_LSR_FE | UART_LSR_OE)) {
+                       /*
+                        * For statistics only
+                        */
+                       if (*status & UART_LSR_BI) {
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);
+                               icount->brk++;
+                       } else if (*status & UART_LSR_PE)
+                               icount->parity++;
+                       else if (*status & UART_LSR_FE)
+                               icount->frame++;
+                       if (*status & UART_LSR_OE)
+                               icount->overrun++;
+
+                       /*
+                        * Now check to see if character should be
+                        * ignored, and mask off conditions which
+                        * should be ignored.
+ */
+                       if (*status & info->ignore_status_mask) {
+                               if (++ignored > 100)
+                                       break;
+                               goto ignore_char;
+                       }
+                       *status &= info->read_status_mask;
+
+                       if (*status & (UART_LSR_BI)) {
+#ifdef SERIAL_DEBUG_INTR
+                               printk("handling break....");
+#endif
+                               *tty->flip.flag_buf_ptr = TTY_BREAK;
+                               if (info->flags & ASYNC_SAK)
+                                       do_SAK(tty);
+                       } else if (*status & UART_LSR_PE)
+                               *tty->flip.flag_buf_ptr = TTY_PARITY;
+                       else if (*status & UART_LSR_FE)
+                               *tty->flip.flag_buf_ptr = TTY_FRAME;
+                       if (*status & UART_LSR_OE) {
+                               /*
+                                * Overrun is special, since it's
+                                * reported immediately, and doesn't
+                                * affect the current character
+                                */
+                               if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+                                       tty->flip.count++;
+                                       tty->flip.flag_buf_ptr++;
+                                       tty->flip.char_buf_ptr++;
+                                       *tty->flip.flag_buf_ptr = TTY_OVERRUN;
+                               }
+                       }
+               }
+               tty->flip.flag_buf_ptr++;
+               tty->flip.char_buf_ptr++;
+               tty->flip.count++;
+       ignore_char:
+               *status = serial_inp(info, UART_LSR);
+       } while (*status & UART_LSR_DR);
+       tty_flip_buffer_push(tty);
+}
+
+static _INLINE_ void transmit_chars(struct su_struct *info, int *intr_done)
+{
+       int count;
+
+       if (info->x_char) {
+               serial_outp(info, UART_TX, info->x_char);
+               info->icount.tx++;
+               info->x_char = 0;
+               if (intr_done)
+                       *intr_done = 0;
+               return;
+       }
+       if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+           info->tty->hw_stopped) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+               return;
+       }
+
+       count = info->xmit_fifo_size;
+       do {
+               serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
+               info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+               info->icount.tx++;
+               if (--info->xmit_cnt <= 0)
+                       break;
+       } while (--count > 0);
+       
+       if (info->xmit_cnt < WAKEUP_CHARS)
+               su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("THRE...");
+#endif
+       if (intr_done)
+               *intr_done = 0;
+
+       if (info->xmit_cnt <= 0) {
+               info->IER &= ~UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+}
+
+static _INLINE_ void check_modem_status(struct su_struct *info)
+{
+       int     status;
+       struct  async_icount *icount;
+
+       status = serial_in(info, UART_MSR);
+
+       if (status & UART_MSR_ANY_DELTA) {
+               icount = &info->icount;
+               /* update input line counters */
+               if (status & UART_MSR_TERI)
+                       icount->rng++;
+               if (status & UART_MSR_DDSR)
+                       icount->dsr++;
+               if (status & UART_MSR_DDCD) {
+                       icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+                       if ((info->flags & ASYNC_HARDPPS_CD) &&
+                           (status & UART_MSR_DCD))
+                               hardpps();
+#endif
+       }
+               if (status & UART_MSR_DCTS)
+                       icount->cts++;
+               wake_up_interruptible(&info->delta_msr_wait);
+       }
+
+       if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+               printk("ttys%d CD now %s...", info->line,
+                      (status & UART_MSR_DCD) ? "on" : "off");
+#endif         
+               if (status & UART_MSR_DCD)
+                       wake_up_interruptible(&info->open_wait);
+               else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                          (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+                       printk("doing serial hangup...");
+#endif
+                       if (info->tty)
+                               tty_hangup(info->tty);
+       }
+       }
+       if (info->flags & ASYNC_CTS_FLOW) {
+               if (info->tty->hw_stopped) {
+                       if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx start...");
+#endif
+                               info->tty->hw_stopped = 0;
+                               info->IER |= UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                               su_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+                               return;
+                       }
+               } else {
+                       if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+                               printk("CTS tx stop...");
+#endif
+                               info->tty->hw_stopped = 1;
+                               info->IER &= ~UART_IER_THRI;
+                               serial_out(info, UART_IER, info->IER);
+                       }
+               }
+       }
+}
+       
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+/*
+ * This is the serial driver's generic interrupt routine
+        */
+static void su_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status;
+       struct su_struct *info;
+       int pass_counter = 0;
+       struct su_struct *end_mark = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT
+       int first_multi = 0;
+       struct su_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("su_interrupt(%s)...", __irq_itoa(irq));
+#endif
+
+       info = IRQ_ports[irq];
+       if (!info)
+               return;
+       
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       multi = &rs_multiport[irq];
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+#endif
+
+       do {
+               if (!info->tty ||
+                   (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
+                       if (!end_mark)
+                               end_mark = info;
+                       goto next;
+               }
+               end_mark = 0;
+
+               info->last_active = jiffies;
+       
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+
+       next:
+               info = info->next_port;
+               if (!info) {
+                       info = IRQ_ports[irq];
+                       if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 0
+                               printk("rs loop break\n");
+#endif
+                               break;  /* Prevent infinite loops */
+                       }
+                       continue;
+               }
+       } while (end_mark != info);
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       if (multi->port_monitor)
+               printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
+                      info->irq, first_multi,
+                      inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */
+       
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+static void su_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status;
+       int pass_counter = 0;
+       struct su_struct * info;
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       int first_multi = 0;
+       struct rs_multiport_struct *multi;
+#endif
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("su_interrupt_single(%d) int=%x ...", irq,
+                       serial_inp(&su_table[0], UART_IIR));
+#endif
+       
+       info = IRQ_ports[irq];
+       if (!info || !info->tty)
+               return;
+
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       multi = &rs_multiport[irq];
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+#endif
+
+       do {
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 0
+                       printk("su_single loop break.\n");
+#endif
+                       break;
+               }
+       } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
+       info->last_active = jiffies;
+#ifdef CONFIG_SERIAL_MULTIPORT 
+       if (multi->port_monitor)
+               printk("rs port monitor (single) irq %s: 0x%x, 0x%x\n",
+                      __irq_itoa(info->irq), first_multi,
+                      inb(multi->port_monitor));
+#endif
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+
+#ifdef CONFIG_SERIAL_MULTIPORT 
+/*
+ * This is the serial driver's for multiport boards
+ */
+static void su_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs)
+{
+       int status;
+       struct su_struct * info;
+       int pass_counter = 0;
+       int first_multi= 0;
+       struct rs_multiport_struct *multi;
+
+#ifdef SERIAL_DEBUG_INTR
+       printk("rs_interrupt_multi(%d)...", irq);
+#endif
+
+       info = IRQ_ports[irq];
+       if (!info)
+               return;
+       multi = &rs_multiport[irq];
+       if (!multi->port1) {
+               /* Should never happen */
+               printk("rs_interrupt_multi: NULL port1!\n");
+               return;
+       }
+       if (multi->port_monitor)
+               first_multi = inb(multi->port_monitor);
+
+       while (1) {
+               if (!info->tty ||
+                   (serial_in(info, UART_IIR) & UART_IIR_NO_INT))
+                       goto next;
+
+               info->last_active = jiffies;
+
+               status = serial_inp(info, UART_LSR);
+#ifdef SERIAL_DEBUG_INTR
+               printk("status = %x...", status);
+#endif
+               if (status & UART_LSR_DR)
+                       receive_chars(info, &status, regs);
+               check_modem_status(info);
+               if (status & UART_LSR_THRE)
+                       transmit_chars(info, 0);
+
+       next:
+               info = info->next_port;
+               if (info)
+                       continue;
+
+               info = IRQ_ports[irq];
+               if (pass_counter++ > RS_ISR_PASS_LIMIT) {
+#if 1
+                       printk("rs_multi loop break\n");
+#endif
+                       break;  /* Prevent infinite loops */
+               }
+               if (multi->port_monitor)
+                       printk("rs port monitor irq %d: 0x%x, 0x%x\n",
+                              info->irq, first_multi,
+                              inb(multi->port_monitor));
+               if ((inb(multi->port1) & multi->mask1) != multi->match1)
+                       continue;
+               if (!multi->port2)
+                       break;
+               if ((inb(multi->port2) & multi->mask2) != multi->match2)
+                       continue;
+               if (!multi->port3)
+                       break;
+               if ((inb(multi->port3) & multi->mask3) != multi->match3)
+                       continue;
+               if (!multi->port4)
+                       break;
+               if ((inb(multi->port4) & multi->mask4) == multi->match4)
+                       continue;
+               break;
+       } 
+#ifdef SERIAL_DEBUG_INTR
+       printk("end.\n");
+#endif
+}
+#endif
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * su_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using su_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+       run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+       struct su_struct        *info = (struct su_struct *) private_;
+       struct tty_struct       *tty;
+       
+       tty = info->tty;
+       if (!tty)
+               return;
+
+       if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                   tty->ldisc.write_wakeup)
+                       (tty->ldisc.write_wakeup)(tty);
+               wake_up_interruptible(&tty->write_wait);
+       }
+}
+
+/*
+ * This subroutine is called when the RS_TIMER goes off.  It is used
+ * by the serial driver to handle ports that do not have an interrupt
+ * (irq=0).  This doesn't work very well for 16450's, but gives barely
+ * passable results for a 16550A.  (Although at the expense of much
+ * CPU overhead).
+ */
+static void su_timer(void)
+{
+       static unsigned long last_strobe = 0;
+       struct su_struct *info;
+       unsigned int    i;
+
+       if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
+               for (i=1; i < NR_IRQS; i++) {
+                       info = IRQ_ports[i];
+                       if (!info)
+                               continue;
+                       cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                       if (info->next_port) {
+                               do {
+                                       serial_out(info, UART_IER, 0);
+                                       info->IER |= UART_IER_THRI;
+                                       serial_out(info, UART_IER, info->IER);
+                                       info = info->next_port;
+                               } while (info);
+#ifdef CONFIG_SERIAL_MULTIPORT
+                               if (rs_multiport[i].port1)
+                                       rs_interrupt_multi(i, NULL, NULL);
+                               else
+#endif
+                                       su_interrupt(i, NULL, NULL);
+                       } else
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+                               su_interrupt_single(i, NULL, NULL);
+                       sti();
+               }
+       }
+       last_strobe = jiffies;
+       timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME;
+       timer_active |= 1 << RS_TIMER;
+
+       if (IRQ_ports[0]) {
+               cli();
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+               su_interrupt(0, NULL, NULL);
+#else
+               su_interrupt_single(0, NULL, NULL);
+#endif
+               sti();
+
+               timer_table[RS_TIMER].expires = jiffies + IRQ_timeout[0] - 2;
+       }
+}
+
+/*
+ * ---------------------------------------------------------------
+ * Low level utility subroutines for the serial driver:  routines to
+ * figure out the appropriate timeout for an interrupt chain, routines
+ * to initialize and startup a serial port, and routines to shutdown a
+ * serial port.  Useful stuff like that.
+ * ---------------------------------------------------------------
+ */
+
+/*
+ * This routine figures out the correct timeout for a particular IRQ.
+ * It uses the smallest timeout of all of the serial ports in a
+ * particular interrupt chain.  Now only used for IRQ 0....
+ */
+static void figure_IRQ_timeout(int irq)
+{
+       struct su_struct        *info;
+       int     timeout = 60*HZ;        /* 60 seconds === a long time :-) */
+
+       info = IRQ_ports[irq];
+       if (!info) {
+               IRQ_timeout[irq] = 60*HZ;
+               return;
+       }
+       while (info) {
+               if (info->timeout < timeout)
+                       timeout = info->timeout;
+               info = info->next_port;
+       }
+       if (!irq)
+               timeout = timeout / 2;
+       IRQ_timeout[irq] = timeout ? timeout : 1;
+}
+
+static int startup(struct su_struct *info)
+{
+       unsigned long flags;
+       int     retval=0;
+       void (*handler)(int, void *, struct pt_regs *);
+       unsigned long page;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       unsigned short ICP;
+#endif
+
+       page = get_free_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
+
+       save_flags(flags); cli();
+
+       if (info->flags & ASYNC_INITIALIZED) {
+               free_page(page);
+               goto errout;
+       }
+
+       if (info->port == 0 || info->type == PORT_UNKNOWN) {
+               if (info->tty)
+                       set_bit(TTY_IO_ERROR, &info->tty->flags);
+               free_page(page);
+               goto errout;
+       }
+       if (info->xmit_buf)
+               free_page(page);
+       else
+               info->xmit_buf = (unsigned char *) page;
+
+       if (uart_config[info->type].flags & UART_STARTECH) {
+               /* Wake up UART */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               serial_outp(info, UART_IER, 0);
+               serial_outp(info, UART_EFR, 0);
+               serial_outp(info, UART_LCR, 0);
+       }
+
+       if (info->type == PORT_16750) {
+               /* Wake up UART */
+               serial_outp(info, UART_IER, 0);
+       }
+
+       /*
+        * Clear the FIFO buffers and disable them
+        * (they will be reenabled in change_speed())
+        */
+       if (uart_config[info->type].flags & UART_CLEAR_FIFO)
+               serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+                                            UART_FCR_CLEAR_XMIT));
+
+       /*
+        * At this point there's no way the LSR could still be 0xFF;
+        * if it is, then bail out, because there's likely no UART
+        * here.
+        */
+       if (serial_inp(info, UART_LSR) == 0xff) {
+               if (capable(CAP_SYS_ADMIN)) {
+                       if (info->tty)
+                               set_bit(TTY_IO_ERROR, &info->tty->flags);
+               } else
+                       retval = -ENODEV;
+               goto errout;
+       }
+
+       /*
+        * Allocate the IRQ if necessary
+        */
+       if (info->irq && (!IRQ_ports[info->irq] ||
+                         !IRQ_ports[info->irq]->next_port)) {
+               if (IRQ_ports[info->irq]) {
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+                       free_irq(IRQ_4M(info->irq), info);
+#ifdef CONFIG_SERIAL_MULTIPORT                         
+                       if (rs_multiport[info->irq].port1)
+                               handler = rs_interrupt_multi;
+                       else
+#endif
+                               handler = su_interrupt;
+#else
+                       retval = -EBUSY;
+                       goto errout;
+#endif /* CONFIG_SERIAL_SHARE_IRQ */
+               } else 
+                       handler = su_interrupt_single;
+
+               retval = request_irq(IRQ_4M(info->irq), handler, IRQ_T(info),
+                                    "serial", info);
+               if (retval) {
+                       if (capable(CAP_SYS_ADMIN)) {
+                               if (info->tty)
+                                       set_bit(TTY_IO_ERROR,
+                                               &info->tty->flags);
+                               retval = 0;
+                       }
+                       goto errout;
+               }
+       }
+
+       /*
+        * Insert serial port into IRQ chain.
+        */
+       info->prev_port = 0;
+       info->next_port = IRQ_ports[info->irq];
+       if (info->next_port)
+               info->next_port->prev_port = info;
+       IRQ_ports[info->irq] = info;
+       figure_IRQ_timeout(info->irq);
+
+       /*
+        * Clear the interrupt registers.
+        */
+     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
+       (void) serial_inp(info, UART_RX);
+       (void) serial_inp(info, UART_IIR);
+       (void) serial_inp(info, UART_MSR);
+
+       /*
+        * Now, initialize the UART 
+        */
+       serial_outp(info, UART_LCR, UART_LCR_WLEN8);    /* reset DLAB */
+
+       info->MCR = 0;
+       if (info->tty->termios->c_cflag & CBAUD)
+               info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               if (info->irq == 0)
+                       info->MCR |= UART_MCR_OUT1;
+       } else
+#endif
+       {
+               if (info->irq != 0)
+                       info->MCR |= UART_MCR_OUT2;
+       }
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+       /*
+        * DEC did something gratutiously wrong....
+        */
+       info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
+#endif
+       serial_outp(info, UART_MCR, info->MCR);
+
+       /*
+        * Finally, enable interrupts
+        */
+       info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
+       serial_outp(info, UART_IER, info->IER); /* enable interrupts */
+
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               /* Enable interrupts on the AST Fourport board */
+               ICP = (info->port & 0xFE0) | 0x01F;
+               outb_p(0x80, ICP);
+               (void) inb_p(ICP);
+       }
+#endif
+
+       /*
+        * And clear the interrupt registers again for luck.
+        */
+       (void)serial_inp(info, UART_LSR);
+       (void)serial_inp(info, UART_RX);
+       (void)serial_inp(info, UART_IIR);
+       (void)serial_inp(info, UART_MSR);
+
+       if (info->tty)
+               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+       /*
+        * Set up serial timers...
+        */
+       timer_table[RS_TIMER].expires = jiffies + 2*HZ/100;
+       timer_active |= 1 << RS_TIMER;
+
+       /*
+        * Set up the tty->alt_speed kludge
+        */
+       if (info->tty) {
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                       info->tty->alt_speed = 57600;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                       info->tty->alt_speed = 115200;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+                       info->tty->alt_speed = 230400;
+               if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+                       info->tty->alt_speed = 460800;
+       }
+
+       /*
+        * and set the speed of the serial port
+        */
+       change_speed(info);
+
+       info->flags |= ASYNC_INITIALIZED;
+       restore_flags(flags);
+       return 0;
+
+errout:
+       restore_flags(flags);
+       return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct su_struct *info)
+{
+       unsigned long   flags;
+       int             retval;
+
+       if (!(info->flags & ASYNC_INITIALIZED))
+               return;
+
+       save_flags(flags); cli(); /* Disable interrupts */
+
+       /*
+        * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+        * here so the queue might never be waken up
+        */
+       wake_up_interruptible(&info->delta_msr_wait);
+       
+       /*
+        * First unlink the serial port from the IRQ chain...
+        */
+       if (info->next_port)
+               info->next_port->prev_port = info->prev_port;
+       if (info->prev_port)
+               info->prev_port->next_port = info->next_port;
+       else
+               IRQ_ports[info->irq] = info->next_port;
+       figure_IRQ_timeout(info->irq);
+
+       /*
+        * Free the IRQ, if necessary
+        */
+       if (info->irq && (!IRQ_ports[info->irq] ||
+                         !IRQ_ports[info->irq]->next_port)) {
+               if (IRQ_ports[info->irq]) {
+                       free_irq(IRQ_4M(info->irq), info);
+                       retval = request_irq(IRQ_4M(info->irq),
+                           su_interrupt_single, IRQ_T(info), "serial", info);
+                       
+                       if (retval)
+                               printk("serial shutdown: request_irq: error %d"
+                                      "  Couldn't reacquire IRQ.\n", retval);
+               } else
+                       free_irq(IRQ_4M(info->irq), info);
+       }
+
+       if (info->xmit_buf) {
+               free_page((unsigned long) info->xmit_buf);
+               info->xmit_buf = 0;
+       }
+
+       info->IER = 0;
+       serial_outp(info, UART_IER, 0x00);      /* disable all intrs */
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       if (info->flags & ASYNC_FOURPORT) {
+               /* reset interrupts on the AST Fourport board */
+               (void) inb((info->port & 0xFE0) | 0x01F);
+               info->MCR |= UART_MCR_OUT1;
+       } else
+#endif
+               info->MCR &= ~UART_MCR_OUT2;
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+       /*
+        * DEC did something gratutiously wrong....
+        */
+       info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
+#endif
+
+       /* disable break condition */
+       serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+
+       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+       serial_outp(info, UART_MCR, info->MCR);
+
+       /* disable FIFO's */    
+       serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       (void)serial_in(info, UART_RX);    /* read data port to reset things */
+
+       if (info->tty)
+               set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+       if (uart_config[info->type].flags & UART_STARTECH) {
+               /* Arrange to enter sleep mode */
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR, UART_EFR_ECB);
+               serial_outp(info, UART_IER, UART_IERX_SLEEP);
+               serial_outp(info, UART_LCR, 0);
+       }
+       if (info->type == PORT_16750) {
+               /* Arrange to enter sleep mode */
+               serial_outp(info, UART_IER, UART_IERX_SLEEP);
+       }
+       info->flags &= ~ASYNC_INITIALIZED;
+       restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct su_struct *info)
+{
+       unsigned short port;
+       int     quot = 0, baud_base, baud;
+       unsigned cflag, cval, fcr = 0;
+       int     bits;
+       unsigned long flags;
+
+       if (!info->tty || !info->tty->termios)
+               return;
+       cflag = info->tty->termios->c_cflag;
+       if (!(port = info->port))
+               return;
+
+       /* byte size and parity */
+       switch (cflag & CSIZE) {
+             case CS5: cval = 0x00; bits = 7; break;
+             case CS6: cval = 0x01; bits = 8; break;
+             case CS7: cval = 0x02; bits = 9; break;
+             case CS8: cval = 0x03; bits = 10; break;
+               /* Never happens, but GCC is too dumb to figure it out */
+             default:  cval = 0x00; bits = 7; break;
+       }
+       if (cflag & CSTOPB) {
+               cval |= 0x04;
+               bits++;
+       }
+       if (cflag & PARENB) {
+               cval |= UART_LCR_PARITY;
+               bits++;
+       }
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+#ifdef CMSPAR
+       if (cflag & CMSPAR)
+               cval |= UART_LCR_SPAR;
+#endif
+
+       /* Determine divisor based on baud rate */
+       baud = tty_get_baud_rate(info->tty);
+       baud_base = info->baud_base;
+       if (baud == 38400 &&
+           ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+               quot = info->custom_divisor;
+       else {
+               if (baud == 134)
+                       /* Special case since 134 is really 134.5 */
+                       quot = (2*baud_base / 269);
+               else if (baud)
+                       quot = baud_base / baud;
+       }
+       /* If the quotient is ever zero, default to 9600 bps */
+       if (!quot)
+               quot = baud_base / 9600;
+       info->quot = quot;
+       info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
+       info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
+       /* Set up FIFO's */
+       if (uart_config[info->type].flags & UART_USE_FIFO) {
+               if ((info->baud_base / quot) < 2400)
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+               else
+                       fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
+       }
+       if (info->type == PORT_16750)
+               fcr |= UART_FCR7_64BYTE;
+
+       /* CTS flow control flag and modem status interrupts */
+       info->IER &= ~UART_IER_MSI;
+       if (info->flags & ASYNC_HARDPPS_CD)
+               info->IER |= UART_IER_MSI;
+       if (cflag & CRTSCTS) {
+               info->flags |= ASYNC_CTS_FLOW;
+               info->IER |= UART_IER_MSI;
+       } else
+               info->flags &= ~ASYNC_CTS_FLOW;
+       if (cflag & CLOCAL)
+               info->flags &= ~ASYNC_CHECK_CD;
+       else {
+               info->flags |= ASYNC_CHECK_CD;
+               info->IER |= UART_IER_MSI;
+       }
+       serial_out(info, UART_IER, info->IER);
+
+       /*
+        * Set up parity check flag
+        */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+       info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+       if (I_INPCK(info->tty))
+               info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+       if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+               info->read_status_mask |= UART_LSR_BI;
+
+       /*
+        * Characters to ignore
+        */
+       info->ignore_status_mask = 0;
+       if (I_IGNPAR(info->tty))
+               info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+       if (I_IGNBRK(info->tty)) {
+               info->ignore_status_mask |= UART_LSR_BI;
+               /*
+                * If we're ignore parity and break indicators, ignore 
+                * overruns too.  (For real raw support).
+                */
+               if (I_IGNPAR(info->tty))
+                       info->ignore_status_mask |= UART_LSR_OE;
+       }
+       /*
+        * !!! ignore all characters if CREAD is not set
+        */
+       if ((cflag & CREAD) == 0)
+               info->ignore_status_mask |= UART_LSR_DR;
+       save_flags(flags); cli();
+       if (uart_config[info->type].flags & UART_STARTECH) {
+               serial_outp(info, UART_LCR, 0xBF);
+               serial_outp(info, UART_EFR,
+                           (cflag & CRTSCTS) ? UART_EFR_CTS : 0);
+       }
+       serial_outp(info, UART_LCR, cval | UART_LCR_DLAB);      /* set DLAB */
+       serial_outp(info, UART_DLL, quot & 0xff);       /* LS of divisor */
+       serial_outp(info, UART_DLM, quot >> 8);         /* MS of divisor */
+       if (info->type == PORT_16750)
+               serial_outp(info, UART_FCR, fcr);       /* set fcr */
+       serial_outp(info, UART_LCR, cval);              /* reset DLAB */
+       if (info->type != PORT_16750)
+               serial_outp(info, UART_FCR, fcr);       /* set fcr */
+       restore_flags(flags);
+       info->quot = quot;
+}
+
+static void su_put_char(struct tty_struct *tty, unsigned char ch)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "su_put_char"))
+               return;
+
+       if (!tty || !info->xmit_buf)
+               return;
+
+       save_flags(flags); cli();
+       if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+               restore_flags(flags);
+               return;
+       }
+
+       info->xmit_buf[info->xmit_head++] = ch;
+       info->xmit_head &= SERIAL_XMIT_SIZE-1;
+       info->xmit_cnt++;
+       restore_flags(flags);
+}
+
+static void su_put_char_kbd(unsigned char c)
+{
+       struct su_struct *info;
+       int i;
+       int lsr;
+
+       for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
+               if (info->kbd_node != 0)
+                       break;
+       }
+       if (i >= NR_PORTS) {
+               /* XXX P3: I would put a printk here but it may flood. */
+               return;
+       }
+
+       do {
+               lsr = serial_in(info, UART_LSR);
+       } while (!(lsr & UART_LSR_THRE));
+
+       /* Send the character out. */
+       su_outb(info, UART_TX, c);
+}
+
+static void su_change_mouse_baud(int baud)
+{
+       struct su_struct *info = su_table;
+       int i;
+
+       for (i = 0, info = su_table; i < NR_PORTS; i++, info++)
+               if (info->kbd_node != 0) break;
+       if (i >= NR_PORTS) return;
+
+       info->cflag &= ~(CBAUDEX | CBAUD);
+       switch(baud) {
+               case 1200:
+                       info->cflag |= B1200;
+                       break;
+               case 2400:
+                       info->cflag |= B2400;
+                       break;
+               case 4800:
+                       info->cflag |= B4800;
+                       break;
+               case 9600:
+                       info->cflag |= B9600;
+                       break;
+               default:
+                       printk("su_change_mouse_baud: unknown baud rate %d, "
+                              "defaulting to 1200\n", baud);
+                       info->cflag |= 1200;
+                       break;
+       }
+       change_speed(info);
+}
+
+static void su_flush_chars(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+                               
+       if (serial_paranoia_check(info, tty->device, "su_flush_chars"))
+               return;
+
+       if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+           !info->xmit_buf)
+               return;
+
+       save_flags(flags); cli();
+       info->IER |= UART_IER_THRI;
+       serial_out(info, UART_IER, info->IER);
+       restore_flags(flags);
+}
+
+static int su_write(struct tty_struct * tty, int from_user,
+                   const unsigned char *buf, int count)
+{
+       int     c, ret = 0;
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (serial_paranoia_check(info, tty->device, "su_write"))
+               return 0;
+
+       if (!tty || !info->xmit_buf || !tmp_buf)
+               return 0;
+
+       save_flags(flags);
+       if (from_user) {
+               down(&tmp_buf_sem);
+               while (1) {
+                       c = MIN(count,
+                               MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                   SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0)
+                               break;
+
+                       c -= copy_from_user(tmp_buf, buf, c);
+                       if (!c) {
+                               if (!ret)
+                                       ret = -EFAULT;
+                               break;
+                       }
+                       cli();
+                       c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       info->xmit_head = ((info->xmit_head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+               up(&tmp_buf_sem);
+       } else {
+               while (1) {
+                       cli();          
+                       c = MIN(count,
+                               MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                   SERIAL_XMIT_SIZE - info->xmit_head));
+                       if (c <= 0) {
+                               restore_flags(flags);
+                               break;
+                       }
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
+                       info->xmit_head = ((info->xmit_head + c) &
+                                          (SERIAL_XMIT_SIZE-1));
+                       info->xmit_cnt += c;
+                       restore_flags(flags);
+                       buf += c;
+                       count -= c;
+                       ret += c;
+               }
+       }
+       if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
+           !(info->IER & UART_IER_THRI)) {
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+       return ret;
+}
+
+static int su_write_room(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       int     ret;
+
+       if (serial_paranoia_check(info, tty->device, "su_write_room"))
+               return 0;
+       ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+       if (ret < 0)
+               ret = 0;
+       return ret;
+}
+
+static int su_chars_in_buffer(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+                               
+       if (serial_paranoia_check(info, tty->device, "su_chars_in_buffer"))
+               return 0;
+       return info->xmit_cnt;
+}
+
+static void su_flush_buffer(struct tty_struct *tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "su_flush_buffer"))
+               return;
+       cli();
+       info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+       sti();
+       wake_up_interruptible(&tty->write_wait);
+       if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+           tty->ldisc.write_wakeup)
+               (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void su_send_xchar(struct tty_struct *tty, char ch)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "su_send_char"))
+               return;
+
+       info->x_char = ch;
+       if (ch) {
+               /* Make sure transmit interrupts are on */
+               info->IER |= UART_IER_THRI;
+               serial_out(info, UART_IER, info->IER);
+       }
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void su_throttle(struct tty_struct * tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("throttle %s: %d....\n", tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "su_throttle"))
+               return;
+       
+       if (I_IXOFF(tty))
+               su_send_xchar(tty, STOP_CHAR(tty));
+
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR &= ~UART_MCR_RTS;
+
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+}
+
+static void su_unthrottle(struct tty_struct * tty)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+       char    buf[64];
+       
+       printk("unthrottle %s: %d....\n", tty_name(tty, buf),
+              tty->ldisc.chars_in_buffer(tty));
+#endif
+
+       if (serial_paranoia_check(info, tty->device, "su_unthrottle"))
+               return;
+       
+       if (I_IXOFF(tty)) {
+               if (info->x_char)
+                       info->x_char = 0;
+               else
+                       su_send_xchar(tty, START_CHAR(tty));
+       }
+       if (tty->termios->c_cflag & CRTSCTS)
+               info->MCR |= UART_MCR_RTS;
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#if 0
+static int get_serial_info(struct su_struct * info,
+                          struct serial_struct * retinfo)
+{
+       struct serial_struct tmp;
+
+       if (!retinfo)
+               return -EFAULT;
+       memset(&tmp, 0, sizeof(tmp));
+       tmp.type = info->type;
+       tmp.line = info->line;
+       tmp.port = info->port;
+       tmp.irq = info->irq;
+       tmp.flags = info->flags;
+       tmp.xmit_fifo_size = info->xmit_fifo_size;
+       tmp.baud_base = info->baud_base;
+       tmp.close_delay = info->close_delay;
+       tmp.closing_wait = info->closing_wait;
+       tmp.custom_divisor = info->custom_divisor;
+       tmp.hub6 = 0;
+       if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_serial_info(struct su_struct * info,
+                          struct serial_struct * new_info)
+{
+       struct serial_struct new_serial;
+       struct serial_state old_state, *state;
+       unsigned int            i,change_irq,change_port;
+       int                     retval = 0;
+
+       if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+               return -EFAULT;
+       old_state = *state;
+  
+       change_irq = new_serial.irq != state->irq;
+       change_port = (new_serial.port != state->port);
+  
+       if (!capable(CAP_SYS_ADMIN)) {
+               if (change_irq || change_port ||
+                   (new_serial.baud_base != state->baud_base) ||
+                   (new_serial.type != state->type) ||
+                   (new_serial.close_delay != state->close_delay) ||
+                   (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
+                   ((new_serial.flags & ~ASYNC_USR_MASK) !=
+                    (state->flags & ~ASYNC_USR_MASK)))
+                       return -EPERM;
+               state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+                              (new_serial.flags & ASYNC_USR_MASK));
+               state->custom_divisor = new_serial.custom_divisor;
+               goto check_and_exit;
+       }
+
+       new_serial.irq = irq_cannonicalize(new_serial.irq);
+
+       if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
+           (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) {
+               return -EINVAL;
+       }
+
+       /* Make sure address is not already in use */
+       if (new_serial.type) {
+               for (i = 0 ; i < NR_PORTS; i++)
+                       if ((state != &su_table[i]) &&
+                           (su_table[i].port == new_serial.port) &&
+                           su_table[i].type)
+                               return -EADDRINUSE;
+       }
+
+       if ((change_port || change_irq) && (state->count > 1))
+               return -EBUSY;
+
+       /*
+        * OK, past this point, all the error checking has been done.
+        * At this point, we start making changes.....
+        */
+
+       state->baud_base = new_serial.baud_base;
+       state->flags = ((state->flags & ~ASYNC_FLAGS) |
+                       (new_serial.flags & ASYNC_FLAGS));
+       info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+                      (info->flags & ASYNC_INTERNAL_FLAGS));
+       state->custom_divisor = new_serial.custom_divisor;
+       state->type = new_serial.type;
+       state->close_delay = new_serial.close_delay * HZ/100;
+       state->closing_wait = new_serial.closing_wait * HZ/100;
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       info->xmit_fifo_size = state->xmit_fifo_size =
+               new_serial.xmit_fifo_size;
+
+       release_region(state->port,8);
+       if (change_port || change_irq) {
+               /*
+                * We need to shutdown the serial port at the old
+                * port/irq combination.
+                */
+               shutdown(info);
+               state->irq = new_serial.irq;
+               info->port = state->port = new_serial.port;
+               info->hub6 = state->hub6 = new_serial.hub6;
+       }
+       if (state->type != PORT_UNKNOWN)
+               request_region(state->port,8,"serial(set)");
+
+check_and_exit:
+       if (!state->port || !state->type)
+               return 0;
+       if (state->type != old_state.type)
+               info->xmit_fifo_size = state->xmit_fifo_size =
+                       uart_config[state->type].dfl_xmit_fifo_size;
+       if (state->flags & ASYNC_INITIALIZED) {
+               if (((old_state.flags & ASYNC_SPD_MASK) !=
+                    (state->flags & ASYNC_SPD_MASK)) ||
+                   (old_state.custom_divisor != state->custom_divisor)) {
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+                               info->tty->alt_speed = 57600;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+                               info->tty->alt_speed = 115200;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+                               info->tty->alt_speed = 230400;
+                       if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+                               info->tty->alt_speed = 460800;
+                       change_speed(info);
+               }
+       } else
+               retval = startup(info);
+       return retval;
+}
+#endif
+
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ *         is emptied.  On bus types like RS485, the transmitter must
+ *         release the bus after transmitting. This must be done when
+ *         the transmit shift register is empty, not be done when the
+ *         transmit holding register is empty.  This functionality
+ *         allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct su_struct * info, unsigned int *value)
+{
+       unsigned char status;
+       unsigned int result;
+
+       cli();
+       status = serial_in(info, UART_LSR);
+       sti();
+       result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+       return put_user(result,value);
+}
+
+
+static int get_modem_info(struct su_struct * info, unsigned int *value)
+{
+       unsigned char control, status;
+       unsigned int result;
+
+       control = info->MCR;
+       cli();
+       status = serial_in(info, UART_MSR);
+       sti();
+       result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+               | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+               | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+               | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+               | ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+               | ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+               | ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+               | ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+       return put_user(result,value);
+}
+
+static int set_modem_info(struct su_struct * info, unsigned int cmd,
+                         unsigned int *value)
+{
+       int error;
+       unsigned int arg;
+
+       error = get_user(arg, value);
+       if (error)
+               return error;
+       switch (cmd) {
+       case TIOCMBIS: 
+               if (arg & TIOCM_RTS)
+                       info->MCR |= UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR |= UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR |= UART_MCR_OUT2;
+#endif
+               break;
+       case TIOCMBIC:
+               if (arg & TIOCM_RTS)
+                       info->MCR &= ~UART_MCR_RTS;
+               if (arg & TIOCM_DTR)
+                       info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+               if (arg & TIOCM_OUT1)
+                       info->MCR &= ~UART_MCR_OUT1;
+               if (arg & TIOCM_OUT2)
+                       info->MCR &= ~UART_MCR_OUT2;
+#endif
+               break;
+       case TIOCMSET:
+               info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+                                           UART_MCR_OUT1 |
+                                           UART_MCR_OUT2 |
+#endif
+                                           UART_MCR_DTR))
+                            | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+                            | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+                            | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+                            | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+               break;
+       default:
+               return -EINVAL;
+       }
+       cli();
+       serial_out(info, UART_MCR, info->MCR);
+       sti();
+       return 0;
+}
+
+#if 0
+static int do_autoconfig(struct su_struct * info)
+{
+       int                     retval;
+       
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (info->state->count > 1)
+               return -EBUSY;
+       
+       shutdown(info);
+
+       autoconfig(info->state);
+       if ((info->state->flags & ASYNC_AUTO_IRQ) && (info->state->port != 0))
+               info->state->irq = detect_uart_irq(info->state);
+
+       retval = startup(info);
+       if (retval)
+               return retval;
+       return 0;
+}
+#endif
+
+/*
+ * su_break() --- routine which turns the break handling on or off
+ */
+static void su_break(struct tty_struct *tty, int break_state)
+{
+       struct su_struct * info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+       
+       if (serial_paranoia_check(info, tty->device, "su_break"))
+               return;
+
+       if (!info->port)
+               return;
+       save_flags(flags); cli();
+       if (break_state == -1)
+               serial_out(info, UART_LCR,
+                          serial_inp(info, UART_LCR) | UART_LCR_SBC);
+       else
+               serial_out(info, UART_LCR,
+                          serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+       restore_flags(flags);
+}
+
+#ifdef CONFIG_SERIAL_MULTIPORT
+static int get_multiport_struct(struct su_struct * info,
+                               struct serial_multiport_struct *retinfo)
+{
+       struct serial_multiport_struct ret;
+       struct rs_multiport_struct *multi;
+       
+       multi = &rs_multiport[info->state->irq];
+
+       ret.port_monitor = multi->port_monitor;
+       
+       ret.port1 = multi->port1;
+       ret.mask1 = multi->mask1;
+       ret.match1 = multi->match1;
+       
+       ret.port2 = multi->port2;
+       ret.mask2 = multi->mask2;
+       ret.match2 = multi->match2;
+       
+       ret.port3 = multi->port3;
+       ret.mask3 = multi->mask3;
+       ret.match3 = multi->match3;
+       
+       ret.port4 = multi->port4;
+       ret.mask4 = multi->mask4;
+       ret.match4 = multi->match4;
+
+       ret.irq = info->state->irq;
+
+       if (copy_to_user(retinfo,&ret,sizeof(*retinfo)))
+               return -EFAULT;
+       return 0;
+}
+
+static int set_multiport_struct(struct su_struct * info,
+                               struct serial_multiport_struct *in_multi)
+{
+       struct serial_multiport_struct new_multi;
+       struct rs_multiport_struct *multi;
+       struct serial_state *state;
+       int     was_multi, now_multi;
+       int     retval;
+       void (*handler)(int, void *, struct pt_regs *);
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+       state = info->state;
+       
+       if (copy_from_user(&new_multi, in_multi,
+                          sizeof(struct serial_multiport_struct)))
+               return -EFAULT;
+       
+       if (new_multi.irq != state->irq || state->irq == 0 ||
+           !IRQ_ports[state->irq])
+               return -EINVAL;
+
+       multi = &rs_multiport[state->irq];
+       was_multi = (multi->port1 != 0);
+       
+       multi->port_monitor = new_multi.port_monitor;
+       
+       if (multi->port1)
+               release_region(multi->port1,1);
+       multi->port1 = new_multi.port1;
+       multi->mask1 = new_multi.mask1;
+       multi->match1 = new_multi.match1;
+       if (multi->port1)
+               request_region(multi->port1,1,"serial(multiport1)");
+
+       if (multi->port2)
+               release_region(multi->port2,1);
+       multi->port2 = new_multi.port2;
+       multi->mask2 = new_multi.mask2;
+       multi->match2 = new_multi.match2;
+       if (multi->port2)
+               request_region(multi->port2,1,"serial(multiport2)");
+
+       if (multi->port3)
+               release_region(multi->port3,1);
+       multi->port3 = new_multi.port3;
+       multi->mask3 = new_multi.mask3;
+       multi->match3 = new_multi.match3;
+       if (multi->port3)
+               request_region(multi->port3,1,"serial(multiport3)");
+
+       if (multi->port4)
+               release_region(multi->port4,1);
+       multi->port4 = new_multi.port4;
+       multi->mask4 = new_multi.mask4;
+       multi->match4 = new_multi.match4;
+       if (multi->port4)
+               request_region(multi->port4,1,"serial(multiport4)");
+
+       now_multi = (multi->port1 != 0);
+       
+       if (IRQ_ports[state->irq]->next_port &&
+           (was_multi != now_multi)) {
+               free_irq(IRQ_4M(state->irq), info);
+               if (now_multi)
+                       handler = rs_interrupt_multi;
+               else
+                       handler = su_interrupt;
+
+               retval = request_irq(IRQ_4M(state->irq), handler, IRQ_T(info),
+                                    "serial", info);
+               if (retval) {
+                       printk("Couldn't reallocate serial interrupt "
+                              "driver!!\n");
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int su_ioctl(struct tty_struct *tty, struct file * file,
+                   unsigned int cmd, unsigned long arg)
+{
+       int error;
+       struct su_struct * info = (struct su_struct *)tty->driver_data;
+       struct async_icount cprev, cnow;        /* kernel counter temps */
+       struct serial_icounter_struct *p_cuser; /* user space */
+
+       if (serial_paranoia_check(info, tty->device, "su_ioctl"))
+               return -ENODEV;
+
+       if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+           (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+           (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+               if (tty->flags & (1 << TTY_IO_ERROR))
+                   return -EIO;
+       }
+
+       switch (cmd) {
+               case TIOCMGET:
+                       return get_modem_info(info, (unsigned int *) arg);
+               case TIOCMBIS:
+               case TIOCMBIC:
+               case TIOCMSET:
+                       return set_modem_info(info, cmd, (unsigned int *) arg);
+#if 0
+               case TIOCGSERIAL:
+                       return get_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSSERIAL:
+                       return set_serial_info(info,
+                                              (struct serial_struct *) arg);
+               case TIOCSERCONFIG:
+                       return do_autoconfig(info);
+#endif
+
+               case TIOCSERGETLSR: /* Get line status register */
+                       return get_lsr_info(info, (unsigned int *) arg);
+
+#if 0
+               case TIOCSERGSTRUCT:
+                       if (copy_to_user((struct async_struct *) arg,
+                                        info, sizeof(struct async_struct)))
+                               return -EFAULT;
+                       return 0;
+#endif
+                               
+#ifdef CONFIG_SERIAL_MULTIPORT
+               case TIOCSERGETMULTI:
+                       return get_multiport_struct(info,
+                                      (struct serial_multiport_struct *) arg);
+               case TIOCSERSETMULTI:
+                       return set_multiport_struct(info,
+                                      (struct serial_multiport_struct *) arg);
+#endif
+                       
+               /*
+                * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+                * - mask passed in arg for lines of interest
+                *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+                * Caller should use TIOCGICOUNT to see which one it was
+                */
+               case TIOCMIWAIT:
+                       cli();
+                       /* note the counters on entry */
+                       cprev = info->icount;
+                       sti();
+                       while (1) {
+                               interruptible_sleep_on(&info->delta_msr_wait);
+                               /* see if a signal did it */
+                               if (signal_pending(current))
+                                       return -ERESTARTSYS;
+                               cli();
+                               cnow = info->icount; /* atomic copy */
+                               sti();
+                               if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && 
+                                   cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+                                       return -EIO; /* no change => error */
+                               if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+                                    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+                                    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+                                    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+                                       return 0;
+                               }
+                               cprev = cnow;
+                       }
+                       /* NOTREACHED */
+
+               /* 
+                * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+                * Return: write counters to the user passed counter struct
+                * NB: both 1->0 and 0->1 transitions are counted except for
+                *     RI where only 0->1 is counted.
+                */
+               case TIOCGICOUNT:
+                       cli();
+                       cnow = info->icount;
+                       sti();
+                       p_cuser = (struct serial_icounter_struct *) arg;
+                       error = put_user(cnow.cts, &p_cuser->cts);
+                       if (error) return error;
+                       error = put_user(cnow.dsr, &p_cuser->dsr);
+                       if (error) return error;
+                       error = put_user(cnow.rng, &p_cuser->rng);
+                       if (error) return error;
+                       error = put_user(cnow.dcd, &p_cuser->dcd);
+                       if (error) return error;
+                       return 0;
+
+               default:
+                       return -ENOIOCTLCMD;
+               }
+       /* return 0; */ /* Trigger warnings is fall through by a chance. */
+}
+
+static void su_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+
+       if (   (tty->termios->c_cflag == old_termios->c_cflag)
+           && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+               == RELEVANT_IFLAG(old_termios->c_iflag)))
+         return;
+
+       change_speed(info);
+
+       /* Handle transition to B0 status */
+       if ((old_termios->c_cflag & CBAUD) &&
+           !(tty->termios->c_cflag & CBAUD)) {
+               info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               cli();
+               serial_out(info, UART_MCR, info->MCR);
+               sti();
+       }
+       
+       /* Handle transition away from B0 status */
+       if (!(old_termios->c_cflag & CBAUD) &&
+           (tty->termios->c_cflag & CBAUD)) {
+               info->MCR |= UART_MCR_DTR;
+               if (!(tty->termios->c_cflag & CRTSCTS) || 
+                   !test_bit(TTY_THROTTLED, &tty->flags)) {
+                       info->MCR |= UART_MCR_RTS;
+               }
+               cli();
+               serial_out(info, UART_MCR, info->MCR);
+               sti();
+       }
+       
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+           !(tty->termios->c_cflag & CRTSCTS)) {
+               tty->hw_stopped = 0;
+               su_start(tty);
+       }
+
+#if 0
+       /*
+        * No need to wake up processes in open wait, since they
+        * sample the CLOCAL flag once, and don't recheck it.
+        * XXX  It's not clear whether the current behavior is correct
+        * or not.  Hence, this may change.....
+        */
+       if (!(old_termios->c_cflag & CLOCAL) &&
+           (tty->termios->c_cflag & CLOCAL))
+               wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void su_close(struct tty_struct *tty, struct file * filp)
+{
+       struct su_struct *info = (struct su_struct *)tty->driver_data;
+       unsigned long flags;
+
+       if (!info || serial_paranoia_check(info, tty->device, "su_close"))
+               return;
+
+       save_flags(flags); cli();
+       
+       if (tty_hung_up_p(filp)) {
+               DBG_CNT("before DEC-hung");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       
+#ifdef SERIAL_DEBUG_OPEN
+       printk("su_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+       if ((tty->count == 1) && (info->count != 1)) {
+               /*
+                * Uh, oh.  tty->count is 1, which means that the tty
+                * structure will be freed.  info->count should always
+                * be one in these conditions.  If it's greater than
+                * one, we've got real problems, since it means the
+                * serial port won't be shutdown.
+                */
+               printk("su_close: bad serial port count; tty->count is 1, "
+                      "info->count is %d\n", info->count);
+               info->count = 1;
+       }
+       if (--info->count < 0) {
+               printk("su_close: bad serial port count for ttys%d: %d\n",
+                      info->line, info->count);
+               info->count = 0;
+       }
+       if (info->count) {
+               DBG_CNT("before DEC-2");
+               MOD_DEC_USE_COUNT;
+               restore_flags(flags);
+               return;
+       }
+       info->flags |= ASYNC_CLOSING;
+       /*
+        * Save the termios structure, since this port may have
+        * separate termios for callout and dialin.
+        */
+       if (info->flags & ASYNC_NORMAL_ACTIVE)
+               info->normal_termios = *tty->termios;
+       if (info->flags & ASYNC_CALLOUT_ACTIVE)
+               info->callout_termios = *tty->termios;
+       /*
+        * Now we wait for the transmit buffer to clear; and we notify 
+        * the line discipline to only process XON/XOFF characters.
+        */
+       tty->closing = 1;
+       if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+               tty_wait_until_sent(tty, info->closing_wait);
+       /*
+        * At this point we stop accepting input.  To do this, we
+        * disable the receive line status interrupts, and tell the
+        * interrupt driver to stop checking the data ready bit in the
+        * line status register.
+        */
+       info->IER &= ~UART_IER_RLSI;
+       info->read_status_mask &= ~UART_LSR_DR;
+       if (info->flags & ASYNC_INITIALIZED) {
+               serial_out(info, UART_IER, info->IER);
+               /*
+                * Before we drop DTR, make sure the UART transmitter
+                * has completely drained; this is especially
+                * important if there is a transmit FIFO!
+                */
+               su_wait_until_sent(tty, info->timeout);
+       }
+       shutdown(info);
+       if (tty->driver.flush_buffer)
+               tty->driver.flush_buffer(tty);
+       if (tty->ldisc.flush_buffer)
+               tty->ldisc.flush_buffer(tty);
+       tty->closing = 0;
+       info->event = 0;
+       info->tty = 0;
+       if (info->blocked_open) {
+               if (info->close_delay) {
+                       current->state = TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies + info->close_delay;
+                       schedule();
+               }
+               wake_up_interruptible(&info->open_wait);
+       }
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+                        ASYNC_CLOSING);
+       wake_up_interruptible(&info->close_wait);
+       MOD_DEC_USE_COUNT;
+       restore_flags(flags);
+}
+
+/*
+ * su_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void su_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+       struct su_struct * info = (struct su_struct *)tty->driver_data;
+       unsigned long orig_jiffies, char_time;
+       int lsr;
+
+       if (serial_paranoia_check(info, tty->device, "su_wait_until_sent"))
+               return;
+
+       if (info->type == PORT_UNKNOWN)
+               return;
+
+       orig_jiffies = jiffies;
+       /*
+        * Set the check interval to be 1/5 of the estimated time to
+        * send a single character, and make it at least 1.  The check
+        * interval should also be less than the timeout.
+        * 
+        * Note: we have to use pretty tight timings here to satisfy
+        * the NIST-PCTS.
+        */
+       char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
+       char_time = char_time / 5;
+       if (char_time == 0)
+               char_time = 1;
+       if (timeout)
+         char_time = MIN(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("In su_wait_until_sent(%d) check=%lu...", timeout, char_time);
+       printk("jiff=%lu...", jiffies);
+#endif
+       while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+               printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+               current->state = TASK_INTERRUPTIBLE;
+               current->counter = 0;   /* make us low-priority */
+               current->timeout = jiffies + char_time;
+               schedule();
+               if (signal_pending(current))
+                       break;
+               if (timeout && ((orig_jiffies + timeout) < jiffies))
+                       break;
+       }
+       current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+       printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * su_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void su_hangup(struct tty_struct *tty)
+{
+       struct su_struct * info = (struct su_struct *)tty->driver_data;
+
+       if (serial_paranoia_check(info, tty->device, "su_hangup"))
+               return;
+
+       su_flush_buffer(tty);
+       shutdown(info);
+       info->event = 0;
+       info->count = 0;
+       info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+       info->tty = 0;
+       wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * su_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+                          struct su_struct *info)
+{
+       struct wait_queue wait = { current, NULL };
+       int             retval;
+       int             do_clocal = 0;
+
+       /*
+        * If the device is in the middle of being closed, then block
+        * until it's done, and then try again.
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+
+       /*
+        * If this is a callout device, then just make sure the normal
+        * device isn't being used.
+        */
+       if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+               if (info->flags & ASYNC_NORMAL_ACTIVE)
+                       return -EBUSY;
+               if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (info->flags & ASYNC_SESSION_LOCKOUT) &&
+                   (info->session != current->session))
+                   return -EBUSY;
+               if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (info->flags & ASYNC_PGRP_LOCKOUT) &&
+                   (info->pgrp != current->pgrp))
+                   return -EBUSY;
+               info->flags |= ASYNC_CALLOUT_ACTIVE;
+               return 0;
+       }
+
+       /*
+        * If non-blocking mode is set, or the port is not enabled,
+        * then make the check up front and then exit.
+        */
+       if ((filp->f_flags & O_NONBLOCK) ||
+           (tty->flags & (1 << TTY_IO_ERROR))) {
+               if (info->flags & ASYNC_CALLOUT_ACTIVE)
+                       return -EBUSY;
+               info->flags |= ASYNC_NORMAL_ACTIVE;
+               return 0;
+       }
+
+       if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+               if (info->normal_termios.c_cflag & CLOCAL)
+                       do_clocal = 1;
+       } else {
+               if (tty->termios->c_cflag & CLOCAL)
+                       do_clocal = 1;
+       }
+       
+       /*
+        * Block waiting for the carrier detect and the line to become
+        * free (i.e., not in use by the callout).  While we are in
+        * this loop, info->count is dropped by one, so that
+        * su_close() knows when to free things.  We restore it upon
+        * exit, either normal or abnormal.
+        */
+       retval = 0;
+       add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready before block: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       cli();
+       if (!tty_hung_up_p(filp)) 
+               info->count--;
+       sti();
+       info->blocked_open++;
+       while (1) {
+               cli();
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   (tty->termios->c_cflag & CBAUD))
+                       serial_out(info, UART_MCR,
+                                  serial_inp(info, UART_MCR) |
+                                  (UART_MCR_DTR | UART_MCR_RTS));
+               sti();
+               current->state = TASK_INTERRUPTIBLE;
+               if (tty_hung_up_p(filp) ||
+                   !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+                       if (info->flags & ASYNC_HUP_NOTIFY)
+                               retval = -EAGAIN;
+                       else
+                               retval = -ERESTARTSYS;  
+#else
+                       retval = -EAGAIN;
+#endif
+                       break;
+               }
+               if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+                   !(info->flags & ASYNC_CLOSING) &&
+                   (do_clocal || (serial_in(info, UART_MSR) &
+                                  UART_MSR_DCD)))
+                       break;
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       break;
+               }
+#ifdef SERIAL_DEBUG_OPEN
+               printk("block_til_ready blocking: ttys%d, count = %d\n",
+                      info->line, info->count);
+#endif
+               schedule();
+       }
+       current->state = TASK_RUNNING;
+       remove_wait_queue(&info->open_wait, &wait);
+       if (!tty_hung_up_p(filp))
+               info->count++;
+       info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+       printk("block_til_ready after blocking: ttys%d, count = %d\n",
+              info->line, info->count);
+#endif
+       if (retval)
+               return retval;
+       info->flags |= ASYNC_NORMAL_ACTIVE;
+       return 0;
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+        */
+static int su_open(struct tty_struct *tty, struct file * filp)
+{
+       struct su_struct        *info;
+       int                     retval, line;
+       unsigned long           page;
+
+       line = MINOR(tty->device) - tty->driver.minor_start;
+       if ((line < 0) || (line >= NR_PORTS))
+               return -ENODEV;
+       info = su_table + line;
+       if (serial_paranoia_check(info, tty->device, "su_open"))
+               return -ENODEV;
+       info->count++;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("su_open %s%d, count = %d\n", tty->driver.name, info->line,
+              info->count);
+#endif
+       tty->driver_data = info;
+       info->tty = tty;
+       info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+       if (!tmp_buf) {
+               page = get_free_page(GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
+               if (tmp_buf)
+                       free_page(page);
+               else
+                       tmp_buf = (unsigned char *) page;
+       }
+
+       /*
+        * If the port is the middle of closing, bail out now
+        */
+       if (tty_hung_up_p(filp) ||
+           (info->flags & ASYNC_CLOSING)) {
+               if (info->flags & ASYNC_CLOSING)
+                       interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+               return ((info->flags & ASYNC_HUP_NOTIFY) ?
+                       -EAGAIN : -ERESTARTSYS);
+#else
+               return -EAGAIN;
+#endif
+       }
+       
+       /*
+        * Start up serial port
+        */
+       retval = startup(info);
+       if (retval)
+               return retval;
+
+       MOD_INC_USE_COUNT;
+       retval = block_til_ready(tty, filp, info);
+       if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+               printk("su_open returning after block_til_ready with %d\n",
+                      retval);
+#endif
+               return retval;
+       }
+
+       if ((info->count == 1) &&
+           (info->flags & ASYNC_SPLIT_TERMIOS)) {
+               if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+                       *tty->termios = info->normal_termios;
+               else 
+                       *tty->termios = info->callout_termios;
+               change_speed(info);
+       }
+#ifdef CONFIG_SERIAL_CONSOLE
+       if (sercons.cflag && sercons.index == line) {
+               tty->termios->c_cflag = sercons.cflag;
+               sercons.cflag = 0;
+       change_speed(info);
+       }
+#endif
+       info->session = current->session;
+       info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+       printk("su_open ttys%d successful...", info->line);
+#endif
+       return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static inline int line_info(char *buf, struct su_struct *info)
+{
+       char    stat_buf[30], control, status;
+       int     ret;
+
+       ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+                     info->line, uart_config[info->type].name, 
+                     (int)info->port, info->irq);
+
+       if (info->port == 0 || info->type == PORT_UNKNOWN) {
+               ret += sprintf(buf+ret, "\n");
+               return ret;
+       }
+
+       /*
+        * Figure out the current RS-232 lines
+        */
+       cli();
+       status = serial_in(info, UART_MSR);
+       control = info ? info->MCR : serial_in(info, UART_MCR);
+       sti();
+
+       stat_buf[0] = 0;
+       stat_buf[1] = 0;
+       if (control & UART_MCR_RTS)
+               strcat(stat_buf, "|RTS");
+       if (status & UART_MSR_CTS)
+               strcat(stat_buf, "|CTS");
+       if (control & UART_MCR_DTR)
+               strcat(stat_buf, "|DTR");
+       if (status & UART_MSR_DSR)
+               strcat(stat_buf, "|DSR");
+       if (status & UART_MSR_DCD)
+               strcat(stat_buf, "|CD");
+       if (status & UART_MSR_RI)
+               strcat(stat_buf, "|RI");
+
+       if (info->quot) {
+               ret += sprintf(buf+ret, " baud:%d",
+                              info->baud_base / info->quot);
+       }
+
+       ret += sprintf(buf+ret, " tx:%d rx:%d",
+                     info->icount.tx, info->icount.rx);
+
+       if (info->icount.frame)
+               ret += sprintf(buf+ret, " fe:%d", info->icount.frame);
+
+       if (info->icount.parity)
+               ret += sprintf(buf+ret, " pe:%d", info->icount.parity);
+
+       if (info->icount.brk)
+               ret += sprintf(buf+ret, " brk:%d", info->icount.brk);   
+
+       if (info->icount.overrun)
+               ret += sprintf(buf+ret, " oe:%d", info->icount.overrun);
+
+       /*
+        * Last thing is the RS-232 status lines
+        */
+       ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+       return ret;
+}
+
+int su_read_proc(char *page, char **start, off_t off, int count,
+                int *eof, void *data)
+{
+       int i, len = 0;
+       off_t   begin = 0;
+
+       len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+       for (i = 0; i < NR_PORTS && len < 4000; i++) {
+               len += line_info(page + len, &su_table[i]);
+               if (len+begin > off+count)
+                       goto done;
+               if (len+begin < off) {
+                       begin += len;
+                       len = 0;
+               }
+       }
+       *eof = 1;
+done:
+       if (off >= len+begin)
+               return 0;
+       *start = page + (begin-off);
+       return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * su_init() and friends
+ *
+ * su_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_su_version(void)
+{
+       printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+#ifdef CONFIG_SERIAL_MANY_PORTS
+       printk(" MANY_PORTS");
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_MULTIPORT
+       printk(" MULTIPORT");
+#define SERIAL_OPT
+#endif
+#ifdef CONFIG_SERIAL_SHARE_IRQ
+       printk(" SHARE_IRQ");
+#endif
+#define SERIAL_OPT
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+       printk(" DETECT_IRQ");
+#endif
+#ifdef SERIAL_OPT
+       printk(" enabled\n");
+#else
+       printk(" no serial options enabled\n");
+#endif
+#undef SERIAL_OPT
+}
+
+/*
+ * This routine is called by su_init() to initialize a specific serial
+ * port.  It determines what type of UART chip this serial port is
+ * using: 8250, 16450, 16550, 16550A.  The important question is
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
+ */
+static void
+autoconfig(struct su_struct *info)
+{
+       unsigned char status1, status2, scratch, scratch2;
+#ifdef __sparc_v9__
+       struct linux_ebus_device *dev = 0;
+       struct linux_ebus *ebus;
+#else
+       struct linux_prom_registers reg0;
+#endif
+       unsigned long flags;
+
+#ifdef __sparc_v9__
+       for_each_ebus(ebus) {
+               for_each_ebusdev(dev, ebus) {
+                       if (!strncmp(dev->prom_name, "su", 2)) {
+                               if (dev->prom_node == info->kbd_node)
+                                       goto ebus_done;
+                               if (dev->prom_node == info->ms_node)
+                                       goto ebus_done;
+                       }
+               }
+       }
+ebus_done:
+       if (!dev)
+               return;
+
+       info->port = dev->base_address[0];
+       if (check_region(info->port, 8))
+               return;
+
+       info->irq = dev->irqs[0];
+
+#ifdef DEBUG_SERIAL_OPEN
+       printk("Found 'su' at %016lx IRQ %s\n", dev->base_address[0],
+              __irq_itoa(dev->irqs[0]));
+#endif
+
+#else
+       if (info->port_node == 0) {
+               return;
+       }
+       if (prom_getproperty(info->port_node, "reg",
+           (char *)&reg0, sizeof(reg0)) == -1) {
+               prom_printf("su: no \"reg\" property\n");
+               return;
+       }
+       prom_apply_obio_ranges(&reg0, 1);
+       if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr,
+           0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) {
+               prom_printf("su: cannot map\n");
+               return;
+       }
+       /*
+        * There is no intr property on MrCoffee, so hardwire it. Krups?
+        */
+       info->irq = 13;
+#endif
+
+       info->magic = SERIAL_MAGIC;
+
+       save_flags(flags); cli();
+       
+       /*
+        * Do a simple existence test first; if we fail this, there's
+        * no point trying anything else.
+        *
+        * 0x80 is used as a nonsense port to prevent against false
+        * positives due to ISA bus float.  The assumption is that
+        * 0x80 is a non-existent port; which should be safe since
+        * include/asm/io.h also makes this assumption.
+        */
+       scratch = serial_in(info, UART_IER);
+       su_outb(info, UART_IER, 0);
+       scratch2 = serial_in(info, UART_IER);
+       su_outb(info, UART_IER, scratch);
+       if (scratch2) {
+               restore_flags(flags);
+               return;         /* We failed; there's nothing here */
+       }
+
+#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
+       scratch = serial_in(info, UART_MCR);
+       su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
+       scratch2 = serial_in(info, UART_MSR);
+       su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+       status1 = serial_in(info, UART_MSR) & 0xF0;
+       su_outb(info, UART_MCR, scratch);
+       su_outb(info, UART_MSR, scratch2);
+       if (status1 != 0x90) {
+               restore_flags(flags);
+               return;
+       } 
+#endif
+
+       scratch2 = serial_in(info, UART_LCR);
+       su_outb(info, UART_LCR, 0xBF);  /* set up for StarTech test */
+       su_outb(info, UART_EFR, 0);     /* EFR is the same as FCR */
+       su_outb(info, UART_LCR, 0);
+       su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+       scratch = serial_in(info, UART_IIR) >> 6;
+       switch (scratch) {
+               case 0:
+                       info->type = PORT_16450;
+                       break;
+               case 1:
+                       info->type = PORT_UNKNOWN;
+                       break;
+               case 2:
+                       info->type = PORT_16550;
+                       break;
+               case 3:
+                       info->type = PORT_16550A;
+                       break;
+       }
+       if (info->type == PORT_16550A) {
+               /* Check for Startech UART's */
+               su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+               if (su_inb(info, UART_EFR) == 0) {
+                       info->type = PORT_16650;
+               } else {
+                       su_outb(info, UART_LCR, 0xBF);
+                       if (su_inb(info, UART_EFR) == 0)
+                               info->type = PORT_16650V2;
+               }
+       }
+       if (info->type == PORT_16550A) {
+               /* Check for TI 16750 */
+               su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+               su_outb(info, UART_FCR,
+                           UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+               scratch = su_inb(info, UART_IIR) >> 5;
+               if (scratch == 7) {
+                       su_outb(info, UART_LCR, 0);
+                       su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+                       scratch = su_inb(info, UART_IIR) >> 5;
+                       if (scratch == 6)
+                               info->type = PORT_16750;
+               }
+               su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+       }
+       su_outb(info, UART_LCR, scratch2);
+       if (info->type == PORT_16450) {
+               scratch = su_inb(info, UART_SCR);
+               su_outb(info, UART_SCR, 0xa5);
+               status1 = su_inb(info, UART_SCR);
+               su_outb(info, UART_SCR, 0x5a);
+               status2 = su_inb(info, UART_SCR);
+               su_outb(info, UART_SCR, scratch);
+
+               if ((status1 != 0xa5) || (status2 != 0x5a))
+                       info->type = PORT_8250;
+       }
+       info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size;
+
+       if (info->type == PORT_UNKNOWN) {
+               restore_flags(flags);
+               return;
+       }
+
+#ifdef __sparc_v9__
+       sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+       request_region(info->port, 8, info->name);
+#else
+       strcpy(info->name, "su(serial)");
+#endif
+
+       /*
+        * Reset the UART.
+        */
+       su_outb(info, UART_MCR, 0x00);
+       su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+                                    UART_FCR_CLEAR_XMIT));
+       su_inb(info, UART_RX);
+
+       restore_flags(flags);
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+__initfunc(int su_init(void))
+{
+       int i;
+       struct su_struct *info;
+       extern void atomwide_serial_init (void);
+       extern void dualsp_serial_init (void);
+       
+#ifdef CONFIG_ATOMWIDE_SERIAL
+       atomwide_serial_init ();
+#endif
+#ifdef CONFIG_DUALSP_SERIAL
+       dualsp_serial_init ();
+#endif
+       
+       init_bh(SERIAL_BH, do_serial_bh);
+       timer_table[RS_TIMER].fn = su_timer;
+       timer_table[RS_TIMER].expires = 0;
+
+       for (i = 0; i < NR_IRQS; i++) {
+               IRQ_ports[i] = 0;
+               IRQ_timeout[i] = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT
+               memset(&rs_multiport[i], 0,
+                      sizeof(struct rs_multiport_struct));
+#endif
+       }
+#if 0  /* Must be shared with keyboard on MrCoffee. */
+#ifdef CONFIG_SERIAL_CONSOLE
+       /*
+        *      The interrupt of the serial console port
+        *      can't be shared.
+        */
+       if (sercons.flags & CON_CONSDEV) {
+               for(i = 0; i < NR_PORTS; i++)
+                       if (i != sercons.index &&
+                           su_table[i].irq == su_table[sercons.index].irq)
+                               su_table[i].irq = 0;
+       }
+#endif
+#endif
+       show_su_version();
+
+       /* Initialize the tty_driver structure */
+
+       memset(&serial_driver, 0, sizeof(struct tty_driver));
+       serial_driver.magic = TTY_DRIVER_MAGIC;
+       serial_driver.driver_name = "su";
+       serial_driver.name = "ttyS";
+       serial_driver.major = TTY_MAJOR;
+       serial_driver.minor_start = 64;
+       serial_driver.num = NR_PORTS;
+       serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver.subtype = SERIAL_TYPE_NORMAL;
+       serial_driver.init_termios = tty_std_termios;
+       serial_driver.init_termios.c_cflag =
+               B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       serial_driver.flags = TTY_DRIVER_REAL_RAW;
+       serial_driver.refcount = &serial_refcount;
+       serial_driver.table = serial_table;
+       serial_driver.termios = serial_termios;
+       serial_driver.termios_locked = serial_termios_locked;
+
+       serial_driver.open = su_open;
+       serial_driver.close = su_close;
+       serial_driver.write = su_write;
+       serial_driver.put_char = su_put_char;
+       serial_driver.flush_chars = su_flush_chars;
+       serial_driver.write_room = su_write_room;
+       serial_driver.chars_in_buffer = su_chars_in_buffer;
+       serial_driver.flush_buffer = su_flush_buffer;
+       serial_driver.ioctl = su_ioctl;
+       serial_driver.throttle = su_throttle;
+       serial_driver.unthrottle = su_unthrottle;
+       serial_driver.send_xchar = su_send_xchar;
+       serial_driver.set_termios = su_set_termios;
+       serial_driver.stop = su_stop;
+       serial_driver.start = su_start;
+       serial_driver.hangup = su_hangup;
+       serial_driver.break_ctl = su_break;
+       serial_driver.wait_until_sent = su_wait_until_sent;
+       serial_driver.read_proc = su_read_proc;
+
+       /*
+        * The callout device is just like normal device except for
+        * major number and the subtype code.
+        */
+       callout_driver = serial_driver;
+       callout_driver.name = "cua";
+       callout_driver.major = TTYAUX_MAJOR;
+       callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+       callout_driver.read_proc = 0;
+       callout_driver.proc_entry = 0;
+
+       if (tty_register_driver(&serial_driver))
+               panic("Couldn't register regular su\n");
+       if (tty_register_driver(&callout_driver))
+               panic("Couldn't register callout su\n");
+
+       for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
+               info->magic = SSTATE_MAGIC;
+               info->line = i;
+               info->type = PORT_UNKNOWN;
+               info->baud_base = BAUD_BASE;
+               /* info->flags = 0; */
+               info->custom_divisor = 0;
+               info->close_delay = 5*HZ/10;
+               info->closing_wait = 30*HZ;
+               info->callout_termios = callout_driver.init_termios;
+               info->normal_termios = serial_driver.init_termios;
+               info->icount.cts = info->icount.dsr = 
+                       info->icount.rng = info->icount.dcd = 0;
+               info->icount.rx = info->icount.tx = 0;
+               info->icount.frame = info->icount.parity = 0;
+               info->icount.overrun = info->icount.brk = 0;
+               info->tqueue.routine = do_softint;
+               info->tqueue.data = info;
+
+               if (info->kbd_node)
+                       info->cflag = B1200 | CS8 | CREAD;
+               else if (info->ms_node)
+                       info->cflag = B4800 | CS8 | CREAD;
+               else
+                       info->cflag = B9600 | CS8 | CREAD;
+
+               autoconfig(info);
+               if (info->type == PORT_UNKNOWN)
+                       continue;
+
+               printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+                      info->name, info->port, __irq_itoa(info->irq),
+                      uart_config[info->type].name);
+
+               /*
+                * We want startup here because we want mouse and keyboard
+                * working without opening. On SPARC console will work
+                * without startup.
+                */
+               if (info->kbd_node) {
+                       startup(info);
+                       keyboard_zsinit(su_put_char_kbd);
+               } else if (info->ms_node) {
+               startup(info);
+                       sun_mouse_zsinit();
+       }
+       }
+
+       return 0;
+}
+
+__initfunc(int su_probe (unsigned long *memory_start))
+{
+       struct su_struct *info = su_table;
+        int node, enode, tnode, sunode;
+       int kbnode = 0, msnode = 0;
+       int devices = 0;
+       char prop[128];
+       int len;
+
+       /*
+        * Find su on MrCoffee. We return OK code if find any.
+        * Then su_init finds every one and initializes them.
+        * We do this early because MrCoffee got no aliases.
+        */
+       node = prom_getchild(prom_root_node);
+       if ((node = prom_searchsiblings(node, "obio")) != 0) {
+               if ((sunode = prom_getchild(node)) != 0) {
+                       if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
+                               info->port_node = sunode;
+#ifdef CONFIG_SERIAL_CONSOLE
+                               /*
+                                * Console must be initiated after the generic initialization.
+                                * sunserial_setinitfunc inverts order, so call this before next one.
+                                */
+                               sunserial_setinitfunc(memory_start, su_serial_console_init);
+#endif
+                               sunserial_setinitfunc(memory_start, su_init);
+                               return 0;
+                       }
+               }
+       }
+
+       /*
+        * Get the nodes for keyboard and mouse from 'aliases'...
+        */
+        node = prom_getchild(prom_root_node);
+       node = prom_searchsiblings(node, "aliases");
+       if (!node)
+               return -ENODEV;
+
+       len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
+       if (len > 0) {
+               prop[len] = 0;
+               kbnode = prom_finddevice(prop);
+       }
+       if (!kbnode)
+               return -ENODEV;
+
+       len = prom_getproperty(node, "mouse", prop, sizeof(prop));
+       if (len > 0) {
+               prop[len] = 0;
+               msnode = prom_finddevice(prop);
+       }
+       if (!msnode)
+               return -ENODEV;
+
+       /*
+        * Find matching EBus nodes...
+        */
+        node = prom_getchild(prom_root_node);
+       if ((node = prom_searchsiblings(node, "pci")) == 0) {
+               return -ENODEV;         /* Plain sparc */
+       }
+
+       /*
+        * Check for SUNW,sabre on Ultra 5/10/AXi.
+        */
+       len = prom_getproperty(node, "model", prop, sizeof(prop));
+       if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
+               node = prom_getchild(node);
+               node = prom_searchsiblings(node, "pci");
+       }
+
+       /*
+        * For each PCI bus...
+        */
+       while (node) {
+               enode = prom_getchild(node);
+               enode = prom_searchsiblings(enode, "ebus");
+
+               /*
+                * For each EBus on this PCI...
+                */
+               while (enode) {
+                       sunode = prom_getchild(enode);
+                       tnode = prom_searchsiblings(sunode, "su");
+                       if (!tnode)
+                               tnode = prom_searchsiblings(sunode, "su_pnp");
+                       sunode = tnode;
+
+                       /*
+                        * For each 'su' on this EBus...
+                        */
+                       while (sunode) {
+                               /*
+                                * Does it match?
+                                */
+                               if (sunode == kbnode) {
+                                       info->kbd_node = sunode;
+                                       ++info;
+                                       ++devices;
+                               }
+                               if (sunode == msnode) {
+                                       info->ms_node = sunode;
+                                       ++info;
+                                       ++devices;
+                               }
+
+                               /*
+                                * Found everything we need?
+                                */
+                               if (devices == NR_PORTS)
+                                       goto found;
+
+                               sunode = prom_getsibling(sunode);
+                               tnode = prom_searchsiblings(sunode, "su");
+                               if (!tnode)
+                                       tnode = prom_searchsiblings(sunode,
+                                                                   "su_pnp");
+                               sunode = tnode;
+                       }
+                       enode = prom_getsibling(enode);
+                       enode = prom_searchsiblings(enode, "ebus");
+               }
+               node = prom_getsibling(node);
+               node = prom_searchsiblings(node, "pci");
+       }
+       return -ENODEV;
+
+found:
+        sunserial_setinitfunc(memory_start, su_init);
+        rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
+       sunkbd_setinitfunc(memory_start, sun_kbd_init);
+       kbd_ops.compute_shiftstate = sun_compute_shiftstate;
+       kbd_ops.setledstate = sun_setledstate;
+       kbd_ops.getledstate = sun_getledstate;
+       kbd_ops.setkeycode = sun_setkeycode;
+       kbd_ops.getkeycode = sun_getkeycode;
+#ifdef CONFIG_PCI
+       sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
+                              sun_func_buf, sun_func_table,
+                              sun_funcbufsize, sun_funcbufleft,
+                              sun_accent_table, sun_accent_table_size);
+#endif
+       return 0;
+}
+
+#if 0
+#ifdef MODULE
+int init_module(void)
+{
+       return su_init();       /* rs_init? su_probe? XXX */
+}
+
+void cleanup_module(void) 
+{
+       unsigned long flags;
+       int e1, e2;
+       int i;
+
+       /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+       save_flags(flags);
+       cli();
+       timer_active &= ~(1 << RS_TIMER);
+       timer_table[RS_TIMER].fn = NULL;
+       timer_table[RS_TIMER].expires = 0;
+        remove_bh(SERIAL_BH);
+       if ((e1 = tty_unregister_driver(&serial_driver)))
+               printk("SERIAL: failed to unregister serial driver (%d)\n",
+                      e1);
+       if ((e2 = tty_unregister_driver(&callout_driver)))
+               printk("SERIAL: failed to unregister callout driver (%d)\n", 
+                      e2);
+       restore_flags(flags);
+
+       for (i = 0; i < NR_PORTS; i++) {
+               if (su_table[i].type != PORT_UNKNOWN)
+                       release_region(su_table[i].port, 8);
+       }
+       if (tmp_buf) {
+               free_page((unsigned long) tmp_buf);
+               tmp_buf = NULL;
+       }
+}
+#endif /* MODULE */
+#endif /* deadwood */
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ *     Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct su_struct *info)
+{
+       int lsr;
+       unsigned int tmout = 1000000;
+
+       do {
+               lsr = su_inb(info, UART_LSR);
+               if (--tmout == 0)
+                       break;
+       } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+}
+
+/*
+ *     Print a string to the serial port trying not to disturb
+ *     any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+                               unsigned count)
+{
+       struct su_struct *info;
+       int ier;
+       unsigned i;
+
+       info = su_table + co->index;
+       /*
+        *      First save the IER then disable the interrupts
+        */
+       ier = su_inb(info, UART_IER);
+       su_outb(info, UART_IER, 0x00);
+
+       /*
+        *      Now, do each character
+        */
+       for (i = 0; i < count; i++, s++) {
+               wait_for_xmitr(info);
+
+               /*
+                *      Send the character out.
+                *      If a LF, also do CR...
+                */
+               su_outb(info, UART_TX, *s);
+               if (*s == 10) {
+                       wait_for_xmitr(info);
+                       su_outb(info, UART_TX, 13);
+               }
+       }
+
+       /*
+        *      Finally, Wait for transmitter & holding register to empty
+        *      and restore the IER
+        */
+       wait_for_xmitr(info);
+       su_outb(info, UART_IER, ier);
+}
+
+/*
+ *     Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+       struct su_struct *info;
+       int ier;
+       int lsr;
+       int c;
+
+       info = su_table + co->index;
+
+       /*
+        *      First save the IER then disable the interrupts so
+        *      that the real driver for the port does not get the
+        *      character.
+        */
+       ier = su_inb(info, UART_IER);
+       su_outb(info, UART_IER, 0x00);
+
+       do {
+               lsr = su_inb(info, UART_LSR);
+       } while (!(lsr & UART_LSR_DR));
+       c = su_inb(info, UART_RX);
+
+       /*
+        *      Restore the interrupts
+        */
+       su_outb(info, UART_IER, ier);
+
+       return c;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+       return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ *     Setup initial baud/bits/parity. We do two things here:
+ *     - construct a cflag setting for the first su_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+       struct su_struct *info;
+       unsigned cval;
+       int     baud = 9600;
+       int     bits = 8;
+       int     parity = 'n';
+       int     cflag = CREAD | HUPCL | CLOCAL;
+       int     quot = 0;
+       char    *s;
+
+       if (options) {
+               baud = simple_strtoul(options, NULL, 10);
+               s = options;
+               while(*s >= '0' && *s <= '9')
+                       s++;
+               if (*s) parity = *s++;
+               if (*s) bits   = *s - '0';
+       }
+
+       /*
+        *      Now construct a cflag setting.
+        */
+       switch(baud) {
+               case 1200:
+                       cflag |= B1200;
+                       break;
+               case 2400:
+                       cflag |= B2400;
+                       break;
+               case 4800:
+                       cflag |= B4800;
+                       break;
+               case 19200:
+                       cflag |= B19200;
+                       break;
+               case 38400:
+                       cflag |= B38400;
+                       break;
+               case 57600:
+                       cflag |= B57600;
+                       break;
+               case 115200:
+                       cflag |= B115200;
+                       break;
+               case 9600:
+               default:
+                       cflag |= B9600;
+                       break;
+       }
+       switch(bits) {
+               case 7:
+                       cflag |= CS7;
+                       break;
+               default:
+               case 8:
+                       cflag |= CS8;
+                       break;
+       }
+       switch(parity) {
+               case 'o': case 'O':
+                       cflag |= PARODD;
+                       break;
+               case 'e': case 'E':
+                       cflag |= PARENB;
+                       break;
+       }
+       co->cflag = cflag;
+
+       /*
+        *      Divisor, bytesize and parity
+        */
+       info = su_table + co->index;
+       quot = BAUD_BASE / baud;
+       cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+       cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+       cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+       if (cflag & PARENB)
+               cval |= UART_LCR_PARITY;
+       if (!(cflag & PARODD))
+               cval |= UART_LCR_EPAR;
+
+       /*
+        *      Disable UART interrupts, set DTR and RTS high
+        *      and set speed.
+        */
+       su_outb(info, UART_IER, 0);
+       su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+       su_outb(info, UART_LCR, cval | UART_LCR_DLAB);  /* set DLAB */
+       su_outb(info, UART_DLL, quot & 0xff);           /* LS of divisor */
+       su_outb(info, UART_DLM, quot >> 8);             /* MS of divisor */
+       su_outb(info, UART_LCR, cval);                  /* reset DLAB */
+       info->quot = quot;
+
+       /*
+        *      If we read 0xff from the LSR, there is no UART here.
+        */
+       if (su_inb(info, UART_LSR) == 0xff)
+               return -1;
+
+       return 0;
+}
+
+static struct console sercons = {
+       "ttyS",
+       serial_console_write,
+       NULL,
+       serial_console_device,
+       serial_console_wait_key,
+       NULL,
+       serial_console_setup,
+       CON_PRINTBUFFER,
+       -1,
+       0,
+       NULL
+};
+
+/*
+ *     Register console.
+ */
+__initfunc(int su_serial_console_init(void))
+{
+       extern int con_is_present(void);
+
+       if (con_is_present())
+               return 0;
+       if (serial_console == 0)
+               return 0;
+       if (su_table[0].port == 0 || su_table[0].port_node == 0)
+               return 0;
+       sercons.index = 0;
+       register_console(&sercons);
+       return 0;
+}
+
+#endif /* CONFIG_SERIAL_CONSOLE */
index 59b77a5e4d265edb6393a9c7f1f3b436755a4ada..b720afbec4bc0dfaaece7ca439c568de8c83b559 100644 (file)
@@ -1325,11 +1325,11 @@ kbd_read (struct file *f, char *buffer, size_t count, loff_t *ppos)
 }
 
 /* Needed by X */
-static int kbd_fasync (struct file *filp, int on)
+static int kbd_fasync (int fd, struct file *filp, int on)
 {
        int retval;
 
-       retval = fasync_helper (filp, on, &kb_fasync);
+       retval = fasync_helper (fd, filp, on, &kb_fasync);
        if (retval < 0)
                return retval;
        return 0;
@@ -1479,7 +1479,7 @@ kbd_close (struct inode *i, struct file *f)
        kbd_redirected = 0;
        kbd_opened = 0;
 
-       kbd_fasync (f, 0);
+       kbd_fasync (-1, f, 0);
        return 0;
 }
 
index 3a6d672fbf577ee3d0796021383482a6da80e5d1..1c000b661b64d491f3dee88f8a618509f69c1ace 100644 (file)
@@ -329,11 +329,11 @@ sun_mouse_open(struct inode * inode, struct file * file)
        return 0;
 }
 
-static int sun_mouse_fasync (struct file *filp, int on)
+static int sun_mouse_fasync (int fd, struct file *filp, int on)
 {
        int retval;
 
-       retval = fasync_helper (filp, on, &sunmouse.fasync);
+       retval = fasync_helper (fd, filp, on, &sunmouse.fasync);
        if (retval < 0)
                return retval;
        return 0;
@@ -342,7 +342,7 @@ static int sun_mouse_fasync (struct file *filp, int on)
 static int
 sun_mouse_close(struct inode *inode, struct file *file)
 {
-       sun_mouse_fasync (file, 0);
+       sun_mouse_fasync (-1, file, 0);
        if (--sunmouse.active)
                return 0;
        sunmouse.ready = 0;
index 5a45c85ae0b0fb976028be4b920ecb76211092b4..ccc5496e8647ac0fd8c202a8eddd3c48349c3308 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sunserial.c,v 1.61 1998/07/28 13:59:52 jj Exp $
+/* $Id: sunserial.c,v 1.66 1998/09/21 05:48:48 jj Exp $
  * serial.c: Serial port driver infrastructure for the Sparc.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -69,8 +69,9 @@ rs_kgdb_hook(int channel))
        rs_ops.rs_kgdb_hook(channel);
 }
 
-__initfunc(void serial_console_init(void))
+__initfunc(long serial_console_init(long kmem_start, long kmem_end))
 {
+       return kmem_start;
 }
 
 void rs_change_mouse_baud(int baud)
@@ -169,7 +170,6 @@ int getkeycode (unsigned int scancode)
        return kbd_ops.getkeycode(scancode);
 }
 
-
 void
 sunserial_setinitfunc(unsigned long *memory_start, int (*init) (void))
 {
@@ -343,29 +343,41 @@ sunkbd_install_keymaps(unsigned long *memory_start,
 }
 #endif
 
+extern int su_probe(unsigned long *);
 extern int zs_probe(unsigned long *);
 #ifdef CONFIG_SAB82532
 extern int sab82532_probe(unsigned long *);
 #endif
 #ifdef CONFIG_PCI
 extern int ps2kbd_probe(unsigned long *);
-extern int su_probe(unsigned long *);
 #endif
 
 __initfunc(unsigned long
 sun_serial_setup(unsigned long memory_start))
 {
-       int ret = -ENODEV;
-
-       /* Probe for controllers. */
-       ret = zs_probe(&memory_start);
-       if (!ret)
+       int ret = 1;
+       
+#if defined(CONFIG_PCI) && !defined(__sparc_v9__)
+       /*
+        * Probing sequence on sparc differs from sparc64.
+        * Keyboard is probed ahead of su because we want su function
+        * when keyboard is active. su is probed ahead of zs in order to
+        * get console on MrCoffee with fine but disconnected zs.
+        */
+       if (!serial_console)
+               ps2kbd_probe(&memory_start);
+       if (su_probe(&memory_start) == 0)
                return memory_start;
+#endif
 
+       if (zs_probe(&memory_start) == 0)
+               return memory_start;
+               
 #ifdef CONFIG_SAB82532
        ret = sab82532_probe(&memory_start);
 #endif
-#ifdef CONFIG_PCI
+
+#if defined(CONFIG_PCI) && defined(__sparc_v9__)
        /*
         * Keyboard serial devices.
         *
@@ -384,6 +396,7 @@ sun_serial_setup(unsigned long memory_start))
                        return memory_start;
        }
 #endif
+
        if (!ret)
                return memory_start;
 
index b16581679f47406fd9b29f80a78daae9d8060f00..e3c5d13c4f95c1bc710ad0d959bfa545bdb83621 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
-#include <linux/uaccess.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -31,6 +30,7 @@
 #include <asm/delay.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/uaccess.h>
 
 #define VFC_MAJOR (60)
 
index 9bc0b27171b1a1ea2603e8c6255f9a137123a31f..bb0ce2bf2efd6669e981a652e7fe87aa95798fab 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: zs.c,v 1.26 1998/08/03 23:58:14 davem Exp $
+/* $Id: zs.c,v 1.29 1998/09/21 05:06:53 jj Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
- * Fixes by Pete A. Zaitcev <zaitcev@ipmce.su>.
+ * Fixes by Pete A. Zaitcev <zaitcev@metabyte.com>.
  */
 
 #include <linux/errno.h>
 #include <asm/sbus.h>
 #ifdef __sparc_v9__
 #include <asm/fhc.h>
+#endif
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #endif
-#endif
 
 #include "sunserial.h"
 #include "zs.h"
@@ -111,7 +111,7 @@ static unsigned char zscons_regs[16] = {
 
 DECLARE_TASK_QUEUE(tq_serial);
 
-struct tty_driver serial_driver, callout_driver;
+static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
 /* serial subtype definitions */
@@ -1808,7 +1808,7 @@ int zs_open(struct tty_struct *tty, struct file * filp)
 
 static void show_serial_version(void)
 {
-       char *revision = "$Revision: 1.26 $";
+       char *revision = "$Revision: 1.29 $";
        char *version, *p;
 
        version = strchr(revision, ' ');
index 31153efbc7481abd184f2420482728d6cdeef993..ec7f2a275761f4684e30904b142ebc1de448ef51 100644 (file)
@@ -138,24 +138,24 @@ __initfunc(void sun4_dvma_init(void))
        struct Linux_SBus_DMA *dchain;
 
        if(sun4_dma_physaddr) {
-       dma = kmalloc(sizeof(struct Linux_SBus_DMA), GFP_ATOMIC);
+               dma = kmalloc(sizeof(struct Linux_SBus_DMA), GFP_ATOMIC);
 
-       /* No SBUS */
-       dma->SBus_dev = 0x0;
+               /* No SBUS */
+               dma->SBus_dev = 0x0;
 
-       /* Only one DMA device */
-       dma_chain=dma;
+               /* Only one DMA device */
+               dma_chain=dma;
 
-       dma->regs = (struct sparc_dma_registers *)
-               sparc_alloc_io (sun4_dma_physaddr, 0,
-                               PAGE_SIZE, "dma", 0x0, 0x0);
+               dma->regs = (struct sparc_dma_registers *)
+                       sparc_alloc_io (sun4_dma_physaddr, 0,
+                                       PAGE_SIZE, "dma", 0x0, 0x0);
 
-       /* No prom node */
-       dma->node = 0x0;
+               /* No prom node */
+               dma->node = 0x0;
 
-       init_one_dvma(dma, 0);
+               init_one_dvma(dma, 0);
        } else {
-         dma_chain=0x0;
+               dma_chain=0x0;
        }
 }
 
index d3922b27ae328b727f6f72ea719080fbf078059a..7ea65c98e04d329b8da43b3307dbaa940a01e46e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.69 1998/07/28 16:53:11 jj Exp $
+/* $Id: sbus.c,v 1.72 1998/09/05 17:25:51 jj Exp $
  * sbus.c:  SBus support routines.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -9,6 +9,7 @@
 #include <linux/config.h>
 #include <linux/init.h>
 #include <linux/malloc.h>
+#include <linux/pci.h>
 
 #include <asm/system.h>
 #include <asm/sbus.h>
@@ -246,7 +247,7 @@ __initfunc(void sbus_init(void))
        int num_sbus = 0;  /* How many did we find? */
        
 #ifdef CONFIG_SUN4
-       return sun4_init();
+       return sun4_dvma_init();
 #endif
 
        topnd = prom_getchild(prom_root_node);
@@ -257,7 +258,10 @@ __initfunc(void sbus_init(void))
                nd = prom_searchsiblings(topnd, "sbus");
                if(nd == 0) {
 #ifdef CONFIG_PCI
-                       /* printk("SBUS: No SBUS's found.\n"); */
+                       if (!pcibios_present()) {       
+                               prom_printf("Neither SBUS nor PCI found.\n");
+                               prom_halt();
+                       }
                        return;
 #else
                        prom_printf("YEEE, UltraSparc sbus not found\n");
@@ -418,21 +422,9 @@ __initfunc(void sbus_init(void))
 #endif
 #ifdef __sparc_v9__
        if (sparc_cpu_model == sun4u) {
-               extern void sun4u_start_timers(void);
                extern void clock_probe(void);
 
-               sun4u_start_timers();
                clock_probe();
        }
 #endif
 }
-
-#ifdef CONFIG_SUN4
-
-extern void sun4_dvma_init(void);
-
-__initfunc(void sun4_init(void))
-{
-       sun4_dvma_init();
-}
-#endif
index 37a929adb1a0e30f17a3d685c61c723ec9cc6e15..c3d4102bf405d62c19bf6ab04b6408d3ba64adab 100644 (file)
@@ -564,6 +564,9 @@ static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
 }
 
 static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+#ifndef __sparc_v9__
+static void do_qlogicpti_intr_handler_sun4m(int irq, void *dev_id, struct pt_regs *regs);
+#endif
 
 /* Detect all PTI Qlogic ISP's in the machine. */
 __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
@@ -671,34 +674,30 @@ __initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
 
                        qpti_host->irq = qpti->irq = qpti->qdev->irqs[0];
 
-#ifndef __sparc_v9__
-                       /* Allocate the irq only if necessary. */
+                       /* On Ultra and S{S1,C2}000 we must always call request_irq for each
+                        * qpti, so that imap registers get setup etc.
+                        * But irq values are different in that case anyway...
+                        * Otherwise allocate the irq only if necessary.
+                        */
                        for_each_qlogicpti(qlink) {
                                if((qlink != qpti) && (qpti->irq == qlink->irq)) {
                                        goto qpti_irq_acquired; /* BASIC rulez */
                                }
                        }
-                       if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
-                                      SA_SHIRQ, "PTI Qlogic/ISP SCSI", NULL)) {
-                               printk("Cannot acquire PTI Qlogic/ISP irq line\n");
-                               /* XXX Unmap regs, unregister scsi host, free things. */
-                               continue;
-                       }
-qpti_irq_acquired:
-                       printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->qhost->irq);
-#else
-                       /* On Ultra we must always call request_irq for each
-                        * qpti, so that imap registers get setup etc.
-                        */
-                       if(request_irq(qpti->qhost->irq, do_qlogicpti_intr_handler,
+                       if(request_irq(qpti->qhost->irq, 
+#ifndef __sparc_v9__                   
+                                      (sparc_cpu_model == sun4m || sparc_cpu_model == sun4c) ?
+                                          do_qlogicpti_intr_handler_sun4m :
+#endif
+                                          do_qlogicpti_intr_handler,
                                       SA_SHIRQ, "PTI Qlogic/ISP SCSI", qpti)) {
                                printk("Cannot acquire PTI Qlogic/ISP irq line\n");
                                /* XXX Unmap regs, unregister scsi host, free things. */
                                continue;
                        }
+qpti_irq_acquired:
                        printk("qpti%d: IRQ %s ",
                               qpti->qpti_id, __irq_itoa(qpti->qhost->irq));
-#endif
 
                        /* Figure out our scsi ID on the bus */
                        qpti->scsi_id = prom_getintdefault(qpti->prom_node,
@@ -809,8 +808,8 @@ const char *qlogicpti_info(struct Scsi_Host *host)
        static char buf[80];
        struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
 
-       sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %08lx",
-               host->irq, (unsigned long) qpti->qregs);
+       sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %08lx",
+               __irq_itoa(qpti->qhost->irq), (unsigned long) qpti->qregs);
        return buf;
 }
 
@@ -1068,162 +1067,89 @@ static int qlogicpti_return_status(struct Status_Entry *sts)
        return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
 }
 
-#ifndef __sparc_v9__
-
-static __inline__ void qlogicpti_intr_handler(int irq, void *dev_id,
-                                             struct pt_regs *regs)
+static __inline__ int qlogicpti_intr_handler(struct qlogicpti *qpti)
 {
-       static int running = 0;
        Scsi_Cmnd *Cmnd;
        struct Status_Entry *sts;
-       struct qlogicpti *qpti;
        u_int in_ptr, out_ptr;
-       int again;
-
-       /* It is ok to take irq's on one qpti while the other
-        * is amidst the processing of a reset.
-        */
-       running++;
-
-#if 0 /* XXX Investigate why resets cause this with one controller. */
-       if(running > qptis_running)
-               printk("qlogicpti_intr_handler: yieee, recursive interrupt!\n");
-#endif
-
-       /* Handle all ISP interrupts showing */
-repeat:
-       again = 0;
-       for_each_qlogicpti(qpti) {
-               if(qpti->qregs->sbus_stat & SBUS_STAT_RINT) {
-                       struct qlogicpti_regs *qregs = qpti->qregs;
-
-                       again = 1;
-                       in_ptr = qregs->mbox5;
-                       qregs->hcctrl = HCCTRL_CRIRQ;
-                       if(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK) {
-                               switch(qregs->mbox0) {
-                               case ASYNC_SCSI_BUS_RESET:
-                               case EXECUTION_TIMEOUT_RESET:
-                                       qpti->send_marker = 1;
-                                       break;
-                               case INVALID_COMMAND:
-                               case HOST_INTERFACE_ERROR:
-                               case COMMAND_ERROR:
-                               case COMMAND_PARAM_ERROR:
-                                       break;
-                               }
-                               qregs->sbus_semaphore = 0;
-                       }
+       struct qlogicpti_regs *qregs;
 
-                       /* This looks like a network driver! */
-                       out_ptr = qpti->res_out_ptr;
-                       while(out_ptr != in_ptr) {
-                               sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
-                               out_ptr = NEXT_RES_PTR(out_ptr);
-                               Cmnd = (Scsi_Cmnd *) ((unsigned long)sts->handle);
-                               if(sts->completion_status == CS_RESET_OCCURRED ||
-                                  sts->completion_status == CS_ABORTED ||
-                                  (sts->status_flags & STF_BUS_RESET))
-                                       qpti->send_marker = 1;
-
-                               if(sts->state_flags & SF_GOT_SENSE)
-                                       memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-                                              sizeof(Cmnd->sense_buffer));
-
-                               if(sts->hdr.entry_type == ENTRY_STATUS)
-                                       Cmnd->result = qlogicpti_return_status(sts);
-                               else
-                                       Cmnd->result = DID_ERROR << 16;
-
-                               if(Cmnd->use_sg)
-                                       mmu_release_scsi_sgl((struct mmu_sglist *)
-                                                            Cmnd->buffer,
-                                                            Cmnd->use_sg - 1,
-                                                            qpti->qdev->my_bus);
-                               else
-                                       mmu_release_scsi_one((__u32)Cmnd->SCp.ptr,
-                                                            Cmnd->request_bufflen,
-                                                            qpti->qdev->my_bus);
-
-                               qpti->cmd_count[Cmnd->target]--;
-                               qregs->mbox5 = out_ptr;
-                               Cmnd->scsi_done(Cmnd);
-                       }
-                       qpti->res_out_ptr = out_ptr;
+       if(!(qpti->qregs->sbus_stat & SBUS_STAT_RINT))
+               return 0;
+               
+       qregs = qpti->qregs;
+
+       in_ptr = qregs->mbox5;
+       qregs->hcctrl = HCCTRL_CRIRQ;
+       if(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK) {
+               switch(qregs->mbox0) {
+               case ASYNC_SCSI_BUS_RESET:
+               case EXECUTION_TIMEOUT_RESET:
+                       qpti->send_marker = 1;
+                       break;
+               case INVALID_COMMAND:
+               case HOST_INTERFACE_ERROR:
+               case COMMAND_ERROR:
+               case COMMAND_PARAM_ERROR:
+                       break;
                }
+               qregs->sbus_semaphore = 0;
        }
-       if(again)
-               goto repeat;
-       running--;
+
+       /* This looks like a network driver! */
+       out_ptr = qpti->res_out_ptr;
+       while(out_ptr != in_ptr) {
+               sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
+               out_ptr = NEXT_RES_PTR(out_ptr);
+               Cmnd = (Scsi_Cmnd *) (((unsigned long)sts->handle)+PAGE_OFFSET);
+
+               if(sts->completion_status == CS_RESET_OCCURRED ||
+                  sts->completion_status == CS_ABORTED ||
+                  (sts->status_flags & STF_BUS_RESET))
+                       qpti->send_marker = 1;
+
+               if(sts->state_flags & SF_GOT_SENSE)
+                       memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+                              sizeof(Cmnd->sense_buffer));
+
+               if(sts->hdr.entry_type == ENTRY_STATUS)
+                       Cmnd->result = qlogicpti_return_status(sts);
+               else
+                       Cmnd->result = DID_ERROR << 16;
+
+               if(Cmnd->use_sg)
+                       mmu_release_scsi_sgl((struct mmu_sglist *)
+                                            Cmnd->buffer,
+                                            Cmnd->use_sg - 1,
+                                            qpti->qdev->my_bus);
+               else
+                       mmu_release_scsi_one((__u32)((unsigned long)Cmnd->SCp.ptr),
+                                            Cmnd->request_bufflen,
+                                            qpti->qdev->my_bus);
+
+               qpti->cmd_count[Cmnd->target]--;
+               qregs->mbox5 = out_ptr;
+               Cmnd->scsi_done(Cmnd);
+       }
+       qpti->res_out_ptr = out_ptr;
+       return 1;
 }
 
-#else /* __sparc_v9__ */
+#ifndef __sparc_v9__
 
-static __inline__ void qlogicpti_intr_handler(int irq, void *dev_id,
-                                             struct pt_regs *regs)
+static void do_qlogicpti_intr_handler_sun4m(int irq, void *dev_id, struct pt_regs *regs)
 {
-       struct qlogicpti *qpti = dev_id;
-       Scsi_Cmnd *Cmnd;
-       struct Status_Entry *sts;
-       u_int in_ptr, out_ptr;
-
-       if(qpti->qregs->sbus_stat & SBUS_STAT_RINT) {
-               struct qlogicpti_regs *qregs = qpti->qregs;
-
-               in_ptr = qregs->mbox5;
-               qregs->hcctrl = HCCTRL_CRIRQ;
-               if(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK) {
-                       switch(qregs->mbox0) {
-                       case ASYNC_SCSI_BUS_RESET:
-                       case EXECUTION_TIMEOUT_RESET:
-                               qpti->send_marker = 1;
-                               break;
-                       case INVALID_COMMAND:
-                       case HOST_INTERFACE_ERROR:
-                       case COMMAND_ERROR:
-                       case COMMAND_PARAM_ERROR:
-                               break;
-                       }
-                       qregs->sbus_semaphore = 0;
-               }
+       unsigned long flags;
+       struct qlogicpti *qpti;
+       int again;
 
-               /* This looks like a network driver! */
-               out_ptr = qpti->res_out_ptr;
-               while(out_ptr != in_ptr) {
-                       sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
-                       out_ptr = NEXT_RES_PTR(out_ptr);
-                       Cmnd = (Scsi_Cmnd *) (((unsigned long)sts->handle)+PAGE_OFFSET);
-
-                       if(sts->completion_status == CS_RESET_OCCURRED ||
-                          sts->completion_status == CS_ABORTED ||
-                          (sts->status_flags & STF_BUS_RESET))
-                               qpti->send_marker = 1;
-
-                       if(sts->state_flags & SF_GOT_SENSE)
-                               memcpy(Cmnd->sense_buffer, sts->req_sense_data,
-                                      sizeof(Cmnd->sense_buffer));
-
-                       if(sts->hdr.entry_type == ENTRY_STATUS)
-                               Cmnd->result = qlogicpti_return_status(sts);
-                       else
-                               Cmnd->result = DID_ERROR << 16;
-
-                       if(Cmnd->use_sg)
-                               mmu_release_scsi_sgl((struct mmu_sglist *)
-                                                    Cmnd->buffer,
-                                                    Cmnd->use_sg - 1,
-                                                    qpti->qdev->my_bus);
-                       else
-                               mmu_release_scsi_one((__u32)((unsigned long)Cmnd->SCp.ptr),
-                                                    Cmnd->request_bufflen,
-                                                    qpti->qdev->my_bus);
-
-                       qpti->cmd_count[Cmnd->target]--;
-                       qregs->mbox5 = out_ptr;
-                       Cmnd->scsi_done(Cmnd);
-               }
-               qpti->res_out_ptr = out_ptr;
-       }
+       spin_lock_irqsave(&io_request_lock, flags);
+       again = 0;
+       do {
+               for_each_qlogicpti(qpti)
+                       again |= qlogicpti_intr_handler(qpti);
+       } while (again);
+       spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
 #endif
@@ -1233,7 +1159,7 @@ static void do_qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *reg
        unsigned long flags;
 
        spin_lock_irqsave(&io_request_lock, flags);
-       qlogicpti_intr_handler(irq, dev_id, regs);
+       qlogicpti_intr_handler((struct qlogicpti *)dev_id);
        spin_unlock_irqrestore(&io_request_lock, flags);
 }
 
index 86e346a5c390e5895cd387743bc9c6bff61c1532..c83c83c967527398e34109c8caf830feaca10497 100644 (file)
@@ -572,7 +572,7 @@ __initfunc(void s3triofb_init_of(struct device_node *dp))
     else
        disp.dispsw = &fbcon_cfb8;
 #else
-    disp.dispsw = NULL;
+    disp.dispsw = &fbcon_dummy;
 #endif
     disp.scrollmode = fb_var.accel_flags & FB_ACCELF_TEXT ? 0 : SCROLL_YREDRAW;
 
@@ -610,6 +610,7 @@ __initfunc(void s3triofb_init_of(struct device_node *dp))
     }
 #endif /* CONFIG_FB_COMPAT_XPMAC) */
 
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
     if (register_framebuffer(&fb_info) < 0)
        return;
 
index f7e5ef8162310c4cfa615dcf5f8807606b5319a3..a20259904683f6776cd6daf324ab2596d9742d06 100644 (file)
@@ -220,7 +220,7 @@ acornfb_set_disp(int con)
                break;
 #endif
        default:
-               display->dispsw = NULL;
+               display->dispsw = &fbcon_dummy;
                break;
        }
 }
@@ -381,6 +381,7 @@ acornfb_init(unsigned long mem_start))
        fb_info.switch_con      = acornfb_switch;
        fb_info.updatevar       = acornfb_update_var;
        fb_info.blank           = acornfb_blank;
+       fb_info.flags           = FBINFO_FLAG_DEFAULT;
 
        acornfb_set_disp(-1);
        fb_set_cmap(fb_default_cmap(current_par.palette_size),
index 3060c9d33958f9fd8fbec25120b11ad49dcb8ec4..3913569a3c14581671773b61dd9f6794526048d1 100644 (file)
@@ -1503,7 +1503,7 @@ static int amifb_set_var(struct fb_var_screeninfo *var, int con,
                                break;
 #endif
                            default:
-                               display->dispsw = NULL;
+                               display->dispsw = &fbcon_dummy;
                        }
                        if (fb_info.changevar)
                                (*fb_info.changevar)(con);
@@ -1857,6 +1857,7 @@ default_chipset:
        fb_info.switch_con = &amifbcon_switch;
        fb_info.updatevar = &amifbcon_updatevar;
        fb_info.blank = &amifbcon_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
 
        chipptr = chipalloc(videomemorysize+
                            SPRITEMEMSIZE+
index 173d85b2a9b8abe6b3f2c37c5eb9f224728c5484..527d0ffc5e015ad514b95907b9cf3d57265e2370 100644 (file)
@@ -2845,6 +2845,7 @@ __initfunc(void atafb_init(void))
        fb_info.switch_con = &atafb_switch;
        fb_info.updatevar = &fb_update_var;
        fb_info.blank = &atafb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
        do_fb_set_var(&atafb_predefined[default_par-1], 1);
        strcat(fb_info.modename, fb_var_names[default_par-1][0]);
 
index 2c2e8c5507e9de58f41c2ed78457139691c59e25..51bf7e5ccef5537bf8bfb6928efdb8e6e481044f 100644 (file)
@@ -1,4 +1,4 @@
-/*  $Id: atyfb.c,v 1.75 1998/09/03 20:13:21 geert Exp $
+/*  $Id: atyfb.c,v 1.77 1998/09/14 08:01:46 jj Exp $
  *  linux/drivers/video/atyfb.c -- Frame buffer device for ATI Mach64
  *
  *     Copyright (C) 1997-1998  Geert Uytterhoeven
@@ -1970,9 +1970,6 @@ static int atyfb_get_var(struct fb_var_screeninfo *var, int con,
 static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info,
                           int bpp, int accel)
 {
-           unsigned long flags;
-
-           save_flags(flags); cli();
            switch (bpp) {
 #ifdef FBCON_HAS_CFB8
                case 8:
@@ -2008,7 +2005,6 @@ static void atyfb_set_disp(struct display *disp, struct fb_info_aty *info,
                info->dispsw.cursor = atyfb_cursor;
                info->dispsw.set_font = atyfb_set_font;
            }
-           restore_flags(flags);
 }
 
 
@@ -2522,6 +2518,7 @@ __initfunc(static int aty_init(struct fb_info_aty *info, const char *name))
     info->fb_info.switch_con = &atyfbcon_switch;
     info->fb_info.updatevar = &atyfbcon_updatevar;
     info->fb_info.blank = &atyfbcon_blank;
+    info->fb_info.flags = FBINFO_FLAG_DEFAULT;
 
     for (j = 0; j < 16; j++) {
        k = color_table[j];
index 52de96a9ef2f1c60b920437bf81773aee7dc2709..00db47d103bd216a5c1f1ede750d50abaced1088 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bwtwofb.c,v 1.5 1998/08/23 14:20:40 mj Exp $
+/* $Id: bwtwofb.c,v 1.6 1998/09/15 15:45:35 jj Exp $
  * bwtwofb.c: BWtwo frame buffer driver
  *
  * Copyright (C) 1998 Jakub Jelinek   (jj@ultra.linux.cz)
@@ -135,7 +135,7 @@ static u8 bw2regs_66hz[] __initdata = {
 
 static char idstring[60] __initdata = { 0 };
 
-__initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
+char __init *bwtwofb_init(struct fb_info_sbusfb *fb)
 {
        struct fb_fix_screeninfo *fix = &fb->fix;
        struct display *disp = &fb->disp;
@@ -153,7 +153,7 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
        if (!fb->s.bw2.regs) {
                fb->s.bw2.regs = (struct bw2_regs *)sparc_alloc_io(phys+BWTWO_REGISTER_OFFSET, 0, 
                                sizeof(struct bw2_regs), "bw2_regs", fb->iospace, 0);
-               if (!prom_getbool(fb->prom_node, "width")) {
+               if ((!ARCH_SUN4) && (!prom_getbool(fb->prom_node, "width"))) {
                        /* Ugh, broken PROM didn't initialize us.
                         * Let's deal with this ourselves.
                         */
@@ -201,6 +201,7 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
        fix->line_length = fb->var.xres_virtual>>3;
        
        disp->scrollmode = SCROLL_YREDRAW;
+       disp->inverse = 1;
        if (!disp->screen_base)
                disp->screen_base = (char *)sparc_alloc_io(phys, 0, 
                        type->fb_size, "bw2_ram", fb->iospace, 0);
@@ -208,8 +209,10 @@ __initfunc(char *bwtwofb_init(struct fb_info_sbusfb *fb))
        fb->dispsw = fbcon_mfb;
        fix->visual = FB_VISUAL_MONO01;
 
+#ifndef CONFIG_SUN4
        fb->blank = bw2_blank;
        fb->unblank = bw2_unblank;
+#endif
        fb->margins = bw2_margins;
        
        fb->physbase = phys;
index a2caf6ccb5e590c4e6934928a317a6dfae0a8088..98f734129ccd8f4aeeede52acde86bac7cda57a6 100644 (file)
@@ -67,13 +67,35 @@ struct fb_info_chips {
 #endif
 };
 
-#define write_xr(num,val)      { out_8(p->io_base + 0x3D6, num); out_8(p->io_base + 0x3D7, val); }
-#define read_xr(num,var)       { out_8(p->io_base + 0x3D6, num); var = in_8(p->io_base + 0x3D7); }
-#define write_fr(num,val)      { out_8(p->io_base + 0x3D0, num); out_8(p->io_base + 0x3D1, val); }
-#define read_fr(num,var)       { out_8(p->io_base + 0x3D0, num); var = in_8(p->io_base + 0x3D1); }
-#define write_cr(num,val)      { out_8(p->io_base + 0x3D4, num); out_8(p->io_base + 0x3D5, val); }
-#define read_cr(num,var)       { out_8(p->io_base + 0x3D4, num); var = in_8(p->io_base + 0x3D5); }
-
+#define write_ind(num, val, ap, dp)    do { \
+       out_8(p->io_base + (ap), (num)); out_8(p->io_base + (dp), (val)); \
+} while (0)
+#define read_ind(num, var, ap, dp)     do { \
+       out_8(p->io_base + (ap), (num)); var = in_8(p->io_base + (dp)); \
+} while (0);
+
+/* extension registers */
+#define write_xr(num, val)     write_ind(num, val, 0x3d6, 0x3d7)
+#define read_xr(num, var)      read_ind(num, var, 0x3d6, 0x3d7)
+/* flat panel registers */
+#define write_fr(num, val)     write_ind(num, val, 0x3d0, 0x3d1)
+#define read_fr(num, var)      read_ind(num, var, 0x3d0, 0x3d1)
+/* CRTC registers */
+#define write_cr(num, val)     write_ind(num, val, 0x3d4, 0x3d5)
+#define read_cr(num, var)      read_ind(num, var, 0x3d4, 0x3d5)
+/* graphics registers */
+#define write_gr(num, val)     write_ind(num, val, 0x3ce, 0x3cf)
+#define read_gr(num, var)      read_ind(num, var, 0x3ce, 0x3cf)
+/* sequencer registers */
+#define write_sr(num, val)     write_ind(num, val, 0x3c4, 0x3c5)
+#define read_sr(num, var)      read_ind(num, var, 0x3c4, 0x3c5)
+/* attribute registers - slightly strange */
+#define write_ar(num, val)     do { \
+       in_8(p->io_base + 0x3da); write_ind(num, val, 0x3c0, 0x3c0); \
+} while (0)
+#define read_ar(num, var)      do { \
+       in_8(p->io_base + 0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
+} while (0)
 
 static struct fb_info_chips *all_chips;
 
@@ -289,8 +311,10 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
                             u_int transp, struct fb_info *info)
 {
        struct fb_info_chips *p = (struct fb_info_chips *) info;
+       int hr;
 
-       if (regno > 255)
+       hr = (p->fix.visual != FB_VISUAL_PSEUDOCOLOR)? (regno << 3): regno;
+       if (hr > 255)
                return 1;
        red >>= 8;
        green >>= 8;
@@ -298,7 +322,7 @@ static int chipsfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
        p->palette[regno].red = red;
        p->palette[regno].green = green;
        p->palette[regno].blue = blue;
-       out_8(p->io_base + 0x3c8, regno);
+       out_8(p->io_base + 0x3c8, hr);
        udelay(1);
        out_8(p->io_base + 0x3c9, red);
        out_8(p->io_base + 0x3c9, green);
@@ -334,12 +358,11 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
                if (con == currcon) {
                        write_cr(0x13, 200);            // 16 bit display width (decimal)
                        write_xr(0x81, 0x14);           // 15 bit (TrueColor) color mode
-                       write_xr(0x82, 0x00);           // disable palettes
                        write_xr(0x20, 0x10);           // 16 bit blitter mode
                }
 
                fix->line_length = 800*2;
-               fix->visual = FB_VISUAL_TRUECOLOR;
+               fix->visual = FB_VISUAL_DIRECTCOLOR;
 
                var->red.offset = 10;
                var->green.offset = 5;
@@ -350,13 +373,12 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
                disp->dispsw = &fbcon_cfb16;
                disp->dispsw_data = p->fbcon_cfb16_cmap;
 #else
-               disp->dispsw = NULL;
+               disp->dispsw = &fbcon_dummy;
 #endif
-    } else if (bpp == 8) {
+       } else if (bpp == 8) {
                if (con == currcon) {
                        write_cr(0x13, 100);            // 8 bit display width (decimal)
                        write_xr(0x81, 0x12);           // 8 bit color mode
-                       write_xr(0x82, 0x08);           // Graphics gamma enable
                        write_xr(0x20, 0x00);           // 8 bit blitter mode
                }
 
@@ -369,7 +391,7 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
 #ifdef FBCON_HAS_CFB8
                disp->dispsw = &fbcon_cfb8;
 #else
-               disp->dispsw = NULL;
+               disp->dispsw = &fbcon_dummy;
 #endif
        }
 
@@ -391,6 +413,135 @@ static void chips_set_bitdepth(struct fb_info_chips *p, struct display* disp, in
        do_install_cmap(con, (struct fb_info *)p);
 }
 
+struct chips_init_reg {
+       unsigned char addr;
+       unsigned char data;
+};
+
+#define N_ELTS(x)      (sizeof(x) / sizeof(x[0]))
+
+static struct chips_init_reg chips_init_sr[] = {
+       { 0x00, 0x03 },
+       { 0x01, 0x01 },
+       { 0x02, 0x0f },
+       { 0x04, 0x0e }
+};
+
+static struct chips_init_reg chips_init_gr[] = {
+       { 0x05, 0x00 },
+       { 0x06, 0x0d },
+       { 0x08, 0xff }
+};
+
+static struct chips_init_reg chips_init_ar[] = {
+       { 0x10, 0x01 },
+       { 0x12, 0x0f },
+       { 0x13, 0x00 }
+};
+
+static struct chips_init_reg chips_init_cr[] = {
+       { 0x00, 0x7f },
+       { 0x01, 0x63 },
+       { 0x02, 0x63 },
+       { 0x03, 0x83 },
+       { 0x04, 0x66 },
+       { 0x05, 0x10 },
+       { 0x06, 0x72 },
+       { 0x07, 0x3e },
+       { 0x08, 0x00 },
+       { 0x09, 0x40 },
+       { 0x0c, 0x00 },
+       { 0x0d, 0x00 },
+       { 0x10, 0x59 },
+       { 0x11, 0x0d },
+       { 0x12, 0x57 },
+       { 0x13, 0x64 },
+       { 0x14, 0x00 },
+       { 0x15, 0x57 },
+       { 0x16, 0x73 },
+       { 0x17, 0xe3 },
+       { 0x18, 0xff },
+       { 0x30, 0x02 },
+       { 0x31, 0x02 },
+       { 0x32, 0x02 },
+       { 0x33, 0x02 },
+       { 0x40, 0x00 },
+       { 0x41, 0x00 },
+       { 0x40, 0x80 }
+};
+
+static struct chips_init_reg chips_init_fr[] = {
+       { 0x01, 0x02 },
+       { 0x03, 0x08 },
+       { 0x04, 0x81 },
+       { 0x05, 0x21 },
+       { 0x08, 0x0c },
+       { 0x0a, 0x74 },
+       { 0x0b, 0x11 },
+       { 0x10, 0x0c },
+       { 0x11, 0xe0 },
+       { 0x12, 0x40 },
+       { 0x20, 0x63 },
+       { 0x21, 0x68 },
+       { 0x22, 0x19 },
+       { 0x23, 0x7f },
+       { 0x24, 0x68 },
+       { 0x26, 0x00 },
+       { 0x27, 0x0f },
+       { 0x30, 0x57 },
+       { 0x31, 0x58 },
+       { 0x32, 0x0d },
+       { 0x33, 0x72 },
+       { 0x34, 0x02 },
+       { 0x35, 0x22 },
+       { 0x36, 0x02 },
+       { 0x37, 0x00 }
+};
+
+static struct chips_init_reg chips_init_xr[] = {
+       { 0xce, 0x00 },         /* set default memory clock */
+       { 0xcc, 0x43 },         /* memory clock ratio */
+       { 0xcd, 0x18 },
+       { 0xce, 0xa1 },
+       { 0xc8, 0x84 },
+       { 0xc9, 0x0a },
+       { 0xca, 0x00 },
+       { 0xcb, 0x20 },
+       { 0xcf, 0x06 },
+       { 0xd0, 0x0e },
+       { 0x09, 0x01 },
+       { 0x0a, 0x02 },
+       { 0x0b, 0x01 },
+       { 0x20, 0x00 },
+       { 0x40, 0x03 },
+       { 0x41, 0x01 },
+       { 0x42, 0x00 },
+       { 0x80, 0x82 },
+       { 0x81, 0x12 },
+       { 0x82, 0x08 },
+       { 0xa0, 0x00 },
+       { 0xa8, 0x00 }
+};
+
+__initfunc(static void chips_hw_init(struct fb_info_chips *p))
+{
+       int i;
+
+       for (i = 0; i < N_ELTS(chips_init_xr); ++i)
+               write_xr(chips_init_xr[i].addr, chips_init_xr[i].data);
+       out_8(p->io_base + 0x3c2, 0x29); /* set misc output reg */
+       for (i = 0; i < N_ELTS(chips_init_sr); ++i)
+               write_sr(chips_init_sr[i].addr, chips_init_sr[i].data);
+       for (i = 0; i < N_ELTS(chips_init_gr); ++i)
+               write_gr(chips_init_gr[i].addr, chips_init_gr[i].data);
+       for (i = 0; i < N_ELTS(chips_init_ar); ++i)
+               write_ar(chips_init_ar[i].addr, chips_init_ar[i].data);
+       for (i = 0; i < N_ELTS(chips_init_cr); ++i)
+               write_cr(chips_init_cr[i].addr, chips_init_cr[i].data);
+       for (i = 0; i < N_ELTS(chips_init_fr); ++i)
+               write_fr(chips_init_fr[i].addr, chips_init_fr[i].data);
+}
+
 __initfunc(static void init_chips(struct fb_info_chips *p))
 {
        int i;
@@ -439,6 +590,7 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
        p->info.switch_con = &chipsfb_switch;
        p->info.updatevar = &chipsfb_updatevar;
        p->info.blank = &chipsfb_blank;
+       p->info.flags = FBINFO_FLAG_DEFAULT;
 
        for (i = 0; i < 16; ++i) {
                int j = color_table[i];
@@ -454,6 +606,8 @@ __initfunc(static void init_chips(struct fb_info_chips *p))
 
        printk("fb%d: Chips 65550 frame buffer\n", GET_FB_IDX(p->info.node));
 
+       chips_hw_init(p);
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
        if (!console_fb_info) {
                display_info.height = p->var.yres;
index be25b9705cc11e3f89f6433d1993c943169ae2e8..8cc875548754778c570900bacb6fd2bd3d480bf7 100644 (file)
@@ -1413,7 +1413,7 @@ static void clgen_set_dispsw(const void *par, struct display *disp,
 
     default:
        printk("unsupported color depth\n");
-       disp->dispsw = NULL;
+       disp->dispsw = &fbcon_dummy;
        break;
     }
 }
@@ -1570,6 +1570,7 @@ __initfunc(void clgenfb_init(void))
     fb_info->gen.info.switch_con = &fbgen_switch;
     fb_info->gen.info.updatevar  = &fbgen_update_var;
     fb_info->gen.info.blank      = &fbgen_blank;
+    fb_info->gen.info.flags     = FBINFO_FLAG_DEFAULT;
     
     /* mark this board as "autoconfigured" */
     zorro_config_board(key, 0);
index e2b8f798a2041359aaed6857a58b2da55f9bab95..586d7aefc065232eb784dc9d004719a2b9bf48f6 100644 (file)
@@ -481,6 +481,7 @@ __initfunc(static void init_control(struct fb_info_control *p))
        
        control_par_to_all(p, 1);
        
+       p->info.flags = FBINFO_FLAG_DEFAULT;
        if (register_framebuffer(&p->info) < 0) {
                kfree(p);
                return;
index 2e138b7c70d34a3a563764c8814532cff7882880..32943ed274dd5dfbb0c2911d9b4307d9fa361d82 100644 (file)
@@ -141,8 +141,8 @@ static struct control_regvals control_reg_init_17 = {
        1024, 768
 };
 
-/* Register values for 1024x768, 72Hz mode (15) */
-static struct control_regvals control_reg_init_15 = {
+/* Register values for 1024x768, 72Hz mode (16 (15?)) */
+static struct control_regvals control_reg_init_16 = {
        { 1024, 2048, 4096 },
        { 0x10, 0x28, 0x50 },
        { 1607, 1604, 68, 39, 10, 1610, 1612, 132,
@@ -253,8 +253,8 @@ static struct control_regvals *control_reg_init[VMODE_MAX] = {
        &control_reg_init_12,
        &control_reg_init_13,
        &control_reg_init_14,
-       &control_reg_init_15,
-       NULL,
+       &control_reg_init_16,
+       &control_reg_init_16,
        &control_reg_init_17,
        &control_reg_init_18,
        &control_reg_init_19,
index 7847ceddd0bfdbe007595b9e6663c57c3b6a9b5c..1150504d50c2f438412ea81b253fc0447b55e03c 100644 (file)
@@ -1044,6 +1044,7 @@ __initfunc(void cyberfb_init(void))
        fb_info.switch_con = &Cyberfb_switch;
        fb_info.updatevar = &Cyberfb_updatevar;
        fb_info.blank = &Cyberfb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
 
        fbhw->init();
        fbhw->decode_var(&cyberfb_default, &par);
index cf25d89b9dca35bccc2342ce0348d91fd73eb9d3..e0da396bf332b6d0e699d0803bd3b1892f0f390d 100644 (file)
@@ -321,6 +321,7 @@ void dnfb_init(void)
        fb_info.blank=&dnfbcon_blank;   
        fb_info.node = -1;
        fb_info.fbops = &dnfb_ops;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
        
         outb(RESET_CREG, AP_CONTROL_3A);
         outw(0x0, AP_WRITE_ENABLE);
index eb70db52b75c4f9ea8fb5e0ac150d2f2ea0563fb..6afb301959eb9b172d061d2569608ddc9816bb78 100644 (file)
@@ -340,6 +340,12 @@ static void fbcon_init(struct vc_data *conp, int init)
                             fb_display[unit].var.bits_per_pixel);
     fb_display[unit].conp = conp;
     fb_display[unit].fb_info = info;
+    /* clear out the cmap so we don't have dangling pointers */
+    fb_display[unit].cmap.len = 0;
+    fb_display[unit].cmap.red = 0;
+    fb_display[unit].cmap.green = 0;
+    fb_display[unit].cmap.blue = 0;
+    fb_display[unit].cmap.transp = 0;
     fbcon_setup(unit, init, !init);
     /* Must be done after fbcon_setup to prevent excess updates */
     conp->vc_display_fg = &info->display_fg;
@@ -410,10 +416,9 @@ static void fbcon_setup(int con, int init, int logo)
     unsigned short *save = NULL, *r, *q;
     int i, charcnt = 256;
     struct fbcon_font_desc *font;
-    /* Only if not module */
-    int initmem_freed = 1;
     
-    if (con != fg_console || initmem_freed || p->type == FB_TYPE_TEXT)
+    if (con != fg_console || (p->fb_info->flags & FBINFO_FLAG_MODULE) ||
+        p->type == FB_TYPE_TEXT)
        logo = 0;
 
     p->var.xoffset = p->var.yoffset = p->yscroll = 0;  /* reset wrap/pan */
@@ -551,7 +556,8 @@ static void fbcon_setup(int con, int init, int logo)
     if (!init) {
        if (conp->vc_cols != nr_cols || conp->vc_rows != nr_rows)
            vc_resize_con(nr_rows, nr_cols, con);
-       else if (CON_IS_VISIBLE(conp)) {
+       else if (CON_IS_VISIBLE(conp) &&
+                vt_cons[conp->vc_num]->vc_mode == KD_TEXT) {
            if (p->dispsw->clear_margins)
                p->dispsw->clear_margins(conp, p, 0);
            update_screen(con);
@@ -1165,7 +1171,7 @@ static int fbcon_switch(struct vc_data *conp)
 
     if (info && info->switch_con)
        (*info->switch_con)(unit, info);
-    if (p->dispsw->clear_margins)
+    if (p->dispsw->clear_margins && vt_cons[unit]->vc_mode == KD_TEXT)
        p->dispsw->clear_margins(conp, p, 0);
     if (logo_shown == -2) {
        logo_shown = fg_console;
@@ -1336,7 +1342,7 @@ static int fbcon_do_set_font(int unit, struct console_font_op *op, u8 *data, int
        p->vrows = p->var.yres_virtual/h;
        updatescrollmode(p);
        vc_resize_con( p->var.yres/h, p->var.xres/w, unit );
-    } else if (CON_IS_VISIBLE(p->conp)) {
+    } else if (CON_IS_VISIBLE(p->conp) && vt_cons[unit]->vc_mode == KD_TEXT) {
        if (p->dispsw->clear_margins)
            p->dispsw->clear_margins(p->conp, p, 0);
        update_screen(unit);
index b4d12971756b4681061c626053059c5c8cdd1170..50b486887cb1d50124fd0684171a033f9290de22 100644 (file)
@@ -14,8 +14,6 @@
  *  more details.
  */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -410,6 +408,7 @@ __initfunc(void g364fb_init(void))
     fb_info.switch_con = &g364fbcon_switch;
     fb_info.updatevar = &g364fbcon_updatevar;
     fb_info.blank = &g364fbcon_blank;
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
 
     g364fb_set_var(&fb_var, -1, &fb_info);
 
index d9a737de1f40c8d3479c192ba4341eef36191825..11689b1502319c8cdd40e461fd04d6879d8c610e 100644 (file)
@@ -360,6 +360,7 @@ __initfunc(int hpfb_init_one(unsigned long base))
        fb_info.switch_con = &hpfb_switch;
        fb_info.updatevar = &fb_update_var;
        fb_info.blank = &hpfb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
        do_fb_set_var(&hpfb_defined, 1);
 
        hpfb_get_var(&disp.var, -1, &fb_info);
index bbad3cbf2d517b2c448598875f009748a870f7cd..105d7d7d1faa8d5fd4a1b4da71afe18e0b87f3f0 100644 (file)
@@ -553,10 +553,10 @@ set_imstt_regvals_tvp (struct fb_info_imstt *p, struct imstt_regvals *init, int
        p->cmap_regs[TVPADDRW] = TVPIRPLA;      eieio();
        p->cmap_regs[TVPIDATA] = 0x00;          eieio();
        p->cmap_regs[TVPADDRW] = TVPIRPPD;      eieio();
-       p->cmap_regs[TVPIDATA] = init->pclk_n;  eieio();
-       p->cmap_regs[TVPADDRW] = TVPIRPPD;      eieio();
        p->cmap_regs[TVPIDATA] = init->pclk_m;  eieio();
        p->cmap_regs[TVPADDRW] = TVPIRPPD;      eieio();
+       p->cmap_regs[TVPIDATA] = init->pclk_n;  eieio();
+       p->cmap_regs[TVPADDRW] = TVPIRPPD;      eieio();
        p->cmap_regs[TVPIDATA] = init->pclk_p;  eieio();
 
        p->cmap_regs[TVPADDRW] = TVPIRTCC;      eieio();
@@ -691,6 +691,84 @@ set_16 (struct fb_info_imstt *p, __u8 x)
 #define set_555(_p)    set_16(_p, 15)  /* need 220 or 224 for X */
 #define set_565(_p)    set_16(_p, 0)   /* 220, 224 is darker in X */
 
+void
+imsttfb_rectcopy (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
+{
+       struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
+       __u32 tmp, cnt_reg;
+       __u32   line_pitch = disp->var.xres * (disp->var.bits_per_pixel >> 3),
+               rect_height = height,
+               rect_width = width * (disp->var.bits_per_pixel >> 3),
+               fb_offset_old = sy * line_pitch + (sx * (disp->var.bits_per_pixel >> 3)),
+               fb_offset_new = dy * line_pitch + (dx * (disp->var.bits_per_pixel >> 3));
+
+       cnt_reg = ((rect_height - 1) << 16) | (rect_width - 1);
+
+       tmp = (line_pitch << 16) | line_pitch;
+       out_le32(&p->dc_regs[SP], tmp);
+       tmp = line_pitch;
+       out_le32(&p->dc_regs[DP_OCTRL], tmp);
+#if 0
+       do {
+               tmp = in_le32(&p->dc_regs[SSTATUS]);
+               eieio();
+       } while (tmp & 0x80);
+#endif
+       out_le32(&p->dc_regs[CNT], cnt_reg);
+       out_le32(&p->dc_regs[S1SA], fb_offset_old);
+       out_le32(&p->dc_regs[S2SA], fb_offset_new);
+       out_le32(&p->dc_regs[DSA], fb_offset_new);
+       out_le32(&p->dc_regs[BLTCTL], 0x5);
+#if 0
+       do {
+               tmp = in_le32(&p->dc_regs[SSTATUS]);
+               eieio();
+       } while (tmp & 0x80);
+
+       do {
+               tmp = in_le32(&p->dc_regs[SSTATUS]);
+               eieio();
+       } while (tmp & 0x40);
+#endif
+}
+
+static void
+imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
+{
+       sy *= fontheight(disp);
+       sx *= fontwidth(disp);
+       dy *= fontheight(disp);
+       dx *= fontwidth(disp);
+       height *= fontheight(disp);
+       width *= fontwidth(disp);
+
+       imsttfb_rectcopy(disp, sy, sx, dy, dx, height, width);
+}
+
+static struct display_switch fbcon_imstt8 = {
+       fbcon_cfb8_setup, imsttfbcon_bmove, fbcon_cfb8_clear, fbcon_cfb8_putc,
+       fbcon_cfb8_putcs, fbcon_cfb8_revc, NULL, NULL, fbcon_cfb8_clear_margins,
+       FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
+static struct display_switch fbcon_imstt16 = {
+       fbcon_cfb16_setup, imsttfbcon_bmove, fbcon_cfb16_clear, fbcon_cfb16_putc,
+       fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL, fbcon_cfb16_clear_margins,
+       FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
+static struct display_switch fbcon_imstt24 = {
+       fbcon_cfb24_setup, imsttfbcon_bmove, fbcon_cfb24_clear, fbcon_cfb24_putc,
+       fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL, fbcon_cfb24_clear_margins,
+       FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
+static struct display_switch fbcon_imstt32 = {
+       fbcon_cfb32_setup, imsttfbcon_bmove, fbcon_cfb32_clear, fbcon_cfb32_putc,
+       fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL, fbcon_cfb32_clear_margins,
+       FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+
 #ifdef CONFIG_FB_COMPAT_XPMAC
 #include <asm/vc_ioctl.h>
 
@@ -834,7 +912,7 @@ imsttfb_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
 
        *fix = p->fix;
        fix->visual = var->bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
-                                              : FB_VISUAL_TRUECOLOR;
+                                              : FB_VISUAL_DIRECTCOLOR;
        fix->line_length = var->xres * (var->bits_per_pixel >> 3);
 
        return 0;
@@ -853,7 +931,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        struct display *disp;
-       unsigned int oldbpp, oldxres, oldyres, oldgreenlen;
+       unsigned int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
        struct imstt_regvals *init;
 
        disp = &fb_display[con];
@@ -880,6 +958,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
        oldxres = disp->var.xres;
        oldyres = disp->var.yres;
        oldgreenlen = disp->var.green.length;
+       oldaccel = disp->var.accel_flags;
 
        disp->var = *var;
 
@@ -898,11 +977,15 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
 
        disp->screen_base = p->frame_buffer;
        disp->inverse = 0;
+       disp->ypanstep = 1;
+       disp->ywrapstep = 0;
        disp->scrollmode = SCROLL_YREDRAW;
 
-       if (oldbpp != disp->var.bits_per_pixel) {
+       if (oldbpp != disp->var.bits_per_pixel || oldaccel != disp->var.accel_flags) {
+               unsigned int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
+
                disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
-                                                            : FB_VISUAL_TRUECOLOR;
+                                                            : FB_VISUAL_DIRECTCOLOR;
                disp->dispsw = &fbcon_dummy;
                disp->dispsw_data = 0;
                switch (disp->var.bits_per_pixel) {
@@ -916,7 +999,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
                                disp->var.transp.offset = 0;
                                disp->var.transp.length = 0;
 #ifdef FBCON_HAS_CFB8
-                               disp->dispsw = &fbcon_cfb8;
+                               disp->dispsw = accel ? &fbcon_imstt8 : &fbcon_cfb8;
 #endif
                                break;
                        case 16:        /* RGB 565 */
@@ -931,7 +1014,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
                                disp->var.transp.offset = 0;
                                disp->var.transp.length = 0;
 #ifdef FBCON_HAS_CFB16
-                               disp->dispsw = &fbcon_cfb16;
+                               disp->dispsw = accel ? &fbcon_imstt16 : &fbcon_cfb16;
                                disp->dispsw_data = p->fbcon_cmap.cfb16;
 #endif
                                break;
@@ -945,7 +1028,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
                                disp->var.transp.offset = 0;
                                disp->var.transp.length = 0;
 #ifdef FBCON_HAS_CFB24
-                               disp->dispsw = &fbcon_cfb24;
+                               disp->dispsw = accel ? &fbcon_imstt24 : &fbcon_cfb24;
                                disp->dispsw_data = p->fbcon_cmap.cfb24;
 #endif
                                break;
@@ -959,7 +1042,7 @@ imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
                                disp->var.transp.offset = 24;
                                disp->var.transp.length = 8;
 #ifdef FBCON_HAS_CFB32
-                               disp->dispsw = &fbcon_cfb32;
+                               disp->dispsw = accel ? &fbcon_imstt32 : &fbcon_cfb32;
                                disp->dispsw_data = p->fbcon_cmap.cfb32;
 #endif
                                break;
@@ -1127,7 +1210,7 @@ static struct fb_ops imsttfb_ops = {
 };
 
 static int
-imsttfb_switch (int con, struct fb_info *info)
+imsttfbcon_switch (int con, struct fb_info *info)
 {
        struct display *old = &fb_display[currcon], *new = &fb_display[con];
 
@@ -1157,7 +1240,7 @@ imsttfb_switch (int con, struct fb_info *info)
 }
 
 static int
-imsttfb_updatevar (int con, struct fb_info *info)
+imsttfbcon_updatevar (int con, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        unsigned int off;
@@ -1172,7 +1255,7 @@ imsttfb_updatevar (int con, struct fb_info *info)
 }
 
 static void
-imsttfb_blank (int blank, struct fb_info *info)
+imsttfbcon_blank (int blank, struct fb_info *info)
 {
        struct fb_info_imstt *p = (struct fb_info_imstt *)info;
        __u32 ctrl;
@@ -1203,6 +1286,7 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
 {
        __u32 i, tmp;
        struct imstt_regvals *init;
+       unsigned int accel;
 
        tmp = in_le32(&p->dc_regs[SSTATUS]);
        /* printk("chip version %ld, ", (tmp & 0x0F00) >> 8); */
@@ -1262,6 +1346,10 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
        p->disp.var.left_margin = p->disp.var.right_margin = 16;
        p->disp.var.upper_margin = p->disp.var.lower_margin = 16;
        p->disp.var.hsync_len = p->disp.var.vsync_len = 8;
+       p->disp.var.accel_flags = 0; /* FB_ACCELF_TEXT; */
+
+       accel = p->disp.var.accel_flags & FB_ACCELF_TEXT;
+
        p->disp.dispsw = &fbcon_dummy;
        p->disp.dispsw_data = 0;
        switch (p->disp.var.bits_per_pixel) {
@@ -1275,7 +1363,7 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
                        p->disp.var.transp.offset = 0;
                        p->disp.var.transp.length = 0;
 #ifdef FBCON_HAS_CFB8
-                       p->disp.dispsw = &fbcon_cfb8;
+                       p->disp.dispsw = accel ? &fbcon_imstt8 : &fbcon_cfb8;
 #endif
                        break;
                case 16:        /* RGB 565 */
@@ -1290,7 +1378,7 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
                        p->disp.var.transp.offset = 0;
                        p->disp.var.transp.length = 0;
 #ifdef FBCON_HAS_CFB16
-                       p->disp.dispsw = &fbcon_cfb16;
+                       p->disp.dispsw = accel ? &fbcon_imstt16 : &fbcon_cfb16;
                        p->disp.dispsw_data = p->fbcon_cmap.cfb16;
 #endif
                        break;
@@ -1304,7 +1392,7 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
                        p->disp.var.transp.offset = 0;
                        p->disp.var.transp.length = 0;
 #ifdef FBCON_HAS_CFB24
-                       p->disp.dispsw = &fbcon_cfb24;
+                       p->disp.dispsw = accel ? &fbcon_imstt24 : &fbcon_cfb24;
                        p->disp.dispsw_data = p->fbcon_cmap.cfb24;
 #endif
                        break;
@@ -1318,7 +1406,7 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
                        p->disp.var.transp.offset = 24;
                        p->disp.var.transp.length = 8;
 #ifdef FBCON_HAS_CFB32
-                       p->disp.dispsw = &fbcon_cfb32;
+                       p->disp.dispsw = accel ? &fbcon_imstt32 : &fbcon_cfb32;
                        p->disp.dispsw_data = p->fbcon_cmap.cfb32;
 #endif
                        break;
@@ -1343,10 +1431,14 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
        p->fix.smem_len = p->total_vram;
        p->fix.mmio_start = (__u8 *)p->dc_regs_phys;
        p->fix.mmio_len = 0x40000;
+       p->fix.accel = FB_ACCEL_IMS_TWINTURBO;
        p->fix.type = FB_TYPE_PACKED_PIXELS;
        p->fix.visual = p->disp.var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
                                                        : FB_VISUAL_DIRECTCOLOR;
        p->fix.line_length = p->disp.var.xres * (p->disp.var.bits_per_pixel >> 3);
+       p->fix.xpanstep = 8;
+       p->fix.ypanstep = 1;
+       p->fix.ywrapstep = 0;
 
        p->disp.screen_base = p->frame_buffer;
        p->disp.visual = p->fix.visual;
@@ -1354,6 +1446,8 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
        p->disp.type_aux = p->fix.type_aux;
        p->disp.line_length = p->fix.line_length;
        p->disp.can_soft_blank = 1;
+       p->disp.ypanstep = 1;
+       p->disp.ywrapstep = 0;
        p->disp.scrollmode = SCROLL_YREDRAW;
 
        strcpy(p->info.modename, p->fix.id);
@@ -1362,9 +1456,10 @@ __initfunc(static void init_imstt(struct fb_info_imstt *p))
        p->info.disp = &p->disp;
        p->info.fontname[0] = 0;
        p->info.changevar = 0;
-       p->info.switch_con = &imsttfb_switch;
-       p->info.updatevar = &imsttfb_updatevar;
-       p->info.blank = &imsttfb_blank;
+       p->info.switch_con = &imsttfbcon_switch;
+       p->info.updatevar = &imsttfbcon_updatevar;
+       p->info.blank = &imsttfbcon_blank;
+       p->info.flags = FBINFO_FLAG_DEFAULT;
 
        for (i = 0; i < 16; i++) {
                unsigned int j = color_table[i];
index bbf6be468ed549fe78a151d97e4dd0ccaf38541b..2d0ad292496bfac25ee2bc08f2478ef1fecd7d8b 100644 (file)
@@ -414,6 +414,7 @@ __initfunc(void macfb_init(void))
        fb_info.switch_con=&macfb_switch;
        fb_info.updatevar=&fb_update_var;
        fb_info.blank=&macfb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
        do_fb_set_var(&macfb_defined,1);
 
        macfb_get_var(&disp.var, -1, &fb_info);
index 35310307f3d004e24f2d1e8ccf8636dd2d0e180e..5dc604584a430e82934ada9e5909dedfa9d7e361 100644 (file)
@@ -19,6 +19,7 @@
  *  more details.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
index d345bfab49bcc00711d8099d35551f1733984bfe..32e59982d562453bd43e90f6aceda1b24e217a4f 100644 (file)
@@ -31,6 +31,7 @@
 #endif
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/bootx.h>
 
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
@@ -91,6 +92,12 @@ struct fb_info *console_fb_info = NULL;
 struct vc_mode display_info;
 #endif /* CONFIG_FB_COMPAT_XPMAC */
 
+extern boot_infos_t *boot_infos;
+
+static int offb_init_driver(struct device_node *);
+static void offb_init_nodriver(struct device_node *);
+static void offb_init_fb(const char *name, const char *full_name, int width,
+                     int height, int depth, int pitch, unsigned long address);
 
     /*
      *  Interface to the low level console driver
@@ -302,214 +309,298 @@ extern void platinum_of_init(struct device_node *dp);
 __initfunc(void offb_init(void))
 {
     struct device_node *dp;
-    int i, *pp;
-    unsigned int dpy, len;
-    unsigned *up, address;
-    struct fb_fix_screeninfo *fix;
-    struct fb_var_screeninfo *var;
-    struct display *disp;
-    struct fb_info_offb *info;
+    unsigned int dpy;
+    struct device_node *displays = find_type_devices("display");
+    struct device_node *macos_display = NULL;
+
+    /* If we're booted from BootX... */
+    if (prom_num_displays == 0 && boot_infos != 0) {
+       unsigned long addr = (unsigned long) boot_infos->dispDeviceBase;
+       if (!ofonly) {
+           /* find the device node corresponding to the macos display */
+           for (dp = displays; dp != NULL; dp = dp->next) {
+               int i;
+               /*
+                * Grrr...  It looks like the MacOS ATI driver
+                * munges the assigned-addresses property (but
+                * the AAPL,address value is OK).
+                */
+               if (strncmp(dp->name, "ATY,", 4) == 0 && dp->n_addrs == 1) {
+                   unsigned int *ap = (unsigned int *)
+                       get_property(dp, "AAPL,address", NULL);
+                   if (ap != NULL) {
+                       dp->addrs[0].address = *ap;
+                       dp->addrs[0].size = 0x01000000;
+                   }
+               }
+               /*
+                * See if the display address is in one of the address
+                * ranges for this display.
+                */
+               for (i = 0; i < dp->n_addrs; ++i) {
+                   if (dp->addrs[i].address <= addr
+                       && addr < dp->addrs[i].address + dp->addrs[i].size)
+                       break;
+               }
+               if (i < dp->n_addrs) {
+                   printk(KERN_INFO "MacOS display is %s\n", dp->full_name);
+                   macos_display = dp;
+                   break;
+               }
+           }
+       }
+
+       /* initialize it */
+       if (macos_display == NULL || !offb_init_driver(macos_display)) {
+           offb_init_fb("MacOS display", "MacOS display",
+                        boot_infos->dispDeviceRect[2],
+                        boot_infos->dispDeviceRect[3],
+                        boot_infos->dispDeviceDepth,
+                        boot_infos->dispDeviceRowBytes, addr);
+       }
+    }
 
     for (dpy = 0; dpy < prom_num_displays; dpy++) {
-       if (!(dp = find_path_device(prom_display_paths[dpy])))
-           continue;
+       if ((dp = find_path_device(prom_display_paths[dpy])))
+           if (ofonly || !offb_init_driver(dp))
+               offb_init_nodriver(dp);
+    }
 
-       if (!ofonly) {
+    if (!ofonly) {
+       for (dp = find_type_devices("display"); dp != NULL; dp = dp->next) {
+           for (dpy = 0; dpy < prom_num_displays; dpy++)
+               if (strcmp(dp->full_name, prom_display_paths[dpy]) == 0)
+                   break;
+           if (dpy >= prom_num_displays && dp != macos_display)
+               offb_init_driver(dp);
+       }
+    }
+}
+
+__initfunc(static int offb_init_driver(struct device_node *dp))
+{
 #ifdef CONFIG_FB_ATY
-           if (!strncmp(dp->name, "ATY", 3)) {
-               atyfb_of_init(dp);
-               continue;
-           }
+    if (!strncmp(dp->name, "ATY", 3)) {
+       atyfb_of_init(dp);
+       return 1;
+    }
 #endif /* CONFIG_FB_ATY */
 #ifdef CONFIG_FB_S3TRIO
-            if (s3triofb_init_of(dp))
-                continue;
+    if (s3triofb_init_of(dp))
+       return 1;
 #endif /* CONFIG_FB_S3TRIO */
 #ifdef CONFIG_FB_IMSTT
-           if (!strncmp(dp->name, "IMS,tt128mb", 11)) {
-               imsttfb_of_init(dp);
-               continue;
-           }
+    if (!strncmp(dp->name, "IMS,tt128mb", 11)) {
+       imsttfb_of_init(dp);
+       return 1;
+    }
 #endif
 #ifdef CONFIG_FB_CT65550
-           if (!strcmp(dp->name, "chips65550")) {
-               chips_of_init(dp);
-               continue;
-           }
+    if (!strcmp(dp->name, "chips65550")) {
+       chips_of_init(dp);
+       return 1;
+    }
 #endif /* CONFIG_FB_CT65550 */
 #ifdef CONFIG_FB_CONTROL
-               if(!strcmp(dp->name, "control")) {
-                       control_of_init(dp);
-                       continue;
-               }
+    if(!strcmp(dp->name, "control")) {
+       control_of_init(dp);
+       return 1;
+    }
 #endif /* CONFIG_FB_CONTROL */
 #ifdef CONFIG_FB_VALKYRIE
-               if(!strcmp(dp->name, "valkyrie")) {
-                       valkyrie_of_init(dp);
-                       continue;
-               }
+    if(!strcmp(dp->name, "valkyrie")) {
+       valkyrie_of_init(dp);
+       return 1;
+    }
 #endif /* CONFIG_FB_VALKYRIE */
 #ifdef CONFIG_FB_PLATINUM
-           if (!strncmp(dp->name, "platinum",8)) {
-               platinum_of_init(dp);
-               continue;
-           }
+    if (!strncmp(dp->name, "platinum",8)) {
+       platinum_of_init(dp);
+       return 1;
+    }
 #endif /* CONFIG_FB_PLATINUM */
+    return 0;
+}
+
+__initfunc(static void offb_init_nodriver(struct device_node *dp))
+{
+    int *pp, i;
+    unsigned int len;
+    int width = 640, height = 480, depth = 8, pitch;
+    unsigned *up, address;
+
+    if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+       && len == sizeof(int))
+       depth = *pp;
+    if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+       && len == sizeof(int))
+       width = *pp;
+    if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+       && len == sizeof(int))
+       height = *pp;
+    if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+       && len == sizeof(int))
+       pitch = *pp;
+    else
+       pitch = width;
+    if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
+       && len == sizeof(unsigned))
+       address = (u_long)*up;
+    else {
+       for (i = 0; i < dp->n_addrs; ++i)
+           if (dp->addrs[i].size >= len)
+               break;
+       if (i >= dp->n_addrs) {
+           printk("no framebuffer address found for %s\n", dp->full_name);
+           return;
        }
+       address = (u_long)dp->addrs[i].address;
+
+       /* kludge for valkyrie */
+       if (strcmp(dp->name, "valkyrie") == 0) 
+           address += 0x1000;
+    }
+    offb_init_fb(dp->name, dp->full_name, width, height, depth,
+                pitch, address);
+}
+
+__initfunc(static void offb_init_fb(const char *name, const char *full_name,
+                                   int width, int height, int depth,
+                                   int pitch, unsigned long address))
+{
+    int i;
+    struct fb_fix_screeninfo *fix;
+    struct fb_var_screeninfo *var;
+    struct display *disp;
+    struct fb_info_offb *info;
 
-       info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
-       if (info == 0)
-           continue;
-       memset(info, 0, sizeof(*info));
+    printk(KERN_INFO "Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
+          width, height, name, address, depth, pitch);
+    if (depth != 8) {
+       printk("%s: can't use depth = %d\n", full_name, depth);
+       return;
+    }
 
-       fix = &info->fix;
-       var = &info->var;
-       disp = &info->disp;
+    info = kmalloc(sizeof(struct fb_info_offb), GFP_ATOMIC);
+    if (info == 0)
+       return;
+    memset(info, 0, sizeof(*info));
 
-       strcpy(fix->id, "OFfb ");
-       strncat(fix->id, dp->name, sizeof(fix->id));
-       fix->id[sizeof(fix->id)-1] = '\0';
+    fix = &info->fix;
+    var = &info->var;
+    disp = &info->disp;
 
-       if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
-           && len == sizeof(int) && *pp != 8) {
-           printk("%s: can't use depth = %d\n", dp->full_name, *pp);
-           kfree(info);
-           continue;
-       }
-       if ((pp = (int *)get_property(dp, "width", &len)) != NULL
-           && len == sizeof(int))
-           var->xres = var->xres_virtual = *pp;
-       if ((pp = (int *)get_property(dp, "height", &len)) != NULL
-           && len == sizeof(int))
-           var->yres = var->yres_virtual = *pp;
-       if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
-           && len == sizeof(int))
-           fix->line_length = *pp;
-       else
-           fix->line_length = var->xres_virtual;
-       fix->smem_len = fix->line_length*var->yres;
-       if ((up = (unsigned *)get_property(dp, "address", &len)) != NULL
-           && len == sizeof(unsigned))
-           address = (u_long)*up;
-       else {
-           for (i = 0; i < dp->n_addrs; ++i)
-               if (dp->addrs[i].size >= len)
-                   break;
-           if (i >= dp->n_addrs) {
-               printk("no framebuffer address found for %s\n", dp->full_name);
-               kfree(info);
-               continue;
-           }
-           address = (u_long)dp->addrs[i].address;
+    strcpy(fix->id, "OFfb ");
+    strncat(fix->id, name, sizeof(fix->id));
+    fix->id[sizeof(fix->id)-1] = '\0';
 
-               /* kludge for valkyrie */
-           if (strcmp(dp->name, "valkyrie") == 0) 
-                       address += 0x1000;
+    var->xres = var->xres_virtual = width;
+    var->yres = var->yres_virtual = height;
+    fix->line_length = pitch;
 
-       }
-       fix->smem_start = (char *)address;
-       fix->type = FB_TYPE_PACKED_PIXELS;
-       fix->type_aux = 0;
+    fix->smem_start = (char *)address;
+    fix->smem_len = pitch * height;
+    fix->type = FB_TYPE_PACKED_PIXELS;
+    fix->type_aux = 0;
 
        /* XXX kludge for ati */
-       if (strncmp(dp->name, "ATY,", 4) == 0) {
-           info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
-           info->cmap_data = info->cmap_adr + 1;
-       }
+    if (strncmp(name, "ATY,", 4) == 0) {
+       info->cmap_adr = ioremap(address + 0x7ff000, 0x1000) + 0xcc0;
+       info->cmap_data = info->cmap_adr + 1;
+    }
 
-       fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
-                                      FB_VISUAL_STATIC_PSEUDOCOLOR;
-
-       var->xoffset = var->yoffset = 0;
-       var->bits_per_pixel = 8;
-       var->grayscale = 0;
-       var->red.offset = var->green.offset = var->blue.offset = 0;
-       var->red.length = var->green.length = var->blue.length = 8;
-       var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
-       var->transp.offset = var->transp.length = var->transp.msb_right = 0;
-       var->nonstd = 0;
-       var->activate = 0;
-       var->height = var->width = -1;
-       var->pixclock = 10000;
-       var->left_margin = var->right_margin = 16;
-       var->upper_margin = var->lower_margin = 16;
-       var->hsync_len = var->vsync_len = 8;
-       var->sync = 0;
-       var->vmode = FB_VMODE_NONINTERLACED;
-
-       disp->var = *var;
-       disp->cmap.start = 0;
-       disp->cmap.len = 0;
-       disp->cmap.red = NULL;
-       disp->cmap.green = NULL;
-       disp->cmap.blue = NULL;
-       disp->cmap.transp = NULL;
-       disp->screen_base = ioremap(address, fix->smem_len);
-       disp->visual = fix->visual;
-       disp->type = fix->type;
-       disp->type_aux = fix->type_aux;
-       disp->ypanstep = 0;
-       disp->ywrapstep = 0;
-       disp->line_length = fix->line_length;
-       disp->can_soft_blank = info->cmap_adr ? 1 : 0;
-       disp->inverse = 0;
+    fix->visual = info->cmap_adr ? FB_VISUAL_PSEUDOCOLOR :
+       FB_VISUAL_STATIC_PSEUDOCOLOR;
+
+    var->xoffset = var->yoffset = 0;
+    var->bits_per_pixel = 8;
+    var->grayscale = 0;
+    var->red.offset = var->green.offset = var->blue.offset = 0;
+    var->red.length = var->green.length = var->blue.length = 8;
+    var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+    var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+    var->nonstd = 0;
+    var->activate = 0;
+    var->height = var->width = -1;
+    var->pixclock = 10000;
+    var->left_margin = var->right_margin = 16;
+    var->upper_margin = var->lower_margin = 16;
+    var->hsync_len = var->vsync_len = 8;
+    var->sync = 0;
+    var->vmode = FB_VMODE_NONINTERLACED;
+
+    disp->var = *var;
+    disp->cmap.start = 0;
+    disp->cmap.len = 0;
+    disp->cmap.red = NULL;
+    disp->cmap.green = NULL;
+    disp->cmap.blue = NULL;
+    disp->cmap.transp = NULL;
+    disp->screen_base = ioremap(address, fix->smem_len);
+    disp->visual = fix->visual;
+    disp->type = fix->type;
+    disp->type_aux = fix->type_aux;
+    disp->ypanstep = 0;
+    disp->ywrapstep = 0;
+    disp->line_length = fix->line_length;
+    disp->can_soft_blank = info->cmap_adr ? 1 : 0;
+    disp->inverse = 0;
 #ifdef FBCON_HAS_CFB8
-       disp->dispsw = &fbcon_cfb8;
+    disp->dispsw = &fbcon_cfb8;
 #else
-       disp->dispsw = &fbcon_dummy;
+    disp->dispsw = &fbcon_dummy;
 #endif
-       disp->scrollmode = SCROLL_YREDRAW;
-
-       strcpy(info->info.modename, "OFfb ");
-       strncat(info->info.modename, dp->full_name,
-               sizeof(info->info.modename));
-       info->info.node = -1;
-       info->info.fbops = &offb_ops;
-       info->info.disp = disp;
-       info->info.fontname[0] = '\0';
-       info->info.changevar = NULL;
-       info->info.switch_con = &offbcon_switch;
-       info->info.updatevar = &offbcon_updatevar;
-       info->info.blank = &offbcon_blank;
-
-       for (i = 0; i < 16; i++) {
-           int j = color_table[i];
-           info->palette[i].red = default_red[j];
-           info->palette[i].green = default_grn[j];
-           info->palette[i].blue = default_blu[j];
-       }
-       offb_set_var(var, -1, &info->info);
+    disp->scrollmode = SCROLL_YREDRAW;
+
+    strcpy(info->info.modename, "OFfb ");
+    strncat(info->info.modename, full_name, sizeof(info->info.modename));
+    info->info.node = -1;
+    info->info.fbops = &offb_ops;
+    info->info.disp = disp;
+    info->info.fontname[0] = '\0';
+    info->info.changevar = NULL;
+    info->info.switch_con = &offbcon_switch;
+    info->info.updatevar = &offbcon_updatevar;
+    info->info.blank = &offbcon_blank;
+    info->info.flags = FBINFO_FLAG_DEFAULT;
+
+    for (i = 0; i < 16; i++) {
+       int j = color_table[i];
+       info->palette[i].red = default_red[j];
+       info->palette[i].green = default_grn[j];
+       info->palette[i].blue = default_blu[j];
+    }
+    offb_set_var(var, -1, &info->info);
 
-       if (register_framebuffer(&info->info) < 0) {
-           kfree(info);
-           return;
-       }
+    if (register_framebuffer(&info->info) < 0) {
+       kfree(info);
+       return;
+    }
 
-       printk("fb%d: Open Firmware frame buffer device on %s\n",
-              GET_FB_IDX(info->info.node), dp->full_name);
+    printk("fb%d: Open Firmware frame buffer device on %s\n",
+          GET_FB_IDX(info->info.node), full_name);
 
 #ifdef CONFIG_FB_COMPAT_XPMAC
-       if (!console_fb_info) {
-           display_info.height = var->yres;
-           display_info.width = var->xres;
-           display_info.depth = 8;
-           display_info.pitch = fix->line_length;
-           display_info.mode = 0;
-           strncpy(display_info.name, dp->name, sizeof(display_info.name));
-           display_info.fb_address = address;
-           display_info.cmap_adr_address = 0;
-           display_info.cmap_data_address = 0;
-           display_info.disp_reg_address = 0;
-           /* XXX kludge for ati */
-           if (strncmp(dp->name, "ATY,", 4) == 0) {
-                   display_info.disp_reg_address = address + 0x7ffc00;
-                   display_info.cmap_adr_address = address + 0x7ffcc0;
-                   display_info.cmap_data_address = address + 0x7ffcc1;
-           }
-           console_fb_info = &info->info;
+    if (!console_fb_info) {
+       display_info.height = var->yres;
+       display_info.width = var->xres;
+       display_info.depth = 8;
+       display_info.pitch = fix->line_length;
+       display_info.mode = 0;
+       strncpy(display_info.name, name, sizeof(display_info.name));
+       display_info.fb_address = address;
+       display_info.cmap_adr_address = 0;
+       display_info.cmap_data_address = 0;
+       display_info.disp_reg_address = 0;
+       /* XXX kludge for ati */
+       if (strncmp(name, "ATY,", 4) == 0) {
+           display_info.disp_reg_address = address + 0x7ffc00;
+           display_info.cmap_adr_address = address + 0x7ffcc0;
+           display_info.cmap_data_address = address + 0x7ffcc1;
        }
-#endif /* CONFIG_FB_COMPAT_XPMAC) */
+       console_fb_info = &info->info;
     }
+#endif /* CONFIG_FB_COMPAT_XPMAC) */
 }
 
 
index 78a25bc4b58cdb9b6e9e1c8b2c288e7c53d96244..89f6860f28583d2921dee4a90e617e496e1f76ad 100644 (file)
@@ -632,6 +632,7 @@ __initfunc(static int init_platinum(struct fb_info_platinum *info))
        info->fb_info.switch_con = &platinum_switch;
        info->fb_info.updatevar = &platinum_updatevar;
        info->fb_info.blank = &platinum_blank;
+       info->fb_info.flags = FBINFO_FLAG_DEFAULT;
 
        for (j = 0; j < 16; j++) {
                k = color_table[j];
index 7f30d1ac471d895a0bc2b357cbd8970a6f5d8802..42c43ced9ca38dc0b75f91dff54a3dd23efa6106 100644 (file)
@@ -1530,6 +1530,7 @@ __initfunc(void retz3fb_init(void))
        fb_info.switch_con = &z3fb_switch;
        fb_info.updatevar = &z3fb_updatevar;
        fb_info.blank = &z3fb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
 
        if (z3fb_mode == -1)
                retz3fb_default = retz3fb_predefined[0].var;
index f948075f583b616ae30e9876e4457bf7db37a088..bbe37b27396f5f0032a8153329a0688ead1197c9 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/vt_kern.h>
 
 #include <asm/uaccess.h>
+#include <asm/pgtable.h>       /* io_remap_page_range() */
 
 #include <video/sbusfb.h>
 
@@ -91,8 +92,6 @@ static int sbusfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
                            u_long arg, int con, struct fb_info *info);
 static void sbusfb_cursor(struct display *p, int mode, int x, int y);
 static void sbusfb_clear_margin(struct display *p, int s);
-extern int io_remap_page_range(unsigned long from, unsigned long offset, 
-                       unsigned long size, pgprot_t prot, int space);
                            
 
     /*
@@ -421,13 +420,13 @@ static int sbus_hw_scursor (struct fbcursor *cursor, struct fb_info_sbusfb *fb)
                    copy_from_user (fb->cursor.bits [1], f.image, bytes))
                        return -EFAULT;
                if (f.size.fbx <= 32) {
-                       u = ~(0xffffffff >> f.size.fbx);
+                       u = 0xffffffff << (32 - f.size.fbx);
                        for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
                                fb->cursor.bits [0][i] &= u;
                                fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
                        }
                } else {
-                       u = ~(0xffffffff >> (f.size.fbx - 32));
+                       u = 0xffffffff << (64 - f.size.fbx);
                        for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
                                fb->cursor.bits [0][2*i+1] &= u;
                                fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i];
@@ -1017,6 +1016,7 @@ sizechange:
        fb->info.switch_con = &sbusfbcon_switch;
        fb->info.updatevar = &sbusfbcon_updatevar;
        fb->info.blank = &sbusfbcon_blank;
+       fb->info.flags = FBINFO_FLAG_DEFAULT;
        
        fb->cursor.hwsize.fbx = 32;
        fb->cursor.hwsize.fby = 32;
index f10840d79af70523027cca0132db4e1990ba2a5a..a99a3a0cdfd38e81b537296221f3588bb11129be 100644 (file)
@@ -311,6 +311,7 @@ __initfunc(void xxxfb_init(void))
     fb_info.gen.info.switch_con = &xxxfb_switch;
     fb_info.gen.info.updatevar = &xxxfb_update_var;
     fb_info.gen.info.blank = &xxxfb_blank;
+    fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
     /* This should give a reasonable default video mode */
     fbgen_get_var(&disp.var, -1, &fb_info.gen.info);
     fbgen_do_set_var(&disp.var, 1, &fb_info.gen);
index 029e8b0d7d37a3b380f2b65f0be794fd3eb01daf..50acdc50ea6f7e69bf6da966990c38ea2d3f4a84 100644 (file)
@@ -763,6 +763,7 @@ __initfunc(void tgafb_init(void))
     fb_info.switch_con = &tgafbcon_switch;
     fb_info.updatevar = &tgafbcon_updatevar;
     fb_info.blank = &tgafbcon_blank;
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
 
     tgafb_set_var(&fb_var, -1, &fb_info);
 
index 60127c81f9d6a027bac8cc080fd6d321205873b9..d7f2131de4e6f642fc05ca663670401f65854ebc 100644 (file)
@@ -830,7 +830,7 @@ static void valkyrie_par_to_display(struct fb_par_valkyrie *par,
         }
 }
 
-static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
+static void __init valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
 {
        strcpy(info->modename, p->fix.id);
        info->node = -1;        /* ??? danj */
@@ -841,6 +841,7 @@ static void valkyrie_init_info(struct fb_info *info, struct fb_info_valkyrie *p)
        info->switch_con = &valkyriefb_switch;
        info->updatevar = &valkyriefb_updatevar;
        info->blank = &valkyriefb_blank;
+       info->flags = FBINFO_FLAG_DEFAULT;
 }
 
 
index ede487d2a432c45180bc6c67363251e6404321dd..3c43bb76cc065d68fb59a1d45cd4391317ec45f5 100644 (file)
@@ -4,9 +4,9 @@
  * switching to graphics mode happens at boot time (while
  * running in real mode, see arch/i386/video.S).
  *
- * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
+ * (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
  *
- */ 
+ */
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -29,6 +29,7 @@
 #include <video/fbcon.h>
 #include <video/fbcon-cfb8.h>
 #include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
 #include <video/fbcon-cfb32.h>
 
 #define dac_reg        (0x3c8)
@@ -82,6 +83,9 @@ static union {
 #ifdef FBCON_HAS_CFB16
     u16 cfb16[16];
 #endif
+#ifdef FBCON_HAS_CFB24
+    u32 cfb24[16];
+#endif
 #ifdef FBCON_HAS_CFB32
     u32 cfb32[16];
 #endif
@@ -90,8 +94,8 @@ static union {
 static int             inverse   = 0;
 static int             currcon   = 0;
 
-static int             pmi_setpal = 1; /* pmi for palette changes ??? */
-static int             ypan       = 1;
+static int             pmi_setpal = 0; /* pmi for palette changes ??? */
+static int             ypan       = 0;
 static int             ywrap      = 0;
 static unsigned short  *pmi_base  = 0;
 static void            (*pmi_start)(void);
@@ -220,6 +224,12 @@ static void vesafb_set_disp(int con)
                display->dispsw_data = fbcon_cmap.cfb16;
                break;
 #endif
+#ifdef FBCON_HAS_CFB24
+       case 24:
+               sw = &fbcon_cfb24;
+               display->dispsw_data = fbcon_cmap.cfb24;
+               break;
+#endif
 #ifdef FBCON_HAS_CFB32
        case 32:
                sw = &fbcon_cfb32;
@@ -339,7 +349,13 @@ static int vesa_setcolreg(unsigned regno, unsigned red, unsigned green,
 #endif
 #ifdef FBCON_HAS_CFB24
        case 24:
-               /* FIXME: todo */
+               red   >>= 8;
+               green >>= 8;
+               blue  >>= 8;
+               fbcon_cmap.cfb24[regno] =
+                       (red   << vesafb_defined.red.offset)   |
+                       (green << vesafb_defined.green.offset) |
+                       (blue  << vesafb_defined.blue.offset);
                break;
 #endif
 #ifdef FBCON_HAS_CFB32
@@ -398,7 +414,7 @@ static int vesafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
        return 0;
 }
 
-static int vesafb_ioctl(struct inode *inode, struct file *file, 
+static int vesafb_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg, int con,
                       struct fb_info *info)
 {
@@ -437,8 +453,10 @@ void vesafb_setup(char *options, int *ints)
                        ywrap=0,ypan=1;
                else if (! strcmp(this_opt, "ywrap"))
                        ywrap=1,ypan=0;
-               else if (! strcmp(this_opt, "nopal"))
+               else if (! strcmp(this_opt, "vgapal"))
                        pmi_setpal=0;
+               else if (! strcmp(this_opt, "pmipal"))
+                       pmi_setpal=1;
                else if (!strncmp(this_opt, "font:", 5))
                        strcpy(fb_info.fontname, this_opt+5);
        }
@@ -578,6 +596,7 @@ __initfunc(void vesafb_init(void))
        fb_info.switch_con=&vesafb_switch;
        fb_info.updatevar=&vesafb_update_var;
        fb_info.blank=&vesafb_blank;
+       fb_info.flags=FBINFO_FLAG_DEFAULT;
        vesafb_set_disp(-1);
 
        if (register_framebuffer(&fb_info)<0)
index e4a31367f474a4307d587fa14605ce1c800bbcd8..ccc5e2a2753afc50d2aae6039e47ff07792e5f28 100644 (file)
@@ -445,6 +445,7 @@ __initfunc(void vfb_init(void))
     fb_info.switch_con = &vfbcon_switch;
     fb_info.updatevar = &vfbcon_updatevar;
     fb_info.blank = &vfbcon_blank;
+    fb_info.flags = FBINFO_FLAG_DEFAULT;
 
     vfb_set_var(&vfb_default, -1, &fb_info);
 
index 59ae403cc91df8ab24ef60dc2ce57a4e2ba4aecf..c7533d2cc2bda37b40141f3dbfb74dd1eeca2c26 100644 (file)
@@ -1059,6 +1059,7 @@ __initfunc(void virgefb_init(void))
        fb_info.switch_con = &Cyberfb_switch;
        fb_info.updatevar = &Cyberfb_updatevar;
        fb_info.blank = &Cyberfb_blank;
+       fb_info.flags = FBINFO_FLAG_DEFAULT;
 
        fbhw->init();
        fbhw->decode_var(&virgefb_default, &par);
index 5664f22e31cfab408a9e665e1b5cb0722f3ca8b2..4f28c91fb647c3f0ba10b198ee2a520137bfbb6b 100644 (file)
@@ -44,10 +44,6 @@ static int load_elf_library(int fd);
 extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
 extern void dump_thread(struct pt_regs *, struct user *);
 
-#ifdef __sparc__
-extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len);
-#endif
-
 #ifndef elf_addr_t
 #define elf_addr_t unsigned long
 #define elf_caddr_t char *
index 7043188f87e70f4424960def87372698bfae5318..8247ce277c83b2db5c14ceed615375b0440b32b8 100644 (file)
@@ -179,9 +179,9 @@ static int load_inode_bitmap (struct super_block * sb,
  */
 void ext2_free_inode (struct inode * inode)
 {
+       struct super_block * sb = inode->i_sb;
        int is_directory;
        unsigned long ino;
-       struct super_block * sb;
        struct buffer_head * bh;
        struct buffer_head * bh2;
        unsigned long block_group;
@@ -190,8 +190,6 @@ void ext2_free_inode (struct inode * inode)
        struct ext2_group_desc * gdp;
        struct ext2_super_block * es;
 
-       if (!inode)
-               return;
        if (!inode->i_dev) {
                printk ("ext2_free_inode: inode has no device\n");
                return;
@@ -205,7 +203,7 @@ void ext2_free_inode (struct inode * inode)
                        inode->i_nlink);
                return;
        }
-       if (!inode->i_sb) {
+       if (!sb) {
                printk("ext2_free_inode: inode on nonexistent device\n");
                return;
        }
@@ -213,15 +211,21 @@ void ext2_free_inode (struct inode * inode)
        ino = inode->i_ino;
        ext2_debug ("freeing inode %lu\n", ino);
 
-       sb = inode->i_sb;
+       /*
+        * Note: we must free any quota before locking the superblock,
+        * as writing the quota to disk may need the lock as well.
+        */
+       DQUOT_FREE_INODE(sb, inode);
+       DQUOT_DROP(inode);
+
        lock_super (sb);
-       if (ino < EXT2_FIRST_INO(sb) ||
-           ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) {
+       es = sb->u.ext2_sb.s_es;
+       if (ino < EXT2_FIRST_INO(sb) || 
+           ino > le32_to_cpu(es->s_inodes_count)) {
                ext2_error (sb, "free_inode",
                            "reserved inode or nonexistent inode");
                goto error_return;
        }
-       es = sb->u.ext2_sb.s_es;
        block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
        bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
        bitmap_nr = load_inode_bitmap (sb, block_group);
@@ -233,7 +237,6 @@ void ext2_free_inode (struct inode * inode)
        is_directory = S_ISDIR(inode->i_mode);
 
        /* Do this BEFORE marking the inode not in use */
-       DQUOT_FREE_INODE(sb, inode);
        clear_inode (inode);
 
        /* Ok, now we can actually update the inode bitmaps.. */
index b3871059e14bd35ba11dd953993e2bbea02aa96f..5e694afcec633653a991a9a0fb75200c6bd4674c 100644 (file)
@@ -1,7 +1,8 @@
-/* $Id: openpromfs.c,v 1.26 1998/01/28 09:55:32 ecd Exp $
+/* $Id: openpromfs.c,v 1.31 1998/08/26 10:32:19 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
- * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996-1998 Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
  */
 
 #include <linux/module.h>
@@ -27,7 +28,9 @@ typedef struct {
 
 typedef struct {
 #define OPP_STRING     0x10
-#define OPP_BINARY     0x20
+#define OPP_STRINGLIST 0x20
+#define OPP_BINARY     0x40
+#define OPP_HEXSTRING  0x80
 #define OPP_DIRTY      0x01
 #define OPP_QUOTED     0x02
 #define OPP_NOTQUOTED  0x04
@@ -83,7 +86,7 @@ static ssize_t property_read(struct file *filp, char *buf,
        struct inode *inode = filp->f_dentry->d_inode;
        int i, j, k;
        u32 node;
-       char *p;
+       char *p, *s;
        u32 *q;
        openprom_property *op;
        char buffer[64];
@@ -129,28 +132,51 @@ static ssize_t property_read(struct file *filp, char *buf,
                        return -EIO;
                op->value [k] = 0;
                if (k) {
-                       for (p = op->value; *p >= ' ' && *p <= '~'; p++);
-                       if (p >= op->value + k - 1 && !*p) {
-                               op->flag |= OPP_STRING;
-                               if (p == op->value + k - 1) {
-                                       op->flag |= OPP_ASCIIZ;
-                                       op->len--;
+                       for (s = 0, p = op->value; p < op->value + k; p++) {
+                               if ((*p >= ' ' && *p <= '~') || *p == '\n') {
+                                       op->flag |= OPP_STRING;
+                                       s = p;
+                                       continue;
                                }
-                       } else if (!(k & 3))
-                               op->flag |= OPP_BINARY;
-                       else {
-                               printk ("/proc/openprom: Strange property "
-                                       "size %d\n", i);
-                               return -EIO;
+                               if (p > op->value && !*p && s == p - 1) {
+                                       if (p < op->value + k - 1)
+                                               op->flag |= OPP_STRINGLIST;
+                                       else
+                                               op->flag |= OPP_ASCIIZ;
+                                       continue;
+                               }
+                               if (k == 1 && !*p) {
+                                       op->flag |= (OPP_STRING|OPP_ASCIIZ);
+                                       break;
+                               }
+                               op->flag &= ~(OPP_STRING|OPP_STRINGLIST);
+                               if (k & 3)
+                                       op->flag |= OPP_HEXSTRING;
+                               else
+                                       op->flag |= OPP_BINARY;
+                               break;
                        }
+                       if (op->flag & OPP_STRINGLIST)
+                               op->flag &= ~(OPP_STRING);
+                       if (op->flag & OPP_ASCIIZ)
+                               op->len--;
                }
        } else
                op = (openprom_property *)filp->private_data;
-       if (!count || !op->len) return 0;
-       if (op->flag & OPP_STRING)
+       if (!count || !(op->len || (op->flag & OPP_ASCIIZ)))
+               return 0;
+       if (op->flag & OPP_STRINGLIST) {
+               for (k = 0, p = op->value; p < op->value + op->len; p++)
+                       if (!*p)
+                               k++;
+               i = op->len + 4 * k + 3;
+       } else if (op->flag & OPP_STRING) {
                i = op->len + 3;
-       else
-               i = (op->len * 9)>>2;
+       } else if (op->flag & OPP_BINARY) {
+               i = (op->len * 9) >> 2;
+       } else {
+               i = (op->len << 1) + 1;
+       }
        k = filp->f_pos;
        if (k >= i) return 0;
        if (count > i - k) count = i - k;
@@ -160,20 +186,48 @@ static ssize_t property_read(struct file *filp, char *buf,
                        k++;
                        count--;
                }
+
                if (k + count >= i - 2)
                        j = i - 2 - k;
                else
                        j = count;
+
                if (j >= 0) {
                        copy_to_user(buf + k - filp->f_pos,
                                     op->value + k - 1, j);
                        count -= j;
                        k += j;
                }
+
                if (count)
                        __put_user('\'', &buf [k++ - filp->f_pos]);
                if (count > 1)
                        __put_user('\n', &buf [k++ - filp->f_pos]);
+
+       } else if (op->flag & OPP_STRINGLIST) {
+               char *tmp;
+
+               tmp = kmalloc (i, GFP_KERNEL);
+               if (!tmp)
+                       return -ENOMEM;
+
+               s = tmp;
+               *s++ = '\'';
+               for (p = op->value; p < op->value + op->len; p++) {
+                       if (!*p) {
+                               strcpy(s, "' + '");
+                               s += 5;
+                               continue;
+                       }
+                       *s++ = *p;
+               }
+               strcpy(s, "'\n");
+
+               copy_to_user(buf, tmp + k, count);
+
+               kfree(tmp);
+               k += count;
+
        } else if (op->flag & OPP_BINARY) {
                char buffer[10];
                u32 *first, *last;
@@ -205,9 +259,35 @@ static ssize_t property_read(struct file *filp, char *buf,
                                }
                        }
                }
+
                if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
                        __put_user('\n', (buf - 1));
+
                k += count;
+
+       } else if (op->flag & OPP_HEXSTRING) {
+               char buffer[2];
+
+               if ((k < i - 1) && (k & 1)) {
+                       sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+                       __put_user(buffer[1], &buf[k++ - filp->f_pos]);
+                       count--;
+               }
+
+               for (; (count > 1) && (k < i - 1); k += 2) {
+                       sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+                       copy_to_user (buf + k - filp->f_pos, buffer, 2);
+                       count -= 2;
+               }
+
+               if (count && (k < i - 1)) {
+                       sprintf (buffer, "%02x", *(op->value + (k >> 1)));
+                       __put_user(buffer[0], &buf[k++ - filp->f_pos]);
+                       count--;
+               }
+
+               if (count)
+                       __put_user('\n', &buf [k++ - filp->f_pos]);
        }
        count = k - filp->f_pos;
        filp->f_pos = k;
index c7918fb97eaa5442832fbd1c18787854f008a7ff..f8db4f4782af1816cea95621d57e17ecd1f5e23a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: linux_logo.h,v 1.3 1998/06/29 19:36:17 geert Exp $
+/* $Id: linux_logo.h,v 1.6 1998/07/30 16:30:20 jj Exp $
  * include/asm-alpha/linux_logo.h: This is a linux logo
  *                                 to be displayed on boot.
  *
 
 #define linux_logo_banner "Linux/AXP version " UTS_RELEASE
 
-#define LINUX_LOGO_COLORS 221
+#define LINUX_LOGO_COLORS 214
 
 #ifdef INCLUDE_LINUX_LOGO_DATA
 
+#define INCLUDE_LINUX_LOGOBW
 #define INCLUDE_LINUX_LOGO16
 
 #include <linux/linux_logo.h>
index ba3a969aea665d87c3ef297970681360a23c9227..5cd7e94d67a0b1495599ba44c71172dd125ccfef 100644 (file)
@@ -29,9 +29,7 @@ __initfunc(static void no_halt(char *s, int *ints))
 __initfunc(static void no_387(char *s, int *ints))
 {
        boot_cpu_data.hard_math = 0;
-       __asm__("movl %%cr0,%%eax\n\t"
-               "orl $0xE,%%eax\n\t"
-               "movl %%eax,%%cr0\n\t" : : : "ax");
+       write_cr0(0xE | read_cr0());
 }
 
 static char __initdata fpu_error = 0;
index cb04cefe4703e00672ff82432e79c3d8c78bc710..64886fc7cff546246c27921388a7406d34ba00ba 100644 (file)
@@ -104,14 +104,16 @@ static inline unsigned long _get_base(char * addr)
  * Clear and set 'TS' bit respectively
  */
 #define clts() __asm__ __volatile__ ("clts")
-#define stts() \
-__asm__ __volatile__ ( \
-       "movl %%cr0,%%eax\n\t" \
-       "orl $8,%%eax\n\t" \
-       "movl %%eax,%%cr0" \
-       : /* no outputs */ \
-       : /* no inputs */ \
-       :"ax")
+#define read_cr0() ({ \
+       unsigned int __dummy; \
+       __asm__( \
+               "movl %%cr0,%0\n\t" \
+               :"=r" (__dummy)); \
+       __dummy; \
+})
+#define write_cr0(x) \
+       __asm__("movl %0,%%cr0": :"r" (x));
+#define stts() write_cr0(8 | read_cr0())
 
 #endif /* __KERNEL__ */
 
index 7c3e4d0dabf47233a023e5889a07d1ac17709e26..fbaa0f005d8668ec076fbb4ab3300134ecc2570a 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.51 1998/07/26 03:05:37 davem Exp $
+/* $Id: bitops.h,v 1.54 1998/09/21 05:07:34 jj Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -108,7 +108,7 @@ extern __inline__ unsigned long test_and_set_bit(unsigned long nr, __SMPVOL void
        : "0" (mask), "r" (ADDR)
        : "g3", "g4", "g5", "g7", "cc");
 
-       return mask;
+       return mask != 0;
 }
 
 extern __inline__ void set_bit(unsigned long nr, __SMPVOL void *addr)
@@ -131,7 +131,7 @@ extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, __SMPVOL vo
        : "0" (mask), "r" (ADDR)
        : "g3", "g4", "g5", "g7", "cc");
 
-       return mask;
+       return mask != 0;
 }
 
 extern __inline__ void clear_bit(unsigned long nr, __SMPVOL void *addr)
@@ -154,7 +154,7 @@ extern __inline__ unsigned long test_and_change_bit(unsigned long nr, __SMPVOL v
        : "0" (mask), "r" (ADDR)
        : "g3", "g4", "g5", "g7", "cc");
 
-       return mask;
+       return mask != 0;
 }
 
 extern __inline__ void change_bit(unsigned long nr, __SMPVOL void *addr)
diff --git a/include/asm-sparc/ebus.h b/include/asm-sparc/ebus.h
new file mode 100644 (file)
index 0000000..2c8aa9f
--- /dev/null
@@ -0,0 +1,101 @@
+/* $Id: ebus.h,v 1.1 1998/09/22 05:54:41 jj Exp $
+ * ebus.h: PCI to Ebus pseudo driver software state.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 
+ *
+ * Adopted for sparc by V. Roganov and G. Raiko.
+ */
+
+#ifndef __SPARC_EBUS_H
+#define __SPARC_EBUS_H
+
+#include <asm/oplib.h>
+
+struct linux_ebus_child {
+       struct linux_ebus_child         *next;
+       struct linux_ebus_device        *parent;
+       struct linux_ebus               *bus;
+       int                              prom_node;
+       char                             prom_name[64];
+       unsigned long                    base_address[PROMREG_MAX];
+       int                              num_addrs;
+       unsigned int                     irqs[PROMINTR_MAX];
+       int                              num_irqs;
+};
+
+struct linux_ebus_device {
+       struct linux_ebus_device        *next;
+       struct linux_ebus_child         *children;
+       struct linux_ebus               *bus;
+       int                              prom_node;
+       char                             prom_name[64];
+       unsigned long                    base_address[PROMREG_MAX];
+       int                              num_addrs;
+       unsigned int                     irqs[PROMINTR_MAX];
+       int                              num_irqs;
+};
+
+struct linux_ebus {
+       struct linux_ebus               *next;
+       struct linux_ebus_device        *devices;
+       struct linux_pbm_info           *parent;
+       struct pci_dev                  *self;
+       int                              prom_node;
+       char                             prom_name[64];
+       struct linux_prom_ebus_ranges    ebus_ranges[PROMREG_MAX];
+       int                              num_ebus_ranges;
+};
+
+struct linux_ebus_dma {
+       unsigned int dcsr;
+       unsigned int dacr;
+       unsigned int dbcr;
+};
+
+#define EBUS_DCSR_INT_PEND     0x00000001
+#define EBUS_DCSR_ERR_PEND     0x00000002
+#define EBUS_DCSR_DRAIN                0x00000004
+#define EBUS_DCSR_INT_EN       0x00000010
+#define EBUS_DCSR_RESET                0x00000080
+#define EBUS_DCSR_WRITE                0x00000100
+#define EBUS_DCSR_EN_DMA       0x00000200
+#define EBUS_DCSR_CYC_PEND     0x00000400
+#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
+#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
+#define EBUS_DCSR_EN_CNT       0x00002000
+#define EBUS_DCSR_TC           0x00004000
+#define EBUS_DCSR_DIS_CSR_DRN  0x00010000
+#define EBUS_DCSR_BURST_SZ_MASK        0x000c0000
+#define EBUS_DCSR_BURST_SZ_1   0x00080000
+#define EBUS_DCSR_BURST_SZ_4   0x00000000
+#define EBUS_DCSR_BURST_SZ_8   0x00040000
+#define EBUS_DCSR_BURST_SZ_16  0x000c0000
+#define EBUS_DCSR_DIAG_EN      0x00100000
+#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
+#define EBUS_DCSR_TCI_DIS      0x00800000
+#define EBUS_DCSR_EN_NEXT      0x01000000
+#define EBUS_DCSR_DMA_ON       0x02000000
+#define EBUS_DCSR_A_LOADED     0x04000000
+#define EBUS_DCSR_NA_LOADED    0x08000000
+#define EBUS_DCSR_DEV_ID_MASK  0xf0000000
+
+extern struct linux_ebus               *ebus_chain;
+
+extern void ebus_init(void);
+
+#define for_each_ebus(bus)                                             \
+        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
+
+#define for_each_ebusdev(dev, bus)                                     \
+        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
+
+#define for_each_edevchild(dev, child)                                 \
+        for((child) = (dev)->children; (child); (child) = (child)->next)
+
+/* P3: Actually unused in sparc */
+#define for_all_ebusdev(dev, bus)                                      \
+       for ((bus) = ebus_chain, ((dev) = (bus) ? (bus)->devices : 0);  \
+            (bus); ((dev) = (dev)->next ? (dev)->next :                \
+            ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+
+#endif /* !(__SPARC_EBUS_H) */
index fb680d30f2e3bc7de03fc574af833afaa2743c39..acc8f418e3b77ddde85ba7d1e07f46832f769d13 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.17 1998/05/11 08:40:10 davem Exp $ */
+/* $Id: elf.h,v 1.20 1998/09/14 09:11:10 davem Exp $ */
 #ifndef __ASMSPARC_ELF_H
 #define __ASMSPARC_ELF_H
 
 #include <asm/ptrace.h>
 #include <asm/mbus.h>
 
+/* For the most part we present code dumps in the format
+ * Solaris does.
+ */
 typedef unsigned long elf_greg_t;
-
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+#define ELF_NGREG 38
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
-typedef unsigned long elf_fpregset_t;
+/* Format is:
+ *     G0 --> G7
+ *     O0 --> O7
+ *     L0 --> L7
+ *     I0 --> I7
+ *     PSR, PC, nPC, Y, WIM, TBR
+ */
+#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs)      \
+do {   unsigned long *dest = &(__elf_regs[0]);         \
+       struct pt_regs *src = (__pt_regs);              \
+       unsigned long *sp;                              \
+       memcpy(&dest[0], &src->u_regs[0],               \
+              sizeof(unsigned long) * 16);             \
+       /* Don't try this at home kids... */            \
+       set_fs(USER_DS);                                \
+       sp = (unsigned long *) src->u_regs[14];         \
+       copy_from_user(&dest[16], sp,                   \
+                      sizeof(unsigned long) * 16);     \
+       set_fs(KERNEL_DS);                              \
+       dest[32] = src->psr;                            \
+       dest[33] = src->pc;                             \
+       dest[34] = src->npc;                            \
+       dest[35] = src->y;                              \
+       dest[36] = dest[37] = 0; /* XXX */              \
+} while(0);
+
+typedef struct {
+       union {
+               unsigned long   pr_regs[32];
+               double          pr_dregs[16];
+       } pr_fr;
+       unsigned long __unused;
+       unsigned long   pr_fsr;
+       unsigned char   pr_qcnt;
+       unsigned char   pr_q_entrysize;
+       unsigned char   pr_en;
+       unsigned int    pr_q[64];
+} elf_fpregset_t;
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -42,7 +81,7 @@ typedef unsigned long elf_fpregset_t;
    the loader.  We need to make sure that it is out of the way of the program
    that it will "exec", and that there is sufficient room for the brk.  */
 
-#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE + 0x1000000)
+#define ELF_ET_DYN_BASE         (0x08000000)
 
 /* This yields a mask that user programs can use to figure out what
    instruction set this cpu supports.  This can NOT be done in userspace
index 443e3b18446726c07547faa53fbc4dcc1715d01f..41329f311a2d8405db8c7eaddb42a67dafd0d280 100644 (file)
@@ -35,6 +35,7 @@
 
 /* Does not seem to be listed in the Sun file either */
 #define FBTYPE_CREATOR          22
+#define FBTYPE_PCI_IGA1682     23
 
 /* fbio ioctls */
 /* Returned by FBIOGTYPE */
index 775a800d4f222f250a1dfd9d621bbbff65f31d0b..a8a3423cdeed969c6ccf1caea508cc17e94ec337 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.9 1997/02/04 07:29:20 davem Exp $ */
+/* $Id: fcntl.h,v 1.10 1998/08/26 10:33:29 davem Exp $ */
 #ifndef _SPARC_FCNTL_H
 #define _SPARC_FCNTL_H
 
index 3ccc7976659719e7ff12084cec2736e9a92ef2ac..933358872b3e8dc7875f400818997acb6d0897b5 100644 (file)
@@ -73,10 +73,6 @@ static struct sun_floppy_ops sun_fdops;
 
 #define FLOPPY_MOTOR_MASK         0x10
 
-/* It's all the same... */
-#define virt_to_bus(x)            (x)
-#define bus_to_virt(x)            (x)
-
 /* XXX This isn't really correct. XXX */
 #define get_dma_residue(x)        (0)
 
@@ -320,6 +316,8 @@ static int sun_floppy_init(void)
                                                                "floppy",
                                                                fd_regs[0].which_io,
                                                                0x0);
+       release_region((long)sun_fdc & PAGE_MASK, 
+                      (((long)sun_fdc & ~PAGE_MASK) + fd_regs[0].reg_size + PAGE_SIZE - 1) & PAGE_MASK);
        /* Last minute sanity check... */
        if(sun_fdc->status_82072 == 0xff) {
                sun_fdc = NULL;
index 8b0f4f9e2868184768bbd6dfc281ff7db3c69899..c3b50138b61ef751e11006fbb3ff169efd6e79d0 100644 (file)
@@ -19,7 +19,7 @@ extern unsigned int local_irq_count[NR_CPUS];
 #define hardirq_enter(cpu)     (local_irq_count[cpu]++)
 #define hardirq_exit(cpu)      (local_irq_count[cpu]--)
 
-#define synchronize_irq()      do { } while(0)
+#define synchronize_irq()      barrier()
 
 #else /* __SMP__ */
 
index 93e5fde773d24982fd588851381a400eee6a64f4..a26453b2fc1f8bf288d6d624556f6674e589a011 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.15 1998/01/30 10:59:51 jj Exp $ */
+/* $Id: io.h,v 1.18 1998/09/21 05:07:17 jj Exp $ */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
  * space only works on sun4's
  */
 
-extern __inline__ unsigned long inb_local(unsigned long addr)
+#define virt_to_bus virt_to_phys
+
+extern __inline__ unsigned  flip_dword (unsigned d) {
+        return ((d&0xff)<<24) | (((d>>8)&0xff)<<16) | (((d>>16)&0xff)<<8)| ((d>>24)&0xff);
+}
+
+extern __inline__ unsigned short flip_word (unsigned short d) {
+        return ((d&0xff) << 8) | ((d>>8)&0xff);
+}
+
+extern __inline__ unsigned long readb(unsigned long addr)
 {
-       return 0;
+       return *(volatile unsigned char*)addr;
 }
 
-extern __inline__ void outb_local(unsigned char b, unsigned long addr)
+extern __inline__ unsigned long readw(unsigned long addr)
 {
-       return;
+       return flip_word(*(volatile unsigned short*)addr);
 }
 
-extern __inline__ unsigned long inb(unsigned long addr)
+extern __inline__ unsigned long readl(unsigned long addr)
 {
-       return 0;
+       return flip_dword(*(volatile unsigned long*)addr);
 }
 
-extern __inline__ unsigned long inw(unsigned long addr)
+extern __inline__ void writeb(unsigned short b, unsigned long addr)
 {
-       return 0;
+       *(volatile unsigned char*)addr = b;
 }
 
-extern __inline__ unsigned long inl(unsigned long addr)
+extern __inline__ void writew(unsigned short b, unsigned long addr)
 {
-       return 0;
+       *(volatile unsigned short*)addr = flip_word(b);
 }
 
-extern __inline__ void outb(unsigned char b, unsigned long addr)
+extern __inline__ void writel(unsigned int b, unsigned long addr)
 {
-       return;
+        *(volatile unsigned long*)addr = flip_dword(b);
 }
 
-extern __inline__ void outw(unsigned short b, unsigned long addr)
+extern __inline__ unsigned long inb_local(unsigned long addr)
 {
-       return;
+       return readb(addr);
 }
 
-extern __inline__ void outl(unsigned int b, unsigned long addr)
+extern __inline__ void outb_local(unsigned char b, unsigned long addr)
 {
-       return;
+       return writeb(b,addr);
 }
 
-/*
- * Memory functions
- */
-extern __inline__ unsigned long readb(unsigned long addr)
+extern __inline__ unsigned long inb(unsigned long addr)
 {
-       return 0;
+       return readb(addr);
 }
 
-extern __inline__ unsigned long readw(unsigned long addr)
+extern __inline__ unsigned long inw(unsigned long addr)
 {
-       return 0;
+       return readw(addr);
 }
 
-extern __inline__ unsigned long readl(unsigned long addr)
+extern __inline__ unsigned long inl(unsigned long addr)
 {
-       return 0;
+       return readl(addr);
 }
 
-extern __inline__ void writeb(unsigned short b, unsigned long addr)
+extern __inline__ void outb(unsigned char b, unsigned long addr)
 {
-       return;
+       return writeb(b,addr);
 }
 
-extern __inline__ void writew(unsigned short b, unsigned long addr)
+extern __inline__ void outw(unsigned short b, unsigned long addr)
 {
-       return;
+       return writew(b,addr);
 }
 
-extern __inline__ void writel(unsigned int b, unsigned long addr)
+extern __inline__ void outl(unsigned int b, unsigned long addr)
 {
-       return;
+       return writel(b,addr);
 }
 
 #define inb_p inb
index 5cd982c28582d7ad5cd25d33373dfd39a94b6640..080be851cbb5950ae642cccba6da1db913f4e0d7 100644 (file)
 #define TIOCSERGETLSR   0x5459 /* Get line status register */
 #define TIOCSERGETMULTI 0x545A /* Get multiport config  */
 #define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT     0x545C /* Wait input */
+#define TIOCGICOUNT    0x545D /* Read serial port inline interrupt counts */
 
 /* Kernel definitions */
 #ifdef __KERNEL__
diff --git a/include/asm-sparc/keyboard.h b/include/asm-sparc/keyboard.h
new file mode 100644 (file)
index 0000000..9dd63c3
--- /dev/null
@@ -0,0 +1,52 @@
+/* $Id: keyboard.h,v 1.1 1998/09/22 05:54:42 jj Exp $
+ * linux/include/asm-sparc/keyboard.h
+ *
+ * sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
+ */
+
+/*
+ *  This file contains the Ultra/PCI architecture specific keyboard definitions
+ */
+
+#ifndef _SPARC_KEYBOARD_H
+#define _SPARC_KEYBOARD_H 1
+
+#ifdef __KERNEL__
+
+#define KEYBOARD_IRQ                   13
+#define DISABLE_KBD_DURING_INTERRUPTS  0
+
+extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pcikbd_getkeycode(unsigned int scancode);
+extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
+                           char raw_mode);
+extern char pcikbd_unexpected_up(unsigned char keycode);
+extern void pcikbd_leds(unsigned char leds);
+extern void pcikbd_init_hw(void);
+extern unsigned char pcikbd_sysrq_xlate[128];
+
+#define kbd_setkeycode                 pcikbd_setkeycode
+#define kbd_getkeycode                 pcikbd_getkeycode
+#define kbd_pretranslate               pcikbd_pretranslate
+#define kbd_translate                  pcikbd_translate
+#define kbd_unexpected_up              pcikbd_unexpected_up
+#define kbd_leds                       pcikbd_leds
+#define kbd_init_hw                    pcikbd_init_hw
+#define kbd_sysrq_xlate                        pcikbd_sysrq_xlate
+#define kbd_init                       pcikbd_init
+
+#define compute_shiftstate             pci_compute_shiftstate
+#define keyboard_wait_for_keypress     pci_wait_for_keypress
+#define getkeycode                     pci_getkeycode
+#define setkeycode                     pci_setkeycode
+#define getledstate                    pci_getledstate
+#define setledstate                    pci_setledstate
+#define register_leds                  pci_register_leds
+
+/* #define SYSRQ_KEY 0x54 */   /* sparc64 */
+#define SYSRQ_KEY 0x63         /* sparc */
+
+#endif /* __KERNEL__ */
+
+#endif /* !(_SPARC_KEYBOARD_H) */
index 4078693481d3fd12be769ecea1ba70c4c47f823f..e83d44d3c4baa10c9009263af6705cfe3bc2cc14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mostek.h,v 1.9 1998/07/28 16:53:25 jj Exp $
+/* $Id: mostek.h,v 1.10 1998/08/18 15:03:11 davem Exp $
  * mostek.h:  Describes the various Mostek time of day clock registers.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
index 91f5ffb68959f05a4b8216ccb91efe56b600fd80..c88dc02a175670a33d215f1f132e768d3b66554e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.20 1997/04/10 06:41:06 davem Exp $ */
+/* $Id: openprom.h,v 1.23 1998/09/21 05:07:26 jj Exp $ */
 #ifndef __SPARC_OPENPROM_H
 #define __SPARC_OPENPROM_H
 
@@ -205,6 +205,55 @@ struct linux_prom_ranges {
        unsigned int or_size;
 };
 
+/* Ranges and reg properties are a bit different for PCI. */
+struct linux_prom_pci_registers {
+       /* 
+        * We don't know what information this field contain.
+        * We guess, PCI device function is in bits 15:8
+        * So, ...
+        */
+       unsigned int which_io;  /* Let it be which_io */
+
+       unsigned int phys_hi;
+       unsigned int phys_lo;
+
+       unsigned int size_hi;
+       unsigned int size_lo;
+};
+
+struct linux_prom_pci_ranges {
+       unsigned int child_phys_hi;     /* Only certain bits are encoded here. */
+       unsigned int child_phys_mid;
+       unsigned int child_phys_lo;
+
+       unsigned int parent_phys_hi;
+       unsigned int parent_phys_lo;
+
+       unsigned int size_hi;
+       unsigned int size_lo;
+};
+
+struct linux_prom_pci_assigned_addresses {
+       unsigned int which_io;
+
+       unsigned int phys_hi;
+       unsigned int phys_lo;
+
+       unsigned int size_hi;
+       unsigned int size_lo;
+};
+
+struct linux_prom_ebus_ranges {
+       unsigned int child_phys_hi;
+       unsigned int child_phys_lo;
+
+       unsigned int parent_phys_hi;
+       unsigned int parent_phys_mid;
+       unsigned int parent_phys_lo;
+
+       unsigned int size;
+};
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(__SPARC_OPENPROM_H) */
index 2d1094b07a0f6fca35a508214e1c1052e12e8f05..396f9ef0742522a28936416d393c67fcfc00dd16 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.19 1998/01/30 10:59:53 jj Exp $
+/* $Id: oplib.h,v 1.20 1998/09/17 11:05:25 jj Exp $
  * oplib.h:  Describes the interface and available routines in the
  *           Linux Prom library.
  *
@@ -280,6 +280,9 @@ extern char *prom_firstprop(int node, char *buffer);
  */
 extern char *prom_nextprop(int node, char *prev_property, char *buffer);
 
+/* Returns phandle of the path specified */
+extern int prom_finddevice(char *name);
+
 /* Returns 1 if the specified node has given property. */
 extern int prom_node_has_property(int node, char *property);
 
diff --git a/include/asm-sparc/pbm.h b/include/asm-sparc/pbm.h
new file mode 100644 (file)
index 0000000..a8ef7cc
--- /dev/null
@@ -0,0 +1,56 @@
+/* $Id: pbm.h,v 1.1 1998/09/22 05:54:44 jj Exp $
+ * pbm.h: PCI bus module pseudo driver software state
+ *        Adopted from sparc64 by V. Roganov and G. Raiko
+ *
+ * Original header:
+ * pbm.h: U2P PCI bus module pseudo driver software state.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC_PBM_H
+#define __SPARC_PBM_H
+
+#include <linux/pci.h>
+#include <asm/oplib.h>
+
+struct linux_pbm_info;
+
+/* This is what we use to determine what the PROM has assigned so
+ * far, so that we can perform assignments for addresses which
+ * were not taken care of by OBP.  See psycho.c for details.
+ * Per-PBM these are ordered by start address.
+ */
+struct pci_vma {
+       struct pci_vma                  *next;
+       struct linux_pbm_info           *pbm;
+       unsigned int                    start;
+       unsigned int                    end;
+       unsigned int                    offset;
+       unsigned int                    _pad;
+};
+
+struct linux_pbm_info {
+       struct pci_vma                  *IO_assignments;
+       struct pci_vma                  *MEM_assignments;
+       int                             prom_node;
+       char                            prom_name[64];
+       struct linux_prom_pci_ranges    pbm_ranges[PROMREG_MAX];
+       int                             num_pbm_ranges;
+
+       /* Now things for the actual PCI bus probes. */
+       unsigned int                    pci_first_busno;
+       unsigned int                    pci_last_busno;
+       struct pci_bus                  pci_bus;
+};
+
+/* PCI devices which are not bridges have this placed in their pci_dev
+ * sysdata member.  This makes OBP aware PCI device drivers easier to
+ * code.
+ */
+struct pcidev_cookie {
+       struct linux_pbm_info           *pbm;
+       int                             prom_node;
+};
+
+#endif /* !(__SPARC_PBM_H) */
diff --git a/include/asm-sparc/pcic.h b/include/asm-sparc/pcic.h
new file mode 100644 (file)
index 0000000..c0d4dbb
--- /dev/null
@@ -0,0 +1,106 @@
+/* $Id: pcic.h,v 1.1 1998/09/22 05:54:39 jj Exp $
+ * pcic.h: JavaEngine 1 specific PCI definitions.
+ *
+ * Copyright (C) 1998 V. Roganov and G. Raiko
+ */
+
+#ifndef __SPARC_PCIC_H
+#define __SPARC_PCIC_H
+
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+#include <asm/pbm.h>
+
+struct linux_pcic {
+        unsigned long           pcic_regs;
+        unsigned long           pcic_io;
+        unsigned long           pcic_io_phys;
+        unsigned long           pcic_mapped_io;
+        unsigned long           pcic_config_space_addr;
+        unsigned long           pcic_config_space_data;
+        struct linux_pbm_info   pbm;
+};
+
+extern unsigned long pcic_alloc_io(unsigned long* addr);
+extern void pcic_probe(void);
+extern void sun4m_pci_init_IRQ(void);
+
+/* Size of PCI Space */
+#define PCI_SPACE_SIZE                  0x1000000       /* 16 MB */
+
+/* PCIC Register Set. */
+#define PCI_DIAGNOSTIC_0                0x40    /* 32 bits */
+#define PCI_SIZE_0                      0x44    /* 32 bits */
+#define PCI_SIZE_1                      0x48    /* 32 bits */
+#define PCI_SIZE_2                      0x4c    /* 32 bits */
+#define PCI_SIZE_3                      0x50    /* 32 bits */
+#define PCI_SIZE_4                      0x54    /* 32 bits */
+#define PCI_SIZE_5                      0x58    /* 32 bits */
+#define PCI_PIO_CONTROL                 0x60    /* 8  bits */
+#define PCI_DVMA_CONTROL                0x62    /* 8  bits */
+#define  PCI_DVMA_CONTROL_INACTIVITY_REQ        (1<<0)
+#define  PCI_DVMA_CONTROL_IOTLB_ENABLE          (1<<0)
+#define  PCI_DVMA_CONTROL_IOTLB_DISABLE         0
+#define  PCI_DVMA_CONTROL_INACTIVITY_ACK        (1<<4)
+#define PCI_INTERRUPT_CONTROL           0x63    /* 8  bits */
+#define PCI_CPU_INTERRUPT_PENDING       0x64    /* 32 bits */
+#define PCI_DIAGNOSTIC_1                0x68    /* 16 bits */
+#define PCI_SOFTWARE_INT_CLEAR          0x6a    /* 16 bits */
+#define PCI_SOFTWARE_INT_SET            0x6e    /* 16 bits */
+#define PCI_SYS_INT_PENDING             0x70    /* 32 bits */
+#define PCI_SYS_INT_TARGET_MASK         0x74    /* 32 bits */
+#define PCI_SYS_INT_TARGET_MASK_CLEAR   0x78    /* 32 bits */
+#define PCI_SYS_INT_TARGET_MASK_SET     0x7c    /* 32 bits */
+#define PCI_SYS_INT_PENDING_CLEAR       0x83    /* 8  bits */
+#define PCI_IOTLB_CONTROL               0x84    /* 8  bits */
+#define PCI_INT_SELECT_LO               0x88    /* 16 bits */
+#define PCI_ARBITRATION_SELECT          0x8a    /* 16 bits */
+#define PCI_INT_SELECT_HI               0x8c    /* 16 bits */
+#define PCI_HW_INT_OUTPUT               0x8e    /* 16 bits */
+#define PCI_IOTLB_RAM_INPUT             0x90    /* 32 bits */
+#define PCI_IOTLB_CAM_INPUT             0x94    /* 32 bits */
+#define PCI_IOTLB_RAM_OUTPUT            0x98    /* 32 bits */
+#define PCI_IOTLB_CAM_OUTPUT            0x9c    /* 32 bits */
+#define PCI_SMBAR0                      0xa0    /* 8  bits */
+#define PCI_MSIZE0                      0xa1    /* 8  bits */
+#define PCI_PMBAR0                      0xa2    /* 8  bits */
+#define PCI_SMBAR1                      0xa4    /* 8  bits */
+#define PCI_MSIZE1                      0xa5    /* 8  bits */
+#define PCI_PMBAR1                      0xa6    /* 8  bits */
+#define PCI_SIBAR                       0xa8    /* 8  bits */
+#define   PCI_SIBAR_ADDRESS_MASK        0xf
+#define PCI_ISIZE                       0xa9    /* 8  bits */
+#define   PCI_ISIZE_16M                 0xf
+#define   PCI_ISIZE_32M                 0xe
+#define   PCI_ISIZE_64M                 0xc
+#define   PCI_ISIZE_128M                0x8
+#define   PCI_ISIZE_256M                0x0
+#define PCI_PIBAR                       0xaa    /* 8  bits */
+#define PCI_CPU_COUNTER_LIMIT_HI        0xac    /* 32 bits */
+#define PCI_CPU_COUNTER_LIMIT_LO        0xb0    /* 32 bits */
+#define PCI_CPU_COUNTER_LIMIT           0xb4    /* 32 bits */
+#define PCI_SYS_LIMIT                   0xb8    /* 32 bits */
+#define PCI_SYS_COUNTER                 0xbc    /* 32 bits */
+#define   PCI_SYS_COUNTER_OVERFLOW      (1<<31) /* Limit reached */
+#define PCI_SYS_LIMIT_PSEUDO            0xc0    /* 32 bits */
+#define PCI_USER_TIMER_CONTROL          0xc4    /* 8  bits */
+#define PCI_USER_TIMER_CONFIG           0xc5    /* 8  bits */
+#define PCI_COUNTER_IRQ                 0xc6    /* 8  bits */
+#define  PCI_COUNTER_IRQ_SET(sys_irq, cpu_irq)  ((((sys_irq) & 0xf) << 4) | \
+                                                  ((cpu_irq) & 0xf))
+#define  PCI_COUNTER_IRQ_SYS(v)                 (((v) >> 4) & 0xf)
+#define  PCI_COUNTER_IRQ_CPU(v)                 ((v) & 0xf)
+#define PCI_PIO_ERROR_COMMAND           0xc7    /* 8  bits */
+#define PCI_PIO_ERROR_ADDRESS           0xc8    /* 32 bits */
+#define PCI_IOTLB_ERROR_ADDRESS         0xcc    /* 32 bits */
+#define PCI_SYS_STATUS                  0xd0    /* 8  bits */
+#define   PCI_SYS_STATUS_RESET_ENABLE           (1<<0)
+#define   PCI_SYS_STATUS_RESET                  (1<<1)
+#define   PCI_SYS_STATUS_WATCHDOG_RESET         (1<<4)
+#define   PCI_SYS_STATUS_PCI_RESET              (1<<5)
+#define   PCI_SYS_STATUS_PCI_RESET_ENABLE       (1<<6)
+#define   PCI_SYS_STATUS_PCI_SATTELITE_MODE     (1<<7)
+
+#endif /* !(__SPARC_PCIC_H) */
index 54420d89d3ad0cba7d47cc0976e349743b8b5646..174984e11e452e83c1b2cbaf9568528b73c69fd3 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.3 1995/11/25 02:32:42 davem Exp $ */
+/* $Id: shmparam.h,v 1.4 1998/09/28 07:15:01 jj Exp $ */
 #ifndef _ASMSPARC_SHMPARAM_H
 #define _ASMSPARC_SHMPARAM_H
 
@@ -34,7 +34,7 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX (1024 * 1024)           /* max shared seg size (bytes) */
+#define SHMMAX 0x1000000               /* max shared seg size (bytes) */
 #define SHMMIN 1 /* really PAGE_SIZE */        /* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)       /* max num of segs system wide */
 #define SHMALL                         /* max shm system wide (pages) */ \
index 0a666b4e2fb7a3e52bbe3a362c253a7c1ddb51e1..f20a5a81cb16a5b1c2f70d4a3ccf8a0248d14e07 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: siginfo.h,v 1.2 1998/07/30 11:31:49 davem Exp $
+/* $Id: siginfo.h,v 1.3 1998/08/26 10:33:29 davem Exp $
  * siginfo.c:
  */
 
index 3cbb49c8689233b4d6cf34055222f902c224a3ad..2a4b6a69f2237b533524aef9a4fa58095362f044 100644 (file)
@@ -65,6 +65,9 @@ void smp_callin(void);
 void smp_boot_cpus(void);
 void smp_store_cpu_info(int);
 
+int smp_bogo_info(char *buf);
+int smp_info(char *buf);
+
 BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
 BTFIXUPDEF_CALL(void, smp_message_pass, int, int, unsigned long, int)
 BTFIXUPDEF_CALL(int, __smp_processor_id, void)
@@ -74,12 +77,6 @@ BTFIXUPDEF_BLACKBOX(load_current)
 #define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5)
 #define smp_message_pass(target,msg,data,wait) BTFIXUP_CALL(smp_message_pass)(target,msg,data,wait)
 
-BTFIXUPDEF_CALL(int, smp_bogo_info, char *)
-BTFIXUPDEF_CALL(int, smp_info, char *)
-
-#define smp_bogo_info(buf) BTFIXUP_CALL(smp_bogo_info)(buf)
-#define smp_info(buf) BTFIXUP_CALL(smp_info)(buf)
-
 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); }
@@ -184,8 +181,7 @@ extern __inline__ int hard_smp_processor_id(void)
 
 #define SMP_FROM_INT           1
 #define SMP_FROM_SYSCALL       2
-
-#else /* !(__SMP__) */
+#endif /* !(__SMP__) */
 
 #define NO_PROC_ID            0xFF
 
index 50fbc20e70cfffe36deacbe95b889b65a709553a..5cabdc0e79bc8a8f5f41b353fb0da2f87067bacf 100644 (file)
@@ -99,7 +99,7 @@ extern int __sparc_bh_counter;
 #define softirq_trylock(cpu) (__sparc_bh_counter ? 0 : (__sparc_bh_counter=1))
 #define softirq_endlock(cpu) (__sparc_bh_counter = 0)
 #define clear_active_bhs(x)    (bh_active &= ~(x))
-#define synchronize_bh()       do { } while (0) /* XXX implement SMP version -DaveM */
+#define synchronize_bh()       barrier() /* XXX implement SMP version -DaveM */
 
 #define init_bh(nr, routine)   \
 do {   int ent = nr;           \
index 1683df48ecd3d7e661db9f60c49f222c10df6e49..22fe5e280b2205a8f8e8da64b64b4c6dab3151e0 100644 (file)
@@ -61,7 +61,7 @@ typedef struct { } rwlock_t;
 #include <asm/psr.h>
 
 /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
-/* #define SPIN_LOCK_DEBUG */
+#define SPIN_LOCK_DEBUG
 
 #ifdef SPIN_LOCK_DEBUG
 struct _spinlock_debug {
@@ -72,69 +72,71 @@ typedef struct _spinlock_debug spinlock_t;
 
 #define SPIN_LOCK_UNLOCKED     { 0, 0 }
 #define spin_lock_init(lp)     do { (lp)->owner_pc = 0; (lp)->lock = 0; } while(0)
-#define spin_unlock_wait(lp)   \
-do { barrier();        \
-} while(*(volatile unsigned char *)(&(lp)->lock))
+#define spin_unlock_wait(lp)   do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock))
 
-extern void _spin_lock(spinlock_t *lock);
+extern void _do_spin_lock(spinlock_t *lock, char *str);
 extern int _spin_trylock(spinlock_t *lock);
-extern void _spin_unlock(spinlock_t *lock);
-extern void _spin_lock_irq(spinlock_t *lock);
-extern void _spin_unlock_irq(spinlock_t *lock);
-extern void _spin_lock_irqsave(spinlock_t *lock);
-extern void _spin_unlock_irqrestore(spinlock_t *lock);
-
-#define spin_lock(lp)                  _spin_lock(lp)
-#define spin_trylock(lp)               _spin_trylock(lp)
-#define spin_unlock(lp)                        _spin_unlock(lp)
-#define spin_lock_irq(lp)              _spin_lock_irq(lp)
-#define spin_unlock_irq(lp)            _spin_unlock_irq(lp)
-#define spin_lock_irqsave(lp, flags)   do { __save_and_cli(flags); \
-                                            _spin_lock_irqsave(lp); } while (0)
-#define spin_unlock_irqrestore(lp, flags) do { _spin_unlock_irqrestore(lp); \
-                                              __restore_flags(flags); } while(0)
+extern void _do_spin_unlock(spinlock_t *lock);
+
+#define spin_trylock(lp)       _spin_trylock(lp)
+
+#define spin_lock(lock)                _do_spin_lock(lock, "spin_lock")
+#define spin_lock_irq(lock)    do { __cli(); _do_spin_lock(lock, "spin_lock_irq"); } while(0)
+#define spin_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_spin_lock(lock, "spin_lock_irqsave"); } while(0)
+
+#define spin_unlock(lock)      _do_spin_unlock(lock)
+#define spin_unlock_irq(lock)  do { _do_spin_unlock(lock); __sti(); } while(0)
+#define spin_unlock_irqrestore(lock, flags) do { _do_spin_unlock(lock); __restore_flags(flags); } while(0)
 
 struct _rwlock_debug {
        volatile unsigned int lock;
        unsigned long owner_pc;
+       unsigned long reader_pc[NCPUS];
 };
 typedef struct _rwlock_debug rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0 }
-
-extern void _read_lock(rwlock_t *rw);
-extern void _read_unlock(rwlock_t *rw);
-extern void _write_lock(rwlock_t *rw);
-extern void _write_unlock(rwlock_t *rw);
-extern void _read_lock_irq(rwlock_t *rw);
-extern void _read_unlock_irq(rwlock_t *rw);
-extern void _write_lock_irq(rwlock_t *rw);
-extern void _write_unlock_irq(rwlock_t *rw);
-extern void _read_lock_irqsave(rwlock_t *rw);
-extern void _read_unlock_irqrestore(rwlock_t *rw);
-extern void _write_lock_irqsave(rwlock_t *rw);
-extern void _write_unlock_irqrestore(rwlock_t *rw);
-
-#define read_lock(rw)          _read_lock(rw)
-#define read_unlock(rw)                _read_unlock(rw)
-#define write_lock(rw)         _write_lock(rw)
-#define write_unlock(rw)       _write_unlock(rw)
-#define read_lock_irq(rw)      _read_lock_irq(rw)
-#define read_unlock_irq(rw)    _read_unlock_irq(rw)
-#define write_lock_irq(rw)     _write_lock_irq(rw)
-#define write_unlock_irq(rw)   _write_unlock_irq(rw)
-
-#define read_lock_irqsave(rw, flags) \
-do { __save_and_cli(flags); _read_lock_irqsave(rw); } while (0)
-
-#define read_unlock_irqrestore(rw, flags) do { _read_unlock_irqrestore(rw); \
-                                              __restore_flags(flags); } while(0)
-
-#define write_lock_irqsave(rw, flags) \
-do { __save_and_cli(flags); _write_lock_irqsave(rw); } while(0)
-
-#define write_unlock_irqrestore(rw, flags) do { _write_unlock_irqrestore(rw); \
-                                               __restore_flags(flags); } while(0)
+#define RW_LOCK_UNLOCKED { 0, 0, {0} }
+
+extern void _do_read_lock(rwlock_t *rw, char *str);
+extern void _do_read_unlock(rwlock_t *rw, char *str);
+extern void _do_write_lock(rwlock_t *rw, char *str);
+extern void _do_write_unlock(rwlock_t *rw);
+
+#define read_lock(lock)        \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_read_lock(lock, "read_lock"); \
+       __restore_flags(flags); \
+} while(0)
+#define read_lock_irq(lock)    do { __cli(); _do_read_lock(lock, "read_lock_irq"); } while(0)
+#define read_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_read_lock(lock, "read_lock_irqsave"); } while(0)
+
+#define read_unlock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_read_unlock(lock, "read_unlock"); \
+       __restore_flags(flags); \
+} while(0)
+#define read_unlock_irq(lock)  do { _do_read_unlock(lock, "read_unlock_irq"); __sti() } while(0)
+#define read_unlock_irqrestore(lock, flags) do { _do_read_unlock(lock, "read_unlock_irqrestore"); __restore_flags(flags); } while(0)
+
+#define write_lock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_write_lock(lock, "write_lock"); \
+       __restore_flags(flags); \
+} while(0)
+#define write_lock_irq(lock)   do { __cli(); _do_write_lock(lock, "write_lock_irq"); } while(0)
+#define write_lock_irqsave(lock, flags) do { __save_and_cli(flags); _do_write_lock(lock, "write_lock_irqsave"); } while(0)
+
+#define write_unlock(lock) \
+do {   unsigned long flags; \
+       __save_and_cli(flags); \
+       _do_write_unlock(lock); \
+       __restore_flags(flags); \
+} while(0)
+#define write_unlock_irq(lock) do { _do_write_unlock(lock); __sti(); } while(0)
+#define write_unlock_irqrestore(lock, flags) do { _do_write_unlock(lock); __restore_flags(flags); } while(0)
 
 #else /* !SPIN_LOCK_DEBUG */
 
index 01ed7659eac75fe237cacf9f4d7a116de3b55765..82244a33f7cfb6da550c0fbbd3c49de9b231dcb0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.69 1998/04/24 12:30:19 davem Exp $ */
+/* $Id: system.h,v 1.70 1998/09/29 09:46:32 davem Exp $ */
 #include <linux/config.h>
 
 #ifndef __SPARC_SYSTEM_H
@@ -151,7 +151,7 @@ extern __inline__ void __cli(void)
 
        __asm__ __volatile__("
                rd      %%psr, %0
-               nop; nop; nop;
+               nop; nop; nop;          /* Sun4m + Cypress + SMP bug */
                or      %0, %1, %0
                wr      %0, 0x0, %%psr
                nop; nop; nop
@@ -166,7 +166,7 @@ extern __inline__ void __sti(void)
 
        __asm__ __volatile__("
                rd      %%psr, %0       
-               nop; nop; nop;
+               nop; nop; nop;          /* Sun4m + Cypress + SMP bug */
                andn    %0, %1, %0
                wr      %0, 0x0, %%psr
                nop; nop; nop
@@ -189,7 +189,7 @@ extern __inline__ unsigned long swap_pil(unsigned long __new_psr)
 
        __asm__ __volatile__("
                rd      %%psr, %0
-               nop; nop; nop;
+               nop; nop; nop;          /* Sun4m + Cypress + SMP bug */
                and     %0, %2, %%g1
                and     %1, %2, %%g2
                xorcc   %%g1, %%g2, %%g0
@@ -211,7 +211,7 @@ extern __inline__ unsigned long read_psr_and_cli(void)
 
        __asm__ __volatile__("
                rd      %%psr, %0
-               nop; nop; nop;
+               nop; nop; nop;          /* Sun4m + Cypress + SMP bug */
                or      %0, %1, %%g1
                wr      %%g1, 0x0, %%psr
                nop; nop; nop
index 234343ad6783ee5da9f60f557c60ba325ab2d895..aeefe28e4696c0b8ad2d3471b23e27b90dd0884c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.26 1998/04/12 06:27:19 davem Exp $ */
+/* $Id: termios.h,v 1.27 1998/10/04 06:50:13 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
index f1b41f7e49cf37b914b38f8da2a6a60f3872d080..843ff4b7c665c8200e0d9c18e0c7f45142a9fc52 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: timer.h,v 1.17 1998/04/24 12:30:19 davem Exp $
+/* $Id: timer.h,v 1.20 1998/09/21 05:07:37 jj Exp $
  * timer.h:  Definitions for the timer chips on the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -11,6 +11,7 @@
 
 #include <asm/system.h>  /* For NCPUS */
 #include <asm/sun4paddr.h>
+#include <asm/btfixup.h>
 
 /* Timer structures. The interrupt timer has two properties which
  * are the counter (which is handled in do_timer in sched.c) and the limit.
@@ -102,4 +103,8 @@ extern struct sun4d_timer_regs *sun4d_timers;
 extern __volatile__ unsigned int *master_l10_counter;
 extern __volatile__ unsigned int *master_l10_limit;
 
+/* FIXME: Make do_[gs]ettimeofday btfixup calls */
+BTFIXUPDEF_CALL(void, bus_do_settimeofday, struct timeval *tv)
+#define bus_do_settimeofday(tv) BTFIXUP_CALL(bus_do_settimeofday)(tv)
+
 #endif /* !(_SPARC_TIMER_H) */
index b0adb815820ab6dae8bb96a38391e57f49064d4e..5078d901bda69d00b82386a407c77b60ed3ce0f0 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: turbosparc.h,v 1.3 1997/06/26 12:59:27 jj Exp $
+/* $Id: turbosparc.h,v 1.4 1998/08/16 16:02:42 ecd Exp $
  * turbosparc.h:  Defines specific to the TurboSparc module.
  *            This is SRMMU stuff.
  *
@@ -74,8 +74,10 @@ extern __inline__ void turbosparc_inv_data_tag(unsigned long addr)
 
 extern __inline__ void turbosparc_flush_icache(void)
 {
-       __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : :
-                            "i" (ASI_M_IC_FLCLEAR));
+       unsigned long addr;
+
+        for(addr = 0; addr < 0x4000; addr += 0x20)
+                turbosparc_inv_insn_tag(addr);
 }
 
 extern __inline__ void turbosparc_flush_dcache(void)
@@ -88,7 +90,12 @@ extern __inline__ void turbosparc_flush_dcache(void)
 
 extern __inline__ void turbosparc_idflash_clear(void)
 {
-       turbosparc_flush_icache(); turbosparc_flush_dcache();
+       unsigned long addr;
+
+        for(addr = 0; addr < 0x4000; addr += 0x20) {
+                turbosparc_inv_insn_tag(addr);
+                turbosparc_inv_data_tag(addr);
+       }
 }
 
 extern __inline__ void turbosparc_set_ccreg(unsigned long regval)
index 3f4a586014351a3db46dbb96f775b01a6fe30f51..a2affc181e8370afa200c0cca57f5a05ef34f099 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.15 1998/02/05 14:19:54 jj Exp $
+/* $Id: uaccess.h,v 1.17 1998/09/16 12:25:29 jj Exp $
  * uaccess.h: User space memore access functions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -324,8 +324,6 @@ __kernel_size_t __copy_size = (__kernel_size_t) (n); \
 __kernel_size_t __copy_res; \
 if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \
 __copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
-if(__copy_res) \
-memset((char *)__copy_to + __copy_size - __copy_res, 0, __copy_res); \
 } else __copy_res = __copy_size; \
 __copy_res; })
 
index dae8e0ac3f21634d26c4fa97ef21a64554ebe1ec..fdc7d1acf3297eb6c6c3588c7bb61d45320000d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.42 1998/07/28 13:08:35 jj Exp $ */
+/* $Id: unistd.h,v 1.47 1998/09/21 05:07:22 jj Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -16,7 +16,6 @@
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  */
 
-#define __NR_setup                0 /* Used only by init, to get system going.     */
 #define __NR_exit                 1 /* Common                                      */
 #define __NR_fork                 2 /* Common                                      */
 #define __NR_read                 3 /* Common                                      */
 #define __NR_unlink              10 /* Common                                      */
 #define __NR_execv               11 /* SunOS Specific                              */
 #define __NR_chdir               12 /* Common                                      */
-/* #define __NR_ni_syscall       13    ENOSYS under SunOS                          */
+#define __NR_chown               13 /* Common                                      */
 #define __NR_mknod               14 /* Common                                      */
 #define __NR_chmod               15 /* Common                                      */
-#define __NR_chown               16 /* Common                                      */
+#define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
 /* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
 #define __NR_lseek               19 /* Common                                      */
 #define __NR_setrlimit          145 /* Common                                      */
 #define __NR_killpg             146 /* SunOS Specific                              */
 #define __NR_prctl             147 /* ENOSYS under SunOS                          */
-/* #define __NR_ni_syscall      148    ENOSYS under SunOS                          */
-/* #define __NR_ni_syscall      149    ENOSYS under SunOS                          */
+#define __NR_pciconfig_read     148 /* ENOSYS under SunOS                          */
+#define __NR_pciconfig_write    149 /* ENOSYS under SunOS                          */
 #define __NR_getsockname        150 /* Common                                      */
 #define __NR_getmsg             151 /* SunOS Specific                              */
 #define __NR_putmsg             152 /* SunOS Specific                              */
@@ -426,7 +425,6 @@ return -1; \
 #define __NR__exit __NR_exit
 static __inline__ _syscall0(int,idle)
 static __inline__ _syscall0(int,pause)
-static __inline__ _syscall1(int,setup,int,magic)
 static __inline__ _syscall0(int,sync)
 static __inline__ _syscall0(pid_t,setsid)
 static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
index bc1bdb8dc14dbe217b7347fad4a357134e52ab93..be0a2e243af354b1c019b6e8ce22173dd1f6e99d 100644 (file)
 #define ASIZ_task_cap_inheritable      0x00000004
 #define AOFF_task_cap_permitted        0x0000029c
 #define ASIZ_task_cap_permitted        0x00000004
-#define AOFF_task_rlim 0x000002a0
+#define AOFF_task_user 0x000002a0
+#define ASIZ_task_user 0x00000008
+#define AOFF_task_rlim 0x000002a8
 #define ASIZ_task_rlim 0x000000a0
-#define AOFF_task_used_math    0x00000340
+#define AOFF_task_used_math    0x00000348
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_comm 0x00000342
+#define AOFF_task_comm 0x0000034a
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x00000354
+#define AOFF_task_link_count   0x0000035c
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x00000358
+#define AOFF_task_tty  0x00000360
 #define ASIZ_task_tty  0x00000008
-#define AOFF_task_semundo      0x00000360
+#define AOFF_task_semundo      0x00000368
 #define ASIZ_task_semundo      0x00000008
-#define AOFF_task_semsleeping  0x00000368
+#define AOFF_task_semsleeping  0x00000370
 #define ASIZ_task_semsleeping  0x00000008
-#define AOFF_task_tss  0x00000370
+#define AOFF_task_tss  0x00000380
 #define ASIZ_task_tss  0x00000440
-#define AOFF_task_fs   0x000007b0
+#define AOFF_task_fs   0x000007c0
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x000007b8
+#define AOFF_task_files        0x000007c8
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x000007c0
+#define AOFF_task_mm   0x000007d0
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sigmask_lock 0x000007c8
+#define AOFF_task_sigmask_lock 0x000007d8
 #define ASIZ_task_sigmask_lock 0x00000000
-#define AOFF_task_sig  0x000007c8
+#define AOFF_task_sig  0x000007d8
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_signal       0x000007d0
+#define AOFF_task_signal       0x000007e0
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x000007d8
+#define AOFF_task_blocked      0x000007e8
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x000007e0
+#define AOFF_task_sigqueue     0x000007f0
 #define ASIZ_task_sigqueue     0x00000008
-#define AOFF_task_sigqueue_tail        0x000007e8
+#define AOFF_task_sigqueue_tail        0x000007f8
 #define ASIZ_task_sigqueue_tail        0x00000008
-#define AOFF_task_sas_ss_sp    0x000007f0
+#define AOFF_task_sas_ss_sp    0x00000800
 #define ASIZ_task_sas_ss_sp    0x00000008
-#define AOFF_task_sas_ss_size  0x000007f8
+#define AOFF_task_sas_ss_size  0x00000808
 #define ASIZ_task_sas_ss_size  0x00000008
+#define ASIZ_task      0x00000810
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_cache     0x00000008
 #define ASIZ_mm_cpu_vm_mask    0x00000008
 #define AOFF_mm_segments       0x000000b8
 #define ASIZ_mm_segments       0x00000008
+#define ASIZ_mm        0x000000c0
 #define AOFF_thread_ksp        0x00000000
 #define ASIZ_thread_ksp        0x00000008
 #define AOFF_thread_wstate     0x00000008
 #define ASIZ_thread_gsr        0x00000007
 #define AOFF_thread_xfsr       0x00000408
 #define ASIZ_thread_xfsr       0x00000038
+#define ASIZ_thread    0x00000440
 
 #else /* __SMP__ */
 
 #define ASIZ_task_cap_inheritable      0x00000004
 #define AOFF_task_cap_permitted        0x0000048c
 #define ASIZ_task_cap_permitted        0x00000004
-#define AOFF_task_rlim 0x00000490
+#define AOFF_task_user 0x00000490
+#define ASIZ_task_user 0x00000008
+#define AOFF_task_rlim 0x00000498
 #define ASIZ_task_rlim 0x000000a0
-#define AOFF_task_used_math    0x00000530
+#define AOFF_task_used_math    0x00000538
 #define ASIZ_task_used_math    0x00000002
-#define AOFF_task_comm 0x00000532
+#define AOFF_task_comm 0x0000053a
 #define ASIZ_task_comm 0x00000010
-#define AOFF_task_link_count   0x00000544
+#define AOFF_task_link_count   0x0000054c
 #define ASIZ_task_link_count   0x00000004
-#define AOFF_task_tty  0x00000548
+#define AOFF_task_tty  0x00000550
 #define ASIZ_task_tty  0x00000008
-#define AOFF_task_semundo      0x00000550
+#define AOFF_task_semundo      0x00000558
 #define ASIZ_task_semundo      0x00000008
-#define AOFF_task_semsleeping  0x00000558
+#define AOFF_task_semsleeping  0x00000560
 #define ASIZ_task_semsleeping  0x00000008
-#define AOFF_task_tss  0x00000560
+#define AOFF_task_tss  0x00000570
 #define ASIZ_task_tss  0x00000440
-#define AOFF_task_fs   0x000009a0
+#define AOFF_task_fs   0x000009b0
 #define ASIZ_task_fs   0x00000008
-#define AOFF_task_files        0x000009a8
+#define AOFF_task_files        0x000009b8
 #define ASIZ_task_files        0x00000008
-#define AOFF_task_mm   0x000009b0
+#define AOFF_task_mm   0x000009c0
 #define ASIZ_task_mm   0x00000008
-#define AOFF_task_sigmask_lock 0x000009b8
+#define AOFF_task_sigmask_lock 0x000009c8
 #define ASIZ_task_sigmask_lock 0x00000001
-#define AOFF_task_sig  0x000009c0
+#define AOFF_task_sig  0x000009d0
 #define ASIZ_task_sig  0x00000008
-#define AOFF_task_signal       0x000009c8
+#define AOFF_task_signal       0x000009d8
 #define ASIZ_task_signal       0x00000008
-#define AOFF_task_blocked      0x000009d0
+#define AOFF_task_blocked      0x000009e0
 #define ASIZ_task_blocked      0x00000008
-#define AOFF_task_sigqueue     0x000009d8
+#define AOFF_task_sigqueue     0x000009e8
 #define ASIZ_task_sigqueue     0x00000008
-#define AOFF_task_sigqueue_tail        0x000009e0
+#define AOFF_task_sigqueue_tail        0x000009f0
 #define ASIZ_task_sigqueue_tail        0x00000008
-#define AOFF_task_sas_ss_sp    0x000009e8
+#define AOFF_task_sas_ss_sp    0x000009f8
 #define ASIZ_task_sas_ss_sp    0x00000008
-#define AOFF_task_sas_ss_size  0x000009f0
+#define AOFF_task_sas_ss_size  0x00000a00
 #define ASIZ_task_sas_ss_size  0x00000008
+#define ASIZ_task      0x00000a10
 #define AOFF_mm_mmap   0x00000000
 #define ASIZ_mm_mmap   0x00000008
 #define AOFF_mm_mmap_cache     0x00000008
 #define ASIZ_mm_cpu_vm_mask    0x00000008
 #define AOFF_mm_segments       0x000000b8
 #define ASIZ_mm_segments       0x00000008
+#define ASIZ_mm        0x000000c0
 #define AOFF_thread_ksp        0x00000000
 #define ASIZ_thread_ksp        0x00000008
 #define AOFF_thread_wstate     0x00000008
 #define ASIZ_thread_gsr        0x00000007
 #define AOFF_thread_xfsr       0x00000408
 #define ASIZ_thread_xfsr       0x00000038
+#define ASIZ_thread    0x00000440
 
 #endif /* __SMP__ */
 
index 509d5c25465e54d5348c67f01f8fd32c13a69c1c..521bfb72aab21c2d0331566fead79586f5a8fca7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: elf.h,v 1.17 1998/03/23 10:07:06 jj Exp $ */
+/* $Id: elf.h,v 1.18 1998/09/09 05:36:08 davem Exp $ */
 #ifndef __ASM_SPARC64_ELF_H
 #define __ASM_SPARC64_ELF_H
 
@@ -9,13 +9,6 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 
-typedef unsigned long elf_greg_t;
-
-#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef unsigned long elf_fpregset_t;
-
 /*
  * These are used to set parameters in the core dumps.
  */
@@ -23,6 +16,18 @@ typedef unsigned long elf_fpregset_t;
 #define ELF_ARCH               EM_SPARCV9
 #define ELF_CLASS              ELFCLASS64
 #define ELF_DATA               ELFDATA2MSB
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct {
+       unsigned long   pr_regs[32];
+       unsigned long   pr_fsr;
+       unsigned long   pr_gsr;
+       unsigned long   pr_fprs;
+} elf_fpregset_t;
 #endif
 
 /*
index 1db734bed188c7cc80314405d64cdca363d2e27f..9fca6fdb5277f1d3c8ca5f13e87e8f253bfd7264 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: fcntl.h,v 1.3 1997/04/14 17:05:20 jj Exp $ */
+/* $Id: fcntl.h,v 1.4 1998/08/26 10:33:36 davem Exp $ */
 #ifndef _SPARC64_FCNTL_H
 #define _SPARC64_FCNTL_H
 
index 1ac952bdb7df1362a241b5682920c4f5613824fe..342fbd9a8910c800c94116249a2093c6fff83c9b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.11 1998/05/22 14:33:39 jj Exp $
+/* $Id: floppy.h,v 1.15 1998/09/14 18:28:37 ecd Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 #include <asm/sbus.h>
 #include <asm/irq.h>
 
+
+/*
+ * Define this to enable exchanging drive 0 and 1 if only drive 1 is
+ * probed on PCI machines.
+ */
+#undef PCI_FDC_SWAP_DRIVES
+
+
 /* References:
  * 1) Netbsd Sun floppy driver.
  * 2) NCR 82077 controller manual
@@ -31,7 +39,7 @@ struct sun_flpy_controller {
        volatile unsigned char status1_82077; /* Auxiliary Status reg. 1 */
        volatile unsigned char status2_82077; /* Auxiliary Status reg. 2 */
        volatile unsigned char dor_82077;     /* Digital Output reg. */
-       volatile unsigned char tapectl_82077; /* What the? Tape control reg? */
+       volatile unsigned char tapectl_82077; /* Tape Control reg */
        volatile unsigned char status_82077;  /* Main Status Register. */
 #define drs_82077              status_82077   /* Digital Rate Select reg. */
        volatile unsigned char data_82077;    /* Data fifo. */
@@ -41,7 +49,7 @@ struct sun_flpy_controller {
 };
 
 /* You'll only ever find one controller on an Ultra anyways. */
-static struct sun_flpy_controller *sun_fdc = NULL;
+static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
 volatile unsigned char *fdc_status;
 static struct linux_sbus_device *floppy_sdev = NULL;
 
@@ -83,19 +91,20 @@ static struct sun_floppy_ops sun_fdops;
 
 static int FLOPPY_MOTOR_MASK = 0x10;
 
-#define FLOPPY0_TYPE  4
-#define FLOPPY1_TYPE  0
-
 /* Super paranoid... */
 #undef HAVE_DISABLE_HLT
 
+static int sun_floppy_types[2] = { 0, 0 };
+
 /* Here is where we catch the floppy driver trying to initialize,
  * therefore this is where we call the PROM device tree probing
  * routine etc. on the Sparc.
  */
-#define FDC1                      sun_floppy_init()
+#define FLOPPY0_TYPE           sun_floppy_init()
+#define FLOPPY1_TYPE           sun_floppy_types[1]
 
-static int FDC2 = -1;
+#define FDC1                   ((unsigned long)sun_fdc)
+static int FDC2 =              -1;
 
 #define N_FDC    1
 #define N_DRIVE  8
@@ -256,8 +265,10 @@ static int sun_fd_eject(int drive)
 
 #ifdef CONFIG_PCI
 #include <asm/ebus.h>
+#include <asm/ns87303.h>
 
-static struct linux_ebus_dma *sun_fd_ebus_dma;
+static struct linux_ebus_dma *sun_pci_fd_ebus_dma;
+static int sun_pci_broken_drive = -1;
 
 extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
@@ -271,44 +282,81 @@ static void sun_pci_fd_outb(unsigned char val, unsigned long port)
        outb(val, port);
 }
 
+static void sun_pci_fd_broken_outb(unsigned char val, unsigned long port)
+{
+       /*
+        * XXX: Due to SUN's broken floppy connector on AX and AXi
+        *      we need to turn on MOTOR_0 also, if the floppy is
+        *      jumpered to DS1 (like most PC floppies are). I hope
+        *      this does not hurt correct hardware like the AXmp.
+        *      (Eddie, Sep 12 1998).
+        */
+       if (port == ((unsigned long)sun_fdc) + 2) {
+               if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x20)) {
+                       val |= 0x10;
+               }
+       }
+       outb(val, port);
+}
+
+#ifdef PCI_FDC_SWAP_DRIVES
+static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long port)
+{
+       /*
+        * XXX: Due to SUN's broken floppy connector on AX and AXi
+        *      we need to turn on MOTOR_0 also, if the floppy is
+        *      jumpered to DS1 (like most PC floppies are). I hope
+        *      this does not hurt correct hardware like the AXmp.
+        *      (Eddie, Sep 12 1998).
+        */
+       if (port == ((unsigned long)sun_fdc) + 2) {
+               if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x10)) {
+                       val &= ~(0x03);
+                       val |= 0x21;
+               }
+       }
+       outb(val, port);
+}
+#endif /* PCI_FDC_SWAP_DRIVES */
+
 static void sun_pci_fd_reset_dma(void)
 {
        unsigned int dcsr;
 
-       writel(EBUS_DCSR_RESET, &sun_fd_ebus_dma->dcsr);
+       writel(EBUS_DCSR_RESET, &sun_pci_fd_ebus_dma->dcsr);
 
        dcsr = EBUS_DCSR_BURST_SZ_16 | EBUS_DCSR_TCI_DIS |
               EBUS_DCSR_EN_CNT | EBUS_DCSR_INT_EN;
-       writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+       writel(dcsr, (unsigned long)&sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_enable_dma(void)
 {
        unsigned int dcsr;
 
-       dcsr = readl(&sun_fd_ebus_dma->dcsr);
+       dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        dcsr |= EBUS_DCSR_EN_DMA;
-       writel(dcsr, &sun_fd_ebus_dma->dcsr);
+       writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_disable_dma(void)
 {
        unsigned int dcsr;
 
-       dcsr = readl(&sun_fd_ebus_dma->dcsr);
+       dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        while (dcsr & EBUS_DCSR_DRAIN)
-               dcsr = readl(&sun_fd_ebus_dma->dcsr);
+               dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        dcsr &= ~(EBUS_DCSR_EN_DMA);
        if (dcsr & EBUS_DCSR_ERR_PEND)
                sun_pci_fd_reset_dma();
-       writel(dcsr, &sun_fd_ebus_dma->dcsr);
+       writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_set_dma_mode(int mode)
 {
        unsigned int dcsr;
 
-       dcsr = readl(&sun_fd_ebus_dma->dcsr);
+       dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        dcsr |= EBUS_DCSR_EN_CNT | EBUS_DCSR_TC;
        /*
         * For EBus WRITE means to system memory, which is
@@ -318,41 +366,41 @@ static void sun_pci_fd_set_dma_mode(int mode)
                dcsr &= ~(EBUS_DCSR_WRITE);
        else
                dcsr |= EBUS_DCSR_WRITE;
-       writel(dcsr, &sun_fd_ebus_dma->dcsr);
+       writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_set_dma_count(int length)
 {
-       writel(length, &sun_fd_ebus_dma->dbcr);
+       writel(length, &sun_pci_fd_ebus_dma->dbcr);
 }
 
 static void sun_pci_fd_set_dma_addr(char *buffer)
 {
        unsigned int addr = virt_to_bus(buffer);
-       writel(addr, &sun_fd_ebus_dma->dacr);
+       writel(addr, &sun_pci_fd_ebus_dma->dacr);
 }
 
 static unsigned int sun_pci_get_dma_residue(void)
 {
-       return readl(&sun_fd_ebus_dma->dbcr);
+       return readl(&sun_pci_fd_ebus_dma->dbcr);
 }
 
 static void sun_pci_fd_enable_irq(void)
 {
        unsigned int dcsr;
 
-       dcsr = readl(&sun_fd_ebus_dma->dcsr);
+       dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        dcsr |= EBUS_DCSR_INT_EN;
-       writel(dcsr, &sun_fd_ebus_dma->dcsr);
+       writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_disable_irq(void)
 {
        unsigned int dcsr;
 
-       dcsr = readl(&sun_fd_ebus_dma->dcsr);
+       dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
        dcsr &= ~(EBUS_DCSR_INT_EN);
-       writel(dcsr, &sun_fd_ebus_dma->dcsr);
+       writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static int sun_pci_fd_request_irq(void)
@@ -377,7 +425,101 @@ static int sun_pci_fd_eject(int drive)
 {
        return -EINVAL;
 }
-#endif
+
+
+/*
+ * Floppy probing, we'd like to use /dev/fd0 for a single Floppy on PCI,
+ * even if this is configured using DS1, thus looks like /dev/fd1 with
+ * the cabling used in Ultras.
+ */
+#define DOR    (port + 2)
+#define MSR    (port + 4)
+#define FIFO   (port + 5)
+
+static void sun_pci_fd_out_byte(unsigned long port, unsigned char val,
+                               unsigned long reg)
+{
+       unsigned char status;
+       int timeout = 1000;
+
+       while (!((status = inb(MSR)) & 0x80) && --timeout)
+               udelay(100);
+       outb(val, reg);
+}
+
+static unsigned char sun_pci_fd_sensei(unsigned long port)
+{
+       unsigned char result[2] = { 0x70, 0x00 };
+       unsigned char status;
+       int i = 0;
+
+       sun_pci_fd_out_byte(port, 0x08, FIFO);
+       do {
+               int timeout = 1000;
+
+               while (!((status = inb(MSR)) & 0x80) && --timeout)
+                       udelay(100);
+
+               if (!timeout)
+                       break;
+
+               if ((status & 0xf0) == 0xd0)
+                       result[i++] = inb(FIFO);
+               else
+                       break;
+       } while (i < 2);
+
+       return result[0];
+}
+
+static void sun_pci_fd_reset(unsigned long port)
+{
+       unsigned char mask = 0x00;
+       unsigned char status;
+       int timeout = 10000;
+
+       outb(0x80, MSR);
+       do {
+               status = sun_pci_fd_sensei(port);
+               if ((status & 0xc0) == 0xc0)
+                       mask |= 1 << (status & 0x03);
+               else
+                       udelay(100);
+       } while ((mask != 0x0f) && --timeout);
+}
+
+static int sun_pci_fd_test_drive(unsigned long port, int drive)
+{
+       unsigned char status, data;
+       int timeout = 1000;
+       int ready;
+
+       sun_pci_fd_reset(port);
+
+       data = (0x10 << drive) | 0x0c | drive;
+       sun_pci_fd_out_byte(port, data, DOR);
+
+       sun_pci_fd_out_byte(port, 0x07, FIFO);
+       sun_pci_fd_out_byte(port, drive & 0x03, FIFO);
+
+       do {
+               udelay(100);
+               status = sun_pci_fd_sensei(port);
+       } while (((status & 0xc0) == 0x80) && --timeout);
+
+       if (!timeout)
+               ready = 0;
+       else
+               ready = (status & 0x10) ? 0 : 1;
+
+       sun_pci_fd_reset(port);
+       return ready;
+}
+#undef FIFO
+#undef MSR
+#undef DOR
+
+#endif /* CONFIG_PCI */
 
 static struct linux_prom_registers fd_regs[2];
 
@@ -387,6 +529,11 @@ __initfunc(static unsigned long sun_floppy_init(void))
        int fd_node, num_regs;
        struct linux_sbus *bus;
        struct linux_sbus_device *sdev = NULL;
+       static int initialized = 0;
+
+       if (initialized)
+               return sun_floppy_types[0];
+       initialized = 1;
 
        for_all_sbusdev (sdev, bus) {
                if (!strcmp(sdev->prom_name, "SUNW,fdtwo")) 
@@ -408,23 +555,27 @@ __initfunc(static unsigned long sun_floppy_init(void))
                }
        ebus_done:
                if (!edev)
-                       return -1;
+                       return 0;
 
-               prom_getproperty(edev->prom_node, "status", state, sizeof(state));
+               prom_getproperty(edev->prom_node, "status",
+                                state, sizeof(state));
                if(!strncmp(state, "disabled", 8))
-                       return -1;
+                       return 0;
                        
-               if (check_region(edev->base_address[1], sizeof(struct linux_ebus_dma))) {
-                       printk("sun_floppy_init: can't get region %016lx (%d)\n",
-                              edev->base_address[1], (int)sizeof(struct linux_ebus_dma));
-                       return -1;
+               if (check_region(edev->base_address[1],
+                                sizeof(struct linux_ebus_dma))) {
+                       printk("sun_floppy_init: can't get region at %016lx\n",
+                              edev->base_address[1]);
+                       return 0;
                }
-               request_region(edev->base_address[1], sizeof(struct linux_ebus_dma), "floppy DMA");
+               request_region(edev->base_address[1],
+                              sizeof(struct linux_ebus_dma), "floppy DMA");
 
                sun_fdc = (struct sun_flpy_controller *)edev->base_address[0];
                FLOPPY_IRQ = edev->irqs[0];
 
-               sun_fd_ebus_dma = (struct linux_ebus_dma *)edev->base_address[1];
+               sun_pci_fd_ebus_dma = (struct linux_ebus_dma *)
+                                                       edev->base_address[1];
                sun_pci_fd_reset_dma();
 
                sun_fdops.fd_inb = sun_pci_fd_inb;
@@ -448,27 +599,103 @@ __initfunc(static unsigned long sun_floppy_init(void))
                fdc_status = &sun_fdc->status_82077;
                FLOPPY_MOTOR_MASK = 0xf0;
 
-               return (unsigned long)sun_fdc;
+               /*
+                * XXX: Find out on which machines this is really needed.
+                */
+               if (1) {
+                       sun_pci_broken_drive = 1;
+                       sun_fdops.fd_outb = sun_pci_fd_broken_outb;
+               }
+
+               allowed_drive_mask = 0;
+               if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 0))
+                       sun_floppy_types[0] = 4;
+               if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 1))
+                       sun_floppy_types[1] = 4;
+
+#ifdef PCI_FDC_SWAP_DRIVES
+               /*
+                * If only Floppy 1 is present, swap drives.
+                */
+               if (!sun_floppy_types[0] && sun_floppy_types[1]) {
+                       unsigned long config = 0;
+                       unsigned char tmp;
+
+                       for_each_ebus(ebus) {
+                               for_each_ebusdev(edev, ebus) {
+                                       if (!strcmp(edev->prom_name, "ecpp")) {
+                                               config = edev->base_address[1];
+                                               goto config_done;
+                                       }
+                               }
+                       }
+               config_done:
+
+                       /*
+                        * Sanity check, is this really the NS87303?
+                        */
+                       switch (config & 0x3ff) {
+                       case 0x02e:
+                       case 0x15c:
+                       case 0x26e:
+                       case 0x398:
+                               break;
+                       default:
+                               config = 0;
+                       }
+
+                       if (!config)
+                               return sun_floppy_types[0];
+
+                       /*
+                        * Set the drive exchange bit in FCR on NS87303,
+                        * make shure other bits are sane before doing so.
+                        */
+                       tmp = ns87303_readb(config, FER);
+                       tmp &= ~(FER_EDM);
+                       ns87303_writeb(config, FER, tmp);
+                       tmp = ns87303_readb(config, ASC);
+                       tmp &= ~(ASC_DRV2_SEL);
+                       ns87303_writeb(config, ASC, tmp);
+                       tmp = ns87303_readb(config, FCR);
+                       tmp |= FCR_LDE;
+                       ns87303_writeb(config, FCR, tmp);
+
+                       sun_floppy_types[0] = sun_floppy_types[1];
+                       sun_floppy_types[1] = 0;
+
+                       if (sun_pci_broken_drive != -1) {
+                               sun_pci_broken_drive = 1 - sun_pci_broken_drive;
+                               sun_fdops.fd_outb = sun_pci_fd_lde_broken_outb;
+                       }
+               }
+#endif /* PCI_FDC_SWAP_DRIVES */
+
+               return sun_floppy_types[0];
 #else
-               return -1;
+               return 0;
 #endif
        }
        fd_node = sdev->prom_node;
        prom_getproperty(fd_node, "status", state, sizeof(state));
        if(!strncmp(state, "disabled", 8))
-               return -1;
-       num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs, sizeof(fd_regs));
+               return 0;
+       num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs,
+                                   sizeof(fd_regs));
        num_regs = (num_regs / sizeof(fd_regs[0]));
        prom_apply_sbus_ranges(sdev->my_bus, fd_regs, num_regs, sdev);
-       /* We cannot do sparc_alloc_io here: it does request_region, which is the generic
-          floppy driver trying to do once again */
-       sun_fdc = (struct sun_flpy_controller *) (PAGE_OFFSET + fd_regs[0].phys_addr + 
-                                                       (((unsigned long)fd_regs[0].which_io) << 32));
+       /*
+        * We cannot do sparc_alloc_io here: it does request_region,
+        * which the generic floppy driver tries to do once again.
+        */
+       sun_fdc = (struct sun_flpy_controller *)
+                               (PAGE_OFFSET + fd_regs[0].phys_addr + 
+                                (((unsigned long)fd_regs[0].which_io) << 32));
 
        /* Last minute sanity check... */
        if(sun_fdc->status1_82077 == 0xff) {
-               sun_fdc = NULL;
-               return -1;
+               sun_fdc = (struct sun_flpy_controller *)-1;
+               return 0;
        }
 
         sun_fdops.fd_inb = sun_82077_fd_inb;
@@ -490,10 +717,13 @@ __initfunc(static unsigned long sun_floppy_init(void))
        sun_fdops.fd_eject = sun_fd_eject;
 
         fdc_status = &sun_fdc->status_82077;
-        /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
 
        /* Success... */
-       return (unsigned long)sun_fdc;
+       allowed_drive_mask = 0x01;
+       sun_floppy_types[0] = 4;
+       sun_floppy_types[1] = 0;
+
+       return sun_floppy_types[0];
 }
 
 #endif /* !(__ASM_SPARC64_FLOPPY_H) */
index 5ca51ac776db151de8c61a85342978df1bc33894..64d30e8e2b78939ec890777a3ca96d0776a3d548 100644 (file)
@@ -23,7 +23,7 @@ extern unsigned int local_irq_count;
 #define hardirq_enter(cpu)     (local_irq_count++)
 #define hardirq_exit(cpu)      (local_irq_count--)
 
-#define synchronize_irq()      do { } while(0)
+#define synchronize_irq()      barrier()
 
 #else /* (__SMP__) */
 
index 8ac5832816cecb6490e116e97b7d663000ff0e32..503acdb276b497bbeaca365d6b3622b5f470fa06 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ide.h,v 1.9 1998/05/08 21:05:28 davem Exp $
+/* $Id: ide.h,v 1.11 1998/08/12 22:19:37 ecd Exp $
  * ide.h: Ultra/PCI specific IDE glue.
  *
  * Copyright (C) 1997  David S. Miller (davem@caip.rutgers.edu)
@@ -10,6 +10,8 @@
 
 #ifdef __KERNEL__
 
+#include <asm/pgtable.h>
+
 typedef unsigned long ide_ioreg_t;
 
 #undef  MAX_HWIFS
@@ -116,24 +118,19 @@ static __inline__ int ide_ack_intr(ide_ioreg_t status_port, ide_ioreg_t irq_port
 #define insw(port, buf, nr) ide_insw((port), (buf), (nr))
 #define outsw(port, buf, nr) ide_outsw((port), (buf), (nr))
 
-/* We need to use L1 cache bypassing to prevent dcache alias
- * inconsistencies with user space.  -DaveM
- */
 static __inline__ void ide_insw(unsigned long port,
                                void *dst,
                                unsigned long count)
 {
        volatile unsigned short *data_port;
-       u16 *ps = (u16 *)__pa(dst);
+       unsigned long end = (unsigned long)dst + count;
+       u16 *ps = dst;
        u32 *pi;
 
        data_port = (volatile unsigned short *)port;
 
        if(((u64)ps) & 0x2) {
-               __asm__ __volatile__("stha %0, [%1] %2"
-                                    : /* no outputs */
-                                    : "r" (*data_port), "r" (ps++),
-                                      "i" (ASI_PHYS_USE_EC));
+               *ps++ = *data_port;
                count--;
        }
        pi = (u32 *)ps;
@@ -142,18 +139,14 @@ static __inline__ void ide_insw(unsigned long port,
 
                w  = (*data_port) << 16;
                w |= (*data_port);
-               __asm__ __volatile__("stwa %0, [%1] %2"
-                                    : /* no outputs */
-                                    : "r" (w), "r" (pi++),
-                                      "i" (ASI_PHYS_USE_EC));
+               *pi++ = w;
                count -= 2;
        }
        ps = (u16 *)pi;
        if(count)
-               __asm__ __volatile__("stha %0, [%1] %2"
-                                    : /* no outputs */
-                                    : "r" (*data_port), "r" (ps),
-                                      "i" (ASI_PHYS_USE_EC));
+               *ps++ = *data_port;
+
+       __flush_dcache_range((unsigned long)dst, end);
 }
 
 static __inline__ void ide_outsw(unsigned long port,
@@ -161,37 +154,30 @@ static __inline__ void ide_outsw(unsigned long port,
                                 unsigned long count)
 {
        volatile unsigned short *data_port;
-       const u16 *ps = (const u16 *)__pa(src);
+       unsigned long end = (unsigned long)src + count;
+       const u16 *ps = src;
        const u32 *pi;
 
        data_port = (volatile unsigned short *)port;
 
        if(((u64)src) & 0x2) {
-               u16 w;
-               __asm__ __volatile__("lduha [%1] %2, %0"
-                                    : "=r" (w)
-                                    : "r" (ps++), "i" (ASI_PHYS_USE_EC));
-               *data_port = w;
+               *data_port = *ps++;
                count--;
        }
        pi = (const u32 *)ps;
        while(count >= 2) {
                u32 w;
-               __asm__ __volatile__("lduwa [%1] %2, %0"
-                                    : "=r" (w)
-                                    : "r" (pi++), "i" (ASI_PHYS_USE_EC));
+
+               w = *pi++;
                *data_port = (w >> 16);
                *data_port = w;
                count -= 2;
        }
        ps = (const u16 *)pi;
-       if(count) {
-               u16 w;
-               __asm__ __volatile__("lduha [%1] %2, %0"
-                                    : "=r" (w)
-                                    : "r" (ps++), "i" (ASI_PHYS_USE_EC));
-               *data_port = w;
-       }
+       if(count)
+               *data_port = *ps;
+
+       __flush_dcache_range((unsigned long)src, end);
 }
 
 #define T_CHAR          (0x0000)        /* char:  don't touch  */
index a6bdff9a3bfc5164ad74635b2760703db31e0d33..c9e3c84609d72845fee7a103956009d8e5757572 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.18 1998/07/12 12:07:43 ecd Exp $ */
+/* $Id: io.h,v 1.19 1998/08/23 05:41:46 ecd Exp $ */
 #ifndef __SPARC64_IO_H
 #define __SPARC64_IO_H
 
@@ -127,7 +127,10 @@ extern void insl(unsigned long addr, void *dst, unsigned long count);
 #define writew(w, addr)                outw((w), (unsigned long)(addr))
 #define writel(l, addr)                outl((l), (unsigned long)(addr))
 
-/* Memcpy to/from I/O space is just a regular memory operation on Ultra as well. */
+/*
+ * Memcpy to/from I/O space is just a regular memory operation on
+ * Ultra as well.
+ */
 
 /*
  * FIXME: Write faster routines using ASL_*L for this.
@@ -170,7 +173,7 @@ memcpy_toio(void *dst, const void *src, __kernel_size_t n)
 #if 0 /* XXX Not exactly, we need to use ASI_*L from/to the I/O end,
        * XXX so these are disabled until we code that stuff.
        */
-#define eth_io_copy_and_sum(a,b,c,d)   eth_copy_and_sum((a),((char *)(b)),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),((char *)(b)),(c),(d))
 #endif
 
 static inline int check_signature(unsigned long io_addr,
@@ -187,22 +190,39 @@ out:
        return retval;
 }
 
-extern void sparc_ultra_mapioaddr   (unsigned long physaddr, unsigned long virt_addr,
-                                    int bus, int rdonly);
-extern void sparc_ultra_unmapioaddr (unsigned long virt_addr);
+/*
+ * On the sparc we have the whole physical IO address space mapped at all
+ * times, so ioremap() and iounmap() do not need to do anything.
+ */
+extern __inline__ void *ioremap(unsigned long offset, unsigned long size)
+{
+       return __va(offset);
+}
+
+extern __inline__ void iounmap(void *addr)
+{
+}
+
+
+extern void sparc_ultra_mapioaddr(unsigned long physaddr,
+                                 unsigned long virt_addr,
+                                 int bus, int rdonly);
+extern void sparc_ultra_unmapioaddr(unsigned long virt_addr);
 
-extern __inline__ void mapioaddr (unsigned long physaddr, unsigned long virt_addr,
-                                 int bus, int rdonly)
+extern __inline__ void mapioaddr(unsigned long physaddr,
+                                unsigned long virt_addr,
+                                int bus, int rdonly)
 {
-       sparc_ultra_mapioaddr (physaddr, virt_addr, bus, rdonly);
+       sparc_ultra_mapioaddr(physaddr, virt_addr, bus, rdonly);
 }
 
 extern __inline__ void unmapioaddr(unsigned long virt_addr)
 {
-       sparc_ultra_unmapioaddr (virt_addr);
+       sparc_ultra_unmapioaddr(virt_addr);
 }
 
-extern void *sparc_alloc_io (u32 pa, void *va, int sz, char *name, u32 io, int rdonly);
+extern void *sparc_alloc_io(u32 pa, void *va, int sz, char *name,
+                           u32 io, int rdonly);
 extern void sparc_free_io (void *va, int sz);
 extern void *sparc_dvma_malloc (int sz, char *name, __u32 *dvma_addr);
 
index 1d8a9f7eeb53ed84d4de379fc2ac586fd4f8c88f..3e81eeaf76828c2342fff81e2880d38d94c1c1b2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.26 1998/07/31 10:42:38 jj Exp $ */
+/* $Id: mmu_context.h,v 1.31 1998/09/24 03:22:01 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -25,25 +25,47 @@ extern void get_new_mmu_context(struct mm_struct *mm);
 /* Initialize/destroy the context related info for a new mm_struct
  * instance.
  */
-#define init_new_context(mm)   ((mm)->context = NO_CONTEXT)
-#define destroy_context(mm)    do {                                            \
-       if ((mm)->context != NO_CONTEXT) {                                      \
+#define init_new_context(__mm) ((__mm)->context = NO_CONTEXT)
+
+/* Kernel threads like rpciod and nfsd drop their mm, and then use
+ * init_mm, when this happens we must make sure the tsk->tss.ctx is
+ * updated as well.  Otherwise we have disasters relating to
+ * set_fs/get_fs usage later on.
+ *
+ * Also we can only clear the mmu_context_bmap bit when this is
+ * the final reference to the address space.
+ */
+#define destroy_context(__mm)  do {                                            \
+       if ((__mm)->context != NO_CONTEXT &&                                    \
+           atomic_read(&(__mm)->count) == 1) {                                 \
                spin_lock(&scheduler_lock);                                     \
-               if (!(((mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))  \
-                       clear_bit((mm)->context & ~(CTX_VERSION_MASK),          \
+               if (!(((__mm)->context ^ tlb_context_cache) & CTX_VERSION_MASK))\
+                       clear_bit((__mm)->context & ~(CTX_VERSION_MASK),        \
                                  mmu_context_bmap);                            \
                spin_unlock(&scheduler_lock);                                   \
-               (mm)->context = NO_CONTEXT;                                     \
+               (__mm)->context = NO_CONTEXT;                                   \
+               if(current->mm == (__mm)) {                                     \
+                       current->tss.ctx = 0;                                   \
+                       spitfire_set_secondary_context(0);                      \
+                       __asm__ __volatile__("flush %g6");                      \
+               }                                                               \
        }                                                                       \
 } while (0)
 
-extern __inline__ void get_mmu_context(struct task_struct *tsk)
+/* This routine must called with interrupts off,
+ * this is necessary to guarentee that the current->tss.ctx
+ * to CPU secontary context register relationship is maintained
+ * when traps can happen.
+ *
+ * Also the caller must flush the current set of user windows
+ * to the stack (if necessary) before we get here.
+ */
+extern __inline__ void __get_mmu_context(struct task_struct *tsk)
 {
        register unsigned long paddr asm("o5");
        register unsigned long pgd_cache asm("o4");
        struct mm_struct *mm = tsk->mm;
 
-       flushw_user();
        if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD)       &&
           !(tsk->flags & PF_EXITING)) {
                unsigned long ctx = tlb_context_cache;
@@ -65,28 +87,43 @@ extern __inline__ void get_mmu_context(struct task_struct *tsk)
        spitfire_set_secondary_context(tsk->tss.ctx);
        __asm__ __volatile__("flush %g6");
        paddr = __pa(mm->pgd);
-       if(tsk->tss.flags & SPARC_FLAG_32BIT)
+       if((tsk->tss.flags & (SPARC_FLAG_32BIT|SPARC_FLAG_KTHREAD)) ==
+          (SPARC_FLAG_32BIT))
                pgd_cache = (unsigned long) mm->pgd[0];
        else
                pgd_cache = 0;
        __asm__ __volatile__("
-               rdpr            %%pstate, %%o3
-               wrpr            %%o3, %2, %%pstate
+               rdpr            %%pstate, %%o2
+               andn            %%o2, %2, %%o3
+               wrpr            %%o3, %5, %%pstate
                mov             %4, %%g4
                mov             %0, %%g7
                stxa            %1, [%%g4] %3
-               wrpr            %%o3, 0x0, %%pstate
+               wrpr            %%o2, 0x0, %%pstate
        " : /* no outputs */
-         : "r" (paddr), "r" (pgd_cache), "i" (PSTATE_MG|PSTATE_IE),
-           "i" (ASI_DMMU), "i" (TSB_REG)
-         : "o3");
+         : "r" (paddr), "r" (pgd_cache), "i" (PSTATE_IE),
+           "i" (ASI_DMMU), "i" (TSB_REG), "i" (PSTATE_MG)
+         : "o2", "o3");
 }
 
+/* Now we define this as a do nothing macro, because the only
+ * generic user right now is the scheduler, and we handle all
+ * the atomicity issues by having switch_to() call the above
+ * function itself.
+ */
+#define get_mmu_context(x)     do { } while(0)
+
 /*
  * After we have set current->mm to a new value, this activates
  * the context for the new mm so we see the new mappings.
  */
-#define activate_context(tsk)  get_mmu_context(tsk)
+#define activate_context(__tsk)                \
+do {   unsigned long __flags;          \
+       __save_and_cli(__flags);        \
+       flushw_user();                  \
+       __get_mmu_context(__tsk);       \
+       __restore_flags(__flags);       \
+} while(0)
 
 #endif /* !(__ASSEMBLY__) */
 
index 92b3d689c93621f3c84b4c8e69dcdd049db32a6a..cfd159a5a80b95f7b8a98df814923297d003eb14 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ns87303.h,v 1.1 1997/10/14 13:30:37 ecd Exp $
+/* $Id: ns87303.h,v 1.2 1998/09/13 15:38:50 ecd Exp $
  * ns87303.h: Configuration Register Description for the
  *            National Semiconductor PC87303 (SuperIO).
  *
@@ -26,6 +26,9 @@
 #define CS1CF0 0x0c
 #define CS1CF1 0x0d
 
+/* Function Enable Register (FER) bits */
+#define FER_EDM                0x10    /* Encoded Drive and Motor pin information   */
+
 /* Function Address Register (FAR) bits */
 #define FAR_LPT_MASK   0x03
 #define FAR_LPTB       0x00
@@ -39,6 +42,7 @@
                                /*               of the parallel port        */
 
 /* Function Control Register (FCR) bits */
+#define FCR_LDE                0x10    /* Logical Drive Exchange                    */
 #define FCR_ZWS_ENA    0x20    /* Enable short host read/write in ECP/EPP   */
 
 /* Printer Controll Register (PCR) bits */
@@ -55,6 +59,7 @@
 
 /* Advanced SuperIO Config Register (ASC) bits */
 #define ASC_LPT_IRQ7   0x01    /* Allways use IRQ7 for LPT                  */
+#define ASC_DRV2_SEL   0x02    /* Logical Drive Exchange controlled by TDR  */
 
 #ifdef __KERNEL__
 
index 2bc6695b7ff42ee398031cbdfac91dd826faa41b..e1172434724e2933ffad9c1b2a5505e277cb641c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.85 1998/08/04 20:51:33 davem Exp $
+/* $Id: pgtable.h,v 1.90 1998/09/24 03:21:56 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -169,10 +169,13 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
 #define flush_cache_range(mm, start, end)      flushw_user()
 #define flush_cache_page(vma, page)            flushw_user()
 
+extern void flush_page_to_ram(unsigned long page);
+
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page)                        do { } while (0)
 #define flush_icache_range(start, end)         do { } while (0)
 
+extern void __flush_dcache_range(unsigned long start, unsigned long end);
+
 extern void __flush_cache_all(void);
 
 extern void __flush_tlb_all(void);
@@ -517,18 +520,22 @@ extern pgd_t swapper_pg_dir[1];
 
 extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
 {
-       if(pgdir != swapper_pg_dir && tsk == current) {
+       if(pgdir != swapper_pg_dir && tsk->mm == current->mm) {
                register unsigned long paddr asm("o5");
 
                paddr = __pa(pgdir);
                __asm__ __volatile__ ("
                        rdpr            %%pstate, %%o4
                        wrpr            %%o4, %1, %%pstate
+                       mov             %3, %%g4
                        mov             %0, %%g7
+                       stxa            %%g0, [%%g4] %2
                        wrpr            %%o4, 0x0, %%pstate
                " : /* No outputs */
-                 : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE)
+                 : "r" (paddr), "i" (PSTATE_MG|PSTATE_IE),
+                   "i" (ASI_DMMU), "i" (TSB_REG)
                  : "o4");
+               flush_tlb_mm(current->mm);
        }
 }
 
@@ -620,6 +627,9 @@ extern void module_unmap (void *addr);
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define PageSkip(page)         (test_bit(PG_skip, &(page)->flags))
 
+extern int io_remap_page_range(unsigned long from, unsigned long offset,
+                              unsigned long size, pgprot_t prot, int space);
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
index 98b4125a6644f512c040909ac5f25480f134219c..2acf3e4213245ea7263c2eb1aab5dc7ce10c5931 100644 (file)
@@ -7,7 +7,7 @@
  * assume GCC is being used.
  */
 
-#if __GNUC_MINOR__ > 7
+#if (__GNUC__ > 2) || (__GNUC_MINOR__ >= 8)
 typedef unsigned long int      __kernel_size_t;
 #else
 typedef unsigned long long     __kernel_size_t;
index 3b90c34b1ed7dca6faab87aa8583c7081cf88332..1179fd2583ddd05908e0cc1622a1b483ece64ff2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.2 1997/08/04 16:16:55 davem Exp $ */
+/* $Id: shmparam.h,v 1.3 1998/09/28 07:15:03 jj Exp $ */
 #ifndef _ASMSPARC64_SHMPARAM_H
 #define _ASMSPARC64_SHMPARAM_H
 
@@ -36,7 +36,7 @@
  * SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS).
  */
 
-#define SHMMAX (1024 * 1024)           /* max shared seg size (bytes) */
+#define SHMMAX 0x1000000               /* max shared seg size (bytes) */
 #define SHMMIN 1 /* really PAGE_SIZE */        /* min shared seg size (bytes) */
 #define SHMMNI (1<<_SHM_ID_BITS)       /* max num of segs system wide */
 #define SHMALL                         /* max shm system wide (pages) */ \
index 1a07cd850c78b1c2d44d246da10d37c65be4b94e..b074a05cc7046c745f8445d7d061d1013511ffa9 100644 (file)
@@ -93,7 +93,7 @@ extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
 
 #define PROC_CHANGE_PENALTY    20
 
-#else /* !(__SMP__) */
+#endif /* !(__SMP__) */
 
 #define NO_PROC_ID             0xFF
 
index 0e1a6b589187dfd0e9d409be22a4cae5e3b1c9c3..9fe325fc91ed0e5eab2d4bcffa534c9e6c704584 100644 (file)
@@ -23,7 +23,7 @@ extern int __sparc64_bh_counter;
 #define softirq_trylock(cpu)   (__sparc64_bh_counter ? 0 : (__sparc64_bh_counter=1))
 #define softirq_endlock(cpu)   (__sparc64_bh_counter = 0)
 #define clear_active_bhs(x)    (bh_active &= ~(x))
-#define synchronize_bh()       do { } while (0) /* XXX implement SMP version -DaveM */
+#define synchronize_bh()       barrier() /* XXX implement SMP version -DaveM */
 
 #define init_bh(nr, routine)   \
 do {   int ent = nr;           \
index b5293acd95d27581eef9504a35fe64c30c8634df..e08ed5b4b8bbfaf2b0d1e91d2bf5e0f1a4cb3dbd 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: string.h,v 1.11 1998/06/12 14:54:35 jj Exp $
+/* $Id: string.h,v 1.12 1998/10/04 08:44:27 davem Exp $
  * string.h: External definitions for optimized assembly string
  *           routines for the Linux Kernel.
  *
@@ -128,6 +128,15 @@ extern inline void *__nonconstant_memset(void *s, char c, __kernel_size_t count)
 /* Now the str*() stuff... */
 #define __HAVE_ARCH_STRLEN
 
+/* Ugly but it works around a bug in our original sparc64-linux-gcc.  */
+extern __kernel_size_t __strlen(const char *);
+#undef strlen
+#define strlen(__arg0)                                 \
+({     int __strlen_res = __strlen(__arg0) + 1;        \
+       __strlen_res -= 1;                              \
+       __strlen_res;                                   \
+})
+
 #define __HAVE_ARCH_STRNCMP
 
 extern int __strncmp(const char *, const char *, __kernel_size_t);
index 55072c93b5b6d3544a551d9698e2ef7e8b31a957..f103b3e367e55cd70429508b8244eba9e6c430dc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.42 1998/07/29 01:32:51 davem Exp $ */
+/* $Id: system.h,v 1.44 1998/09/21 03:57:22 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -124,6 +124,21 @@ extern __inline__ void flushw_user(void)
 
 #define flush_user_windows flushw_user
 
+#define DEBUG_SWITCH
+
+#ifdef DEBUG_SWITCH
+#define SWITCH_CTX_CHECK(__tsk) \
+do {   unsigned short ctx_now; \
+       ctx_now = spitfire_get_secondary_context(); \
+       if(ctx_now != (__tsk)->tss.ctx) \
+               printk("[%s:%d] Bogus ctx after switch [%x:%x]\n", \
+                      (__tsk)->comm, (__tsk)->pid, \
+                      (__tsk)->tss.ctx, ctx_now); \
+} while(0)
+#else
+#define SWITCH_CTX_CHECK(__tsk)        do { } while(0)
+#endif
+
        /* See what happens when you design the chip correctly?
         *
         * XXX What we are doing here assumes a lot about gcc reload
@@ -142,11 +157,13 @@ extern __inline__ void flushw_user(void)
         */
 #define switch_to(prev, next)                                                  \
 do {   save_and_clear_fpu();                                                   \
-       (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());                 \
        __asm__ __volatile__(                                                   \
-       "rdpr   %%pstate, %%g2\n\t"                                             \
-       "wrpr   %%g2, 0x3, %%pstate\n\t"                                        \
        "flushw\n\t"                                                            \
+       "wrpr   %g0, 0x94, %pstate\n\t");                                       \
+       __get_mmu_context(next);                                                \
+       (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id());                 \
+       __asm__ __volatile__(                                                   \
+       "wrpr   %%g0, 0x95, %%pstate\n\t"                                       \
        "stx    %%l0, [%%sp + 2047 + 0x60]\n\t"                                 \
        "stx    %%l1, [%%sp + 2047 + 0x68]\n\t"                                 \
        "stx    %%i6, [%%sp + 2047 + 0x70]\n\t"                                 \
@@ -168,10 +185,12 @@ do {      save_and_clear_fpu();                                                   \
        "ldx    [%%sp + 2047 + 0x68], %%l1\n\t"                                 \
        "ldx    [%%sp + 2047 + 0x70], %%i6\n\t"                                 \
        "ldx    [%%sp + 2047 + 0x78], %%i7\n\t"                                 \
+       "wrpr   %%g0, 0x94, %%pstate\n\t"                                       \
+       "mov    %%l2, %%g6\n\t"                                                 \
        "wrpr   %%g0, 0x96, %%pstate\n\t"                                       \
        "andcc  %%o7, 0x100, %%g0\n\t"                                          \
        "bne,pn %%icc, ret_from_syscall\n\t"                                    \
-       " mov   %%l2, %%g6\n\t"                                                 \
+       " nop\n\t"                                                              \
        :                                                                       \
        : "r" (next),                                                           \
          "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),  \
@@ -182,6 +201,7 @@ do {        save_and_clear_fpu();                                                   \
          "l2", "l3", "l4", "l5", "l6", "l7",                                   \
          "i0", "i1", "i2", "i3", "i4", "i5",                                   \
          "o0", "o1", "o2", "o3", "o4", "o5", "o7");                            \
+       SWITCH_CTX_CHECK(current);                                              \
 } while(0)
 
 extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
index 005652de9dcd0ec4723d347f174babc97ca42530..767722d4c9895be7054e5c999f701fec675f72e8 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.5 1998/04/12 06:27:22 davem Exp $ */
+/* $Id: termios.h,v 1.6 1998/10/04 06:50:15 davem Exp $ */
 #ifndef _SPARC64_TERMIOS_H
 #define _SPARC64_TERMIOS_H
 
index 9d24346180544bd5973666cf18363f4856538e55..2cd04004a755b60f095b727ef798f1091d915f63 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ttable.h,v 1.8 1998/06/12 14:54:32 jj Exp $ */
+/* $Id: ttable.h,v 1.10 1998/09/25 01:09:45 davem Exp $ */
 #ifndef _SPARC64_TTABLE_H
 #define _SPARC64_TTABLE_H
 
         sethi  %hi(systbl), %l7;                       \
        nop; nop; nop;
        
-#define ACCESS_EXCEPTION_TRAP(routine)                 \
-       rdpr    %pstate, %g1;                           \
-       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
-       ba,pt   %xcc, etrap;                            \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;
-
-#define ACCESS_EXCEPTION_TRAPTL1(routine)              \
-       rdpr    %pstate, %g1;                           \
-       wrpr    %g1, PSTATE_MG|PSTATE_AG, %pstate;      \
-       ba,pt   %xcc, etraptl1;                         \
-        rd     %pc, %g7;                               \
-       call    routine;                                \
-        add    %sp, STACK_BIAS + REGWIN_SZ, %o0;       \
-       ba,pt   %xcc, rtrap;                            \
-        clr    %l6;
-        
 #define INDIRECT_SOLARIS_SYSCALL(num)                  \
        sethi   %hi(109f), %g7;                         \
        ba,pt   %xcc, etrap;                            \
        stxa    %i6, [%sp + STACK_BIAS + 0x70] %asi;    \
        stxa    %i7, [%sp + STACK_BIAS + 0x78] %asi;    \
        saved; retry; nop; nop; nop; nop; nop; nop;     \
-       nop; nop; nop; nop; nop;                        \
+       nop; nop; nop; nop;                             \
+       b,a,pt  %xcc, spill_fixup_dax;                  \
        b,a,pt  %xcc, spill_fixup_mna;                  \
        b,a,pt  %xcc, spill_fixup;
 
        stwa    %i6, [%sp + 0x38] %asi;                 \
        stwa    %i7, [%sp + 0x3c] %asi;                 \
        saved; retry; nop; nop; nop; nop;               \
-       nop; nop; nop; nop; nop; nop;                   \
+       nop; nop; nop; nop; nop;                        \
+       b,a,pt  %xcc, spill_fixup_dax;                  \
        b,a,pt  %xcc, spill_fixup_mna;                  \
        b,a,pt  %xcc, spill_fixup;
 
        ldxa    [%sp + STACK_BIAS + 0x70] %asi, %i6;    \
        ldxa    [%sp + STACK_BIAS + 0x78] %asi, %i7;    \
        restored; retry; nop; nop; nop; nop; nop; nop;  \
-       nop; nop; nop; nop; nop;                        \
+       nop; nop; nop; nop;                             \
+       b,a,pt  %xcc, fill_fixup_dax;                   \
        b,a,pt  %xcc, fill_fixup_mna;                   \
        b,a,pt  %xcc, fill_fixup;
 
        lduwa   [%sp + 0x38] %asi, %i6;                 \
        lduwa   [%sp + 0x3c] %asi, %i7;                 \
        restored; retry; nop; nop; nop; nop;            \
-       nop; nop; nop; nop; nop; nop;                   \
+       nop; nop; nop; nop; nop;                        \
+       b,a,pt  %xcc, fill_fixup_dax;                   \
        b,a,pt  %xcc, fill_fixup_mna;                   \
        b,a,pt  %xcc, fill_fixup;
 
index ec80bb5dc92f50f5c9a082b875593c5ed0179930..dfba3d860435cab624cf7692a82ed712f21e562f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.25 1998/04/28 08:23:34 davem Exp $ */
+/* $Id: uaccess.h,v 1.27 1998/09/23 02:04:57 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -45,8 +45,10 @@ extern spinlock_t scheduler_lock;
 
 #define set_fs(val)                                                            \
 do {                                                                           \
+       unsigned long flags;                                                    \
        if (current->tss.current_ds.seg != val.seg) {                           \
                spin_lock(&scheduler_lock);                                     \
+               __save_and_cli(flags);                                          \
                current->tss.current_ds = (val);                                \
                if (segment_eq((val), KERNEL_DS)) {                             \
                        flushw_user ();                                         \
@@ -56,6 +58,7 @@ do {                                                                          \
                }                                                               \
                spitfire_set_secondary_context(current->tss.ctx);               \
                __asm__ __volatile__("flush %g6");                              \
+               __restore_flags(flags);                                         \
                spin_unlock(&scheduler_lock);                                   \
        }                                                                       \
 } while(0)
index 960d3a01bcbbaf0850933cc67c45f27fbbad4037..8a8ae965e862cf569b9526ef6374920da19e7deb 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.20 1998/07/28 13:08:40 jj Exp $ */
+/* $Id: unistd.h,v 1.22 1998/09/13 04:33:14 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -16,7 +16,6 @@
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  */
 
-#define __NR_setup                0 /* Used only by init, to get system going.     */
 #define __NR_exit                 1 /* Common                                      */
 #define __NR_fork                 2 /* Common                                      */
 #define __NR_read                 3 /* Common                                      */
 #define __NR_unlink              10 /* Common                                      */
 #define __NR_execv               11 /* SunOS Specific                              */
 #define __NR_chdir               12 /* Common                                      */
-/* #define __NR_ni_syscall       13    ENOSYS under SunOS                          */
+#define __NR_chown              13 /* Common                                      */
 #define __NR_mknod               14 /* Common                                      */
 #define __NR_chmod               15 /* Common                                      */
-#define __NR_chown               16 /* Common                                      */
+#define __NR_lchown              16 /* Common                                      */
 #define __NR_brk                 17 /* Common                                      */
 /* #define __NR_ni_syscall       18    ENOSYS under SunOS                          */
 #define __NR_lseek               19 /* Common                                      */
@@ -414,7 +413,6 @@ return -1; \
 #define __NR__exit __NR_exit
 static __inline__ _syscall0(int,idle)
 static __inline__ _syscall0(int,pause)
-static __inline__ _syscall1(int,setup,int,magic)
 static __inline__ _syscall0(int,sync)
 static __inline__ _syscall0(pid_t,setsid)
 static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
index e1de6a384047429c1de75975332619aa08f49787..2cf9e320c6628b811a93680938b5ee678ba04513 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: visasm.h,v 1.2 1998/06/19 12:14:47 jj Exp $ */
+/* $Id: visasm.h,v 1.3 1998/09/04 01:59:48 ecd Exp $ */
 #ifndef _SPARC64_VISASM_H
 #define _SPARC64_VISASM_H
 
@@ -10,7 +10,7 @@
 #include <asm/pstate.h>
 #include <asm/ptrace.h>
 
-#define AOFF_task_fpregs       ((AOFF_task_sigmask_lock + 285)&~255)
+#define AOFF_task_fpregs       (((ASIZ_task) + 255) & ~255)
  
 /* Clobbers %o5, %g1, %g2, %g3, %g7, %icc, %xcc */
 
diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h
new file mode 100644 (file)
index 0000000..bb34520
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _LINUX_ERRQUEUE_H
+#define _LINUX_ERRQUEUE_H 1
+
+struct sock_extended_err
+{
+       __u32   ee_errno;       
+       __u8    ee_origin;
+       __u8    ee_type;
+       __u8    ee_code;
+       __u8    ee_pad;
+       __u32   ee_info;
+       __u32   ee_data;
+};
+
+#define SO_EE_ORIGIN_NONE      0
+#define SO_EE_ORIGIN_LOCAL     1
+#define SO_EE_ORIGIN_ICMP      2
+#define SO_EE_ORIGIN_ICMP6     3
+
+#define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
+
+#ifdef __KERNEL__
+#define SKB_EXT_ERR(skb) ((struct sock_exterr_skb *) ((skb)->cb))
+
+struct sock_exterr_skb
+{
+       union {
+               struct inet_skb_parm    h4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+               struct inet6_skb_parm   h6;
+#endif
+       } header;
+       struct sock_extended_err        ee;
+       u16                             addr_offset;
+       u16                             port;
+};
+
+#endif
+
+#endif
index ca23ef8b5abb771e3f3f754c242fc890e83a361b..d35ab607fc95826450aa28acd819ffadf52caa6e 100644 (file)
@@ -57,6 +57,7 @@
 #define FB_ACCEL_SUN_CREATOR   11      /* Sun Creator/Creator3D        */
 #define FB_ACCEL_SUN_CGSIX     12      /* Sun cg6                      */
 #define FB_ACCEL_SUN_LEO       13      /* Sun leo/zx                   */
+#define FB_ACCEL_IMS_TWINTURBO 14      /* IMS Twin Turbo               */
 
 struct fb_fix_screeninfo {
        char id[16];                    /* identification string eg "TT Builtin" */
@@ -281,6 +282,8 @@ struct display {
 struct fb_info {
    char modename[40];                  /* default video mode */
    int node;
+   int flags;
+#define FBINFO_FLAG_MODULE     1       /* Low-level driver is a module */
    struct fb_ops *fbops;
    struct fb_monspecs monspecs;
    struct display *disp;               /* initial display variable */
@@ -298,6 +301,11 @@ struct fb_info {
    /* From here on everything is device dependent */
 };
 
+#ifdef MODULE
+#define FBINFO_FLAG_DEFAULT    FBINFO_FLAG_MODULE
+#else
+#define FBINFO_FLAG_DEFAULT    0
+#endif
 
     /*
      *  This structure abstracts from the underlying hardware. It is not
index 2cc007a434f8e7569bc9ae4171e6204a86a6c4eb..0dc2231a4d53b444726862e70915c14fad042219 100644 (file)
@@ -57,17 +57,18 @@ struct in_addr {
 #define IP_RETOPTS     7
 #define IP_PKTINFO     8
 #define IP_PKTOPTIONS  9
-#define IP_PMTUDISC    10
+#define IP_MTU_DISCOVER        10
 #define IP_RECVERR     11
 #define IP_RECVTTL     12
 #define        IP_RECVTOS      13
+#define IP_MTU         14
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS IP_RETOPTS
 
-/* IP_PMTUDISC values */
-#define IP_PMTUDISC_WANT               0       /* Use per route hints  */
-#define IP_PMTUDISC_DONT               1       /* Never send DF frames */
+/* IP_MTU_DISCOVER values */
+#define IP_PMTUDISC_DONT               0       /* Never send DF frames */
+#define IP_PMTUDISC_WANT               1       /* Use per route hints  */
 #define IP_PMTUDISC_DO                 2       /* Always DF            */
 
 #define IP_MULTICAST_IF                        32
index b6391841943c5aab008cad01cee42ec87af80cfc..50f9d2d72ff205fe36b4ba67c5e62525606afa65 100644 (file)
@@ -149,5 +149,13 @@ struct ipv6_mreq {
 #define IPV6_ADD_MEMBERSHIP    20
 #define IPV6_DROP_MEMBERSHIP   21
 #define IPV6_ROUTER_ALERT      22
+#define IPV6_MTU_DISCOVER      23
+#define IPV6_MTU               24
+#define IPV6_RECVERR           25
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT             0
+#define IPV6_PMTUDISC_WANT             1
+#define IPV6_PMTUDISC_DO               2
 
 #endif
index f09175b4e69b67499f1af763edecfbae54bfd36e..6675cee9582ee5895572d706b51a1baee65a4a2e 100644 (file)
 #define MAXTTL         255
 #define IPDEFTTL       64
 
-struct timestamp {
-       __u8    len;
-       __u8    ptr;
-#if defined(__LITTLE_ENDIAN_BITFIELD)
-       __u8    flags:4,
-               overflow:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
-       __u8    overflow:4,
-               flags:4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif                                         
-       __u32   data[9];
-};
+/* struct timestamp, struct route and MAX_ROUTES are removed.
 
-
-#define MAX_ROUTE      16
-
-struct route {
-  char         route_size;
-  char         pointer;
-  unsigned long route[MAX_ROUTE];
-};
+   REASONS: it is clear that nobody used them because:
+   - MAX_ROUTES value was wrong.
+   - "struct route" was wrong.
+   - "struct timestamp" had fatally misaligned bitfields and was completely unusable.
+ */
 
 #define IPOPT_OPTVAL 0
 #define IPOPT_OLEN   1
@@ -102,7 +86,7 @@ struct route {
 
 #define        IPOPT_TS_TSONLY         0               /* timestamps only */
 #define        IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
-#define        IPOPT_TS_PRESPEC        2               /* specified modules only */
+#define        IPOPT_TS_PRESPEC        3               /* specified modules only */
 
 struct ip_options {
   __u32                faddr;                          /* Saved first hop address */
index eeaa1eb5f9592323561c0c4321bf9d3ca3c1059b..f36ec7e6f18374b708b30ec26541f4868cd5b12c 100644 (file)
 #ifndef _IP_FWCHAINS_H
 #define _IP_FWCHAINS_H
 
+#ifdef __KERNEL__
 #include <linux/icmp.h>
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
+#endif /* __KERNEL__ */
 #define IP_FW_MAX_LABEL_LENGTH 8
 typedef char ip_chainlabel[IP_FW_MAX_LABEL_LENGTH+1];
 
@@ -91,11 +93,9 @@ struct ip_fwuser
 #define IP_FW_CREATECHAIN      (IP_FW_BASE_CTL+9)  /* Takes ip_chainlabel */
 #define IP_FW_DELETECHAIN      (IP_FW_BASE_CTL+10) /* Takes ip_chainlabel */
 #define IP_FW_POLICY           (IP_FW_BASE_CTL+11) /* Takes ip_fwpolicy */
-/* Masquerade controls */
-#define IP_FW_MASQ_INSERT      (IP_FW_BASE_CTL+12)
-#define IP_FW_MASQ_ADD         (IP_FW_BASE_CTL+13)
-#define IP_FW_MASQ_DEL         (IP_FW_BASE_CTL+14)
-#define IP_FW_MASQ_FLUSH       (IP_FW_BASE_CTL+15)
+/* Masquerade control, only 1 optname */
+
+#define IP_FW_MASQ_CTL         (IP_FW_BASE_CTL+12) /* General ip_masq ctl */
 
 /* Builtin chain labels */
 #define IP_FW_LABEL_FORWARD    "forward"
@@ -167,23 +167,7 @@ struct ip_fwpolicy
  * timeouts for ip masquerading
  */
 
-struct ip_fw_masq;
-
-/* Masquerading stuff */
-#define IP_FW_MASQCTL_MAX 256
-#define IP_MASQ_MOD_NMAX  32
-
-struct ip_fw_masqctl
-{
-       int mctl_action;
-       union {
-               struct {
-                       char name[IP_MASQ_MOD_NMAX];
-                       char data[1];
-               } mod;
-       } u;
-};
-
+extern int ip_fw_masq_timeouts(void *, int);
 
 
 /*
@@ -202,7 +186,7 @@ extern void ip_fw_init(void);
 #endif /* 2.1.x */
 extern int ip_fw_ctl(int, void *, int);
 #ifdef CONFIG_IP_MASQUERADE
-extern int ip_masq_ctl(int, void *, int);
+extern int ip_masq_uctl(int, char *, int);
 #endif
 #endif /* KERNEL */
 
diff --git a/include/linux/ip_masq.h b/include/linux/ip_masq.h
new file mode 100644 (file)
index 0000000..ac7ca60
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *     IP_MASQ user space control interface
+ *     $Id: ip_masq.h,v 1.1 1998/08/29 23:50:56 davem Exp $
+ */
+
+#ifndef _LINUX_IP_MASQ_H
+#define _LINUX_IP_MASQ_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/stddef.h>
+#else
+#include <sys/types.h>
+#include <stddef.h>
+#endif
+
+struct ip_masq_user {
+       int     protocol;
+       u_int16_t       sport, dport, mport;
+       u_int32_t       saddr, daddr, maddr;
+       u_int32_t       rt_daddr;       /* dst address to use for rt query */
+       u_int32_t       rt_saddr;       
+       u_int32_t       ip_tos;         /* TOS */
+       unsigned timeout;               /* in ticks (HZ per sec) */
+       unsigned flags;
+       int fd;                         /* NOT IMPL: attach tunnel to this fd */
+       int state;                      /* NOT IMPL: return conn state */
+};
+
+#define IP_MASQ_USER_F_LISTEN  0x01    /* put entry to LISTEN state */
+#define IP_MASQ_USER_F_DEAD    0x02    /* mark as DEAD */
+#define IP_MASQ_USER_F_FORCE   0x04    /* force operation */
+
+struct ip_masq_timeout {
+       int protocol;
+       union {
+               struct {
+                       unsigned established;
+                       unsigned syn_sent;
+                       unsigned syn_recv;
+                       unsigned fin_wait;
+                       unsigned time_wait;
+                       unsigned close;
+                       unsigned close_wait;
+                       unsigned last_ack;
+                       unsigned listen;
+               } tcp;
+               unsigned udp;
+               unsigned icmp;
+       } u;
+};
+
+/* 
+ *     AUTOFW stuff 
+ */
+#define IP_FWD_RANGE           1
+#define IP_FWD_PORT            2
+#define IP_FWD_DIRECT          3
+
+#define IP_AUTOFW_ACTIVE       1
+#define IP_AUTOFW_USETIME      2
+#define IP_AUTOFW_SECURE       4
+
+
+/* WARNING: bitwise equal to ip_autofw  in net/ip_autofw.h */
+struct ip_autofw_user {
+       void * next;
+       u_int16_t type;
+       u_int16_t low;
+       u_int16_t hidden;
+       u_int16_t high;
+       u_int16_t visible;
+       u_int16_t protocol;
+       u_int32_t lastcontact;
+       u_int32_t where;
+       u_int16_t ctlproto;
+       u_int16_t ctlport;
+       u_int16_t flags;
+       /* struct timer_list timer; */
+};
+
+/* 
+ *     PORTFW stuff 
+ */
+struct ip_portfw_user {
+       u_int16_t       protocol;       /* Which protocol are we talking? */
+       u_int32_t       laddr, raddr;   /* Remote address */
+       u_int16_t       lport, rport;   /* Local and remote port */
+       int             pref;           /* Preference value */
+};
+
+/* 
+ *     MARKFW stuff 
+ */
+struct ip_markfw_user {
+       u_int32_t           fwmark;     /* Firewalling mark */
+       u_int32_t           raddr;      /* remote port */
+       u_int16_t           rport;      /* remote port */
+       u_int16_t           dummy;          /* Make up to multiple of 4 */
+       int             pref;           /* Preference value */
+};
+
+#define IP_FW_MASQCTL_MAX 256
+#define IP_MASQ_TNAME_MAX  32
+
+struct ip_masq_ctl {
+       int m_target;
+       int m_cmd;
+       char m_tname[IP_MASQ_TNAME_MAX];
+       union {
+               struct ip_portfw_user portfw_user;
+               struct ip_autofw_user autofw_user;
+               struct ip_markfw_user markfw_user;
+               struct ip_masq_user user;
+               unsigned char m_raw[IP_FW_MASQCTL_MAX];
+       } u;
+};
+
+#define IP_MASQ_CTL_BSIZE (offsetof (struct ip_masq_ctl,u))
+
+#define IP_MASQ_TARGET_CORE    1
+#define IP_MASQ_TARGET_MOD     2       /* masq_mod is selected by "name" */
+#define IP_MASQ_TARGET_USER    3       
+#define IP_MASQ_TARGET_LAST    4
+
+#define IP_MASQ_CMD_NONE       0
+#define IP_MASQ_CMD_INSERT     1
+#define IP_MASQ_CMD_ADD                2
+#define IP_MASQ_CMD_SET                3
+#define IP_MASQ_CMD_DEL                4
+#define IP_MASQ_CMD_GET                5
+#define IP_MASQ_CMD_FLUSH      6
+#define IP_MASQ_CMD_LIST       7
+#define IP_MASQ_CMD_ENABLE     8
+#define IP_MASQ_CMD_DISABLE    9
+
+#endif /* _LINUX_IP_MASQ_H */
index 1cba27469f3fb901da6e465b3de832c5f229bcc8..69a94b2d991b5fb7a29e1f756f26c582bc3719fd 100644 (file)
@@ -132,7 +132,6 @@ enum
        NET_CORE_RMEM_MAX,
        NET_CORE_WMEM_DEFAULT,
        NET_CORE_RMEM_DEFAULT,
-       NET_CORE_DESTROY_DELAY,
        NET_CORE_MAX_BACKLOG,
        NET_CORE_FASTROUTE,
        NET_CORE_MSG_COST,
index 63ef8b0a204ecf37aafee89de010fad1791a443f..52686031ec54d46327b7daf6e554bcb72d94e7d9 100644 (file)
@@ -166,7 +166,7 @@ extern __inline__ void ip_send(struct sk_buff *skb)
                ip_finish_output(skb);
 }
 
-static __inline__
+extern __inline__
 int ip_decrease_ttl(struct iphdr *iph)
 {
        u16 check = iph->check;
@@ -177,6 +177,14 @@ int ip_decrease_ttl(struct iphdr *iph)
        return --iph->ttl;
 }
 
+extern __inline__
+int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
+{
+       return (sk->ip_pmtudisc == IP_PMTUDISC_DO ||
+               (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
+                !(dst->mxlock&(1<<RTAX_MTU))));
+}
+
 /*
  *     Map a multicast IP onto multicast MAC for type ethernet.
  */
@@ -233,7 +241,10 @@ extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval,
 extern int     ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen);
 extern int     ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct sock *));
 
-extern int             ipv4_backlog_rcv(struct sock *sk, struct sk_buff *skb);  
-
+extern int     ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern void    ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
+                             u16 port, u32 info, u8 *payload);
+extern void    ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
+                              u32 info);
 
 #endif /* _IP_H */
diff --git a/include/net/ip_autofw.h b/include/net/ip_autofw.h
deleted file mode 100644 (file)
index feeec7b..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#ifndef _IP_AUTOFW_H
-#define _IP_AUTOFW_H
-
-#define IP_AUTOFW_EXPIRE            15*HZ
-
-#define IP_FWD_RANGE           1
-#define IP_FWD_PORT            2
-#define IP_FWD_DIRECT          3
-
-#define IP_AUTOFW_ACTIVE       1
-#define IP_AUTOFW_USETIME      2
-#define IP_AUTOFW_SECURE       4
-
-struct ip_autofw {
-       struct ip_autofw * next;
-       __u16 type;
-       __u16 low;
-       __u16 hidden;
-       __u16 high;
-       __u16 visible;
-       __u16 protocol;
-       __u32 lastcontact;
-       __u32 where;
-       __u16 ctlproto;
-       __u16 ctlport;
-       __u16 flags;
-       struct timer_list timer;
-};
-int ip_autofw_init(void);
-#endif /* _IP_AUTOFW_H */
index b79e4d0fbeb5ce5c952e93562cd0857cc7fee259..5c8d6bf8e00ce67af4b87873f3d386e101136891 100644 (file)
@@ -27,17 +27,10 @@ struct kern_rta
        void            *rta_gw;
        u32             *rta_priority;
        void            *rta_prefsrc;
-#ifdef CONFIG_RTNL_OLD_IFINFO
-       unsigned        *rta_window;
-       unsigned        *rta_rtt;
-       unsigned        *rta_mtu;
-       unsigned char   *rta_ifname;
-#else
        struct rtattr   *rta_mx;
        struct rtattr   *rta_mp;
        unsigned char   *rta_protoinfo;
        unsigned char   *rta_flow;
-#endif
        struct rta_cacheinfo *rta_ci;
 };
 
@@ -69,17 +62,12 @@ struct fib_info
        unsigned                fib_flags;
        int                     fib_protocol;
        u32                     fib_prefsrc;
-#ifdef CONFIG_RTNL_OLD_IFINFO
-       unsigned                fib_mtu;
-       unsigned                fib_rtt;
-       unsigned                fib_window;
-#else
+       u32                     fib_priority;
 #define FIB_MAX_METRICS RTAX_RTT
        unsigned                fib_metrics[FIB_MAX_METRICS];
 #define fib_mtu fib_metrics[RTAX_MTU-1]
 #define fib_window fib_metrics[RTAX_WINDOW-1]
 #define fib_rtt fib_metrics[RTAX_RTT-1]
-#endif
        int                     fib_nhs;
 #ifdef CONFIG_IP_ROUTE_MULTIPATH
        int                     fib_power;
index 716eea2efcda65a62a15a02f0d53ed39520699f0..03c65fddce5be09ef583bf0afcd9783a604d75f5 100644 (file)
@@ -2,7 +2,7 @@
  *     IP masquerading functionality definitions
  */
 
-#include <linux/config.h> /* for CONFIG_IP_MASQ_NDEBUG */
+#include <linux/config.h> /* for CONFIG_IP_MASQ_DEBUG */
 #ifndef _IP_MASQ_H
 #define _IP_MASQ_H
 
  */
 #define MASQUERADE_EXPIRE_ICMP      125*HZ
 
-#define IP_MASQ_F_OUT_SEQ                      0x01    /* must do output seq adjust */
-#define IP_MASQ_F_IN_SEQ               0x02    /* must do input seq adjust */
-#define IP_MASQ_F_NO_DPORT                     0x04    /* no dport set yet */
-#define IP_MASQ_F_NO_DADDR             0x08    /* no daddr yet */
-#define IP_MASQ_F_HASHED               0x10    /* hashed entry */
-
-#define IP_MASQ_F_NO_SPORT            0x200    /* no sport set yet */
-#define IP_MASQ_F_NO_REPLY            0x800    /* no reply yet from outside */
-#define IP_MASQ_F_MPORT                      0x1000    /* own mport specified */
+#define IP_MASQ_MOD_CTL                        0x00
+#define IP_MASQ_USER_CTL               0x01
 
 #ifdef __KERNEL__
 
+#define IP_MASQ_TAB_SIZE       256
+
+#define IP_MASQ_F_NO_DADDR           0x0001    /* no daddr yet */
+#define IP_MASQ_F_NO_DPORT                   0x0002    /* no dport set yet */
+#define IP_MASQ_F_NO_SADDR           0x0004    /* no sport set yet */
+#define IP_MASQ_F_NO_SPORT           0x0008    /* no sport set yet */
+
+#define IP_MASQ_F_NO_REPLY           0x0010    /* no reply yet from outside */
+
+#define IP_MASQ_F_HASHED             0x0100    /* hashed entry */
+#define IP_MASQ_F_OUT_SEQ             0x0200   /* must do output seq adjust */
+#define IP_MASQ_F_IN_SEQ              0x0400   /* must do input seq adjust */
+
+#define IP_MASQ_F_MPORT                      0x1000    /* own mport specified */
+#define IP_MASQ_F_USER               0x2000    /* from uspace */
+
 /*
  *     Delta seq. info structure
  *     Each MASQ struct has 2 (output AND input seq. changes).
@@ -81,7 +90,8 @@ struct ip_masq {
 };
 
 /*
- *     timeout values
+ *     Timeout values
+ *     ipchains holds a copy of this definition
  */
 
 struct ip_fw_masq {
@@ -90,8 +100,13 @@ struct ip_fw_masq {
         int udp_timeout;
 };
 
-extern struct ip_fw_masq *ip_masq_expire;
-
+union ip_masq_tphdr {
+               unsigned char *raw;
+               struct udphdr *uh;
+               struct tcphdr *th;
+               struct icmphdr *icmph;
+               __u16 *portp;
+};
 /*
  *     [0]: UDP free_ports
  *     [1]: TCP free_ports
@@ -121,7 +136,18 @@ extern void ip_masq_control_add(struct ip_masq *ms, struct ip_masq* ctl_ms);
 extern void ip_masq_control_del(struct ip_masq *ms);
 extern struct ip_masq * ip_masq_control_get(struct ip_masq *ms);
 
+struct ip_masq_ctl;
+struct ip_masq_hook {
+       int (*ctl)(int, struct ip_masq_ctl *, int);
+       int (*info)(char *, char **, off_t, int, int);
+};
 
+extern struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE];
+extern struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE];
+extern const char * ip_masq_state_name(int state);
+extern struct ip_masq_hook *ip_masq_user_hook;
+extern u32 ip_masq_select_addr(struct device *dev, u32 dst, int scope);
 /*
  *     
  *     IP_MASQ_APP: IP application masquerading definitions 
@@ -201,55 +227,26 @@ static __inline__ struct ip_masq * ip_masq_out_get_iph(const struct iphdr *iph)
 extern void ip_masq_put(struct ip_masq *ms);
 
 
-/* 
- *     Locking stuff
- */
-
-
-static __inline__ void ip_masq_lock(atomic_t *lock, int rw)
-{
-#if 0
-       if (rw) 
-#endif
-               start_bh_atomic();
-       atomic_inc(lock);
-}
-
-static __inline__ void ip_masq_unlock(atomic_t *lock, int rw)
-{
-       atomic_dec(lock);
-#if 0
-       if (rw) 
-#endif
-               end_bh_atomic();
-}
-
+extern rwlock_t __ip_masq_lock;
+
+#ifdef __SMP__
+#define read_lock_bh(lock)     do { start_bh_atomic(); read_lock(lock); \
+                                       } while (0)
+#define read_unlock_bh(lock)   do { read_unlock(lock); end_bh_atomic(); \
+                                       } while (0)
+#define write_lock_bh(lock)    do { start_bh_atomic(); write_lock(lock); \
+                                       } while (0)
+#define write_unlock_bh(lock)  do { write_unlock(lock); end_bh_atomic(); \
+                                       } while (0)
+#else
+#define read_lock_bh(lock)     start_bh_atomic()
+#define read_unlock_bh(lock)   end_bh_atomic()
+#define write_lock_bh(lock)    start_bh_atomic()
+#define write_unlock_bh(lock)  end_bh_atomic()
+#endif 
 /*
- *     Sleep-able lockzzz...
- */
-static __inline__ void ip_masq_lockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
-{
-       if (rw)
-               while(atomic_read(lock)) sleep_on(waitq);
-       ip_masq_lock(lock, rw);
-}
-
-static __inline__ void ip_masq_unlockz(atomic_t *lock, struct wait_queue ** waitq, int rw)
-{
-       ip_masq_unlock(lock, rw);
-       if (rw)
-               wake_up(waitq);
-}
-       
-/*
- *     Perfect for winning races ... ;)
+ *
  */
-static __inline__ int ip_masq_nlocks(atomic_t *lock)
-{
-       return atomic_read(lock);
-}
-
-extern atomic_t __ip_masq_lock;
 
 /*
  *     Debugging stuff
@@ -257,7 +254,7 @@ extern atomic_t __ip_masq_lock;
 
 extern int ip_masq_get_debug_level(void);
 
-#ifndef CONFIG_IP_MASQ_NDEBUG
+#ifdef CONFIG_IP_MASQ_DEBUG
 #define IP_MASQ_DEBUG(level, msg...) do { \
        if (level <= ip_masq_get_debug_level()) \
                printk(KERN_DEBUG "IP_MASQ:" ## msg); \
@@ -279,6 +276,8 @@ extern int ip_masq_get_debug_level(void);
 /*
  *     /proc/net entry
  */
+extern int ip_masq_proc_register(struct proc_dir_entry *);
+extern void ip_masq_proc_unregister(struct proc_dir_entry *);
 extern int ip_masq_app_getinfo(char *buffer, char **start, off_t offset, int length, int dummy);
 
 /*
index 427421d9b6655b7c7f4e6741ecce62692b01211f..7cd9a7f32de0d511943f9984392f3770b2c3d18d 100644 (file)
 #include <linux/proc_fs.h>
 #include <net/ip_masq.h>
 
-enum {
-       IP_MASQ_MOD_NOP,
-       IP_MASQ_MOD_ACCEPT,
-       IP_MASQ_MOD_REJECT
-};
+#define IP_MASQ_MOD_NOP        0
+#define IP_MASQ_MOD_ACCEPT     1
+#define IP_MASQ_MOD_REJECT     -1
 
 struct ip_masq_mod {
        struct ip_masq_mod *next;       /* next mod for addrs. lookups */
@@ -27,29 +25,32 @@ struct ip_masq_mod {
        atomic_t refcnt;
        atomic_t mmod_nent;             /* number of entries */
        struct proc_dir_entry *mmod_proc_ent;
-       int (*mmod_ctl) (int optname, struct ip_fw_masqctl *, int optlen);
+       int (*mmod_ctl) (int optname, struct ip_masq_ctl *, int optlen);
        int (*mmod_init) (void);
        int (*mmod_done) (void);
-       int (*mmod_in_rule) (struct iphdr *, __u16 *);
-       int (*mmod_in_update) (struct iphdr *, struct ip_masq *);
-       struct ip_masq * (*mmod_in_create) (struct iphdr *, __u16 *, __u32);
-       int (*mmod_out_rule) (struct iphdr *, __u16 *);
-       int (*mmod_out_update) (struct iphdr *, __u16 *, struct ip_masq *);
-       struct ip_masq * (*mmod_out_create) (struct iphdr *, __u16 *, __u32);
+       int (*mmod_in_rule)   (const struct sk_buff *, const struct iphdr *);
+       int (*mmod_in_update) (const struct sk_buff *, const struct iphdr *, 
+               struct ip_masq *);
+       struct ip_masq * (*mmod_in_create) (const struct sk_buff *, const struct iphdr *, __u32);
+       int (*mmod_out_rule)   (const struct sk_buff *, const struct iphdr *);
+       int (*mmod_out_update) (const struct sk_buff *, const struct iphdr *,
+               struct ip_masq *);
+       struct ip_masq * (*mmod_out_create) (const struct sk_buff *, const struct iphdr *, __u32);
 };
 
 /*
  *     Service routines (called from ip_masq.c)
  */
-int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp);
-int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
-struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
 
-int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp);
-int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms);
-struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr);
+int ip_masq_mod_out_rule(const struct sk_buff *, const struct iphdr *);
+int ip_masq_mod_out_update(const struct sk_buff *, const struct iphdr *, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr);
+
+int ip_masq_mod_in_rule(const struct sk_buff *, const struct iphdr *iph);
+int ip_masq_mod_in_update(const struct sk_buff *, const struct iphdr *iph, struct ip_masq *ms);
+struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *, const struct iphdr *iph, __u32 maddr);
 
-extern int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *, int len);
+extern int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *, int len);
 
 /*
  *     ip_masq_mod registration functions 
@@ -59,6 +60,13 @@ extern int unregister_ip_masq_mod(struct ip_masq_mod *mmod);
 extern int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod);
 extern int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod);
 
+/*
+ *     init functions protos
+ */
+extern int ip_portfw_init(void);
+extern int ip_markfw_init(void);
+extern int ip_autofw_init(void);
+
 /*
  *     Utility ...
  */
diff --git a/include/net/ip_portfw.h b/include/net/ip_portfw.h
deleted file mode 100644 (file)
index f2b51ea..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _IP_PORTFW_H
-#define  _IP_PORTFW_H
-
-#include <linux/types.h>
-
-#define IP_PORTFW_PORT_MIN 1
-#define IP_PORTFW_PORT_MAX 60999
-
-#ifdef __KERNEL__
-struct ip_portfw {
-       struct          list_head list;
-       __u32           laddr, raddr;
-       __u16           lport, rport;
-       atomic_t        pref_cnt;       /* pref "counter" down to 0 */
-       int             pref;           /* user set pref */
-};
-extern int ip_portfw_init(void);
-
-#endif /* __KERNEL__ */
-
-struct ip_portfw_edits {
-       __u16           protocol;       /* Which protocol are we talking? */
-       __u32           laddr, raddr;   /* Remote address */
-       __u16           lport, rport;   /* Local and remote port */
-       __u16           dummy;          /* Make up to multiple of 4 */
-       int             pref;           /* Preference value */
-};
-
-#endif
index 03f30b6442e83c7f25c15f67ab9ae23f0ec21280..118eec2e945737b4a4e8d0e247d298709c83bc1d 100644 (file)
@@ -4,7 +4,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
- *     $Id: ipv6.h,v 1.13 1998/08/26 12:02:11 davem Exp $
+ *     $Id: ipv6.h,v 1.14 1998/10/03 09:36:45 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -284,6 +284,11 @@ extern void                        ipv6_packet_cleanup(void);
 
 extern void                    ipv6_netdev_notif_cleanup(void);
 
+extern int                     ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len);
+extern void                    ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, u16 port,
+                                               u32 info, u8 *payload);
+extern void                    ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info);
+
 #endif /* __KERNEL__ */
 #endif /* _NET_IPV6_H */
 
index e38826d0b19702b3742a28b1c9789c4e81dbaa64..cc8354b6c1428fcc20e35a0d4f05c52ac6dc0858 100644 (file)
@@ -176,6 +176,8 @@ struct linux_mib
        unsigned long   PruneCalled; 
        unsigned long   RcvPruned;
        unsigned long   OfoPruned;
+       unsigned long   OutOfWindowIcmps; 
+       unsigned long   LockDroppedIcmps; 
 };
        
 #endif
index 4ad46f4acca18c7480e37eb3d3bcc26263dd3891..af485567fdcbc57a853d4644f6c6b3d08445aea7 100644 (file)
@@ -139,6 +139,7 @@ struct ipv6_pinfo {
        struct in6_addr         *daddr_cache;
 
        __u32                   flow_lbl;
+       __u32                   frag_size;
        int                     hop_limit;
        int                     mcast_hops;
        int                     mcast_oif;
@@ -159,7 +160,9 @@ struct ipv6_pinfo {
        } rxopt;
 
        /* sockopt flags */
-       __u8                    mc_loop:1;
+       __u8                    mc_loop:1,
+                               recverr:1,
+                               pmtudisc:2;
 
        struct ipv6_mc_socklist *ipv6_mc_list;
        __u32                   dst_cookie;
@@ -842,20 +845,6 @@ extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        return 0;
 }
 
-extern __inline__ int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
-{
-       /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
-          number of warnings when compiling with -W --ANK
-        */
-       if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
-               return -ENOMEM;
-       skb_set_owner_r(skb, sk);
-       __skb_queue_tail(&sk->receive_queue,skb);
-       if (!sk->dead)
-               sk->data_ready(sk,skb->len);
-       return 0;
-}
-
 extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 {
        /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
@@ -864,7 +853,7 @@ extern __inline__ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)
                return -ENOMEM;
        skb_set_owner_r(skb, sk);
-       __skb_queue_tail(&sk->error_queue,skb);
+       skb_queue_tail(&sk->error_queue,skb);
        if (!sk->dead)
                sk->data_ready(sk,skb->len);
        return 0;
index 2ea480b89c05ab4e59d0119e3f664a4f37c57ae6..0e234075a9e7b270bbbe1a15c4170ec8325f36f6 100644 (file)
@@ -78,8 +78,8 @@ extern long console_init(long, long);
 extern void sock_init(void);
 extern void uidcache_init(void);
 extern void mca_init(void);
-extern long sbus_init(void);
-extern long powermac_init(unsigned long, unsigned long);
+extern void sbus_init(void);
+extern void powermac_init(void);
 extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
index c5b161ae08731f1a573068ce96eafe0b9920f71a..b4210cf9dc7812a10cc225c50295d5f6169244e2 100644 (file)
  *
  * (C) Copyright 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V.
  *
+ *  Plugged two leaks. 1) It didn't return acct_file into the free_filps if
+ *  the file happened to be read-only. 2) If the accounting was suspended
+ *  due to the lack of space it happily allowed to reopen it and completely
+ *  lost the old acct_file. 3/10/98, Al Viro.
  */
 
 #include <linux/config.h>
@@ -123,17 +127,25 @@ asmlinkage int sys_acct(const char *name)
                goto out;
 
        if (name == (char *)NULL) {
-               if (acct_active) {
-                       acct_process(0); 
+               if (acct_file) {
+                       /* fput() may block, so just in case... */
+                       struct file *tmp = acct_file;
+                       if (acct_active)
+                               acct_process(0); 
                        del_timer(&acct_timer);
                        acct_active = 0;
                        acct_needcheck = 0;
-                       fput(acct_file);
+                       acct_file = NULL;
+                       fput(tmp);
                }
                error = 0;
                goto out;
        } else {
-               if (!acct_active) {
+               /*
+                * We can't rely on acct_active - it might be disabled
+                * due to the lack of space.
+                */
+               if (!acct_file) {
                        tmp = getname(name);
                        error = PTR_ERR(tmp);
                        if (IS_ERR(tmp))
@@ -181,11 +193,17 @@ asmlinkage int sys_acct(const char *name)
                                        }
                                        put_write_access(acct_file->f_dentry->d_inode);
                                }
-                               acct_file->f_count--;
+                               /* decrementing f_count is _not_ enough */
+                               put_filp(acct_file);
+                               acct_file = NULL;
                        } else
                                error = -EUSERS;
                        dput(dentry);
                } else
+                       /*
+                        * NB: in this case FreeBSD just closes acct_file
+                        * and opens new one. Maybe it's better behavior...
+                        */
                        error = -EBUSY;
        }
 out:
index 856934441b4cea9bdbafed0c0c5da052fa9c71df..a1ef239aa636ab37ffc2fc5ca9979bce29b550a6 100644 (file)
@@ -461,7 +461,7 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
 {
        unsigned long new_flags = p->flags;
 
-       new_flags &= ~PF_SUPERPRIV;
+       new_flags &= ~(PF_SUPERPRIV | PF_USEDFPU);
        new_flags |= PF_FORKNOEXEC;
        if (!(clone_flags & CLONE_PTRACE))
                new_flags &= ~(PF_PTRACED|PF_TRACESYS);
index f064370d4c7ac12cc113b919f5ae87a4486f6d7d..da09973cd704e14d0390740cbb4ba3dfe3cf3fbd 100644 (file)
@@ -103,6 +103,11 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
        int error;
        struct sk_buff *skb;
 
+       /* Caller is allowed not to check sk->err before skb_recv_datagram() */
+       error = sock_error(sk);
+       if (error)
+               goto no_packet;
+
 restart:
        while(skb_queue_empty(&sk->receive_queue))      /* No data */
        {
@@ -216,11 +221,11 @@ unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *
        mask = 0;
 
        /* exceptional events? */
-       if (sk->err)
+       if (sk->err || !skb_queue_empty(&sk->error_queue))
                mask |= POLLERR;
        if (sk->shutdown & RCV_SHUTDOWN)
                mask |= POLLHUP;
-       
+
        /* readable? */
        if (!skb_queue_empty(&sk->receive_queue))
                mask |= POLLIN | POLLRDNORM;
@@ -237,6 +242,8 @@ unsigned int datagram_poll(struct file * file, struct socket *sock, poll_table *
        /* writable? */
        if (sock_writeable(sk))
                mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+       else
+               sk->socket->flags |= SO_NOSPACE;
 
        return mask;
 }
index ead3b77ffdf64dc30a1f476997d3cd6f00a9bcf2..637322f6550a45f4bd02534405c566a9199d5ea4 100644 (file)
@@ -592,7 +592,7 @@ static __inline__ void neigh_update_hhs(struct neighbour *neigh)
    -- lladdr is new lladdr or NULL, if it is not supplied.
    -- new    is new state.
    -- override==1 allows to override existing lladdr, if it is different.
-   -- arp==0 means that that the change is administrative.
+   -- arp==0 means that the change is administrative.
  */
 
 int neigh_update(struct neighbour *neigh, u8 *lladdr, u8 new, int override, int arp)
index e9e293ec91f6375ac22ae3ea3b18a8fb436ccfe6..f96716634a38a9656e8a45cc3c5eb22c618075a7 100644 (file)
@@ -7,7 +7,7 @@
  *             handler for protocols to use and generic option handler.
  *
  *
- * Version:    $Id: sock.c,v 1.70 1998/08/26 12:03:07 davem Exp $
+ * Version:    $Id: sock.c,v 1.73 1998/10/03 16:08:10 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -138,8 +138,7 @@ __u32 sysctl_rmem_max = SK_RMEM_MAX;
 __u32 sysctl_wmem_default = SK_WMEM_MAX;
 __u32 sysctl_rmem_default = SK_RMEM_MAX;
 
-int sysctl_core_destroy_delay = SOCK_DESTROY_TIME;
-/* Maximal space eaten by iovec (still not made (2.1.88)!) plus some space */
+/* Maximal space eaten by iovec or ancilliary data plus some space */
 int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
 
 /*
@@ -155,7 +154,6 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
        int valbool;
        int err;
        struct linger ling;
-       struct ifreq req;
        int ret = 0;
 
 #ifdef CONFIG_FILTER
@@ -293,31 +291,37 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
                        
 #ifdef CONFIG_NETDEVICES
                case SO_BINDTODEVICE:
+               {
+                       char devname[IFNAMSIZ]; 
+
                        /* Bind this socket to a particular device like "eth0",
-                        * as specified in an ifreq structure. If the device
-                        * is "", socket is NOT bound to a device.
-                        */
+                        * as specified in the passed interface name. If the
+                        * name is "" or the option length is zero the socket 
+                        * is not bound. 
+                        */ 
 
                        if (!valbool) {
                                sk->bound_dev_if = 0;
-                       }
-                       else {
-                               if (copy_from_user(&req, optval, sizeof(req)))
-                                       return -EFAULT;
-
+                       } else {
+                               if (optlen > IFNAMSIZ) 
+                                       optlen = IFNAMSIZ; 
+                               if (copy_from_user(devname, optval, optlen))
+                                   return -EFAULT;
+                                   
                                /* Remove any cached route for this socket. */
                                dst_release(xchg(&sk->dst_cache, NULL));
 
-                               if (req.ifr_ifrn.ifrn_name[0] == '\0') {
+                               if (devname[0] == '\0') {
                                        sk->bound_dev_if = 0;
                                } else {
-                                       struct device *dev = dev_get(req.ifr_ifrn.ifrn_name);
+                                       struct device *dev = dev_get(devname);
                                        if (!dev)
                                                return -EINVAL;
                                        sk->bound_dev_if = dev->ifindex;
                                }
+                               return 0;
                        }
-                       return 0;
+               }
 #endif
 
 
@@ -483,7 +487,8 @@ struct sock *sk_alloc(int family, int priority, int zero_it)
        struct sock *sk = kmem_cache_alloc(sk_cachep, priority);
 
        if(sk) {
-               if (zero_it) memset(sk, 0, sizeof(struct sock));
+               if (zero_it) 
+                       memset(sk, 0, sizeof(struct sock));
                sk->family = family;
        }
 
@@ -498,7 +503,7 @@ void sk_free(struct sock *sk)
        kmem_cache_free(sk_cachep, sk);
 }
 
-__initfunc(void sk_init(void))
+void __init sk_init(void)
 {
        sk_cachep = kmem_cache_create("sock", sizeof(struct sock), 0,
                                      SLAB_HWCACHE_ALIGN, 0, 0);
@@ -508,35 +513,34 @@ __initfunc(void sk_init(void))
 /*
  *     Simple resource managers for sockets.
  */
+
+
+/* 
+ * Write buffer destructor automatically called from kfree_skb. 
+ */
 void sock_wfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
-#if 1
-       if (!sk) {
-               printk(KERN_DEBUG "sock_wfree: sk==NULL\n");
-               return;
-       }
-#endif
+
        /* In case it might be waiting for more memory. */
        atomic_sub(skb->truesize, &sk->wmem_alloc);
        sk->write_space(sk);
 }
 
-
+/* 
+ * Read buffer destructor automatically called from kfree_skb. 
+ */
 void sock_rfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
-#if 1
-       if (!sk) {
-               printk(KERN_DEBUG "sock_rfree: sk==NULL\n");
-               return;
-       }
-#endif
+
        atomic_sub(skb->truesize, &sk->rmem_alloc);
 }
 
 
+/*
+ * Allocate a skb from the socket's send buffer.
+ */
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
        if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) {
@@ -551,6 +555,9 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int
        return NULL;
 }
 
+/*
+ * Allocate a skb from the socket's receive buffer.
+ */ 
 struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
 {
        if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) {
@@ -565,6 +572,9 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
        return NULL;
 }
 
+/* 
+ * Allocate a memory block from the socket's option memory buffer.
+ */ 
 void *sock_kmalloc(struct sock *sk, int size, int priority)
 {
        if (atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) {
@@ -581,6 +591,9 @@ void *sock_kmalloc(struct sock *sk, int size, int priority)
        return NULL;
 }
 
+/*
+ * Free an option memory block.
+ */
 void sock_kfree_s(struct sock *sk, void *mem, int size)
 {
        kfree_s(mem, size); 
@@ -813,7 +826,7 @@ void sklist_destroy_socket(struct sock **list,struct sock *sk)
                 *      Someone is using our buffers still.. defer
                 */
                init_timer(&sk->timer);
-               sk->timer.expires=jiffies+sysctl_core_destroy_delay;
+               sk->timer.expires=jiffies+SOCK_DESTROY_TIME;
                sk->timer.function=sklist_destroy_timer;
                sk->timer.data = (unsigned long)sk;
                add_timer(&sk->timer);
@@ -944,13 +957,22 @@ int sock_no_recvmsg(struct socket *sock, struct msghdr *m, int flags,
  *     Default Socket Callbacks
  */
 
-void sock_def_callback1(struct sock *sk)
+void sock_def_wakeup(struct sock *sk)
 {
        if(!sk->dead)
                wake_up_interruptible(sk->sleep);
 }
 
-void sock_def_callback2(struct sock *sk, int len)
+void sock_def_error_report(struct sock *sk)
+{
+       if (!sk->dead) 
+       {
+               wake_up_interruptible(sk->sleep);
+               sock_wake_async(sk->socket,0); 
+       }
+}
+
+void sock_def_readable(struct sock *sk, int len)
 {
        if(!sk->dead)
        {
@@ -1000,10 +1022,10 @@ void sock_init_data(struct socket *sock, struct sock *sk)
                sock->sk        =       sk;
        }
 
-       sk->state_change        =       sock_def_callback1;
-       sk->data_ready          =       sock_def_callback2;
+       sk->state_change        =       sock_def_wakeup;
+       sk->data_ready          =       sock_def_readable;
        sk->write_space         =       sock_def_write_space;
-       sk->error_report        =       sock_def_callback1;
+       sk->error_report        =       sock_def_error_report;
        sk->destruct            =       sock_def_destruct;
 
        sk->peercred.pid        =       0;
index 47c85d0067219237959390c80ef8cce3d29f7395..aedd1a2a7e90e85bd32cdd1b196fce1661bc62aa 100644 (file)
@@ -37,9 +37,6 @@ ctl_table core_table[] = {
        {NET_CORE_RMEM_DEFAULT, "rmem_default",
         &sysctl_rmem_default, sizeof(int), 0644, NULL,
         &proc_dointvec},
-       {NET_CORE_DESTROY_DELAY, "destroy_delay",
-        &sysctl_core_destroy_delay, sizeof(int), 0644, NULL,
-        &proc_dointvec_jiffies},
        {NET_CORE_MAX_BACKLOG, "netdev_max_backlog",
         &netdev_max_backlog, sizeof(int), 0644, NULL,
         &proc_dointvec},
index bda79e29e0927003320607a03e13cb35ef50a1fe..06f4e308bc15199e362944d51fc9a6b95cc1deab 100644 (file)
@@ -42,8 +42,11 @@ if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
     bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
     comment 'Protocol-specific masquerading support will be built as modules.'
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
-      tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+      bool 'IP: masquerading special modules support' CONFIG_IP_MASQUERADE_MOD 
+      if [ "$CONFIG_IP_MASQUERADE_MOD" = "y" ]; then
+        tristate 'IP: ipautofw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
+        tristate 'IP: ipportfw masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPPORTFW
+      fi
     fi
   fi
 fi
index 2a519f346ce2830b9c9f9187a78900e0efbedce7..ad2a0a65061c4ec75e342b1677c34d19ae0d6e57 100644 (file)
@@ -60,24 +60,30 @@ else
 endif
 
 ifeq ($(CONFIG_IP_MASQUERADE),y)
-IPV4X_OBJS += ip_masq.o ip_masq_mod.o ip_masq_app.o 
-
-ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y)
-IPV4_OBJS += ip_masq_autofw.o
-else
-  ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m)
-  M_OBJS += ip_masq_autofw.o
+IPV4X_OBJS += ip_masq.o ip_masq_app.o 
+
+ifeq ($(CONFIG_IP_MASQUERADE_MOD),y)
+  IPV4X_OBJS += ip_masq_mod.o 
+  
+  ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),y)
+  IPV4_OBJS += ip_masq_autofw.o
+  else
+    ifeq ($(CONFIG_IP_MASQUERADE_IPAUTOFW),m)
+    M_OBJS += ip_masq_autofw.o
+    endif
   endif
-endif
-
-ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y)
-IPV4_OBJS += ip_masq_portfw.o
-else
-  ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m)
-  M_OBJS += ip_masq_portfw.o
+  
+  ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),y)
+  IPV4_OBJS += ip_masq_portfw.o
+  else
+    ifeq ($(CONFIG_IP_MASQUERADE_IPPORTFW),m)
+    M_OBJS += ip_masq_portfw.o
+    endif
   endif
+  
 endif
 
+M_OBJS += ip_masq_user.o
 M_OBJS += ip_masq_ftp.o ip_masq_irc.o ip_masq_raudio.o ip_masq_quake.o
 M_OBJS += ip_masq_vdolive.o ip_masq_cuseeme.o
 endif
index 8282333dcd4b8a79b4387735152674dc4093244b..9d0f3341451a490695d5bfbdfd13add0a72229d6 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             PF_INET protocol family socket handler.
  *
- * Version:    $Id: af_inet.c,v 1.75 1998/08/26 12:03:15 davem Exp $
+ * Version:    $Id: af_inet.c,v 1.79 1998/10/04 06:51:08 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 
 struct linux_mib net_statistics;
 
-extern int sysctl_core_destroy_delay;
-
 extern int raw_get_info(char *, char **, off_t, int, int);
 extern int snmp_get_info(char *, char **, off_t, int, int);
 extern int netstat_get_info(char *, char **, off_t, int, int);
@@ -198,7 +196,7 @@ static __inline__ void kill_sk_later(struct sock *sk)
        sk->destroy = 1;
        sk->ack_backlog = 0;
        release_sock(sk);
-       net_reset_timer(sk, TIME_DESTROY, sysctl_core_destroy_delay);
+       net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
 }
 
 void destroy_sock(struct sock *sk)
@@ -643,33 +641,20 @@ int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
        if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) 
                return (-EINPROGRESS);
 
-#if 1
        if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
                inet_wait_for_connect(sk);
                if (signal_pending(current))
                        return -ERESTARTSYS;
        }
-#else
-       cli();
-       while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
-               interruptible_sleep_on(sk->sleep);
-               if (signal_pending(current)) {
-                       sti();
-                       return(-ERESTARTSYS);
-               }
-               /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
-                  icmp error packets wanting to close a tcp or udp socket. */
-               if (sk->err && sk->protocol == IPPROTO_TCP) {
-                       sock->state = SS_UNCONNECTED;
-                       sti();
-                       return sock_error(sk); /* set by tcp_err() */
-               }
-       }
-       sti();
-#endif
 
        sock->state = SS_CONNECTED;
        if ((sk->state != TCP_ESTABLISHED) && sk->err) {
+               /* This is ugly but needed to fix a race in the ICMP error handler */
+               if (sk->protocol == IPPROTO_TCP && sk->zapped) { 
+                       lock_sock(sk);  
+                       tcp_set_state(sk, TCP_CLOSE);
+                       release_sock(sk); 
+               }
                sock->state = SS_UNCONNECTED;
                return sock_error(sk);
        }
@@ -716,13 +701,6 @@ int inet_accept(struct socket *sock, struct socket *newsock, int flags)
        if (flags & O_NONBLOCK)
                goto do_half_success;
 
-       cli();
-       while (sk2->state == TCP_SYN_RECV) {
-               interruptible_sleep_on(sk2->sleep);
-               if (signal_pending(current))
-                       goto do_interrupted;
-       }
-       sti();
        if(sk2->state == TCP_ESTABLISHED)
                goto do_full_success;
        if(sk2->err > 0)
@@ -749,18 +727,9 @@ do_bad_connection:
        newsk->socket = newsock;
        return err;
 
-do_interrupted:
-       sti();
-       sk1->pair = sk2;
-       sk2->sleep = NULL;
-       sk2->socket = NULL;
-       newsock->sk = newsk;
-       newsk->socket = newsock;
-       err = -ERESTARTSYS;
-do_err:
-       return err;
 do_sk1_err:
        err = sock_error(sk1);
+do_err:
        return err;
 }
 
@@ -805,8 +774,6 @@ int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size,
                return(-EINVAL);
        if (sk->prot->recvmsg == NULL) 
                return(-EOPNOTSUPP);
-       if (sk->err)
-               return sock_error(sk);
        /* We may need to bind the socket. */
        if (inet_autobind(sk) != 0)
                return(-EAGAIN);
index 618d247bda4d97b09205e6f9429471ab23317a53..5232c618ce018c364d3cdd66ab1d98a7df7f7a7b 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 FIB: lookup engine and maintenance routines.
  *
- * Version:    $Id: fib_hash.c,v 1.5 1998/08/26 12:03:27 davem Exp $
+ * Version:    $Id: fib_hash.c,v 1.6 1998/10/03 09:37:06 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -43,9 +43,9 @@
 #include <net/sock.h>
 #include <net/ip_fib.h>
 
-#define FTprint(a...) 
+#define FTprint(a...)
 /*
-printk(KERN_DEBUG a)
+   printk(KERN_DEBUG a)
  */
 
 /*
@@ -140,6 +140,11 @@ extern __inline__ int fn_key_eq(fn_key_t a, fn_key_t b)
        return a.datum == b.datum;
 }
 
+extern __inline__ int fn_key_leq(fn_key_t a, fn_key_t b)
+{
+       return a.datum <= b.datum;
+}
+
 #define FZ_MAX_DIVISOR 1024
 
 #ifdef CONFIG_IP_ROUTE_LARGE_TABLES
@@ -154,9 +159,11 @@ static __inline__ void fn_rebuild_zone(struct fn_zone *fz,
        for (i=0; i<old_divisor; i++) {
                for (f=old_ht[i]; f; f=next) {
                        next = f->fn_next;
-                       f->fn_next = NULL;
-                       for (fp = fz_chain_p(f->fn_key, fz); *fp; fp = &(*fp)->fn_next)
+                       for (fp = fz_chain_p(f->fn_key, fz);
+                            *fp && fn_key_leq((*fp)->fn_key, f->fn_key);
+                            fp = &(*fp)->fn_next)
                                /* NONE */;
+                       f->fn_next = *fp;
                        *fp = f;
                }
        }
@@ -199,7 +206,6 @@ static void fn_rehash_zone(struct fn_zone *fz)
                fn_rebuild_zone(fz, old_ht, old_divisor);
                end_bh_atomic();
                kfree(old_ht);
-FTprint("REHASHED ZONE: order %d mask %08x hash %d/%08x\n", fz->fz_order, fz->fz_mask, fz->fz_divisor, fz->fz_hashmask);
        }
 }
 #endif /* CONFIG_IP_ROUTE_LARGE_TABLES */
@@ -240,7 +246,6 @@ fn_new_zone(struct fn_hash *table, int z)
        for (i=z+1; i<=32; i++)
                if (table->fn_zones[i])
                        break;
-       start_bh_atomic();
        if (i>32) {
                /* No more specific masks, we are the first. */
                fz->fz_next = table->fn_zone_list;
@@ -250,8 +255,6 @@ fn_new_zone(struct fn_hash *table, int z)
                table->fn_zones[i]->fz_next = fz;
        }
        table->fn_zones[z] = fz;
-       end_bh_atomic();
-FTprint("NEW ZONE: order %d mask %08x hash %d/%08x\n", fz->fz_order, fz->fz_mask, fz->fz_divisor, fz->fz_hashmask);
        return fz;
 }
 
@@ -265,19 +268,18 @@ fn_hash_lookup(struct fib_table *tb, const struct rt_key *key, struct fib_result
        for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
                struct fib_node *f;
                fn_key_t k = fz_key(key->dst, fz);
-               int matched = 0;
 
                for (f = fz_chain(k, fz); f; f = f->fn_next) {
-                       if (!fn_key_eq(k, f->fn_key)
-#ifdef CONFIG_IP_ROUTE_TOS
-                           || (f->fn_tos && f->fn_tos != key->tos)
-#endif
-                           ) {
-                               if (matched)
+                       if (!fn_key_eq(k, f->fn_key)) {
+                               if (fn_key_leq(k, f->fn_key))
                                        break;
-                               continue;
+                               else
+                                       continue;
                        }
-                       matched = 1;
+#ifdef CONFIG_IP_ROUTE_TOS
+                       if (f->fn_tos && f->fn_tos != key->tos)
+                               continue;
+#endif
                        f->fn_state |= FN_S_ACCESSED;
 
                        if (f->fn_state&FN_S_ZOMBIE)
@@ -306,11 +308,14 @@ for ( ; ((f) = *(fp)) != NULL; (fp) = &(f)->fn_next)
 #define FIB_SCAN_KEY(f, fp, key) \
 for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)); (fp) = &(f)->fn_next)
 
-#define FIB_CONTINUE(f, fp) \
-{ \
-       fp = &f->fn_next; \
-       continue; \
-}
+#ifndef CONFIG_IP_ROUTE_TOS
+#define FIB_SCAN_TOS(f, fp, key, tos) FIB_SCAN_KEY(f, fp, key)
+#else
+#define FIB_SCAN_TOS(f, fp, key, tos) \
+for ( ; ((f) = *(fp)) != NULL && fn_key_eq((f)->fn_key, (key)) && \
+     (f)->fn_tos == (tos) ; (fp) = &(f)->fn_next)
+#endif
+
 
 #ifdef CONFIG_RTNETLINK
 static void rtmsg_fib(int, struct fib_node*, int, int,
@@ -326,7 +331,7 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                struct nlmsghdr *n, struct netlink_skb_parms *req)
 {
        struct fn_hash *table = (struct fn_hash*)tb->tb_data;
-       struct fib_node *new_f, *f, **fp;
+       struct fib_node *new_f, *f, **fp, **del_fp;
        struct fn_zone *fz;
        struct fib_info *fi;
 
@@ -336,7 +341,6 @@ fn_hash_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
        u8 tos = r->rtm_tos;
 #endif
        fn_key_t key;
-       unsigned state = 0;
        int err;
 
 FTprint("tb(%d)_insert: %d %08x/%d %d %08x\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
@@ -357,10 +361,8 @@ rta->rta_prefsrc ? *(u32*)rta->rta_prefsrc : 0);
                key = fz_key(dst, fz);
        }
 
-       if  ((fi = fib_create_info(r, rta, n, &err)) == NULL) {
-FTprint("fib_create_info err=%d\n", err);
+       if  ((fi = fib_create_info(r, rta, n, &err)) == NULL)
                return err;
-       }
 
 #ifdef CONFIG_IP_ROUTE_LARGE_TABLES
        if (fz->fz_nent > (fz->fz_divisor<<2) &&
@@ -375,7 +377,7 @@ FTprint("fib_create_info err=%d\n", err);
         * Scan list to find the first route with the same destination
         */
        FIB_SCAN(f, fp) {
-               if (fn_key_eq(f->fn_key,key))
+               if (fn_key_leq(key,f->fn_key))
                        break;
        }
 
@@ -389,70 +391,75 @@ FTprint("fib_create_info err=%d\n", err);
        }
 #endif
 
-       if (f && fn_key_eq(f->fn_key, key)
+       del_fp = NULL;
+
+       if (f && (f->fn_state&FN_S_ZOMBIE) &&
 #ifdef CONFIG_IP_ROUTE_TOS
-           && f->fn_tos == tos
+           f->fn_tos == tos &&
 #endif
-           ) {
+           fn_key_eq(f->fn_key, key)) {
+               del_fp = fp;
+               fp = &f->fn_next;
+               f = *fp;
+               goto create;
+       }
+
+       FIB_SCAN_TOS(f, fp, key, tos) {
+               if (fi->fib_priority <= FIB_INFO(f)->fib_priority)
+                       break;
+       }
+
+       /* Now f==*fp points to the first node with the same
+          keys [prefix,tos,priority], if such key already
+          exists or to the node, before which we will insert new one.
+        */
+
+       if (f && 
+#ifdef CONFIG_IP_ROUTE_TOS
+           f->fn_tos == tos &&
+#endif
+           fn_key_eq(f->fn_key, key) &&
+           fi->fib_priority == FIB_INFO(f)->fib_priority) {
                struct fib_node **ins_fp;
 
-               state = f->fn_state;
-               if (n->nlmsg_flags&NLM_F_EXCL && !(state&FN_S_ZOMBIE))
-                       return -EEXIST;
+               err = -EEXIST;
+               if (n->nlmsg_flags&NLM_F_EXCL)
+                       goto out;
+
                if (n->nlmsg_flags&NLM_F_REPLACE) {
-                       struct fib_info *old_fi = FIB_INFO(f);
-                       if (old_fi != fi) {
-                               rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
-                               start_bh_atomic();
-                               FIB_INFO(f) = fi;
-                               f->fn_type = r->rtm_type;
-                               f->fn_scope = r->rtm_scope;
-                               end_bh_atomic();
-                               rtmsg_fib(RTM_NEWROUTE, f, z, tb->tb_id, n, req);
-                       }
-                       state = f->fn_state;
-                       f->fn_state = 0;
-                       fib_release_info(old_fi);
-                       if (state&FN_S_ACCESSED)
-                               rt_cache_flush(-1);
-                       return 0;
+                       del_fp = fp;
+                       fp = &f->fn_next;
+                       f = *fp;
+                       goto replace;
                }
 
                ins_fp = fp;
+               err = -EEXIST;
 
-               for ( ; (f = *fp) != NULL && fn_key_eq(f->fn_key, key)
-#ifdef CONFIG_IP_ROUTE_TOS
-                    && f->fn_tos == tos
-#endif
-                    ; fp = &f->fn_next) {
-                       state |= f->fn_state;
+               FIB_SCAN_TOS(f, fp, key, tos) {
+                       if (fi->fib_priority != FIB_INFO(f)->fib_priority)
+                               break;
                        if (f->fn_type == type && f->fn_scope == r->rtm_scope
-                           && FIB_INFO(f) == fi) {
-                               fib_release_info(fi);
-                               if (f->fn_state&FN_S_ZOMBIE) {
-                                       f->fn_state = 0;
-                                       rtmsg_fib(RTM_NEWROUTE, f, z, tb->tb_id, n, req);
-                                       if (state&FN_S_ACCESSED)
-                                               rt_cache_flush(-1);
-                                       return 0;
-                               }
-                               return -EEXIST;
-                       }
+                           && FIB_INFO(f) == fi)
+                               goto out;
                }
+
                if (!(n->nlmsg_flags&NLM_F_APPEND)) {
                        fp = ins_fp;
                        f = *fp;
                }
-       } else {
-               if (!(n->nlmsg_flags&NLM_F_CREATE))
-                       return -ENOENT;
        }
 
+create:
+       err = -ENOENT;
+       if (!(n->nlmsg_flags&NLM_F_CREATE))
+               goto out;
+
+replace:
+       err = -ENOBUFS;
        new_f = (struct fib_node *) kmalloc(sizeof(struct fib_node), GFP_KERNEL);
-       if (new_f == NULL) {
-               fib_release_info(fi);
-               return -ENOBUFS;
-       }
+       if (new_f == NULL)
+               goto out;
 
        memset(new_f, 0, sizeof(struct fib_node));
 
@@ -473,9 +480,25 @@ FTprint("fib_create_info err=%d\n", err);
        *fp = new_f;
        fz->fz_nent++;
 
+       if (del_fp) {
+               f = *del_fp;
+               /* Unlink replaced node */
+               *del_fp = f->fn_next;
+               if (!(f->fn_state&FN_S_ZOMBIE))
+                       rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
+               if (f->fn_state&FN_S_ACCESSED)
+                       rt_cache_flush(-1);
+               fn_free_node(f);
+               fz->fz_nent--;
+       } else {
+               rt_cache_flush(-1);
+       }
        rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);
-       rt_cache_flush(-1);
        return 0;
+
+out:
+       fib_release_info(fi);
+       return err;
 }
 
 
@@ -484,10 +507,11 @@ fn_hash_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
                struct nlmsghdr *n, struct netlink_skb_parms *req)
 {
        struct fn_hash *table = (struct fn_hash*)tb->tb_data;
-       struct fib_node **fp, *f;
+       struct fib_node **fp, **del_fp, *f;
        int z = r->rtm_dst_len;
        struct fn_zone *fz;
        fn_key_t key;
+       int matched;
 #ifdef CONFIG_IP_ROUTE_TOS
        u8 tos = r->rtm_tos;
 #endif
@@ -513,6 +537,8 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
        FIB_SCAN(f, fp) {
                if (fn_key_eq(f->fn_key, key))
                        break;
+               if (fn_key_leq(key, f->fn_key))
+                       return -ESRCH;
        }
 #ifdef CONFIG_IP_ROUTE_TOS
        FIB_SCAN_KEY(f, fp, key) {
@@ -521,40 +547,47 @@ FTprint("tb(%d)_delete: %d %08x/%d %d\n", tb->tb_id, r->rtm_type, rta->rta_dst ?
        }
 #endif
 
-       while ((f = *fp) != NULL && fn_key_eq(f->fn_key, key)
-#ifdef CONFIG_IP_ROUTE_TOS
-              && f->fn_tos == tos
-#endif
-              ) {
+       matched = 0;
+       del_fp = NULL;
+       FIB_SCAN_TOS(f, fp, key, tos) {
                struct fib_info * fi = FIB_INFO(f);
 
-               if ((f->fn_state&FN_S_ZOMBIE) ||
-                   (r->rtm_type && f->fn_type != r->rtm_type) ||
-                   (r->rtm_scope && f->fn_scope != r->rtm_scope) ||
-                   (r->rtm_protocol && fi->fib_protocol != r->rtm_protocol) ||
-                   fib_nh_match(r, n, rta, fi))
-                       FIB_CONTINUE(f, fp);
-               break;
+               if (f->fn_state&FN_S_ZOMBIE)
+                       return -ESRCH;
+
+               matched++;
+
+               if (del_fp == NULL &&
+                   (!r->rtm_type || f->fn_type == r->rtm_type) &&
+                   (r->rtm_scope == RT_SCOPE_NOWHERE || f->fn_scope == r->rtm_scope) &&
+                   (!r->rtm_protocol || fi->fib_protocol == r->rtm_protocol) &&
+                   fib_nh_match(r, n, rta, fi) == 0)
+                       del_fp = fp;
        }
-       if (!f)
-               return -ESRCH;
-#if 0
-       *fp = f->fn_next;
-       rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
-       fn_free_node(f);
-       fz->fz_nent--;
-       rt_cache_flush(0);
-#else
-       f->fn_state |= FN_S_ZOMBIE;
-       rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
-       if (f->fn_state&FN_S_ACCESSED) {
-               f->fn_state &= ~FN_S_ACCESSED;
-               rt_cache_flush(-1);
+
+       if (del_fp) {
+               f = *del_fp;
+               rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
+
+               if (matched != 1) {
+                       *del_fp = f->fn_next;
+                       if (f->fn_state&FN_S_ACCESSED)
+                               rt_cache_flush(-1);
+                       fn_free_node(f);
+                       fz->fz_nent--;
+               } else {
+                       f->fn_state |= FN_S_ZOMBIE;
+                       if (f->fn_state&FN_S_ACCESSED) {
+                               f->fn_state &= ~FN_S_ACCESSED;
+                               rt_cache_flush(-1);
+                       }
+                       if (++fib_hash_zombies > 128)
+                               fib_flush();
+               }
+
+               return 0;
        }
-       if (++fib_hash_zombies > 128)
-               fib_flush();
-#endif
-       return 0;
+       return -ESRCH;
 }
 
 extern __inline__ int
index 2302f53227ef69115713a251d76815c8fc029b8c..70fa5d8435bceea2616cfce3de7c27f4406f5257 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 Forwarding Information Base: policy rules.
  *
- * Version:    $Id: fib_rules.c,v 1.6 1998/08/26 12:03:30 davem Exp $
+ * Version:    $Id: fib_rules.c,v 1.7 1998/10/03 09:37:09 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -13,6 +13,9 @@
  *             modify it under the terms of the GNU General Public License
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ *             Rani Assaf      :       local_rule cannot be deleted
  */
 
 #include <linux/config.h>
@@ -89,8 +92,10 @@ int inet_rtm_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
                    (!rta[RTA_PRIORITY-1] || memcmp(RTA_DATA(rta[RTA_PRIORITY-1]), &r->r_preference, 4) == 0) &&
                    (!rta[RTA_IIF-1] || strcmp(RTA_DATA(rta[RTA_IIF-1]), r->r_ifname) == 0) &&
                    (!rtm->rtm_table || (r && rtm->rtm_table == r->r_table))) {
+                       if (r == &local_rule)
+                               return -EPERM;
                        *rp = r->r_next;
-                       if (r != &default_rule && r != &main_rule && r != &local_rule)
+                       if (r != &default_rule && r != &main_rule)
                                kfree(r);
                        return 0;
                }
index 36c801e8c3a06afac61fd067dbb41740b8010b9d..c77ecc25170e23bb1142df3993db5cec5176d57f 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             IPv4 Forwarding Information Base: semantics.
  *
- * Version:    $Id: fib_semantics.c,v 1.10 1998/08/26 12:03:32 davem Exp $
+ * Version:    $Id: fib_semantics.c,v 1.11 1998/10/03 09:37:12 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -141,6 +141,7 @@ extern __inline__ struct fib_info * fib_find_info(const struct fib_info *nfi)
                        continue;
                if (nfi->fib_protocol == fi->fib_protocol &&
                    nfi->fib_prefsrc == fi->fib_prefsrc &&
+                   nfi->fib_priority == fi->fib_priority &&
                    nfi->fib_mtu == fi->fib_mtu &&
                    nfi->fib_rtt == fi->fib_rtt &&
                    nfi->fib_window == fi->fib_window &&
@@ -231,6 +232,10 @@ int fib_nh_match(struct rtmsg *r, struct nlmsghdr *nlh, struct kern_rta *rta,
        int nhlen;
 #endif
 
+       if (rta->rta_priority &&
+           *rta->rta_priority != fi->fib_priority)
+               return 1;
+
        if (rta->rta_oif || rta->rta_gw) {
                if ((!rta->rta_oif || *rta->rta_oif == fi->fib_nh->nh_oif) &&
                    (!rta->rta_gw  || memcmp(rta->rta_gw, &fi->fib_nh->nh_gw, 4) == 0))
@@ -405,6 +410,8 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
        fi->fib_protocol = r->rtm_protocol;
        fi->fib_nhs = nhs;
        fi->fib_flags = r->rtm_flags;
+       if (rta->rta_priority)
+               fi->fib_priority = *rta->rta_priority;
        if (rta->rta_mx) {
                int attrlen = RTA_PAYLOAD(rta->rta_mx);
                struct rtattr *attr = RTA_DATA(rta->rta_mx);
@@ -484,34 +491,20 @@ fib_create_info(const struct rtmsg *r, struct kern_rta *rta,
                        goto failure;
        } else {
                change_nexthops(fi) {
-                       if ((err = fib_check_nh(r, fi, nh)) != 0) {
-                               if (err == -EINVAL)
-                                       printk("Einval 2\n");
+                       if ((err = fib_check_nh(r, fi, nh)) != 0)
                                goto failure;
-                       }
                } endfor_nexthops(fi)
        }
 
        if (fi->fib_prefsrc) {
                if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||
                    memcmp(&fi->fib_prefsrc, rta->rta_dst, 4))
-                       if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) {
-                               printk("Einval 3\n");
+                       if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
                                goto err_inval;
-                       }
        }
 
 link_it:
        if ((ofi = fib_find_info(fi)) != NULL) {
-               if (fi->fib_nh[0].nh_scope != ofi->fib_nh[0].nh_scope) {
-                       printk("nh %d/%d gw=%08x/%08x dev=%s/%s\n",
-                              fi->fib_nh[0].nh_scope,
-                              ofi->fib_nh[0].nh_scope,
-                              fi->fib_nh[0].nh_gw,
-                              ofi->fib_nh[0].nh_gw,
-                              fi->fib_nh[0].nh_dev->name,
-                              ofi->fib_nh[0].nh_dev->name);
-               }
                kfree(fi);
                ofi->fib_refcnt++;
                return ofi;
@@ -613,6 +606,8 @@ fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
        if (rtm->rtm_dst_len)
                RTA_PUT(skb, RTA_DST, 4, dst);
        rtm->rtm_protocol = fi->fib_protocol;
+       if (fi->fib_priority)
+               RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);
 #ifdef CONFIG_NET_CLS_ROUTE
        if (fi->fib_nh[0].nh_tclassid)
                RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid);
@@ -720,12 +715,16 @@ fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
        rtm->rtm_dst_len = plen;
        rta->rta_dst = ptr;
 
+       if (r->rt_metric) {
+               *(u32*)&r->rt_pad3 = r->rt_metric - 1;
+               rta->rta_priority = (u32*)&r->rt_pad3;
+       }
        if (r->rt_flags&RTF_REJECT) {
                rtm->rtm_scope = RT_SCOPE_HOST;
                rtm->rtm_type = RTN_UNREACHABLE;
                return 0;
        }
-       rtm->rtm_scope = RT_SCOPE_LINK;
+       rtm->rtm_scope = RT_SCOPE_NOWHERE;
        rtm->rtm_type = RTN_UNICAST;
 
        if (r->rt_dev) {
@@ -735,7 +734,7 @@ fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
                struct device *dev;
                char   devname[IFNAMSIZ];
 
-               if (copy_from_user(devname, r->rt_dev, 15))
+               if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))
                        return -EFAULT;
                devname[IFNAMSIZ-1] = 0;
 #ifdef CONFIG_IP_ALIAS
@@ -777,6 +776,9 @@ fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,
        if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)
                return -EINVAL;
 
+       if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
+               rtm->rtm_scope = RT_SCOPE_LINK;
+
        if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {
                struct rtattr *rec;
                struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);
@@ -974,7 +976,7 @@ void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32
        if (fi) {
                len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
                              fi->fib_dev ? fi->fib_dev->name : "*", prefix,
-                             fi->fib_nh->nh_gw, flags, 0, 0, 0,
+                             fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
                              mask, fi->fib_mtu, fi->fib_window, fi->fib_rtt);
        } else {
                len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
index 9cc7c733ba6b9edb3e6a062f390bd37ad9ce6a16..eae3cf16a7624f86209a8819b7efd0410f083e59 100644 (file)
@@ -3,7 +3,7 @@
  *     
  *             Alan Cox, <alan@cymru.net>
  *
- *     Version: $Id: icmp.c,v 1.45 1998/08/26 12:03:35 davem Exp $
+ *     Version: $Id: icmp.c,v 1.46 1998/10/03 09:37:15 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
  *                                     - IP option length was accounted wrongly
  *                                     - ICMP header length was not accounted at all.
  *
+ * To Fix:
+ *
+ *     - Should use skb_pull() instead of all the manual checking.
+ *       This would also greatly simply some upper layer error handlers. --AK
+ *
  * RFC1122 (Host Requirements -- Comm. Layer) Status:
  * (boy, are there a lot of rules for ICMP)
  *  3.2.2 (Generic ICMP stuff)
@@ -708,12 +713,10 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
        hash = iph->protocol & (MAX_INET_PROTOS - 1);
        if ((raw_sk = raw_v4_htable[hash]) != NULL) 
        {
-               raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex);
-               while (raw_sk) 
-               {
+               while ((raw_sk = raw_v4_lookup(raw_sk, iph->protocol, iph->saddr,
+                                              iph->daddr, skb->dev->ifindex)) != NULL) {
                        raw_err(raw_sk, skb);
-                       raw_sk = raw_v4_lookup(raw_sk->next, iph->protocol,
-                                              iph->saddr, iph->daddr, skb->dev->ifindex);
+                       raw_sk = raw_sk->next;
                }
        }
 
@@ -1072,8 +1075,7 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
 /* TIME EXCEEDED (11) */
  { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time },
 /* PARAMETER PROBLEM (12) */
-/* FIXME: RFC1122 3.2.2.5 - MUST pass PARAM_PROB messages to transport layer */
- { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1, &sysctl_icmp_paramprob_time },
+ { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time },
 /* TIMESTAMP (13) */
  { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0,  },
 /* TIMESTAMP REPLY (14) */
index 8cd0d5962fc548a938f6a38457c9ed773e014c64..b617bc343269fe867c0bbdefa1eb0f666c810b56 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP forwarding functionality.
  *             
- * Version:    $Id: ip_forward.c,v 1.41 1998/08/26 12:03:42 davem Exp $
+ * Version:    $Id: ip_forward.c,v 1.42 1998/10/03 09:37:19 davem Exp $
  *
  * Authors:    see ip.c
  *
@@ -103,8 +103,8 @@ int ip_forward(struct sk_buff *skb)
 #endif
 
 
-#ifdef CONFIG_TRANSPARENT_PROXY
-       if (ip_chk_sock(skb))
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+       if (ip_chksock(skb))
                 goto local_pkt;
 #endif
 
@@ -271,7 +271,7 @@ skip_call_fw_firewall:
        ip_send(skb);
        return 0;
 
-#ifdef CONFIG_TRANSPARENT_PROXY
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
 local_pkt:
        return ip_local_deliver(skb);
 #endif
index b45457c72f445a109f31bd718c7fac3c8bbd4071..ddf38a3a8fb22a90cb9eee02818e15b4c37538f7 100644 (file)
@@ -245,7 +245,7 @@ struct ip_chain
 #endif
 
 /* Lock around ip_fw_chains linked list structure */
-spinlock_t ip_fw_lock = SPIN_LOCK_UNLOCKED;
+rwlock_t ip_fw_lock = RW_LOCK_UNLOCKED;
 
 /* Head of linked list of fw rules */
 static struct ip_chain *ip_fw_chains; 
@@ -531,18 +531,19 @@ ip_fw_domatch(struct ip_fwkernel *f,
 #ifdef CONFIG_IP_FIREWALL_NETLINK
        if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {
                size_t len = min(f->ipfw.fw_outputsize, ntohs(ip->tot_len)) 
-                       + sizeof(skb->fwmark) + IFNAMSIZ;
+                       + sizeof(__u32) + sizeof(skb->fwmark) + IFNAMSIZ;
                struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC);
 
                duprintf("Sending packet out NETLINK (length = %u).\n", 
                         (unsigned int)len);
                if (outskb) {
-                       /* Prepend mark & interface */
+                       /* Prepend length, mark & interface */
                        skb_put(outskb, len);
-                       *((__u32 *)outskb->data) = skb->fwmark;
-                       strcpy(outskb->data+sizeof(__u32), rif);
-                       memcpy(outskb->data+sizeof(__u32)+IFNAMSIZ, ip, 
-                              len-(sizeof(__u32)+IFNAMSIZ));
+                       *((__u32 *)outskb->data) = (__u32)len;
+                       *((__u32 *)(outskb->data+sizeof(__u32))) = skb->fwmark;
+                       strcpy(outskb->data+sizeof(__u32)*2, rif);
+                       memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip, 
+                              len-(sizeof(__u32)*2+IFNAMSIZ));
                        netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);
                }
                else duprintf("netlink post failed - alloc_skb failed!\n");
@@ -1324,28 +1325,7 @@ int ip_fw_ctl(int cmd, void *m, int len)
 
        case IP_FW_MASQ_TIMEOUTS: {
 #ifdef CONFIG_IP_MASQUERADE
-               struct ip_fw_masq *masq;
-
-               if (len != sizeof(struct ip_fw_masq)) {
-                       duprintf("ip_fw_ctl (masq): length %d, expected %d\n",
-                               len, sizeof(struct ip_fw_masq));
-                       ret = EINVAL;
-               }
-               else {
-                       masq = (struct ip_fw_masq *)m;
-                       if (masq->tcp_timeout)
-                               ip_masq_expire->tcp_timeout 
-                                       = masq->tcp_timeout;
-
-                       if (masq->tcp_fin_timeout)
-                               ip_masq_expire->tcp_fin_timeout 
-                                       = masq->tcp_fin_timeout;
-
-                       if (masq->udp_timeout)
-                               ip_masq_expire->udp_timeout 
-                                       = masq->udp_timeout;
-                       ret = 0;
-               }
+               return ip_fw_masq_timeouts(m, len);
 #else
                ret = EINVAL;
 #endif
index 6a2e4eca5415129dd57f71ec804239441b1268e2..6488e9d7072c9d4f7353e3d0cb3e866c329176b4 100644 (file)
@@ -826,6 +826,10 @@ ipgre_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
 
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                err = -EFAULT;
                if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                        goto done;
@@ -859,6 +863,10 @@ ipgre_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
                break;
 
        case SIOCDELTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                if (dev == &ipgre_fb_tunnel_dev) {
                        err = -EFAULT;
                        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
index e06ad82068f00437f62f1ddc42faa77aedb91b16..260d178f1b21d4d01236d511df9b97c7f0d67f10 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) module.
  *
- * Version:    $Id: ip_input.c,v 1.33 1998/08/26 12:03:47 davem Exp $
+ * Version:    $Id: ip_input.c,v 1.34 1998/10/03 09:37:23 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -503,6 +503,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
         {
                int fwres;
                u16 rport;
+               u8  tos = iph->tos;
 
                if ((fwres=call_in_firewall(PF_INET, skb->dev, iph, &rport, &skb))<FW_ACCEPT) {
                        if (fwres==FW_REJECT)
@@ -513,6 +514,18 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
                if (fwres==FW_REDIRECT && (IPCB(skb)->redirport = rport) != 0)
                        return ip_local_deliver(skb);
+#endif
+#ifdef CONFIG_IP_ROUTE_TOS
+               /* It is for 2.2 only. Firewalling should make smart
+                  rerouting itself, ideally, but now it is too late
+                  to teach it.                         --ANK (980905)
+                */
+               if (iph->tos != tos && ((struct rtable*)skb->dst)->rt_type == RTN_UNICAST) {
+                       dst_release(skb->dst);
+                       skb->dst = NULL;
+                       if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
+                               goto drop; 
+               }
 #endif
        }
 #endif
index 2a609358351e12677db38b7c3e1765a580e57811..4058cf3f7f5e6660b53e8bebd8fe3f14a500f441 100644 (file)
@@ -4,7 +4,7 @@
  *
  *     Copyright (c) 1994 Pauline Middelink
  *
- * Version:    @(#)ip_masq.c  0.12      97/11/30
+ *     $Id: ip_masq.c,v 1.26 1998/09/24 03:38:58 davem Exp $
  *
  *
  *     See ip_fw.c for original log
  *     Steven Clarke           :       IP_MASQ_S_xx state design
  *     Juan Jose Ciarlante     :       IP_MASQ_S state implementation 
  *     Juan Jose Ciarlante     :       xx_get() clears timer, _put() inserts it
+ *     Juan Jose Ciarlante     :       create /proc/net/ip_masq/ 
+ *     Juan Jose Ciarlante     :       reworked checksums (save payload csum if possible)
+ *     Juan Jose Ciarlante     :       added missing ip_fw_masquerade checksum
+ *     Juan Jose Ciarlante     :       csum savings
+ *     Juan Jose Ciarlante     :       added user-space tunnel creation/del, etc
+ *     Juan Jose Ciarlante     :       (last) moved to ip_masq_user runtime module
+ *     Juan Jose Ciarlante     :       user timeout handling again
+ *     Juan Jose Ciarlante     :       make new modules support optional
+ *     Juan Jose Ciarlante     :       u-space context => locks reworked
+ *     Juan Jose Ciarlante     :       fixed stupid SMP locking bug
+ *     Juan Jose Ciarlante     :       fixed "tap"ing in demasq path by copy-on-w
  *     
- *
  */
 
 #include <linux/config.h>
 #include <linux/module.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <net/udp.h>
 #include <net/checksum.h>
 #include <net/ip_masq.h>
-#include <net/ip_masq_mod.h>
-#include <linux/sysctl.h>
-#include <linux/ip_fw.h>
 
-#ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
-#include <net/ip_autofw.h>
-#endif
-#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
-#include <net/ip_portfw.h>
+#ifdef CONFIG_IP_MASQUERADE_MOD
+#include <net/ip_masq_mod.h>
 #endif
 
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
 
 int sysctl_ip_masq_debug = 0;
 
@@ -77,6 +87,8 @@ int ip_masq_get_debug_level(void)
        return sysctl_ip_masq_debug;
 }
 
+struct ip_masq_hook *ip_masq_user_hook = NULL;
+
 /*
  *     Timeout table[state]
  */
@@ -98,7 +110,7 @@ static struct ip_masq_timeout_table masq_timeout_table = {
                5*60*HZ,        /*      IP_MASQ_S_UDP,  */
                1*60*HZ,        /*      IP_MASQ_S_ICMP, */
                2*HZ,/* IP_MASQ_S_LAST  */
-       },
+       },      /* timeout */
 };
 
 #define MASQUERADE_EXPIRE_RETRY      masq_timeout_table.timeout[IP_MASQ_S_TIME_WAIT]
@@ -134,7 +146,7 @@ struct masq_tcp_states_t {
        int next_state[IP_MASQ_S_LAST]; /* should be _LAST_TCP */
 };
 
-static const char * masq_state_name(int state)
+const char * ip_masq_state_name(int state)
 {
        if (state >= IP_MASQ_S_LAST)
                return "ERR!";
@@ -224,8 +236,8 @@ tcp_state_out:
                                th->rst? 'R' : '.',
                                ntohl(ms->saddr), ntohs(ms->sport),
                                ntohl(ms->daddr), ntohs(ms->dport),
-                               masq_state_name(ms->state),
-                               masq_state_name(new_state));
+                               ip_masq_state_name(ms->state),
+                               ip_masq_state_name(new_state));
        return masq_set_state_timeout(ms, new_state);
 }
 
@@ -235,20 +247,19 @@ tcp_state_out:
  */
 static int masq_set_state(struct ip_masq *ms, int output, struct iphdr *iph, void *tp)
 {
-       struct tcphdr   *th = tp;
        switch (iph->protocol) {
                case IPPROTO_ICMP:
                        return masq_set_state_timeout(ms, IP_MASQ_S_ICMP);
                case IPPROTO_UDP:
                        return masq_set_state_timeout(ms, IP_MASQ_S_UDP);
                case IPPROTO_TCP:
-                       return masq_tcp_state(ms, output, th);
+                       return masq_tcp_state(ms, output, tp);
        }
        return -1;
 }
 
 /*
- *     Moves tunnel to listen state
+ *     Set LISTEN timeout. (ip_masq_put will setup timer)
  */
 int ip_masq_listen(struct ip_masq *ms)
 {
@@ -256,8 +267,6 @@ int ip_masq_listen(struct ip_masq *ms)
        return ms->timeout;
 }
 
-#define IP_MASQ_TAB_SIZE 256    /* must be power of 2 */
-
 /* 
  *     Dynamic address rewriting 
  */
@@ -266,9 +275,7 @@ extern int sysctl_ip_dynaddr;
 /*
  *     Lookup lock
  */
-static struct wait_queue *masq_wait;
-atomic_t __ip_masq_lock = ATOMIC_INIT(0);
-
+rwlock_t __ip_masq_lock = RW_LOCK_UNLOCKED;
 
 /*
  *     Implement IP packet masquerading
@@ -305,6 +312,9 @@ static __inline__ const __u8 icmp_type_request(__u8 type)
  *     Will cycle in MASQ_PORT boundaries.
  */
 static __u16 masq_port = PORT_MASQ_BEGIN;
+#ifdef __SMP__
+static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 /*
  *     free ports counters (UDP & TCP)
@@ -333,20 +343,26 @@ atomic_t ip_masq_free_ports[3] = {
         ATOMIC_INIT((PORT_MASQ_END-PORT_MASQ_BEGIN) * PORT_MASQ_MUL),/* ICMP */
 };
 
+/*
+ *     Counts entries that have been requested with specific mport.
+ *     Used for incoming packets to "relax" input rule (port in MASQ range).
+ */
+atomic_t mport_count = ATOMIC_INIT(0);
+
 EXPORT_SYMBOL(ip_masq_get_debug_level);
 EXPORT_SYMBOL(ip_masq_new);
 EXPORT_SYMBOL(ip_masq_listen);
-/*
-EXPORT_SYMBOL(ip_masq_set_expire);
-*/
 EXPORT_SYMBOL(ip_masq_free_ports);
-EXPORT_SYMBOL(ip_masq_expire);
 EXPORT_SYMBOL(ip_masq_out_get);
 EXPORT_SYMBOL(ip_masq_in_get);
 EXPORT_SYMBOL(ip_masq_put);
 EXPORT_SYMBOL(ip_masq_control_add);
 EXPORT_SYMBOL(ip_masq_control_del);
 EXPORT_SYMBOL(ip_masq_control_get);
+EXPORT_SYMBOL(ip_masq_user_hook);
+EXPORT_SYMBOL(ip_masq_m_tab);
+EXPORT_SYMBOL(ip_masq_state_name);
+EXPORT_SYMBOL(ip_masq_select_addr);
 EXPORT_SYMBOL(__ip_masq_lock);
 
 /*
@@ -360,13 +376,16 @@ struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE];
  * timeouts
  */
 
+#if 000 /* FIXED timeout handling */
 static struct ip_fw_masq ip_masq_dummy = {
        MASQUERADE_EXPIRE_TCP,
        MASQUERADE_EXPIRE_TCP_FIN,
        MASQUERADE_EXPIRE_UDP
 };
 
+EXPORT_SYMBOL(ip_masq_expire);
 struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
+#endif
 
 
 /*
@@ -375,7 +394,7 @@ struct ip_fw_masq *ip_masq_expire = &ip_masq_dummy;
  *     Warning: it does not check/delete previous timer!
  */
 
-void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
+static void __ip_masq_set_expire(struct ip_masq *ms, unsigned long tout)
 {
         if (tout) {
                 ms->timer.expires = jiffies+tout;
@@ -398,7 +417,7 @@ ip_masq_hash_key(unsigned proto, __u32 addr, __u16 port)
 
 /*
  *     Hashes ip_masq by its proto,addrs,ports.
- *     should be called with masked interrupts.
+ *     should be called with locked tables.
  *     returns bool success.
  */
 
@@ -434,7 +453,7 @@ static int ip_masq_hash(struct ip_masq *ms)
 
 /*
  *     UNhashes ip_masq from ip_masq_[ms]_tables.
- *     should be called with masked interrupts.
+ *     should be called with locked tables.
  *     returns bool success.
  */
 
@@ -488,16 +507,18 @@ static int ip_masq_unhash(struct ip_masq *ms)
  *     phoenix and get a reply from any other interface(==dst)!
  *
  *     [Only for UDP] - AC
+ *     
+ *     Caller must lock tables
  */
 
-struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+static struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
 {
         unsigned hash;
         struct ip_masq *ms = NULL;
 
-       ip_masq_lock(&__ip_masq_lock, 0);
-
         hash = ip_masq_hash_key(protocol, d_addr, d_port);
+
+
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
                if (protocol==ms->protocol &&
                    ((s_addr==ms->daddr || ms->flags & IP_MASQ_F_NO_DADDR)) &&
@@ -521,7 +542,6 @@ struct ip_masq * __ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u3
               d_port);
 
 out:
-       ip_masq_unlock(&__ip_masq_lock, 0);
         return ms;
 }
 
@@ -537,9 +557,11 @@ out:
  *     hash is keyed on source port so if the first lookup fails then try again
  *     with a zero port, this time only looking at entries marked "no source
  *     port".
+ *     
+ *     Caller must lock tables
  */
 
-struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+static struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
 {
         unsigned hash;
         struct ip_masq *ms = NULL;
@@ -549,8 +571,6 @@ struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u
         */
         hash = ip_masq_hash_key(protocol, s_addr, s_port);
        
-       ip_masq_lock(&__ip_masq_lock, 0);
-
         for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
                if (protocol == ms->protocol &&
                    s_addr == ms->saddr && s_port == ms->sport &&
@@ -596,7 +616,6 @@ struct ip_masq * __ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u
               d_port);
 
 out:
-       ip_masq_unlock(&__ip_masq_lock, 0);
         return ms;
 }
 
@@ -604,6 +623,8 @@ out:
 /*
  *     Returns ip_masq for given proto,m_addr,m_port.
  *      called by allocation routine to find an unused m_port.
+ *     
+ *     Caller must lock tables
  */
 
 static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)
@@ -613,8 +634,6 @@ static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_por
 
         hash = ip_masq_hash_key(protocol, m_addr, m_port);
 
-       ip_masq_lock(&__ip_masq_lock, 0);
-
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
                if ( protocol==ms->protocol &&
                     (m_addr==ms->maddr && m_port==ms->mport)) {
@@ -624,7 +643,6 @@ static struct ip_masq * __ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_por
         }
 
 out:
-       ip_masq_unlock(&__ip_masq_lock, 0);
         return ms;
 }
 #endif
@@ -632,7 +650,11 @@ out:
 struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) 
 {
        struct ip_masq *ms;
+
+       read_lock(&__ip_masq_lock);
        ms = __ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port);
+       read_unlock(&__ip_masq_lock);
+
        if (ms)
                __ip_masq_set_expire(ms, 0);
        return ms;
@@ -641,7 +663,11 @@ struct ip_masq * ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32
 struct ip_masq * ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
 {
        struct ip_masq *ms;
+
+       read_lock(&__ip_masq_lock);
        ms =  __ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port);
+       read_unlock(&__ip_masq_lock);
+
        if (ms)
                __ip_masq_set_expire(ms, 0);
        return ms;
@@ -685,8 +711,9 @@ static void masq_expire(unsigned long data)
                        masq_proto_name(ms->protocol),
                        ntohl(ms->saddr),ntohs(ms->sport));
 
-       ip_masq_lock(&__ip_masq_lock, 1);
+       write_lock(&__ip_masq_lock);
 
+#if 0000
        /*
         *      Already locked, do bounce ...
         */
@@ -694,6 +721,7 @@ static void masq_expire(unsigned long data)
                goto masq_expire_later;
        }
 
+#endif
        /*
         *      do I control anybody?
         */
@@ -708,8 +736,11 @@ static void masq_expire(unsigned long data)
                ip_masq_control_del(ms);
 
         if (ip_masq_unhash(ms)) {
-               if (!(ms->flags&IP_MASQ_F_MPORT))
+               if (ms->flags&IP_MASQ_F_MPORT) {
+                       atomic_dec(&mport_count);
+               } else {
                        atomic_inc(ip_masq_free_ports + masq_proto_num(ms->protocol));
+               }
                ip_masq_unbind_app(ms);
         }
 
@@ -718,28 +749,45 @@ static void masq_expire(unsigned long data)
         */
        if (atomic_read(&ms->refcnt) == 1) {
                kfree_s(ms,sizeof(*ms));
+               MOD_DEC_USE_COUNT;
                goto masq_expire_out;
        }
 
 masq_expire_later:
-       IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X nlocks-1=%d masq.refcnt-1=%d masq.n_control=%d\n",
+       IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X masq.refcnt-1=%d masq.n_control=%d\n",
                masq_proto_name(ms->protocol),
                ntohl(ms->saddr), ntohs(ms->sport),
                ntohl(ms->daddr), ntohs(ms->dport),
-               ip_masq_nlocks(&__ip_masq_lock)-1,
                atomic_read(&ms->refcnt)-1,
                atomic_read(&ms->n_control));
 
        ip_masq_put(ms);
 
 masq_expire_out:
-       ip_masq_unlock(&__ip_masq_lock, 1);
+       write_unlock(&__ip_masq_lock);
+}
+
+static __u16 get_next_mport(void)
+{
+       __u16 mport;
+       
+       spin_lock_irq(&masq_port_lock);
+       /*
+        *      Try the next available port number
+        */
+       mport = htons(masq_port++);
+       if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
+
+       spin_unlock_irq(&masq_port_lock);
+       return mport;
 }
 
 /*
  *     Create a new masquerade list entry, also allocate an
  *     unused mport, keeping the portnumber between the
  *     given boundaries MASQ_BEGIN and MASQ_END.
+ *
+ *     Be careful, it can be called from u-space
  */
 
 struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)
@@ -748,6 +796,7 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
         int ports_tried;
        atomic_t *free_ports_p = NULL;
         static int n_fails = 0;
+       int prio;
 
 
        if (masq_proto_num(proto)!=-1 && mport == 0) {
@@ -760,13 +809,17 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                        return NULL;
                }
        }
-        ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC);
+
+       prio = (mflags&IP_MASQ_F_USER) ? GFP_KERNEL : GFP_ATOMIC;
+
+        ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), prio);
         if (ms == NULL) {
                 if (++n_fails < 5)
                         IP_MASQ_ERR("ip_masq_new(proto=%s): no memory available.\n",
                                masq_proto_name(proto));
                 return NULL;
         }
+       MOD_INC_USE_COUNT;
         memset(ms, 0, sizeof(*ms));
        init_timer(&ms->timer);
        ms->timer.data     = (unsigned long)ms;
@@ -805,22 +858,33 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                /* 
                 *      Check 5-upla uniqueness
                 */
-               ip_masq_lock(&__ip_masq_lock, 1);
+               if (mflags & IP_MASQ_F_USER)    
+                       write_lock_bh(&__ip_masq_lock);
+               else 
+                       write_lock(&__ip_masq_lock);
 
                 mst = __ip_masq_in_get(proto, daddr, dport, maddr, mport);
                if (mst==NULL) {
                        ms->flags |= IP_MASQ_F_MPORT;
 
+                       atomic_inc(&mport_count);
                         ip_masq_hash(ms);
-                       ip_masq_unlock(&__ip_masq_lock, 1);
+
+                       if (mflags & IP_MASQ_F_USER)    
+                               write_unlock_bh(&__ip_masq_lock);
+                       else 
+                               write_unlock(&__ip_masq_lock);
 
                        ip_masq_bind_app(ms);
                        atomic_inc(&ms->refcnt);
                        masq_set_state_timeout(ms, IP_MASQ_S_NONE);
                        return ms;
                }
+               if (mflags & IP_MASQ_F_USER)    
+                       write_unlock_bh(&__ip_masq_lock);
+               else 
+                       write_unlock(&__ip_masq_lock);
 
-               ip_masq_unlock(&__ip_masq_lock, 1);
                __ip_masq_put(mst);
 
                IP_MASQ_ERR( "Already used connection: %s, %d.%d.%d.%d:%d => %d.%d.%d.%d:%d, called from %p\n",
@@ -838,20 +902,15 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
             (atomic_read(free_ports_p) && (ports_tried <= (PORT_MASQ_END - PORT_MASQ_BEGIN)));
             ports_tried++){
 
-               cli();
-               /*
-                *      Try the next available port number
-                */
-               mport = ms->mport = htons(masq_port++);
-               if (masq_port==PORT_MASQ_END) masq_port = PORT_MASQ_BEGIN;
-
-               sti();
-
+               mport = ms->mport = get_next_mport();
                /*
                 *      lookup to find out if this connection is used.
                 */
 
-               ip_masq_lock(&__ip_masq_lock, 1);
+               if (mflags & IP_MASQ_F_USER) 
+                       write_lock_bh(&__ip_masq_lock);
+               else
+                       write_lock(&__ip_masq_lock);
 
 #ifdef CONFIG_IP_MASQUERADE_NREUSE
                mst = __ip_masq_getbym(proto, maddr, mport);
@@ -861,12 +920,20 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                if (mst == NULL) {
 
                        if (atomic_read(free_ports_p) == 0) {
-                               ip_masq_unlock(&__ip_masq_lock, 1);
+                               if (mflags & IP_MASQ_F_USER) 
+                                       write_unlock_bh(&__ip_masq_lock);
+                               else
+                                       write_unlock(&__ip_masq_lock);
+
                                break;
                        }
                        atomic_dec(free_ports_p);
                        ip_masq_hash(ms);
-                       ip_masq_unlock(&__ip_masq_lock, 1);
+
+                       if (mflags & IP_MASQ_F_USER) 
+                               write_unlock_bh(&__ip_masq_lock);
+                       else
+                               write_unlock(&__ip_masq_lock);
 
                        ip_masq_bind_app(ms);
                        n_fails = 0;
@@ -874,7 +941,11 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                        masq_set_state_timeout(ms, IP_MASQ_S_NONE);
                        return ms;
                }
-               ip_masq_unlock(&__ip_masq_lock, 1);
+               if (mflags & IP_MASQ_F_USER) 
+                       write_unlock_bh(&__ip_masq_lock);
+               else
+                       write_unlock(&__ip_masq_lock);
+
                __ip_masq_put(mst);
         }
 
@@ -884,48 +955,97 @@ struct ip_masq * ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, _
                       atomic_read(free_ports_p));
 mport_nono:
         kfree_s(ms, sizeof(*ms));
+
+       MOD_DEC_USE_COUNT;
         return NULL;
 }
 
-static void recalc_check(struct udphdr *uh, __u32 saddr,
-       __u32 daddr, int len)
+static __inline__ unsigned proto_doff(unsigned proto, char *th)
 {
-       uh->check=0;
-       uh->check=csum_tcpudp_magic(saddr,daddr,len,
-               IPPROTO_UDP, csum_partial((char *)uh,len,0));
-       if(uh->check==0)
-               uh->check=0xFFFF;
+       switch (proto) {
+               case IPPROTO_UDP:
+                       return sizeof(struct udphdr);
+               case IPPROTO_TCP:
+                       return ((struct tcphdr*)th)->doff << 2;
+       }
+       return 0;
 }
 
-int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
+int ip_fw_masquerade(struct sk_buff **skb_p, __u32 maddr)
 {
-       struct sk_buff  *skb=*skb_ptr;
+       struct sk_buff  *skb = *skb_p;
        struct iphdr    *iph = skb->nh.iph;
-       __u16   *portptr;
+       union ip_masq_tphdr h;
        struct ip_masq  *ms;
        int             size;
 
+       /* 
+        *      Magic "doff" csum semantics
+        *              !0: saved payload csum IS valid, doff is correct
+        *              0: csum not valid
+        */
+       unsigned doff = 0;
+       int csum = 0;
+
        /*
-        * We can only masquerade protocols with ports...
-        * [TODO]
-        * We may need to consider masq-ing some ICMP related to masq-ed protocols
+        * We can only masquerade protocols with ports... and hack some ICMPs
         */
 
-        if (iph->protocol==IPPROTO_ICMP) 
-            return (ip_fw_masq_icmp(skb_ptr, maddr));
+       h.raw = (char*) iph + iph->ihl * 4;
 
-       if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
-               return -1;
+       switch (iph->protocol) {
+       case IPPROTO_ICMP:
+               return(ip_fw_masq_icmp(skb_p, maddr));
+       case IPPROTO_UDP:
+               if (h.uh->check == 0)
+                       /* No UDP checksum */
+                       break;
+       case IPPROTO_TCP:
+               /* Make sure packet is in the masq range */
+               size = ntohs(iph->tot_len) - (iph->ihl * 4);
+               IP_MASQ_DEBUG(3, "O-pkt: %s size=%d\n",
+                               masq_proto_name(iph->protocol),
+                               size);
 
+               /* Check that the checksum is OK */
+               switch (skb->ip_summed)
+               {
+                       case CHECKSUM_NONE:
+                               doff = proto_doff(iph->protocol, h.raw);
+                               csum = csum_partial(h.raw + doff, size - doff, 0);
+                               IP_MASQ_DEBUG(3, "O-pkt: %s I-datacsum=%d\n",
+                                               masq_proto_name(iph->protocol),
+                                               csum);
+
+                               skb->csum = csum_partial(h.raw , doff, csum);
+
+                       case CHECKSUM_HW:
+                               if (csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                               size, iph->protocol, skb->csum))
+                               {
+                                       IP_MASQ_DEBUG(0, "Outgoing failed %s checksum from %d.%d.%d.%d (size=%d)!\n",
+                                              masq_proto_name(iph->protocol),
+                                              NIPQUAD(iph->saddr),
+                                              size);
+                                       return -1;
+                               }
+                       default:
+                               /* CHECKSUM_UNNECESSARY */
+               }
+               break;
+       default:
+               return -1;
+       }
        /*
         *      Now hunt the list to see if we have an old entry
         */
 
-       portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+       /* h.raw = (char*) iph + iph->ihl * 4; */
+
        IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",
                masq_proto_name(iph->protocol),
-               ntohl(iph->saddr), ntohs(portptr[0]),
-               ntohl(iph->daddr), ntohs(portptr[1]));
+               ntohl(iph->saddr), ntohs(h.portp[0]),
+               ntohl(iph->daddr), ntohs(h.portp[1]));
 
         ms = ip_masq_out_get_iph(iph);
         if (ms!=NULL) {
@@ -942,13 +1062,13 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
                                        NIPQUAD(ms->maddr),NIPQUAD(maddr));
                         }
 
-                       ip_masq_lock(&__ip_masq_lock, 1);
+                       write_lock(&__ip_masq_lock);
 
                         ip_masq_unhash(ms);
                         ms->maddr = maddr;
                         ip_masq_hash(ms);
 
-                       ip_masq_unlock(&__ip_masq_lock, 1);
+                       write_unlock(&__ip_masq_lock);
                 }
                 
                /*
@@ -960,13 +1080,13 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
                if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
                        ms->flags &= ~IP_MASQ_F_NO_SPORT;
 
-                       ip_masq_lock(&__ip_masq_lock, 1);
+                       write_lock(&__ip_masq_lock);
                        
                        ip_masq_unhash(ms);
-                       ms->sport = portptr[0];
+                       ms->sport = h.portp[0];
                        ip_masq_hash(ms);       /* hash on new sport */
 
-                       ip_masq_unlock(&__ip_masq_lock, 1);
+                       write_unlock(&__ip_masq_lock);
                        
                        IP_MASQ_DEBUG(1, "ip_fw_masquerade(): filled sport=%d\n",
                               ntohs(ms->sport));
@@ -976,68 +1096,113 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, __u32 maddr)
                 *      Nope, not found, create a new entry for it
                 */
 
-               if (!(ms = ip_masq_mod_out_create(iph, portptr, maddr))) 
+#ifdef CONFIG_IP_MASQUERADE_MOD
+               if (!(ms = ip_masq_mod_out_create(skb, iph, maddr))) 
+#endif
                        ms = ip_masq_new(iph->protocol,
                                        maddr, 0,
-                                       iph->saddr, portptr[0],
-                                       iph->daddr, portptr[1],
+                                       iph->saddr, h.portp[0],
+                                       iph->daddr, h.portp[1],
                                        0);
                 if (ms == NULL)
                        return -1;
        }
 
-       ip_masq_mod_out_update(iph, portptr, ms);
+       /*
+        *      Call module's output update hook
+        */
+
+#ifdef CONFIG_IP_MASQUERADE_MOD
+       ip_masq_mod_out_update(skb, iph, ms);
+#endif
 
        /*
         *      Change the fragments origin
         */
 
-       size = skb->len - ((unsigned char *)portptr - skb->nh.raw);
+       size = skb->len - (h.raw - skb->nh.raw);
+
         /*
          *     Set iph addr and port from ip_masq obj.
          */
        iph->saddr = ms->maddr;
-       portptr[0] = ms->mport;
+       h.portp[0] = ms->mport;
+
+       /*
+        *      Invalidate csum saving if tunnel has masq helper
+        */
+
+       if (ms->app) 
+               doff = 0;
 
        /*
         *      Attempt ip_masq_app call.
          *     will fix ip_masq and iph seq stuff
         */
-        if (ip_masq_app_pkt_out(ms, skb_ptr, maddr) != 0)
+        if (ip_masq_app_pkt_out(ms, skb_p, maddr) != 0)
        {
                 /*
                  *     skb has possibly changed, update pointers.
                  */
-                skb = *skb_ptr;
+                skb = *skb_p;
                 iph = skb->nh.iph;
-                portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-                size = skb->len - ((unsigned char *)portptr-skb->nh.raw);
+               h.raw = (char*) iph + iph->ihl *4;
+                size = skb->len - (h.raw - skb->nh.raw);
         }
 
        /*
         *      Adjust packet accordingly to protocol
         */
 
-       if (iph->protocol == IPPROTO_UDP)
-       {
-               recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
-       } else {
-               struct tcphdr *th = (struct tcphdr *)portptr;
+       /*
+        *      Transport's payload partial csum
+        */
 
+       if (!doff) {
+               doff = proto_doff(iph->protocol, h.raw);
+               csum = csum_partial(h.raw + doff, size - doff, 0);
+       }
+       skb->csum = csum;
 
-               skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
-               th->check = 0;
-               th->check = tcp_v4_check(th, size, iph->saddr, iph->daddr,
-                                        csum_partial((char *)th, sizeof(*th),
-                                                     skb->csum));
-       }
+       IP_MASQ_DEBUG(3, "O-pkt: %s size=%d O-datacsum=%d\n",
+                       masq_proto_name(iph->protocol),
+                       size,
+                       csum);
+
+       /*
+        *      Protocol csum
+        */
+       switch (iph->protocol) {
+               case IPPROTO_TCP:
+                       h.th->check = 0;
+                       h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                       size, iph->protocol, 
+                                       csum_partial(h.raw , doff, csum));
+                       IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",
+                                       masq_proto_name(iph->protocol),
+                                       h.th->check,
+                                       (char*) & (h.th->check) - (char*) h.raw);
 
+                       break;
+               case IPPROTO_UDP:
+                       h.uh->check = 0;
+                       h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                       size, iph->protocol, 
+                                       csum_partial(h.raw , doff, csum));
+                       if (h.uh->check == 0) 
+                               h.uh->check = 0xFFFF;
+                       IP_MASQ_DEBUG(3, "O-pkt: %s O-csum=%d (+%d)\n",
+                                       masq_proto_name(iph->protocol),
+                                       h.uh->check,
+                                       (char*) &(h.uh->check)- (char*) h.raw);
+                       break;
+       }
        ip_send_check(iph);
 
        IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",
                ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
 
-       masq_set_state(ms, 1, iph, portptr);
+       masq_set_state(ms, 1, iph, h.portp);
        ip_masq_put(ms);
 
        return 0;
@@ -1106,13 +1271,13 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
                                       NIPQUAD(ms->maddr), NIPQUAD(maddr));
                        }
 
-                       ip_masq_lock(&__ip_masq_lock, 1);
+                       write_lock(&__ip_masq_lock);
                        
                         ip_masq_unhash(ms);
                         ms->maddr = maddr;
                         ip_masq_hash(ms);
 
-                       ip_masq_unlock(&__ip_masq_lock, 1);
+                       write_unlock(&__ip_masq_lock);
                 }
                 
                iph->saddr = ms->maddr;
@@ -1166,11 +1331,13 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
                       ntohs(icmp_id(cicmph)),
                       cicmph->type);
 
+               read_lock(&__ip_masq_lock);
                ms = __ip_masq_out_get(ciph->protocol, 
                                      ciph->daddr,
                                      icmp_id(cicmph),
                                      ciph->saddr,
                                      icmp_hv_rep(cicmph));
+               read_unlock(&__ip_masq_lock);
 
                if (ms == NULL)
                        return 0;
@@ -1239,11 +1406,13 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
        /* This is pretty much what __ip_masq_in_get_iph() does */
        ms = __ip_masq_in_get(ciph->protocol, ciph->saddr, pptr[0], ciph->daddr, pptr[1]);
 #endif
+       read_lock(&__ip_masq_lock);
        ms = __ip_masq_out_get(ciph->protocol,
                               ciph->daddr,
                               pptr[1],
                               ciph->saddr,
                               pptr[0]);
+       read_unlock(&__ip_masq_lock);
 
        if (ms == NULL)
                return 0;
@@ -1274,6 +1443,30 @@ int ip_fw_masq_icmp(struct sk_buff **skb_p, __u32 maddr)
        return 1;
 }
 
+
+/*
+ *     Own skb_cow() beast, tweaked for rewriting commonly
+ *     used pointers in masq code
+ */
+static struct sk_buff * masq_skb_cow(struct sk_buff **skb_p, 
+                       struct iphdr **iph_p, unsigned char **t_p) {
+       struct sk_buff *skb=(*skb_p);
+       if (skb_cloned(skb)) {
+               skb = skb_copy(skb, GFP_ATOMIC);
+               if (skb) {
+                       /*
+                        *      skb changed, update other pointers
+                        */
+                       struct iphdr *iph = skb->nh.iph;
+                       kfree_skb(*skb_p);
+                       *skb_p = skb;
+                       *iph_p = iph;
+                       *t_p = (char*) iph + iph->ihl * 4;
+               }
+       }
+       return skb;
+}
+
 /*
  *     Handle ICMP messages in reverse (demasquerade) direction.
  *     Find any that might be relevant, check against existing connections,
@@ -1323,6 +1516,11 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
                  */
                 ms->flags &= ~IP_MASQ_F_NO_REPLY;
 
+               if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+                       ip_masq_put(ms);
+                       return -1;
+               }
+
                /* Reset source address */
                iph->daddr = ms->saddr;
                /* Redo IP header checksum */
@@ -1378,15 +1576,23 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
                       ntohs(icmp_id(cicmph)),
                       cicmph->type);
 
+               read_lock(&__ip_masq_lock);
                ms = __ip_masq_in_get(ciph->protocol, 
                                      ciph->daddr, 
                                      icmp_hv_req(cicmph),
                                      ciph->saddr, 
                                      icmp_id(cicmph));
+               read_unlock(&__ip_masq_lock);
 
                if (ms == NULL)
                        return 0;
 
+               if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+                       __ip_masq_put(ms);
+                       return -1;
+               }
+               ciph = (struct iphdr *) (icmph + 1);
+
                /* Now we do real damage to this packet...! */
                /* First change the dest IP address, and recalc checksum */
                iph->daddr = ms->saddr;
@@ -1445,15 +1651,23 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
 
 
        /* This is pretty much what __ip_masq_in_get_iph() does, except params are wrong way round */
+       read_lock(&__ip_masq_lock);
        ms = __ip_masq_in_get(ciph->protocol,
                              ciph->daddr,
                              pptr[1],
                              ciph->saddr,
                              pptr[0]);
+       read_unlock(&__ip_masq_lock);
 
        if (ms == NULL)
                return 0;
 
+       if ((skb=masq_skb_cow(skb_p, &iph, (unsigned char**)&icmph)) == NULL) {
+               __ip_masq_put(ms);
+               return -1;
+       }
+       ciph = (struct iphdr *) (icmph + 1);
+
        /* Now we do real damage to this packet...! */
        /* First change the dest IP address, and recalc checksum */
        iph->daddr = ms->saddr;
@@ -1480,7 +1694,6 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
        return 1;
 }
 
-
  /*
   *    Check if it's an masqueraded port, look it up,
   *    and send it on its way...
@@ -1492,44 +1705,70 @@ int ip_fw_demasq_icmp(struct sk_buff **skb_p)
 
 int ip_fw_demasquerade(struct sk_buff **skb_p)
 {
-        struct sk_buff         *skb = *skb_p;
-       struct iphdr    *iph = skb->nh.iph;
-       __u16   *portptr;
-       struct ip_masq  *ms;
-       unsigned short len;
-
+       struct sk_buff  *skb = *skb_p;
+       struct iphdr    *iph = skb->nh.iph;
+       union ip_masq_tphdr h;
+       struct ip_masq  *ms;
+       unsigned short size;
+       unsigned doff = 0;
+       int csum = 0;
        __u32 maddr;
 
+       /*
+        *      Big tappo: only PACKET_HOST (nor loopback neither mcasts)
+        *      ... don't know why 1st test DOES NOT include 2nd (?)
+        */
+
+       if (skb->pkt_type != PACKET_HOST || skb->dev == &loopback_dev) {
+               IP_MASQ_DEBUG(2, "ip_fw_demasquerade(): packet type=%d proto=%d daddr=%d.%d.%d.%d ignored\n",
+                       skb->pkt_type,
+                       iph->protocol,
+                       NIPQUAD(iph->daddr));
+               return 0;
+       }
+
        maddr = iph->daddr;
+       h.raw = (char*) iph + iph->ihl * 4;
 
        switch (iph->protocol) {
        case IPPROTO_ICMP:
                return(ip_fw_demasq_icmp(skb_p));
        case IPPROTO_TCP:
        case IPPROTO_UDP:
-               /* Make sure packet is in the masq range */
-               portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-               if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN
-                               || ntohs(portptr[1]) > PORT_MASQ_END)
-                               && (ip_masq_mod_in_rule(iph, portptr) != 1))
+               /* 
+                *      Make sure packet is in the masq range 
+                *      ... or some mod-ule relaxes input range
+                *      ... or there is still some `special' mport opened
+                */
+               if ((ntohs(h.portp[1]) < PORT_MASQ_BEGIN
+                               || ntohs(h.portp[1]) > PORT_MASQ_END)
+#ifdef CONFIG_IP_MASQUERADE_MOD
+                               && (ip_masq_mod_in_rule(skb, iph) != 1) 
+#endif
+                               && atomic_read(&mport_count) == 0 )
                        return 0;
 
                /* Check that the checksum is OK */
-               len = ntohs(iph->tot_len) - (iph->ihl * 4);
-               if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
+               size = ntohs(iph->tot_len) - (iph->ihl * 4);
+               if ((iph->protocol == IPPROTO_UDP) && (h.uh->check == 0))
                        /* No UDP checksum */
                        break;
 
                switch (skb->ip_summed)
                {
                        case CHECKSUM_NONE:
-                               skb->csum = csum_partial((char *)portptr, len, 0);
+                               doff = proto_doff(iph->protocol, h.raw);
+                               csum = csum_partial(h.raw + doff, size - doff, 0);
+                               skb->csum = csum_partial(h.raw , doff, csum);
+
                        case CHECKSUM_HW:
-                               if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
-                                                     iph->protocol, skb->csum))
+                               if (csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                               size, iph->protocol, skb->csum))
                                {
-                                       IP_MASQ_DEBUG(2, "failed TCP/UDP checksum from %d.%d.%d.%d!\n",
-                                              NIPQUAD(iph->saddr));
+                                       IP_MASQ_DEBUG(0, "Incoming failed %s checksum from %d.%d.%d.%d (size=%d)!\n",
+                                              masq_proto_name(iph->protocol),
+                                              NIPQUAD(iph->saddr),
+                                              size);
                                        return -1;
                                }
                        default:
@@ -1544,8 +1783,8 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
 
        IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n",
                masq_proto_name(iph->protocol),
-               ntohl(iph->saddr), ntohs(portptr[0]),
-               ntohl(iph->daddr), ntohs(portptr[1]));
+               ntohl(iph->saddr), ntohs(h.portp[0]),
+               ntohl(iph->daddr), ntohs(h.portp[1]));
 
        /*
         * reroute to original host:port if found...
@@ -1553,10 +1792,19 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
 
         ms = ip_masq_in_get_iph(iph);
 
+       /*
+        *      Give additional modules a chance to create an entry
+        */
+#ifdef CONFIG_IP_MASQUERADE_MOD
        if (!ms) 
-               ms = ip_masq_mod_in_create(iph, portptr, maddr);
+               ms = ip_masq_mod_in_create(skb, iph, maddr);
+
+       /*
+        *      Call module's input update hook
+        */
+       ip_masq_mod_in_update(skb, iph, ms);
+#endif
 
-       ip_masq_mod_in_update(iph, portptr, ms);
 
         if (ms != NULL)
         {
@@ -1572,7 +1820,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
 
                 if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /*  && ms->protocol == IPPROTO_TCP ) { */
                         ms->flags &= ~IP_MASQ_F_NO_DPORT;
-                        ms->dport = portptr[0];
+                        ms->dport = h.portp[0];
 
                         IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n",
                                ntohs(ms->dport));
@@ -1582,12 +1830,23 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
                         ms->flags &= ~IP_MASQ_F_NO_DADDR;
                         ms->daddr = iph->saddr;
 
-                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%X\n",
-                               ntohs(ms->daddr));
+                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n",
+                               ntohl(ms->daddr));
 
                 }
+               if ((skb=masq_skb_cow(skb_p, &iph, &h.raw)) == NULL) {
+                       ip_masq_put(ms);
+                       return -1;
+               }
                 iph->daddr = ms->saddr;
-                portptr[1] = ms->sport;
+                h.portp[1] = ms->sport;
+
+               /*
+                *      Invalidate csum saving if tunnel has masq helper
+                */
+
+               if (ms->app) 
+                       doff = 0;
 
                 /*
                  *     Attempt ip_masq_app call.
@@ -1602,34 +1861,48 @@ int ip_fw_demasquerade(struct sk_buff **skb_p)
 
                         skb = *skb_p;
                         iph = skb->nh.iph;
-                        portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
-                        len = ntohs(iph->tot_len) - (iph->ihl * 4);
+                       h.raw = (char*) iph + iph->ihl*4;
+                        size = ntohs(iph->tot_len) - (iph->ihl * 4);
                 }
 
                 /*
-                 * Yug! adjust UDP/TCP and IP checksums, also update
-                * timeouts.
-                * If a TCP RST is seen collapse the tunnel (by using short timeout)!
-                 */
-                if (iph->protocol == IPPROTO_UDP) {
-                        recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
-               } else {
-                       struct tcphdr *th = (struct tcphdr *)portptr;
-                        skb->csum = csum_partial((void *)(th + 1),
-                                                 len - sizeof(struct tcphdr), 0);
+                 * Yug! adjust UDP/TCP checksums
+                */
 
-                       th->check = 0;
-                        th->check = tcp_v4_check(th, len, iph->saddr, iph->daddr,
-                                                csum_partial((char *)th,
-                                                             sizeof(*th),
-                                                             skb->csum));
+               /*
+                *      Transport's payload partial csum
+                */
 
-                }
+               if (!doff) {
+                       doff = proto_doff(iph->protocol, h.raw);
+                       csum = csum_partial(h.raw + doff, size - doff, 0);
+               }
+               skb->csum = csum;
+
+               /*
+                *      Protocol csum
+                */
+               switch (iph->protocol) {
+                       case IPPROTO_TCP:
+                               h.th->check = 0;
+                               h.th->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                               size, iph->protocol, 
+                                               csum_partial(h.raw , doff, csum));
+                               break;
+                       case IPPROTO_UDP:
+                               h.uh->check = 0;
+                               h.uh->check=csum_tcpudp_magic(iph->saddr, iph->daddr, 
+                                               size, iph->protocol, 
+                                               csum_partial(h.raw , doff, csum));
+                               if (h.uh->check == 0) 
+                                       h.uh->check = 0xFFFF;
+                               break;
+               }
                 ip_send_check(iph);
 
-                IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(portptr[1]));
+                IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1]));
 
-               masq_set_state (ms, 0, iph, portptr);
+               masq_set_state (ms, 0, iph, h.portp);
                ip_masq_put(ms);
 
                 return 1;
@@ -1683,6 +1956,7 @@ struct ip_masq * ip_masq_control_get(struct ip_masq *ms)
        return ms->control;
 }
 
+
 #ifdef CONFIG_PROC_FS
 /*
  *     /proc/net entries
@@ -1697,7 +1971,6 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
         int idx = 0;
        int len=0;
 
-       ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
 
        if (offset < 128)
        {
@@ -1710,12 +1983,21 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
        }
        pos = 128;
 
-        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) 
+       {
+       /*
+        *      Lock is actually only need in next loop 
+        *      we are called from uspace: must stop bh.
+        */
+       read_lock_bh(&__ip_masq_lock);
+
         for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
        {
                pos += 128;
-               if (pos <= offset)
+               if (pos <= offset) {
+                       len = 0;
                        continue;
+               }
 
                /*
                 *      We have locked the tables, no need to del/add timers
@@ -1733,12 +2015,17 @@ static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset,
                        ms->timer.expires-jiffies);
                len += sprintf(buffer+len, "%-127s\n", temp);
 
-               if(len >= length)
+               if(len >= length) {
+
+                       read_unlock_bh(&__ip_masq_lock);
                        goto done;
+               }
         }
+       read_unlock_bh(&__ip_masq_lock);
+
+       }
 done:
 
-       ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
 
        begin = len - (pos - offset);
        *start = buffer + begin;
@@ -1748,82 +2035,173 @@ done:
        return len;
 }
 
-static int ip_masq_procinfo(char *buffer, char **start, off_t offset,
-                             int length, int unused)
+#endif
+
+/* 
+ *     Timeouts handling by ipfwadm/ipchains
+ *     From ip_fw.c
+ */
+
+int ip_fw_masq_timeouts(void *m, int len) 
 {
-       off_t pos=0, begin;
-       struct ip_masq *ms;
-       char temp[129];
-        int idx = 0;
-       int len=0;
+       struct ip_fw_masq *masq;
+       int ret = EINVAL;
 
-       ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
+       if (len != sizeof(struct ip_fw_masq)) {
+               IP_MASQ_DEBUG(1, "ip_fw_masq_timeouts: length %d, expected %d\n",
+                               len, sizeof(struct ip_fw_masq));
+       } else {
+               masq = (struct ip_fw_masq *)m;
+               if (masq->tcp_timeout)
+                       masq_timeout_table.timeout[IP_MASQ_S_ESTABLISHED]
+                               = masq->tcp_timeout;
+
+               if (masq->tcp_fin_timeout)
+                       masq_timeout_table.timeout[IP_MASQ_S_FIN_WAIT]
+                               = masq->tcp_fin_timeout;
+
+               if (masq->udp_timeout)
+                       masq_timeout_table.timeout[IP_MASQ_S_UDP]
+                               = masq->udp_timeout;
+               ret = 0;
+       }
+       return ret;
+}
+/*
+ *     Module autoloading stuff
+ */
 
-       if (offset < 128)
-       {
-               sprintf(temp,
-                       "Prot SrcIP    SPrt DstIP    DPrt MAddr    MPrt State        Ref Ctl Expires (free=%d,%d,%d)",
-                       atomic_read(ip_masq_free_ports), 
-                       atomic_read(ip_masq_free_ports+1), 
-                       atomic_read(ip_masq_free_ports+2));
-               len = sprintf(buffer, "%-127s\n", temp);
+static int ip_masq_user_check_hook(void) {
+#ifdef CONFIG_KMOD
+       if (ip_masq_user_hook == NULL) {
+               IP_MASQ_DEBUG(1, "About to request \"ip_masq_user\" module\n");
+               request_module("ip_masq_user");
        }
-       pos = 128;
+#endif /* CONFIG_KMOD */
+       return (ip_masq_user_hook != NULL);
+}
 
-        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
-        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
-       {
-               pos += 128;
-               if (pos <= offset)
-                       continue;
+/*
+ *     user module hook- info
+ */
+static int ip_masq_user_info(char *buffer, char **start, off_t offset,
+                             int len, int *eof, void *data)
+{
+       int ret = -ENOPKG;
+       if (ip_masq_user_check_hook()) {
+               ret = ip_masq_user_hook->info(buffer, start, offset, len, (int) data);
+       }
+       return ret;
+}
 
-               /*
-                *      We have locked the tables, no need to del/add timers
-                *      nor cli()  8)
-                */
+/*
+ *     user module hook- entry mgmt
+ */
+static int ip_masq_user_ctl(int optname, void *arg, int arglen)
+{
+       int ret = -ENOPKG;
+       if (ip_masq_user_check_hook())  {
+               ret = ip_masq_user_hook->ctl(optname, arg, arglen);
+       }
+       return ret;
+}
 
-               sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3d %3d %7lu",
-                       masq_proto_name(ms->protocol),
-                       ntohl(ms->saddr), ntohs(ms->sport),
-                       ntohl(ms->daddr), ntohs(ms->dport),
-                       ntohl(ms->maddr), ntohs(ms->mport),
-                       masq_state_name(ms->state),
-                       atomic_read(&ms->refcnt),
-                       atomic_read(&ms->n_control),
-                       (ms->timer.expires-jiffies)/HZ);
-               len += sprintf(buffer+len, "%-127s\n", temp);
+/*
+ *     Control from ip_sockglue
+ *     MAIN ENTRY point from userspace (apart from /proc *info entries)
+ *     Returns errno
+ */
+int ip_masq_uctl(int optname, char * optval , int optlen)
+{
+       struct ip_masq_ctl masq_ctl;
+       int ret = -EINVAL;
 
-               if(len >= length)
-                       goto done;
-        }
-done:
+       if(optlen>sizeof(masq_ctl))
+               return -EINVAL;
 
-       ip_masq_unlockz(&__ip_masq_lock, &masq_wait, 0);
+       if(copy_from_user(&masq_ctl,optval,optlen))
+               return -EFAULT;
 
-       begin = len - (pos - offset);
-       *start = buffer + begin;
-       len -= begin;
-       if(len>length)
-               len = length;
-       return len;
+       IP_MASQ_DEBUG(1,"ip_masq_ctl(optname=%d, optlen=%d, target=%d, cmd=%d)\n",
+               optname, optlen, masq_ctl.m_target, masq_ctl.m_cmd);
+
+       switch (masq_ctl.m_target) {
+               case IP_MASQ_TARGET_USER:
+                       ret = ip_masq_user_ctl(optname, &masq_ctl, optlen);
+                       break;
+#ifdef CONFIG_IP_MASQUERADE_MOD
+               case IP_MASQ_TARGET_MOD:
+                       ret = ip_masq_mod_ctl(optname, &masq_ctl, optlen);
+                       break;
+#endif
+       }
+
+       /*      
+        *      If ret>0, copy to user space 
+        */
+
+       if (ret > 0 && ret <= sizeof (masq_ctl)) {
+               if (copy_to_user(optval, &masq_ctl, ret) )
+                       return -EFAULT;
+               ret = 0;
+       }
+
+       return ret;
 }
 
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry   *proc_net_ip_masq = NULL;
+
+#ifdef MODULE
+static void ip_masq_proc_count(struct inode *inode, int fill)
+{
+       if (fill)
+               MOD_INC_USE_COUNT;
+       else
+               MOD_DEC_USE_COUNT;
+}
 #endif
 
+int ip_masq_proc_register(struct proc_dir_entry *ent)
+{
+       if (!proc_net_ip_masq) return -1;
+       IP_MASQ_DEBUG(1, "registering \"/proc/net/ip_masq/%s\" entry\n",
+                       ent->name);
+       return proc_register(proc_net_ip_masq, ent);
+}
+void ip_masq_proc_unregister(struct proc_dir_entry *ent)
+{
+       if (!proc_net_ip_masq) return;
+       IP_MASQ_DEBUG(1, "unregistering \"/proc/net/ip_masq/%s\" entry\n",
+                       ent->name);
+       proc_unregister(proc_net_ip_masq, ent->low_ino);
+}
+
 /*
- *     Control from ip_sockglue
- *     From userspace
+ *     Wrapper over inet_select_addr()
  */
-int ip_masq_ctl(int optname, void *arg, int arglen)
+u32 ip_masq_select_addr(struct device *dev, u32 dst, int scope)
 {
-       struct ip_fw_masqctl *mctl = arg;
-       int ret = EINVAL;
-
-       if (1) /*  (mctl->mctl_action == IP_MASQ_MOD_CTL)  */
-               ret = ip_masq_mod_ctl(optname, mctl, arglen);
+       return inet_select_addr(dev, dst, scope);
+}
 
-       return ret;
+__initfunc(static void masq_proc_init(void))
+{      
+       IP_MASQ_DEBUG(1,"registering /proc/net/ip_masq\n");
+       if (!proc_net_ip_masq) {
+               struct proc_dir_entry *ent;
+               ent = create_proc_entry("net/ip_masq", S_IFDIR, 0);
+               if (ent) {
+#ifdef MODULE
+                       ent->fill_inode = ip_masq_proc_count;
+#endif
+                       proc_net_ip_masq = ent;
+                } else {
+                        IP_MASQ_ERR("Could not create \"/proc/net/ip_masq\" entry\n");
+                }
+       }
 }
+#endif /* CONFIG_PROC_FS */
 
 /*
  *     Initialize ip masquerading
@@ -1837,11 +2215,37 @@ __initfunc(int ip_masq_init(void))
                0, &proc_net_inode_operations,
                ip_msqhst_procinfo
        });
-       proc_net_register(&(struct proc_dir_entry) {
-               0, 7, "ip_masq",
+       masq_proc_init();
+
+       ip_masq_proc_register(&(struct proc_dir_entry) {
+               0, 3, "tcp",
+               S_IFREG | S_IRUGO, 1, 0, 0,
+               0, &proc_net_inode_operations,
+               NULL,   /* get_info */
+               NULL,   /* fill_inode */
+               NULL, NULL, NULL,
+               (char *) IPPROTO_TCP,
+               ip_masq_user_info
+       });
+       ip_masq_proc_register(&(struct proc_dir_entry) {
+               0, 3, "udp",
                S_IFREG | S_IRUGO, 1, 0, 0,
                0, &proc_net_inode_operations,
-               ip_masq_procinfo
+               NULL,   /* get_info */
+               NULL,   /* fill_inode */
+               NULL, NULL, NULL,
+               (char *) IPPROTO_UDP,
+               ip_masq_user_info
+       });
+       ip_masq_proc_register(&(struct proc_dir_entry) {
+               0, 4, "icmp",
+               S_IFREG | S_IRUGO, 1, 0, 0,
+               0, &proc_net_inode_operations,
+               NULL,   /* get_info */
+               NULL,   /* fill_inode */
+               NULL, NULL, NULL,
+               (char *) IPPROTO_ICMP,
+               ip_masq_user_info
        });
 #endif 
 #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW
@@ -1849,6 +2253,9 @@ __initfunc(int ip_masq_init(void))
 #endif
 #ifdef CONFIG_IP_MASQUERADE_IPPORTFW
        ip_portfw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPMARKFW
+       ip_markfw_init();
 #endif
         ip_masq_app_init();
 
index 7b4f9c844e483ed7315067902265662677846c2c..84e059fafc5f55c78db000f3dcb0a8d6e178600f 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_APP application masquerading module
  *
  *
- * Version:    @(#)ip_masq_app.c  0.04      96/06/17
+ *     $Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $
  *
  * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
@@ -474,7 +474,7 @@ done:
 
 #ifdef CONFIG_PROC_FS
 static struct proc_dir_entry proc_net_ip_masq_app = {
-       PROC_NET_IP_MASQ_APP, 11, "ip_masq_app",
+       PROC_NET_IP_MASQ_APP, 3, "app",
        S_IFREG | S_IRUGO, 1, 0, 0,
        0, &proc_net_inode_operations,
        ip_masq_app_getinfo
@@ -488,7 +488,7 @@ static struct proc_dir_entry proc_net_ip_masq_app = {
 __initfunc(int ip_masq_app_init(void))
 {
 #ifdef CONFIG_PROC_FS
-       proc_net_register(&proc_net_ip_masq_app);
+       ip_masq_proc_register(&proc_net_ip_masq_app);
 #endif
         return 0;
 }
index 27b98bb0327522694eca3577fe9c0484ad4e4575..d2a1729c5386a5ff4af8785d8d47620d55c77b0d 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_AUTOFW auto forwarding module
  *
  *
- * Version:    @(#)ip_masq_autofw.c  0.02      97/10/22
+ *     $Id: ip_masq_autofw.c,v 1.3 1998/08/29 23:51:10 davem Exp $
  *
  * Author:     Richard Lynch
  *
 #include <linux/ip_fw.h>
 #include <net/ip_masq.h>
 #include <net/ip_masq_mod.h>
-#include <net/ip_autofw.h>
+#include <linux/ip_masq.h>
+
+#define IP_AUTOFW_EXPIRE            15*HZ
+
+/* WARNING: bitwise equal to ip_autofw_user  in linux/ip_masq.h */
+struct ip_autofw {
+       struct ip_autofw * next;
+       __u16 type;
+       __u16 low;
+       __u16 hidden;
+       __u16 high;
+       __u16 visible;
+       __u16 protocol;
+       __u32 lastcontact;
+       __u32 where;
+       __u16 ctlproto;
+       __u16 ctlport;
+       __u16 flags;
+       struct timer_list timer;
+};
 
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
-
-MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
 MODULE_PARM(debug, "i");
+#endif
 
 /*
  *     Auto-forwarding table
@@ -156,11 +175,11 @@ static __inline__ void ip_autofw_expire(unsigned long data)
 
 
 
-static __inline__ int ip_autofw_add(struct ip_autofw * af)
+static __inline__ int ip_autofw_add(struct ip_autofw_user * af)
 {
        struct ip_autofw * newaf;
-       init_timer(&af->timer);
        newaf = kmalloc( sizeof(struct ip_autofw), GFP_KERNEL );
+       init_timer(&newaf->timer);
        if ( newaf == NULL ) 
        {
                printk("ip_autofw_add:  malloc said no\n");
@@ -169,7 +188,7 @@ static __inline__ int ip_autofw_add(struct ip_autofw * af)
 
        MOD_INC_USE_COUNT;
 
-       memcpy(newaf, af, sizeof(struct ip_autofw));
+       memcpy(newaf, af, sizeof(struct ip_autofw_user));
        newaf->timer.data = (unsigned long) newaf;
        newaf->timer.function = ip_autofw_expire;
        newaf->timer.expires = 0;
@@ -180,7 +199,7 @@ static __inline__ int ip_autofw_add(struct ip_autofw * af)
        return(0);
 }
 
-static __inline__ int ip_autofw_del(struct ip_autofw * af)
+static __inline__ int ip_autofw_del(struct ip_autofw_user * af)
 {
        struct ip_autofw ** af_p, *curr;
 
@@ -229,20 +248,21 @@ static __inline__ int ip_autofw_flush(void)
  *     Methods for registered object
  */
 
-static int autofw_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+static int autofw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 {
-       struct ip_autofw *af = (struct ip_autofw*) mctl->u.mod.data;
+       struct ip_autofw_user *af = &mctl->u.autofw_user;
 
-       switch (optname) {
-               case IP_FW_MASQ_ADD:
+       switch (mctl->m_cmd) {
+               case IP_MASQ_CMD_ADD:
+               case IP_MASQ_CMD_INSERT:
                        if (optlen<sizeof(*af))
                                return EINVAL;
                        return ip_autofw_add(af);
-               case IP_FW_MASQ_DEL:
+               case IP_MASQ_CMD_DEL:
                        if (optlen<sizeof(*af))
                                return EINVAL;
                        return ip_autofw_del(af);
-               case IP_FW_MASQ_FLUSH:
+               case IP_MASQ_CMD_FLUSH:
                        return ip_autofw_flush();
 
        }
@@ -250,8 +270,9 @@ static int autofw_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
 }
 
 
-static int autofw_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+static int autofw_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        /* 
         *      Update any ipautofw entries ...
         */
@@ -260,8 +281,9 @@ static int autofw_out_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms
        return IP_MASQ_MOD_NOP;
 }
 
-static struct ip_masq * autofw_out_create(struct iphdr *iph, __u16 * portp, __u32 maddr)
+static struct ip_masq * autofw_out_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        /*
         *      If the source port is supposed to match the masq port, then
         *      make it so 
@@ -278,22 +300,25 @@ static struct ip_masq * autofw_out_create(struct iphdr *iph, __u16 * portp, __u3
 }
 
 #if 0
-static int autofw_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+static int autofw_in_update(const struct sk_buff *skb, const struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        ip_autofw_update_in(iph->saddr, portp[1], iph->protocol);
        return IP_MASQ_MOD_NOP;
 }
 #endif
 
-static int autofw_in_rule(struct iphdr *iph, __u16 *portp)
+static int autofw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        return (ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0)
                || ip_autofw_check_direct(portp[1], iph->protocol)
                || ip_autofw_check_port(portp[1], iph->protocol));
 }
 
-static struct ip_masq * autofw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+static struct ip_masq * autofw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        struct ip_autofw *af;
 
         if ((af=ip_autofw_check_range(iph->saddr, portp[1], iph->protocol, 0))) {
index a306b4f259c9115c7fca28090ceec7029718f92b..a874e55611a66358062f8f690d72dc06648dd63c 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_FTP CUSeeMe masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_cuseeme.c,v 1.2 1997/11/28 15:32:18 alan Exp $
+ * Version:    @(#)$Id: ip_masq_cuseeme.c,v 1.3 1998/08/29 23:51:18 davem Exp $
  *
  * Author:     Richard Lynch
  *             
@@ -94,10 +94,12 @@ struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(debug, "i");
 
 static int
 masq_cuseeme_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
index 1d8edb2531a3f8b921231b2c3fa87953ae0e60d3..be99c7466b4c029f6f26bffa97d05e161bed8f99 100644 (file)
@@ -62,10 +62,12 @@ struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(debug, "i");
 
 /*     Dummy variable */
 static int masq_ftp_pasv;
index c13ca6e9af8914ee0dcea04d5e859bc73d7b1fd4..026a4583fd97fa684a9ff7cfc10c143d49e0e088 100644 (file)
@@ -63,10 +63,12 @@ struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(debug, "i");
 
 
 /*
index 7319a2624af817b82f05db4f8b432c92dd566e20..0053549447536e07c4381bfe4a41abadd257f068 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Author:     Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
- *     $Id: ip_masq_mod.c,v 1.4 1998/03/27 07:02:45 davem Exp $
+ *     $Id: ip_masq_mod.c,v 1.5 1998/08/29 23:51:09 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -22,6 +22,8 @@
 #include <linux/errno.h>
 #include <net/ip_masq.h>
 #include <net/ip_masq_mod.h>
+
+#include <linux/ip_masq.h>
 #ifdef CONFIG_KMOD
 #include <linux/kmod.h>
 #endif
@@ -31,6 +33,10 @@ EXPORT_SYMBOL(unregister_ip_masq_mod);
 EXPORT_SYMBOL(ip_masq_mod_lkp_link);
 EXPORT_SYMBOL(ip_masq_mod_lkp_unlink);
 
+#ifdef __SMP__
+static spinlock_t masq_mod_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
 /*
  *     Base pointer for registered modules
  */
@@ -56,7 +62,7 @@ int ip_masq_mod_register_proc(struct ip_masq_mod *mmod)
                ent->name = mmod->mmod_name;
                ent->namelen = strlen (mmod->mmod_name);
        }
-       ret = proc_net_register(ent);
+       ret = ip_masq_proc_register(ent);
        if (ret) mmod->mmod_proc_ent = NULL;
 
        return ret;
@@ -71,7 +77,7 @@ void ip_masq_mod_unregister_proc(struct ip_masq_mod *mmod)
        struct proc_dir_entry *ent = mmod->mmod_proc_ent;
        if (!ent)
                return;
-       proc_unregister(proc_net, ent->low_ino);
+       ip_masq_proc_unregister(ent);
 #endif
 }
 
@@ -83,28 +89,28 @@ int ip_masq_mod_lkp_unlink(struct ip_masq_mod *mmod)
 {
        struct ip_masq_mod **mmod_p;
 
-       start_bh_atomic();
+       write_lock_bh(&masq_mod_lock);
 
        for (mmod_p = &ip_masq_mod_lkp_base; *mmod_p ; mmod_p = &(*mmod_p)->next)
                if (mmod == (*mmod_p))  {
                        *mmod_p = mmod->next;
                        mmod->next = NULL;
-                       end_bh_atomic();
+                       write_unlock_bh(&masq_mod_lock);
                        return 0;
                }
 
-       end_bh_atomic();
+       write_unlock_bh(&masq_mod_lock);
        return -EINVAL;
 }
 
 int ip_masq_mod_lkp_link(struct ip_masq_mod *mmod)
 {
-       start_bh_atomic();
+       write_lock_bh(&masq_mod_lock);
 
        mmod->next = ip_masq_mod_lkp_base;
        ip_masq_mod_lkp_base=mmod;
 
-       end_bh_atomic();
+       write_unlock_bh(&masq_mod_lock);
        return 0;
 }
 
@@ -164,108 +170,110 @@ int unregister_ip_masq_mod(struct ip_masq_mod *mmod)
        return -EINVAL;
 }
 
-int ip_masq_mod_in_rule(struct iphdr *iph, __u16 *portp)
+int ip_masq_mod_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
 {
        struct ip_masq_mod *mmod;
-       int ret;
+       int ret = IP_MASQ_MOD_NOP;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_in_rule) continue;
-               switch (ret=mmod->mmod_in_rule(iph, portp)) {
+               switch (ret=mmod->mmod_in_rule(skb, iph)) {
                        case IP_MASQ_MOD_NOP:
                                continue;
                        case IP_MASQ_MOD_ACCEPT:
-                               return 1;
                        case IP_MASQ_MOD_REJECT:
-                               return -1;
+                               goto out;
                }
        }
-       return 0;
+out:
+       return ret;
 }
 
-int ip_masq_mod_out_rule(struct iphdr *iph, __u16 *portp)
+int ip_masq_mod_out_rule(const struct sk_buff *skb, const struct iphdr *iph)
 {
        struct ip_masq_mod *mmod;
-       int ret;
+       int ret = IP_MASQ_MOD_NOP;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_out_rule) continue;
-               switch (ret=mmod->mmod_out_rule(iph, portp)) {
+               switch (ret=mmod->mmod_out_rule(skb, iph)) {
                        case IP_MASQ_MOD_NOP:
                                continue;
                        case IP_MASQ_MOD_ACCEPT:
-                               return 1;
                        case IP_MASQ_MOD_REJECT:
-                               return -1;
+                               goto out;
                }
        }
-       return 0;
+out:
+       return ret;
 }
 
-struct ip_masq * ip_masq_mod_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+struct ip_masq * ip_masq_mod_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 {
        struct ip_masq_mod *mmod;
-       struct ip_masq *ms;
+       struct ip_masq *ms = NULL;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_in_create) continue;
-               if ((ms=mmod->mmod_in_create(iph, portp, maddr))) {
-                       return ms;
+               if ((ms=mmod->mmod_in_create(skb, iph, maddr))) {
+                       goto out;
                }
        }
-       return NULL;
+out:
+       return ms;
 }
 
-struct ip_masq * ip_masq_mod_out_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+struct ip_masq * ip_masq_mod_out_create(const struct sk_buff *skb, const struct iphdr *iph,  __u32 maddr)
 {
        struct ip_masq_mod *mmod;
-       struct ip_masq *ms;
+       struct ip_masq *ms = NULL;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_out_create) continue;
-               if ((ms=mmod->mmod_out_create(iph, portp, maddr))) {
-                       return ms;
+               if ((ms=mmod->mmod_out_create(skb, iph, maddr))) {
+                       goto out;
                }
        }
-       return NULL;
+out:
+       return ms;
 }
 
-int ip_masq_mod_in_update(struct iphdr *iph, __u16 *portp, struct ip_masq *ms)
+int ip_masq_mod_in_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
 {
        struct ip_masq_mod *mmod;
-       int ret;
+       int ret = IP_MASQ_MOD_NOP;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_in_update) continue;
-               switch (ret=mmod->mmod_in_update(iph, ms)) {
+               switch (ret=mmod->mmod_in_update(skb, iph, ms)) {
                        case IP_MASQ_MOD_NOP:
                                continue;
                        case IP_MASQ_MOD_ACCEPT:
-                               return 1;
                        case IP_MASQ_MOD_REJECT:
-                               return -1;
+                               goto out;
                }
        }
-       return 0;
+out:
+       return ret;
 }
 
-int ip_masq_mod_out_update(struct iphdr *iph, __u16 *portp,  struct ip_masq *ms)
+int ip_masq_mod_out_update(const struct sk_buff *skb, const struct iphdr *iph, struct ip_masq *ms)
 {
        struct ip_masq_mod *mmod;
-       int ret;
+       int ret = IP_MASQ_MOD_NOP;
 
        for (mmod=ip_masq_mod_lkp_base;mmod;mmod=mmod->next) {
                if (!mmod->mmod_out_update) continue;
-               switch (ret=mmod->mmod_out_update(iph, portp, ms)) {
+               switch (ret=mmod->mmod_out_update(skb, iph, ms)) {
                        case IP_MASQ_MOD_NOP:
                                continue;
                        case IP_MASQ_MOD_ACCEPT:
-                               return 1;
                        case IP_MASQ_MOD_REJECT:
-                               return -1;
+                               goto out;
                }
        }
-       return 0;
+out:
+       return ret;
 }
 
 struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
@@ -287,20 +295,20 @@ struct ip_masq_mod * ip_masq_mod_getbyname(const char *mmod_name)
 /*
  *     Module control entry
  */
-int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
+int ip_masq_mod_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 {
        struct ip_masq_mod * mmod;
 #ifdef CONFIG_KMOD
-       char kmod_name[IP_MASQ_MOD_NMAX+8];
+       char kmod_name[IP_MASQ_TNAME_MAX+8];
 #endif
        /* tappo */
-       mctl->u.mod.name[IP_MASQ_MOD_NMAX-1] = 0;
+       mctl->m_tname[IP_MASQ_TNAME_MAX-1] = 0;
 
-       mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+       mmod = ip_masq_mod_getbyname(mctl->m_tname);
        if (mmod)
                return mmod->mmod_ctl(optname, mctl, optlen);
 #ifdef CONFIG_KMOD
-       sprintf(kmod_name,"ip_masq_%s", mctl->u.mod.name);
+       sprintf(kmod_name,"ip_masq_%s", mctl->m_tname);
 
        IP_MASQ_DEBUG(1, "About to request \"%s\" module\n", kmod_name);
 
@@ -308,7 +316,7 @@ int ip_masq_mod_ctl(int optname, struct ip_fw_masqctl *mctl, int optlen)
         *      Let sleep for a while ...
         */
        request_module(kmod_name);
-       mmod = ip_masq_mod_getbyname(mctl->u.mod.name);
+       mmod = ip_masq_mod_getbyname(mctl->m_tname);
        if (mmod)
                return mmod->mmod_ctl(optname, mctl, optlen);
 #endif
index 862742a213cf3c39af20baafebed185a560fbcda..4384d9cf6bcf37426e49663984afed9bac79f890 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_PORTFW masquerading module
  *
  *
- * Version:    @(#)ip_masq_portfw.c  0.02      97/10/30
+ *     $Id: ip_masq_portfw.c,v 1.2 1998/08/29 23:51:11 davem Exp $
  *
  * Author:     Steven Clarke <steven.clarke@monmouth.demon.co.uk>
  *
@@ -10,9 +10,8 @@
  *     Juan Jose Ciarlante     : created this new file from ip_masq.c and ip_fw.c
  *     Juan Jose Ciarlante     : modularized 
  *     Juan Jose Ciarlante     : use GFP_KERNEL
+ *     Juan Jose Ciarlante     : locking
  *
- *     FIXME
- *             - after creating /proc/net/ip_masq/ direct, put portfw underneath
  */
 
 #include <linux/config.h>
 #include <linux/list.h>
 #include <net/ip.h>
 #include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
 #include <net/ip_masq.h>
 #include <net/ip_masq_mod.h>
-#include <net/ip_portfw.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 
+#define IP_PORTFW_PORT_MIN 1
+#define IP_PORTFW_PORT_MAX 60999
+
+struct ip_portfw {
+       struct          list_head list;
+       __u32           laddr, raddr;
+       __u16           lport, rport;
+       atomic_t        pref_cnt;       /* pref "counter" down to 0 */
+       int             pref;           /* user set pref */
+};
+
 static struct ip_masq_mod *mmod_self = NULL;
+/*
+ *     Debug level
+ */
+#ifdef CONFIG_IP_MASQ_DEBUG
+static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 /*
  *     Lock
  */
-static atomic_t portfw_lock = ATOMIC_INIT(0);
-static struct wait_queue *portfw_wait;
+#ifdef __SMP__
+static spinlock_t portfw_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 static struct list_head portfw_list[2];
 static __inline__ int portfw_idx(int protocol)
@@ -61,7 +79,7 @@ static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __
 
        nent = atomic_read(&mmod_self->mmod_nent);
 
-       ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+       write_lock_bh(&portfw_lock);
 
        for (entry=list->next;entry != list;entry = entry->next)  {
                n = list_entry(entry, struct ip_portfw, list);
@@ -75,7 +93,7 @@ static __inline__ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __
                        MOD_DEC_USE_COUNT;
                }
        }
-       ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+       write_unlock_bh(&portfw_lock);
        
        return nent==atomic_read(&mmod_self->mmod_nent)? ESRCH : 0;
 }
@@ -91,7 +109,7 @@ static __inline__ void ip_portfw_flush(void)
        struct list_head *e;
        struct ip_portfw *n;
 
-       ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+       write_lock_bh(&portfw_lock);
 
        for (prot = 0; prot < 2;prot++) {
                l = &portfw_list[prot];
@@ -104,12 +122,12 @@ static __inline__ void ip_portfw_flush(void)
                }
        }
 
-       ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+       write_unlock_bh(&portfw_lock);
 }
 
 /*
  *     Lookup routine for lport,laddr match
- *     called from ip_masq module (via registered obj)
+ *     must be called with locked tables
  */
 static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)
 {
@@ -118,8 +136,6 @@ static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport
        struct ip_portfw *n = NULL;
        struct list_head *l, *e;
 
-       ip_masq_lock(&portfw_lock, 0);
-
        l = &portfw_list[prot];
 
        for (e=l->next;e!=l;e=e->next) {
@@ -136,7 +152,6 @@ static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport
        }
        n = NULL;
 out:
-       ip_masq_unlock(&portfw_lock, 0);
        return n;
 }
 
@@ -153,7 +168,7 @@ static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, _
        int count = 0;
 
 
-       ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+       read_lock_bh(&portfw_lock);
 
        l = &portfw_list[prot];
 
@@ -169,7 +184,7 @@ static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, _
                }
        }
 
-       ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+       read_unlock_bh(&portfw_lock);
 
        return count;
 }
@@ -212,14 +227,14 @@ static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __
        atomic_set(&npf->pref_cnt, npf->pref);
        INIT_LIST_HEAD(&npf->list);
 
-       ip_masq_lockz(&portfw_lock, &portfw_wait, 1);
+       write_lock_bh(&portfw_lock);
 
        /*
         *      Add at head
         */
        list_add(&npf->list, &portfw_list[prot]);
 
-       ip_masq_unlockz(&portfw_lock, &portfw_wait, 1);
+       write_unlock_bh(&portfw_lock);
 
        ip_masq_mod_inc_nent(mmod_self);
         return 0;
@@ -227,18 +242,34 @@ static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __
 
 
 
-static __inline__ int portfw_ctl(int cmd, struct ip_fw_masqctl *mctl, int optlen)
+static __inline__ int portfw_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
 {
-        struct ip_portfw_edits *mm = (struct ip_portfw_edits *) mctl->u.mod.data;
+        struct ip_portfw_user *mm =  &mctl->u.portfw_user;
        int ret = EINVAL;
+       int arglen = optlen - IP_MASQ_CTL_BSIZE;
+       int cmd;
 
-       /* 
-        *      Don't trust the lusers - plenty of error checking! 
+
+       IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+               arglen,
+               sizeof (*mm),
+               optlen,
+               sizeof (*mctl));
+
+       /*
+        *      Yes, I'm a bad guy ...
         */
-       if (optlen<sizeof(*mm)) 
+       if (arglen != sizeof(*mm) && optlen != sizeof(*mctl)) 
                return EINVAL;
  
-        if (cmd != IP_FW_MASQ_FLUSH) {
+       /* 
+        *      Don't trust the lusers - plenty of error checking! 
+        */
+       cmd = mctl->m_cmd;
+       IP_MASQ_DEBUG(1-debug, "ip_masq_portfw_ctl(cmd=%d)\n", cmd);
+
+
+        if (cmd != IP_MASQ_CMD_FLUSH) {
                if (htons(mm->lport) < IP_PORTFW_PORT_MIN 
                                || htons(mm->lport) > IP_PORTFW_PORT_MAX)
                        return EINVAL;
@@ -249,19 +280,19 @@ static __inline__ int portfw_ctl(int cmd, struct ip_fw_masqctl *mctl, int optlen
 
 
        switch(cmd) {
-       case IP_FW_MASQ_ADD:
+       case IP_MASQ_CMD_ADD:
                ret = ip_portfw_add(mm->protocol,
                                mm->lport, mm->laddr,
                                mm->rport, mm->raddr,
                                mm->pref);
                break;
 
-       case IP_FW_MASQ_DEL:
+       case IP_MASQ_CMD_DEL:
                ret = ip_portfw_del(mm->protocol, 
                                mm->lport, mm->laddr,
                                mm->rport, mm->raddr);
                break;
-       case IP_FW_MASQ_FLUSH:
+       case IP_MASQ_CMD_FLUSH:
                ip_portfw_flush();
                ret = 0;
                break;
@@ -286,7 +317,6 @@ static int portfw_procinfo(char *buffer, char **start, off_t offset,
         int ind;
         int len=0;
 
-       ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
 
         if (offset < 64) 
         {
@@ -295,6 +325,8 @@ static int portfw_procinfo(char *buffer, char **start, off_t offset,
         }
         pos = 64;
 
+       read_lock_bh(&portfw_lock);
+
         for(ind = 0; ind < 2; ind++)
         {
                l = &portfw_list[ind];
@@ -302,8 +334,10 @@ static int portfw_procinfo(char *buffer, char **start, off_t offset,
                 {
                        pf = list_entry(e, struct ip_portfw, list);
                         pos += 64;
-                        if (pos <= offset)
+                        if (pos <= offset) {
+                               len = 0;
                                 continue;
+                       }
 
                         sprintf(temp,"%s  %08lX %5u > %08lX %5u %5d %5d",
                                 ind ? "TCP" : "UDP",
@@ -317,7 +351,7 @@ static int portfw_procinfo(char *buffer, char **start, off_t offset,
                }
         }
 done:
-       ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+       read_unlock_bh(&portfw_lock);
 
         begin = len - (pos - offset);
         *start = buffer + begin;
@@ -329,7 +363,7 @@ done:
 
 static struct proc_dir_entry portfw_proc_entry = {
 /*             0, 0, NULL", */
-               0, 9, "ip_portfw",   /* Just for compatibility, for now ... */
+               0, 6, "portfw",   /* Just for compatibility, for now ... */
                S_IFREG | S_IRUGO, 1, 0, 0,
                0, &proc_net_inode_operations,
                portfw_procinfo
@@ -341,13 +375,26 @@ static struct proc_dir_entry portfw_proc_entry = {
 #define proc_ent NULL
 #endif
 
-static int portfw_in_rule(struct iphdr *iph, __u16 *portp)
+static int portfw_in_rule(const struct sk_buff *skb, const struct iphdr *iph)
 {
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+#ifdef CONFIG_IP_MASQ_DEBUG
+       struct rtable *rt = (struct rtable *)skb->dst;
+#endif
+       struct ip_portfw *pfw;
+
+       IP_MASQ_DEBUG(2, "portfw_in_rule(): skb:= dev=%s (index=%d), rt_iif=%d, rt_flags=0x%x rt_dev___=%s daddr=%d.%d.%d.%d dport=%d\n",
+               skb->dev->name, skb->dev->ifindex, rt->rt_iif, rt->rt_flags,
+               rt->u.dst.dev->name,
+               NIPQUAD(iph->daddr), ntohs(portp[1]));
 
-       return (ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL)!=0);
+       read_lock(&portfw_lock);
+       pfw = ip_portfw_lookup(iph->protocol, portp[1], iph->daddr, NULL, NULL);
+       read_unlock(&portfw_lock);
+       return (pfw!=0);
 }
 
-static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32 maddr)
+static struct ip_masq * portfw_in_create(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)
 {
        /* 
         *      If no entry exists in the masquerading table
@@ -357,13 +404,14 @@ static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32
 
        __u32 raddr;
        __u16 rport;
+       const __u16 *portp = (__u16 *)&(((char *)iph)[iph->ihl*4]);
        struct ip_masq *ms = NULL;
        struct ip_portfw *pf;
 
        /*
-        *      Lock for reading only, by now...
+        *      Lock for writing.
         */
-       ip_masq_lock(&portfw_lock, 0);
+       write_lock(&portfw_lock);
 
        if ((pf=ip_portfw_lookup(iph->protocol, 
                        portp[1], iph->daddr, 
@@ -375,8 +423,8 @@ static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32
                                0);
                ip_masq_listen(ms);
 
-               if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1 || 
-                       ip_masq_nlocks(&portfw_lock) != 1)
+               if (!ms || atomic_read(&mmod_self->mmod_nent) <= 1 
+                       /* || ip_masq_nlocks(&portfw_lock) != 1 */ )
                                /*
                                 *      Maybe later...
                                 */
@@ -390,18 +438,16 @@ static struct ip_masq * portfw_in_create(struct iphdr *iph, __u16 *portp, __u32
                 */
        
                if (atomic_dec_and_test(&pf->pref_cnt)) {
-                       start_bh_atomic();
 
                        atomic_set(&pf->pref_cnt, pf->pref);
                        list_del(&pf->list);
                        list_add(&pf->list, 
                                portfw_list[portfw_idx(iph->protocol)].prev);
 
-                       end_bh_atomic();
                }
        }
 out:
-       ip_masq_unlock(&portfw_lock, 0);
+       write_unlock(&portfw_lock);
        return ms;
 }
 
index 377b8223e695ec83edae8d5810cbf4c9dc249f3b..55c92489fe7ac5309027b0e25ccbea576013518b 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_raudio.c,v 1.9 1998/02/23 02:50:19 davem Exp $
+ * Version:    @(#)$Id: ip_masq_raudio.c,v 1.10 1998/08/29 23:51:17 davem Exp $
  *
  * Author:     Nigel Metheringham
  *             Real Time Streaming code by Progressive Networks
@@ -110,10 +110,12 @@ struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(debug, "i");
 
 
 static int
diff --git a/net/ipv4/ip_masq_user.c b/net/ipv4/ip_masq_user.c
new file mode 100644 (file)
index 0000000..9264301
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *     IP_MASQ_USER user space control module
+ *
+ *
+ *     $Id: ip_masq_user.c,v 1.1 1998/08/29 23:51:08 davem Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <asm/system.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/inet.h>
+#include <linux/init.h>
+#include <net/protocol.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+#include <net/checksum.h>
+#include <net/ip_masq.h>
+#include <net/ip_masq_mod.h>
+#include <linux/sysctl.h>
+#include <linux/ip_fw.h>
+
+#include <linux/ip_masq.h>
+
+/*
+ *     Debug level
+ */
+static int debug=0;
+
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(debug, "i");
+
+/*
+static int check_5uple (struct ip_masq_user *ums) {
+       return 0;
+}
+*/
+static void masq_user_k2u(const struct ip_masq *ms, struct ip_masq_user *ums)
+{
+       ums->protocol = ms->protocol;
+       ums->daddr = ms->daddr;
+       ums->dport = ms->dport;
+       ums->maddr = ms->maddr;
+       ums->mport = ms->mport;
+       ums->saddr = ms->saddr;
+       ums->sport = ms->sport;
+       ums->timeout = ms->timeout;
+}
+
+
+static int ip_masq_user_maddr(struct ip_masq_user *ums)
+{
+       struct device *dev;
+       struct rtable *rt;
+       int ret = -EINVAL;
+       u32 rt_daddr, rt_saddr;
+       u32 tos;
+
+       /*
+        *      Did specify masq address.
+        */
+       if (ums->maddr)
+               return 0;
+
+       /*
+        *      Select address to use for routing query
+        */
+
+       rt_daddr = ums->rt_daddr? ums->rt_daddr : ums->daddr;
+       rt_saddr = ums->rt_saddr? ums->rt_saddr : ums->saddr;
+
+
+       /*
+        *      No address for routing, cannot continue
+        */
+       if (rt_daddr == 0) {
+               IP_MASQ_DEBUG(1-debug, "cannot setup maddr with daddr=%lX, rt_addr=%lX\n",
+                            ntohl(ums->daddr), ntohl(ums->rt_daddr));
+               return -EINVAL;
+       }
+
+       /*
+        *      Find out rt device 
+        */
+
+       rt_saddr = 0; 
+       tos = RT_TOS(ums->ip_tos) | RTO_CONN;
+
+       if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) {
+               IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n",
+                            ntohl(rt_daddr), ntohl(rt_saddr));
+               return ret;
+       }
+       dev = rt->u.dst.dev;
+       ums->maddr = ip_masq_select_addr(dev, rt->rt_gateway, RT_SCOPE_UNIVERSE);
+
+       IP_MASQ_DEBUG(1-debug, "did setup maddr=%lX\n", ntohl(ums->maddr));
+       ip_rt_put(rt);
+       return 0;
+}
+
+/*
+ *     Create new entry (from uspace)
+ */
+static int ip_masq_user_new(struct ip_masq_user *ums)
+{
+       struct ip_masq *ms = NULL;
+       unsigned mflags = 0;
+       int ret;
+
+       if (masq_proto_num (ums->protocol) == -1) {
+               return EPROTONOSUPPORT;
+       }
+
+       if (ums->dport == 0) {
+               ums->flags |= IP_MASQ_USER_F_LISTEN;
+       }
+
+       if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+               if ((ums->saddr == 0) || (ums->sport == 0)) {
+                       return EINVAL;
+               }
+               mflags |= (IP_MASQ_F_NO_DPORT|IP_MASQ_F_NO_DADDR);
+
+       }
+
+       if ((ret = ip_masq_user_maddr(ums)) < 0) {
+               return -ret;
+       }
+
+       mflags |= IP_MASQ_F_USER;
+       ms = ip_masq_new(ums->protocol, 
+                       ums->maddr, ums->mport, 
+                       ums->saddr, ums->sport,
+                       ums->daddr, ums->dport,
+                       mflags);
+       
+       if (ms == NULL) {
+               /*
+                *      FIXME: ip_masq_new() should return errno
+                */
+               return EBUSY;
+       }
+
+       /*
+        *      Setup timeouts for this new entry
+        */
+
+       if (ums->timeout) {
+               ms->timeout = ums->timeout;
+       } else if (ums->flags | IP_MASQ_USER_F_LISTEN) {
+               ip_masq_listen(ms);
+       }
+
+       masq_user_k2u(ms, ums);
+       ip_masq_put(ms);
+       return 0;
+}
+
+/* 
+ *     Delete existing entry
+ */
+static int ip_masq_user_del(struct ip_masq_user *ums)
+{
+       struct ip_masq *ms=NULL;
+
+       if (masq_proto_num (ums->protocol) == -1) {
+               return EPROTONOSUPPORT;
+       }
+       start_bh_atomic();
+       if (ums->mport && ums->maddr) {
+               ms = ip_masq_in_get(ums->protocol, 
+                               ums->daddr, ums->dport, 
+                               ums->maddr, ums->mport);
+               end_bh_atomic();
+       } else if (ums->sport && ums->saddr) {
+               ms = ip_masq_out_get(ums->protocol,
+                               ums->saddr, ums->sport,
+                               ums->daddr, ums->dport);
+               end_bh_atomic();
+       } else
+               return EINVAL;  
+       
+       if (ms == NULL) {
+               return ESRCH;
+       }
+
+       /*
+        *      got (locked) entry, setup almost tiny timeout :) and  
+        *      give away
+        *
+        *      FIXME: should use something better than S_CLOSE
+        */
+       ms->timeout = IP_MASQ_S_CLOSE;
+
+       masq_user_k2u(ms, ums);
+       ip_masq_put(ms);
+       return 0;
+}
+
+static struct ip_masq * ip_masq_user_locked_get (struct ip_masq_user *ums, int *err)
+{
+       struct ip_masq *ms=NULL;
+       if (masq_proto_num (ums->protocol) == -1) {
+               *err = EPROTONOSUPPORT;
+       }
+
+       start_bh_atomic();
+       if (ums->mport && ums->maddr) {
+               ms = ip_masq_in_get(ums->protocol, 
+                               ums->daddr, ums->dport, 
+                               ums->maddr, ums->mport);
+               end_bh_atomic();
+       } else if (ums->sport && ums->saddr) {
+               ms = ip_masq_out_get(ums->protocol,
+                               ums->saddr, ums->sport,
+                               ums->daddr, ums->dport);
+               end_bh_atomic();
+       } else
+               *err = EINVAL;  
+       
+       if (ms == NULL) *err = ESRCH;
+       return ms;
+}
+
+/*
+ *     Get existing entry (complete full tunnel info)
+ */
+static int ip_masq_user_get(struct ip_masq_user *ums)
+{
+       struct ip_masq *ms=NULL;
+       int err;
+
+       ms = ip_masq_user_locked_get(ums, &err);
+       if (ms == NULL)
+               return err;
+
+       masq_user_k2u(ms, ums);
+
+       ip_masq_put(ms);
+       return 0;
+}
+
+/* 
+ *     Set (some, valid) entry parameters
+ */
+static int ip_masq_user_set(struct ip_masq_user *ums)
+{
+       struct ip_masq *ms = NULL;
+       int err;
+
+       ms = ip_masq_user_locked_get(ums, &err);
+       if (ms == NULL)
+               return err;
+       
+       /*
+        *      FIXME: must allow selecting what you want to set
+        */
+       ms->timeout = ums->timeout;
+
+       masq_user_k2u(ms, ums);
+       
+       ip_masq_put(ms);
+       return 0;
+}
+
+
+/*
+ *     Entry point
+ *     ret value:
+ *             <0   err
+ *             ==0  ok
+ *             >0   ok, copy to user
+ */
+static int ip_masq_user_ctl(int optname, struct ip_masq_ctl *mctl, int optlen)
+{
+       struct ip_masq_user *ums = &mctl->u.user;
+       int ret = EINVAL;
+       int arglen = optlen - IP_MASQ_CTL_BSIZE;
+       int cmd;
+
+       IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(len=%d/%d|%d/%d)\n",
+               arglen,
+               sizeof (*ums),
+               optlen,
+               sizeof (*mctl));
+
+       /*
+        *      Yes, I'm a bad guy ...
+        */
+       if (arglen != sizeof(*ums) && optlen != sizeof(*mctl)) 
+               return EINVAL;
+
+       MOD_INC_USE_COUNT;
+
+       /* 
+        *      Don't trust the lusers - plenty of error checking! 
+        */
+       cmd = mctl->m_cmd;
+       IP_MASQ_DEBUG(1-debug, "ip_masq_user_ctl(cmd=%d)\n", cmd);
+
+       switch (mctl->m_cmd) {
+               case IP_MASQ_CMD_ADD:
+               case IP_MASQ_CMD_INSERT:
+                       ret = ip_masq_user_new(ums);
+                       break;
+               case IP_MASQ_CMD_DEL:
+                       ret = ip_masq_user_del(ums);
+                       break;
+               case IP_MASQ_CMD_SET:
+                       ret = ip_masq_user_set(ums);
+                       break;
+               case IP_MASQ_CMD_GET:
+                       ret = ip_masq_user_get(ums);
+                       break;
+       }
+
+       /*
+        *      For all of the above, return masq tunnel info
+        */
+
+       ret = -ret;
+
+       if (ret == 0) {
+               ret = sizeof (*ums) + IP_MASQ_CTL_BSIZE;
+               IP_MASQ_DEBUG(1-debug, "will return %d bytes to user\n", ret);
+       }
+
+       MOD_DEC_USE_COUNT;
+       return ret;
+}
+
+
+#ifdef CONFIG_PROC_FS
+static int ip_masq_user_info(char *buffer, char **start, off_t offset,
+                             int length, int proto)
+{
+       off_t pos=0, begin;
+       struct ip_masq *ms;
+       char temp[129];
+        int idx = 0;
+       int len=0;
+       int magic_control;
+
+       MOD_INC_USE_COUNT;
+
+       IP_MASQ_DEBUG(1-debug, "Entered user_info with proto=%d\n", proto);
+
+       if (offset < 128)
+       {
+               sprintf(temp,
+                       "Prot SrcIP    SPrt DstIP    DPrt MAddr    MPrt State        Flgs Ref Ctl Expires (free=%d,%d,%d)",
+                       atomic_read(ip_masq_free_ports), 
+                       atomic_read(ip_masq_free_ports+1), 
+                       atomic_read(ip_masq_free_ports+2));
+               len = sprintf(buffer, "%-127s\n", temp);
+       }
+       pos = 128;
+
+        for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++)
+       {
+       /*
+        *      Lock is actually only need in next loop 
+        *      we are called from uspace: must stop bh.
+        */
+       read_lock_bh(&__ip_masq_lock);
+        for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
+       {
+               if (ms->protocol != proto) {
+                       continue;
+               }
+
+               pos += 128;
+               if (pos <= offset) {
+                       len = 0;
+                       continue;
+               }
+
+               /*
+                *      We have locked the tables, no need to del/add timers
+                *      nor cli()  8)
+                */
+               
+
+               magic_control = atomic_read(&ms->n_control);
+               if (!magic_control && ms->control) magic_control = -1;
+               sprintf(temp,"%-4s %08lX:%04X %08lX:%04X %08lX:%04X %-12s %3X %4d %3d %7lu",
+                       masq_proto_name(ms->protocol),
+                       ntohl(ms->saddr), ntohs(ms->sport),
+                       ntohl(ms->daddr), ntohs(ms->dport),
+                       ntohl(ms->maddr), ntohs(ms->mport),
+                       ip_masq_state_name(ms->state),
+                       ms->flags,
+                       atomic_read(&ms->refcnt),
+                       magic_control,
+                       (ms->timer.expires-jiffies)/HZ);
+               len += sprintf(buffer+len, "%-127s\n", temp);
+
+               if(len >= length) {
+                       read_unlock_bh(&__ip_masq_lock);
+                       goto done;
+               }
+       }
+       read_unlock_bh(&__ip_masq_lock);
+       }
+
+done:
+
+       if (len) {
+               begin = len - (pos - offset);
+               *start = buffer + begin;
+               len -= begin;
+       }
+       if(len>length)
+               len = length;
+       MOD_DEC_USE_COUNT;
+       return len;
+}
+#else
+#define ip_masq_user_info      NULL
+#endif
+
+static struct ip_masq_hook ip_masq_user = {
+       ip_masq_user_ctl,
+       ip_masq_user_info
+};
+
+int ip_masq_user_init(void)
+{
+       if (ip_masq_user_hook != NULL) 
+               return -EEXIST;
+       ip_masq_user_hook = &ip_masq_user;
+       return 0;
+}
+
+int ip_masq_user_done(void)
+{
+       if (ip_masq_user_hook == NULL) 
+               return ENOENT;
+       ip_masq_user_hook = NULL;
+       return 0;
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+int init_module(void)
+{
+       if (ip_masq_user_init() != 0)
+               return -EIO;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       if (ip_masq_user_done() != 0)
+               printk(KERN_INFO "ip_masq_user_done(): can't remove module");
+}
+
+#endif /* MODULE */
index 3b74d5f6f6ab4887db4cfcea63e9b0ed22ac6134..15e46d49e3b14177b4b285e1d9852cb2d7788f46 100644 (file)
@@ -2,7 +2,7 @@
  *             IP_MASQ_VDOLIVE  - VDO Live masquerading module
  *
  *
- * Version:    @(#)$Id: ip_masq_vdolive.c,v 1.2 1997/11/28 15:32:35 alan Exp $
+ * Version:    @(#)$Id: ip_masq_vdolive.c,v 1.3 1998/08/29 23:51:18 davem Exp $
  *
  * Author:     Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
  *             PLAnet Online Ltd
@@ -52,10 +52,12 @@ struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 /*
  *     Debug level
  */
+#ifdef CONFIG_IP_MASQ_DEBUG
 static int debug=0;
+MODULE_PARM(debug, "i");
+#endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(debug, "i");
 
 static int
 masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
index a08d0776d9fd11583b21e53fbc42f0e7afa16fde..8c21ee5abc691ced7d30f2b8e72f667ad9810b3c 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Dumb Network Address Translation.
  *
- * Version:    $Id: ip_nat_dumb.c,v 1.5 1998/09/07 00:13:54 davem Exp $
+ * Version:    $Id: ip_nat_dumb.c,v 1.6 1998/10/03 09:37:25 davem Exp $
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
@@ -18,6 +18,7 @@
  *             Rani Assaf      :       A zero checksum is a special case
  *                                     only in UDP
  *             Rani Assaf      :       Added ICMP messages rewriting
+ *             Rani Assaf      :       Repaired wrong changes, made by ANK.
  *
  *
  * NOTE:       It is just working model of real NAT.
@@ -40,6 +41,7 @@
 #include <net/checksum.h>
 #include <linux/route.h>
 #include <net/route.h>
+#include <net/ip_fib.h>
 
 
 int
@@ -89,7 +91,8 @@ ip_do_nat(struct sk_buff *skb)
 
                        if ((icmph->type != ICMP_DEST_UNREACH) &&
                            (icmph->type != ICMP_TIME_EXCEEDED) &&
-                           (icmph->type != ICMP_PARAMETERPROB)) break;
+                           (icmph->type != ICMP_PARAMETERPROB))
+                               break;
 
                        ciph = (struct iphdr *) (icmph + 1);
 
@@ -98,8 +101,30 @@ ip_do_nat(struct sk_buff *skb)
 
                        if (rt->rt_flags&RTCF_DNAT && ciph->saddr == odaddr)
                                ciph->saddr = iph->daddr;
-                       if (rt->rt_flags&RTCF_SNAT && ciph->daddr == osaddr)
-                               ciph->daddr = iph->saddr;
+                       if (rt->rt_flags&RTCF_SNAT) {
+                               if (ciph->daddr != osaddr) {
+                                       struct   fib_result res;
+                                       struct   rt_key key;
+                                       unsigned flags = 0;
+
+                                       key.src = ciph->daddr;
+                                       key.dst = ciph->saddr;
+                                       key.iif = skb->dev->ifindex;
+                                       key.oif = 0;
+#ifdef CONFIG_IP_ROUTE_TOS
+                                       key.tos = RT_TOS(ciph->tos);
+#endif
+                                       /* Use fib_lookup() until we get our own
+                                        * hash table of NATed hosts -- Rani
+                                        */
+                                       if (fib_lookup(&key, &res) != 0)
+                                               return 0;
+                                       if (res.r)
+                                               ciph->daddr = fib_rules_policy(ciph->daddr, &res, &flags);
+                               }
+                               else
+                                       ciph->daddr = iph->saddr;
+                       }
                        break;
                }
                default:
index 153c7a391f023c370f20ee5347e90eb696c9bc4e..92502239c45492f535aa23f7bec2b7fa5dbf9913 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The options processing module for ip.c
  *
- * Version:    $Id: ip_options.c,v 1.14 1998/08/26 12:03:51 davem Exp $
+ * Version:    $Id: ip_options.c,v 1.15 1998/10/03 09:37:27 davem Exp $
  *
  * Authors:    A.N.Kuznetsov
  *             
@@ -89,12 +89,6 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
        int     optlen;
        u32     daddr;
 
-#if 111
-       if (skb == NULL) {
-               printk(KERN_DEBUG "no skb in ip_options_echo\n");
-               return -EINVAL;
-       }
-#endif
        memset(dopt, 0, sizeof(struct ip_options));
 
        dopt->is_data = 1;
@@ -145,14 +139,19 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
                                        return -EINVAL;
                                dopt->ts_needtime = 1;
                                soffset += 4;
-                       }
-                       if (((struct timestamp*)(dptr+1))->flags == IPOPT_TS_PRESPEC) {
-                               __u32 addr;
-                               memcpy(&addr, sptr+soffset-9, 4);
-                               if (inet_addr_type(addr) == RTN_UNICAST) {
-                                       dopt->ts_needtime = 0;
-                                       dopt->ts_needaddr = 0;
-                                       soffset -= 8;
+                               if ((dptr[3]&0xF) == IPOPT_TS_PRESPEC) {
+                                       __u32 addr;
+                                       if (soffset + 3 > optlen)
+                                               return -EINVAL;
+                                       soffset += 4;
+                                       if (soffset + 8 <= optlen) {
+                                               dopt->ts_needtime = 0;
+                                               memcpy(&addr, sptr+soffset-1, 4);
+                                               if (inet_addr_type(addr) != RTN_UNICAST) {
+                                                       dopt->ts_needtime = 1;
+                                                       soffset += 8;
+                                               }
+                                       }
                                }
                        }
                        dptr[2] = soffset;
@@ -353,55 +352,56 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
                                goto error;
                        }
                        if (optptr[2] <= optlen) {
-                               struct timestamp * ts = (struct timestamp*)(optptr+1);
                                __u32 * timeptr = NULL;
-                               if (ts->ptr+3 > ts->len) {
+                               if (optptr[2]+3 > optptr[1]) {
                                        pp_ptr = optptr + 2;
                                        goto error;
                                }
-                               switch (ts->flags) {
+                               switch (optptr[3]&0xF) {
                                      case IPOPT_TS_TSONLY:
                                        opt->ts = optptr - iph;
                                        if (skb) 
-                                               timeptr = (__u32*)&optptr[ts->ptr-1];
+                                               timeptr = (__u32*)&optptr[optptr[2]-1];
                                        opt->ts_needtime = 1;
-                                       ts->ptr += 4;
+                                       optptr[2] += 4;
                                        break;
                                      case IPOPT_TS_TSANDADDR:
-                                       if (ts->ptr+7 > ts->len) {
+                                       if (optptr[2]+7 > optptr[1]) {
                                                pp_ptr = optptr + 2;
                                                goto error;
                                        }
                                        opt->ts = optptr - iph;
                                        if (skb) {
-                                               memcpy(&optptr[ts->ptr-1], &rt->rt_spec_dst, 4);
-                                               timeptr = (__u32*)&optptr[ts->ptr+3];
+                                               memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
+                                               timeptr = (__u32*)&optptr[optptr[2]+3];
                                        }
                                        opt->ts_needaddr = 1;
                                        opt->ts_needtime = 1;
-                                       ts->ptr += 8;
+                                       optptr[2] += 8;
                                        break;
                                      case IPOPT_TS_PRESPEC:
-                                       if (ts->ptr+7 > ts->len) {
+                                       if (optptr[2]+7 > optptr[1]) {
                                                pp_ptr = optptr + 2;
                                                goto error;
                                        }
                                        opt->ts = optptr - iph;
                                        {
                                                u32 addr;
-                                               memcpy(&addr, &optptr[ts->ptr-1], 4);
+                                               memcpy(&addr, &optptr[optptr[2]-1], 4);
                                                if (inet_addr_type(addr) == RTN_UNICAST)
                                                        break;
                                                if (skb)
-                                                       timeptr = (__u32*)&optptr[ts->ptr+3];
+                                                       timeptr = (__u32*)&optptr[optptr[2]+3];
                                        }
-                                       opt->ts_needaddr = 1;
                                        opt->ts_needtime = 1;
-                                       ts->ptr += 8;
+                                       optptr[2] += 8;
                                        break;
                                      default:
-                                       pp_ptr = optptr + 3;
-                                       goto error;
+                                       if (!skb && !capable(CAP_NET_RAW)) {
+                                               pp_ptr = optptr + 3;
+                                               goto error;
+                                       }
+                                       break;
                                }
                                if (timeptr) {
                                        struct timeval tv;
@@ -412,14 +412,14 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
                                        opt->is_changed = 1;
                                }
                        } else {
-                               struct timestamp * ts = (struct timestamp*)(optptr+1);
-                               if (ts->overflow == 15) {
+                               unsigned overflow = optptr[3]>>4;
+                               if (overflow == 15) {
                                        pp_ptr = optptr + 3;
                                        goto error;
                                }
                                opt->ts = optptr - iph;
                                if (skb) {
-                                       ts->overflow++;
+                                       optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);
                                        opt->is_changed = 1;
                                }
                        }
@@ -435,7 +435,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
                      case IPOPT_SEC:
                      case IPOPT_SID:
                      default:
-                       if (!skb) {
+                       if (!skb && !capable(CAP_NET_RAW)) {
                                pp_ptr = optptr;
                                goto error;
                        }
@@ -480,10 +480,10 @@ void ip_options_undo(struct ip_options * opt)
                        memset(&optptr[optptr[2]-1], 0, 4);
                        optptr[2] -= 4;
                }
-               if (opt->ts_needaddr) {
+               if (opt->ts_needaddr)
                        memset(&optptr[optptr[2]-1], 0, 4);
+               if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC)
                        optptr[2] -= 4;
-               }
        }
 }
 
index 3f7ac39a83c8ce654583239a7a33476a15d2d6db..5edfbef938d13aab7c386ee8643958765b794bf9 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The Internet Protocol (IP) output module.
  *
- * Version:    $Id: ip_output.c,v 1.62 1998/09/14 01:22:58 davem Exp $
+ * Version:    $Id: ip_output.c,v 1.63 1998/10/03 09:37:30 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -111,8 +111,7 @@ void ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
        iph->ihl      = 5;
        iph->tos      = sk->ip_tos;
        iph->frag_off = 0;
-       if (sk->ip_pmtudisc == IP_PMTUDISC_WANT && 
-               !(rt->u.dst.mxlock&(1<<RTAX_MTU)))
+       if (ip_dont_fragment(sk, &rt->u.dst))
                iph->frag_off |= htons(IP_DF);
        iph->ttl      = sk->ip_ttl;
        iph->daddr    = rt->rt_dst;
@@ -312,7 +311,7 @@ void ip_queue_xmit(struct sk_buff *skb)
        if (tot_len > rt->u.dst.pmtu)
                goto fragment;
 
-       if (sk->ip_pmtudisc == IP_PMTUDISC_WANT && !(rt->u.dst.mxlock & (1 << RTAX_MTU)))
+       if (ip_dont_fragment(sk, &rt->u.dst))
                iph->frag_off |= __constant_htons(IP_DF);
 
        /* Add an IP checksum. */
@@ -323,8 +322,7 @@ void ip_queue_xmit(struct sk_buff *skb)
        return;
 
 fragment:
-       if (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
-           !(rt->u.dst.mxlock & (1 << RTAX_MTU)) &&
+       if (ip_dont_fragment(sk, &rt->u.dst) &&
            tot_len > (iph->ihl<<2) + sizeof(struct tcphdr)+16) {
                /* Reject packet ONLY if TCP might fragment
                   it itself, if were careful enough.
@@ -383,23 +381,24 @@ int ip_build_xmit_slow(struct sock *sk,
        unsigned int fraglen, maxfraglen, fragheaderlen;
        int err;
        int offset, mf;
+       int mtu;
        unsigned short id;
 
        int hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
        int nfrags=0;
        struct ip_options *opt = ipc->opt;
-       int df = htons(IP_DF);
+       int df = 0;
 
-       if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-               (rt->u.dst.mxlock&(1<<RTAX_MTU)))
-               df = 0;
+       mtu = rt->u.dst.pmtu;
+       if (ip_dont_fragment(sk, &rt->u.dst))
+               df = htons(IP_DF);
   
        if (!sk->ip_hdrincl)
                length -= sizeof(struct iphdr);
 
        if (opt) {
                fragheaderlen = sizeof(struct iphdr) + opt->optlen;
-               maxfraglen = ((rt->u.dst.pmtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
+               maxfraglen = ((mtu-sizeof(struct iphdr)-opt->optlen) & ~7) + fragheaderlen;
        } else {
                fragheaderlen = sk->ip_hdrincl ? 0 : sizeof(struct iphdr);
                
@@ -408,11 +407,13 @@ int ip_build_xmit_slow(struct sock *sk,
                 *      out the size of the frames to send.
                 */
         
-               maxfraglen = ((rt->u.dst.pmtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
+               maxfraglen = ((mtu-sizeof(struct iphdr)) & ~7) + fragheaderlen;
        }
 
-       if (length + fragheaderlen > 0xFFFF)
+       if (length + fragheaderlen > 0xFFFF) {
+               ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
                return -EMSGSIZE;
+       }
 
        /*
         *      Start at the end of the frame by handling the remainder.
@@ -443,6 +444,7 @@ int ip_build_xmit_slow(struct sock *sk,
         */
         
        if (offset > 0 && df) { 
+               ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
                return(-EMSGSIZE);
        }
 
@@ -612,10 +614,9 @@ int ip_build_xmit(struct sock *sk,
        /*
         *      Do path mtu discovery if needed.
         */
-       df = htons(IP_DF);
-       if (sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-               (rt->u.dst.mxlock&(1<<RTAX_MTU)))
-               df = 0;
+       df = 0;
+       if (ip_dont_fragment(sk, &rt->u.dst))
+               df = htons(IP_DF);
                
        /* 
         *      Fast path for unfragmented frames without options. 
index 3d8f4fab6b6d99f1bcd1cde49a3a6c15092e0c3f..1391cbd240ad8bdb6515f4dcea860941fd5989c4 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The IP to API glue.
  *             
- * Version:    $Id: ip_sockglue.c,v 1.37 1998/08/26 12:03:57 davem Exp $
+ * Version:    $Id: ip_sockglue.c,v 1.39 1998/10/03 09:37:33 davem Exp $
  *
  * Authors:    see ip.c
  *
 #include <net/transp_v6.h>
 #endif
 
+#ifdef CONFIG_IP_MASQUERADE
+#include <linux/ip_masq.h>
+#endif
+
+#include <linux/errqueue.h>
 #include <asm/uaccess.h>
 
 #define MAX(a,b) ((a)>(b)?(a):(b))
@@ -74,7 +79,8 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
 
 static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb)
 {
-       put_cmsg(msg, SOL_IP, IP_TTL, 1, &skb->nh.iph->ttl);
+       int ttl = skb->nh.iph->ttl;
+       put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl);
 }
 
 static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb)
@@ -221,6 +227,140 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s
        return 0;
 }
 
+void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
+                  u16 port, u32 info, u8 *payload)
+{
+       struct sock_exterr_skb *serr;
+
+       if (!sk->ip_recverr)
+               return;
+
+       skb = skb_clone(skb, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       serr = SKB_EXT_ERR(skb);  
+       serr->ee.ee_errno = err;
+       serr->ee.ee_origin = SO_EE_ORIGIN_ICMP;
+       serr->ee.ee_type = skb->h.icmph->type; 
+       serr->ee.ee_code = skb->h.icmph->code;
+       serr->ee.ee_pad = 0;
+       serr->ee.ee_info = info;
+       serr->ee.ee_data = 0;
+       serr->addr_offset = (u8*)&(((struct iphdr*)(skb->h.icmph+1))->daddr) - skb->nh.raw;
+       serr->port = port;
+
+       skb->h.raw = payload;
+       skb_pull(skb, payload - skb->data);
+
+       if (sock_queue_err_skb(sk, skb))
+               kfree_skb(skb);
+}
+
+void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
+{
+       struct sock_exterr_skb *serr;
+       struct iphdr *iph;
+       struct sk_buff *skb;
+
+       if (!sk->ip_recverr)
+               return;
+
+       skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       iph = (struct iphdr*)skb_put(skb, sizeof(struct iphdr));
+       skb->nh.iph = iph;
+       iph->daddr = daddr;
+
+       serr = SKB_EXT_ERR(skb);  
+       serr->ee.ee_errno = err;
+       serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
+       serr->ee.ee_type = 0; 
+       serr->ee.ee_code = 0;
+       serr->ee.ee_pad = 0;
+       serr->ee.ee_info = info;
+       serr->ee.ee_data = 0;
+       serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+       serr->port = port;
+
+       skb->h.raw = skb->tail;
+       skb_pull(skb, skb->tail - skb->data);
+
+       if (sock_queue_err_skb(sk, skb))
+               kfree_skb(skb);
+}
+
+/* 
+ *     Handle MSG_ERRQUEUE
+ */
+int ip_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+       struct sock_exterr_skb *serr;
+       struct sk_buff *skb, *skb2;
+       struct sockaddr_in *sin;
+       struct {
+               struct sock_extended_err ee;
+               struct sockaddr_in       offender;
+       } errhdr;
+       int err;
+       int copied;
+
+       err = -EAGAIN;
+       skb = skb_dequeue(&sk->error_queue);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+       if (err)
+               goto out_free_skb;
+
+       serr = SKB_EXT_ERR(skb);
+
+       sin = (struct sockaddr_in *)msg->msg_name;
+       if (sin) {
+               sin->sin_family = AF_INET; 
+               sin->sin_addr.s_addr = *(u32*)(skb->nh.raw + serr->addr_offset);
+               sin->sin_port = serr->port; 
+       }
+
+       memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+       sin = &errhdr.offender;
+       sin->sin_family = AF_UNSPEC;
+       if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP) {
+               sin->sin_family = AF_INET;
+               sin->sin_addr.s_addr = skb->nh.iph->saddr;
+               if (sk->ip_cmsg_flags)
+                       ip_cmsg_recv(msg, skb);
+       }
+
+       put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr);
+
+       /* Now we could try to dump offended packet options */
+
+       msg->msg_flags |= MSG_ERRQUEUE;
+       err = copied;
+
+       /* Reset and regenerate socket error */
+       sk->err = 0;
+       if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
+               sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+               sk->error_report(sk);
+       }
+
+out_free_skb:  
+       kfree_skb(skb);
+out:
+       return err;
+}
+
+
 /*
  *     Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
  *     an IP socket.
@@ -234,10 +374,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
 #if defined(CONFIG_IP_FIREWALL)
        char tmp_fw[MAX(sizeof(struct ip_fwtest),sizeof(struct ip_fwnew))];
 #endif
-#ifdef CONFIG_IP_MASQUERADE
-       char masq_ctl[IP_FW_MASQCTL_MAX];
-#endif
-
        if(optlen>=sizeof(int)) {
                if(get_user(val, (int *) optval))
                        return -EFAULT;
@@ -347,23 +483,15 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                                return -ENOPROTOOPT;
                        sk->ip_hdrincl=val?1:0;
                        return 0;
-               case IP_PMTUDISC:
+               case IP_MTU_DISCOVER:
                        if (val<0 || val>2)
                                return -EINVAL;
                        sk->ip_pmtudisc = val;
                        return 0;
                case IP_RECVERR:
-                       if (sk->type==SOCK_STREAM)
-                               return -ENOPROTOOPT;
-                       lock_sock(sk);
-                       if (sk->ip_recverr && !val) {
-                               struct sk_buff *skb;
-                               /* Drain queued errors */
-                               while((skb=skb_dequeue(&sk->error_queue))!=NULL)
-                                       kfree_skb(skb);
-                       }
-                       sk->ip_recverr = val?1:0;
-                       release_sock(sk);
+                       sk->ip_recverr = !!val;
+                       if (!val)
+                               skb_queue_purge(&sk->error_queue);
                        return 0;
                case IP_MULTICAST_TTL: 
                        if (optlen<1)
@@ -466,17 +594,13 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
                        return -err;    /* -0 is 0 after all */
 #endif /* CONFIG_IP_FIREWALL */
 #ifdef CONFIG_IP_MASQUERADE
-               case IP_FW_MASQ_ADD:
-               case IP_FW_MASQ_DEL:
-               case IP_FW_MASQ_FLUSH:
+               case IP_FW_MASQ_CTL:
                        if(!capable(CAP_NET_ADMIN))
                                return -EPERM;
-                       if(optlen>sizeof(masq_ctl) || optlen<1)
+                       if(optlen<1)
                                return -EINVAL;
-                       if(copy_from_user(masq_ctl,optval,optlen))
-                               return -EFAULT;
-                       err=ip_masq_ctl(optname, masq_ctl,optlen);
-                       return -err;    /* -0 is 0 after all */
+                       err=ip_masq_uctl(optname, optval ,optlen);
+                       return err;
                        
 #endif
                default:
@@ -491,7 +615,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
 
 int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen)
 {
-       int val,err;
+       int val;
        int len;
        
        if(level!=SOL_IP)
@@ -554,9 +678,18 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
                case IP_HDRINCL:
                        val=sk->ip_hdrincl;
                        break;
-               case IP_PMTUDISC:
+               case IP_MTU_DISCOVER:
                        val=sk->ip_pmtudisc;
                        break;
+               case IP_MTU:
+                       val = 0;        
+                       lock_sock(sk);
+                       if (sk->dst_cache)              
+                               val = sk->dst_cache->pmtu;
+                       release_sock(sk);
+                       if (!val)
+                               return -ENOTCONN;
+                       break;
                case IP_RECVERR:
                        val=sk->ip_recverr;
                        break;
@@ -566,7 +699,6 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
                case IP_MULTICAST_LOOP:
                        val=sk->ip_mc_loop;
                        break;
-#if 0
                case IP_MULTICAST_IF:
                {
                        struct ip_mreqn mreq;
@@ -580,30 +712,6 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *op
                                return -EFAULT;
                        return 0;
                }
-#endif
-               case IP_MULTICAST_IF:
-               {
-                       struct device *dev = dev_get_by_index(sk->ip_mc_index);
-
-                       printk(KERN_INFO "application %s uses old get IP_MULTICAST_IF. Please, report!\n", current->comm);
-
-                       if (dev == NULL) 
-                       {
-                               len = 0;
-                               return put_user(len, optlen);
-                       }
-                       dev_lock_list();
-                       len = min(len,strlen(dev->name));
-                       err = put_user(len, optlen);
-                       if (!err)
-                       {
-                               err = copy_to_user((void *)optval,dev->name, len);
-                               if(err)
-                                       err=-EFAULT;
-                       }
-                       dev_unlock_list();
-                       return err;
-               }
                default:
                        return(-ENOPROTOOPT);
        }
index 778ac15c1f3e732907f0041decbdc2551309fe52..9175e6fe68c95430d7e0e0a3a862f2a8cb990ed9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Linux NET3:     IP/IP protocol decoder. 
  *
- *     Version: $Id: ipip.c,v 1.23 1998/08/26 12:04:00 davem Exp $
+ *     Version: $Id: ipip.c,v 1.24 1998/10/03 09:37:35 davem Exp $
  *
  *     Authors:
  *             Sam Lantinga (slouken@cs.ucdavis.edu)  02/01/95
@@ -625,6 +625,10 @@ ipip_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
 
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                err = -EFAULT;
                if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                        goto done;
@@ -652,6 +656,10 @@ ipip_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
                break;
 
        case SIOCDELTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                if (dev == &ipip_fb_tunnel_dev) {
                        err = -EFAULT;
                        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
index 49cd6daf5a453055c113b5851336fd9c73bdb2aa..79ecd11022f941b00f687fc7124088f69f8c20e1 100644 (file)
@@ -9,7 +9,7 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     Version: $Id: ipmr.c,v 1.36 1998/08/26 12:04:03 davem Exp $
+ *     Version: $Id: ipmr.c,v 1.37 1998/10/03 09:37:39 davem Exp $
  *
  *     Fixes:
  *     Michael Chastain        :       Incorrect size of copying.
@@ -431,7 +431,6 @@ static void ipmr_cache_resolve(struct mfc_cache *cache)
                                ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
                        }
                        err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).pid, MSG_DONTWAIT);
-                       if (err < 0) printk(KERN_DEBUG "Err=%d", err);
                } else
 #endif
                        ip_mr_forward(skb, cache, 0);
@@ -476,9 +475,10 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
                msg->im_vif = reg_vif_num;
                skb->nh.iph->ihl = sizeof(struct iphdr) >> 2;
                skb->nh.iph->tot_len = htons(ntohs(pkt->nh.iph->tot_len) + sizeof(struct iphdr));
-       } else {
+       } else 
 #endif
-
+       {       
+               
        /*
         *      Copy the IP header
         */
@@ -500,9 +500,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert)
        igmp->code      =       0;
        skb->nh.iph->tot_len=htons(skb->len);                   /* Fix the length */
        skb->h.raw = skb->nh.raw;
-#ifdef CONFIG_IP_PIMSM
         }
-#endif
        
        /*
         *      Deliver to mrouted
@@ -753,7 +751,9 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char *optval,int optlen)
                                                return -EADDRNOTAVAIL;
                                        break;
                                default:
+#if 0
                                        printk(KERN_DEBUG "ipmr_add_vif: flags %02x\n", vif.vifc_flags);
+#endif
                                        return -EINVAL;
                                }
 
@@ -1548,7 +1548,6 @@ done:
                len=length;
        if (len < 0) {
                len = 0;
-               printk(KERN_CRIT "Yep, guys... our template for proc_*_read is crappy :-)\n");
        }
        return len;
 }
index 6f06f434582b6f4c9599d44343b6d94a717bbcf2..b64dacca9b293c0ffa914383ac935b926a1b6a51 100644 (file)
@@ -7,7 +7,7 @@
  *             PROC file system.  It is mainly used for debugging and
  *             statistics.
  *
- * Version:    $Id: proc.c,v 1.31 1998/07/29 20:09:25 freitag Exp $
+ * Version:    $Id: proc.c,v 1.32 1998/10/03 09:37:42 davem Exp $
  *
  * Authors:    Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
@@ -357,15 +357,18 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length, int d
 
        len = sprintf(buffer,
                      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
-                     " EmbryonicRsts PruneCalled RcvPruned OfoPruned\n"
-                     "TcpExt: %lu %lu %lu %lu %lu %lu %lu\n",
+                     " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
+                     " OutOfWindowIcmps LockDroppedIcmps\n"    
+                     "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
                      net_statistics.SyncookiesSent,
                      net_statistics.SyncookiesRecv,
                      net_statistics.SyncookiesFailed,
                      net_statistics.EmbryonicRsts,
                      net_statistics.PruneCalled,
                      net_statistics.RcvPruned,
-                     net_statistics.OfoPruned);
+                     net_statistics.OfoPruned,
+                     net_statistics.OutOfWindowIcmps,
+                     net_statistics.LockDroppedIcmps);
 
        if (offset >= len)
        {
index e10ddc0dd385edce21f8f446ff9ed0ba919e9c32..2700e95906b5d135c0f2cda6c24728de73dff26b 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             RAW - implementation of IP "raw" sockets.
  *
- * Version:    $Id: raw.c,v 1.37 1998/08/26 12:04:07 davem Exp $
+ * Version:    $Id: raw.c,v 1.38 1998/10/03 09:37:45 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -143,26 +143,53 @@ struct sock *raw_v4_lookup(struct sock *sk, unsigned short num,
        return s;
 }
 
-/*
- *     Raw_err does not currently get called by the icmp module - FIXME:
- */
 void raw_err (struct sock *sk, struct sk_buff *skb)
 {
        int type = skb->h.icmph->type;
        int code = skb->h.icmph->code;
-
-       if (sk->ip_recverr) {
-               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-               if (skb2 && sock_queue_err_skb(sk, skb2))
-                       kfree_skb(skb);
+       u32 info = 0;
+       int err = 0;
+       int harderr = 0;
+
+       /* Report error on raw socket, if:
+          1. User requested ip_recverr.
+          2. Socket is connected (otherwise the error indication
+             is useless without ip_recverr and error is hard.
+        */
+       if (!sk->ip_recverr && sk->state != TCP_ESTABLISHED)
+               return;
+
+       switch (type) {
+       default:
+       case ICMP_TIME_EXCEEDED:
+               err = EHOSTUNREACH;
+               break;
+       case ICMP_SOURCE_QUENCH:
+               return;
+       case ICMP_PARAMETERPROB:
+               err = EPROTO;
+               info = ntohl(skb->h.icmph->un.gateway)>>24;
+               harderr = 1;
+               break;
+       case ICMP_DEST_UNREACH:
+               err = EHOSTUNREACH;
+               if (code > NR_ICMP_UNREACH)
+                       break;
+               err = icmp_err_convert[code].errno;
+               harderr = icmp_err_convert[code].fatal;
+               if (code == ICMP_FRAG_NEEDED) {
+                       harderr = (sk->ip_pmtudisc != IP_PMTUDISC_DONT);
+                       err = EMSGSIZE;
+                       info = ntohs(skb->h.icmph->un.frag.mtu);
+               }
        }
 
-       if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-               if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
-                       sk->err = EMSGSIZE;
-                       sk->error_report(sk);
-               }
+       if (sk->ip_recverr)
+               ip_icmp_error(sk, skb, err, 0, info, (u8 *)(skb->h.icmph + 1));
+               
+       if (sk->ip_recverr || harderr) {
+               sk->err = err;
+               sk->error_report(sk);
        }
 }
 
@@ -170,7 +197,7 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
 {
        /* Charge it to the socket. */
        
-       if (__sock_queue_rcv_skb(sk,skb)<0)
+       if (sock_queue_rcv_skb(sk,skb)<0)
        {
                ip_statistics.IpInDiscards++;
                kfree_skb(skb);
@@ -443,23 +470,12 @@ int raw_recvmsg(struct sock *sk, struct msghdr *msg, int len,
 
        if (flags & MSG_OOB)
                return -EOPNOTSUPP;
-               
-       if (sk->shutdown & RCV_SHUTDOWN) 
-               return(0);
 
        if (addr_len)
                *addr_len=sizeof(*sin);
 
-       if (sk->ip_recverr && (skb = skb_dequeue(&sk->error_queue)) != NULL) {
-               err = sock_error(sk);
-               if (msg->msg_controllen == 0) {
-                       skb_free_datagram(sk, skb);
-                       return err;
-               }
-               put_cmsg(msg, SOL_IP, IP_RECVERR, skb->len, skb->data);
-               skb_free_datagram(sk, skb);
-               return 0;
-       }
+       if (flags & MSG_ERRQUEUE)
+               return ip_recv_error(sk, msg, len);
 
        skb=skb_recv_datagram(sk,flags,noblock,&err);
        if(skb==NULL)
index 5788342c9a45fe09a77e731b2797d4bbe0a51c23..a3d002fae6273bb3e6332e268e03cea3afddf907 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             ROUTE - implementation of the IP router.
  *
- * Version:    $Id: route.c,v 1.57 1998/08/26 12:04:09 davem Exp $
+ * Version:    $Id: route.c,v 1.58 1998/10/03 09:37:50 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -333,7 +333,7 @@ void rt_cache_flush(int delay)
                   otherwise fire it at deadline time.
                 */
 
-               if (user_mode && (long)(rt_deadline-now) < ip_rt_max_delay-ip_rt_min_delay)
+               if (user_mode && tmo < ip_rt_max_delay-ip_rt_min_delay)
                        tmo = 0;
                
                if (delay > tmo)
@@ -432,7 +432,7 @@ static struct rtable *rt_intern_hash(unsigned hash, struct rtable * rt)
                rthp = &rth->u.rt_next;
        }
 
-       /* Try to bind route ro arp only if it is output
+       /* Try to bind route to arp only if it is output
           route or unicast forwarding path.
         */
        if (rt->rt_type == RTN_UNICAST || rt->key.iif == 0)
@@ -569,12 +569,26 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
        struct rtable *rt = (struct rtable*)dst;
 
        if (rt != NULL) {
-               if (dst->obsolete || rt->rt_flags&RTCF_REDIRECTED) {
+               if (dst->obsolete) {
+                       ip_rt_put(rt);
+                       return NULL;
+               }
+               if (rt->rt_flags&RTCF_REDIRECTED) {
+                       unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos);
+                       struct rtable **rthp;
 #if RT_CACHE_DEBUG >= 1
                        printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos);
 #endif
                        ip_rt_put(rt);
-                       rt_cache_flush(0);
+                       start_bh_atomic();
+                       for (rthp = &rt_hash_table[hash]; *rthp; rthp = &(*rthp)->u.rt_next) {
+                               if (*rthp == rt) {
+                                       *rthp = rt->u.rt_next;
+                                       rt_free(rt);
+                                       break;
+                               }
+                       }
+                       end_bh_atomic();
                        return NULL;
                }
        }
@@ -654,12 +668,12 @@ static int ip_error(struct sk_buff *skb)
        }
 
        now = jiffies;
-       if ((rt->u.dst.rate_tokens += now - rt->u.dst.rate_last) > ip_rt_error_burst)
+       if ((rt->u.dst.rate_tokens += (now - rt->u.dst.rate_last)) > ip_rt_error_burst)
                rt->u.dst.rate_tokens = ip_rt_error_burst;
+       rt->u.dst.rate_last = now;
        if (rt->u.dst.rate_tokens >= ip_rt_error_cost) {
                rt->u.dst.rate_tokens -= ip_rt_error_cost;
                icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
-               rt->u.dst.rate_last = now;
        }
 
        kfree_skb(skb);
@@ -1004,8 +1018,8 @@ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
                flags |= RTCF_DOREDIRECT;
 
        if (skb->protocol != __constant_htons(ETH_P_IP)) {
-               /* Not IP (i.e. ARP). Do not make route for invalid
-                * destination AND it is not translated destination.
+               /* Not IP (i.e. ARP). Do not create route, if it is
+                * invalid for proxy arp. DNAT routes are always valid.
                 */
                if (out_dev == in_dev && !(flags&RTCF_DNAT))
                        return -EINVAL;
@@ -1069,6 +1083,7 @@ brd_input:
                        flags |= RTCF_DIRECTSRC;
        }
        flags |= RTCF_BROADCAST;
+       res.type = RTN_BROADCAST;
 
 local_input:
        rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
@@ -1227,7 +1242,7 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                   if address is local --- clear the flag.
                 */
                if (dev_out == NULL) {
-                       if (nochecksrc == 0)
+                       if (nochecksrc == 0 || inet_addr_type(saddr) != RTN_UNICAST)
                                return -EINVAL;
                        flags |= RTCF_TPROXY;
                }
@@ -1251,7 +1266,7 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                        (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) {
                        /* Special hack: user can direct multicasts
                           and limited broadcast via necessary interface
-                          without fiddling with IP_MULTICAST_IF or IP_TXINFO.
+                          without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
                           This hack is not just for fun, it allows
                           vic,vat and friends to work.
                           They bind socket to loopback, set ttl to zero
@@ -1280,11 +1295,9 @@ int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int
                        key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
                        goto make_route;
                }
-               if (MULTICAST(daddr)) {
+               if (MULTICAST(daddr))
                        key.src = inet_select_addr(dev_out, 0, key.scope);
-                       goto make_route;
-               }
-               if (!daddr)
+               else if (!daddr)
                        key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
        }
 
@@ -1378,13 +1391,18 @@ make_route:
                flags |= RTCF_LOCAL;
 
        if (res.type == RTN_BROADCAST) {
-               flags |= RTCF_BROADCAST;
-               if (dev_out->flags&IFF_BROADCAST)
-                       flags |= RTCF_LOCAL;
+               flags |= RTCF_BROADCAST|RTCF_LOCAL;
+               res.fi = NULL;
        } else if (res.type == RTN_MULTICAST) {
                flags |= RTCF_MULTICAST|RTCF_LOCAL;
                if (!ip_check_mc(dev_out, daddr))
                        flags &= ~RTCF_LOCAL;
+               /* If multicast route do not exist use
+                  default one, but do not gateway in this case.
+                  Yes, it is hack.
+                */
+               if (res.fi && res.prefixlen < 4)
+                       res.fi = NULL;
        }
 
        rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
index 65bc5f0fc55c748479a27b307403f86e92808b56..ba75608e42fcb605bf06af1087c612e51b3bf397 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.34 1998/04/11 09:38:26 freitag Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.35 1998/10/03 09:37:54 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -43,7 +43,6 @@ extern int sysctl_ip_dynaddr;
 /* From ip_masq.c */
 extern int sysctl_ip_masq_debug;
 
-extern int sysctl_tcp_cong_avoidance;
 extern int sysctl_tcp_hoe_retransmits;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
index 14a244b7e3224ebcccc913a3424f3a14a2f63e58..25b7bbf9f95c6e601e7ca63ffbbdacb8bf0ff16e 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp.c,v 1.121 1998/09/07 00:13:52 davem Exp $
+ * Version:    $Id: tcp.c,v 1.127 1998/10/04 07:04:32 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *   MUST use the RFC 793 clock selection mechanism.  (doesn't, but it's
  *     OK: RFC 793 specifies a 250KHz clock, while we use 1MHz, which is
  *     necessary for 10Mbps networks - and harder than BSD to spoof!
- *     With syncookies we doesn't)
+ *     With syncookies we don't)
  *
  * Simultaneous Open Attempts (4.2.2.10)
  *   MUST support simultaneous open attempts (does)
@@ -598,8 +598,13 @@ unsigned int tcp_poll(struct file * file, struct socket *sock, poll_table *wait)
                     sk->urginline || !tp->urg_data))
                        mask |= POLLIN | POLLRDNORM;
 
-               if (sock_wspace(sk) >= tcp_min_write_space(sk, tp))
-                       mask |= POLLOUT | POLLWRNORM;
+               if (!(sk->shutdown & SEND_SHUTDOWN)) {
+                       if (sock_wspace(sk) >= tcp_min_write_space(sk, tp)) {
+                               mask |= POLLOUT | POLLWRNORM;
+                       } else {  /* send SIGIO later */
+                               sk->socket->flags |= SO_NOSPACE;
+                       }
+               }
 
                if (tp->urg_data & URG_VALID)
                        mask |= POLLPRI;
@@ -729,6 +734,9 @@ static void wait_for_tcp_memory(struct sock * sk)
        lock_sock(sk);
 }
 
+/* When all user supplied data has been queued set the PSH bit */
+#define PSH_NEEDED (seglen == 0 && iovlen == 0)
+
 /*
  *     This routine copies from a user buffer into a socket,
  *     and starts the transmit system.
@@ -742,16 +750,16 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
        int mss_now;
        int err = 0;
        int copied  = 0;
-
-       /* Verify that the socket is locked */
-       if (!atomic_read(&sk->sock_readers))
-               printk("tcp_do_sendmsg: socket not locked!\n");
+       struct sk_buff *skb;
 
        /* Wait for a connection to finish. */
        if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
                if((err = wait_for_tcp_connect(sk, flags)) != 0)
                        return err;
 
+       /* This should be in poll */
+       sk->socket->flags &= ~SO_NOSPACE; /* clear SIGIO XXX */
+
        mss_now = tcp_current_mss(sk);
 
        /* Ok commence sending. */
@@ -763,10 +771,9 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
 
                while(seglen > 0) {
                        int copy, tmp, queue_it;
-                       struct sk_buff *skb;
 
                        if (err)
-                               return -EFAULT;
+                               goto do_fault2;
 
                        /* Stop on errors. */
                        if (sk->err)
@@ -810,12 +817,24 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                                                        from, skb_put(skb, copy),
                                                        copy, skb->csum, &err);
                                        }
+                                       /*
+                                        * FIXME: the *_user functions should
+                                        *        return how much data was
+                                        *        copied before the fault
+                                        *        occured and then a partial
+                                        *        packet with this data should
+                                        *        be sent.  Unfortunately
+                                        *        csum_and_copy_from_user doesn't
+                                        *        return this information.
+                                        *        ATM it might send partly zeroed
+                                        *        data in this case.
+                                        */
                                        tp->write_seq += copy;
                                        TCP_SKB_CB(skb)->end_seq += copy;
                                        from += copy;
                                        copied += copy;
                                        seglen -= copy;
-                                       if(!seglen && !iovlen)
+                                       if (PSH_NEEDED)
                                                TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
                                        continue;
                                }
@@ -884,7 +903,7 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
 
                        /* Prepare control bits for TCP header creation engine. */
                        TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK |
-                                                 ((!seglen && !iovlen) ?
+                                                 (PSH_NEEDED ?
                                                   TCPCB_FLAG_PSH : 0));
                        TCP_SKB_CB(skb)->sacked = 0;
                        if (flags & MSG_OOB) {
@@ -901,6 +920,9 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                        skb->csum = csum_and_copy_from_user(from,
                                        skb_put(skb, copy), copy, 0, &err);
 
+                       if (err)
+                               goto do_fault;
+
                        from += copy;
                        copied += copy;
 
@@ -912,8 +934,6 @@ int tcp_do_sendmsg(struct sock *sk, int iovlen, struct iovec *iov, int flags)
                }
        }
        sk->err = 0;
-       if (err)
-               return -EFAULT;
        return copied;
 
 do_sock_err:
@@ -930,8 +950,14 @@ do_interrupted:
        if(copied)
                return copied;
        return err;
+do_fault:
+       kfree_skb(skb);
+do_fault2:
+       return -EFAULT;
 }
 
+#undef PSH_NEEDED
+
 /*
  *     Send an ack if one is backlogged at this point. Ought to merge
  *     this with tcp_send_ack().
@@ -1046,8 +1072,6 @@ static void cleanup_rbuf(struct sock *sk, int copied)
                tcp_eat_skb(sk, skb);
        }
 
-       SOCK_DEBUG(sk, "sk->rspace = %lu\n", sock_rspace(sk));
-
        /* We send an ACK if we can now advertise a non-zero window
         * which has been raised "significantly".
         */
@@ -1084,6 +1108,9 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
        int err = 0; 
        int target = 1;         /* Read at least this many bytes */
 
+       if (sk->err)
+               return sock_error(sk);
+
        if (sk->state == TCP_LISTEN)
                return -ENOTCONN;
 
@@ -1165,6 +1192,14 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg,
                if (copied >= target)
                        break;
 
+               /*
+                  These three lines and clause if (sk->state == TCP_CLOSE)
+                  are unlikely to be correct, if target > 1.
+                  I DO NOT FIX IT, because I have no idea, what
+                  POSIX prescribes to make here. Probably, it really
+                  wants to lose data 8), if not all target is received.
+                                                                --ANK
+                */
                if (sk->err && !(flags&MSG_PEEK)) {
                        copied = sock_error(sk);
                        break;
@@ -1589,7 +1624,10 @@ struct sock *tcp_accept(struct sock *sk, int flags)
         * This does not pass any already set errors on the new socket
         * to the user, but they will be returned on the first socket operation
         * after the accept.
-        */ 
+        *
+        * Once linux gets a multithreaded net_bh or equivalent there will be a race
+        * here - you'll have to check for sk->zapped as set by the ICMP handler then.
+        */
 
        error = 0;
 out:
index fae5a267e2f10f26ce0d1b262e13bcfcaeaf9f7c..32a9f91eaaad87fa75038fd2f5533b0993a32719 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.128 1998/09/15 02:11:18 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.130 1998/10/04 07:06:47 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -77,7 +77,6 @@ int sysctl_tcp_window_scaling = 1;
 int sysctl_tcp_sack = 1;
 int sysctl_tcp_hoe_retransmits = 1;
 
-int sysctl_tcp_cong_avoidance;
 int sysctl_tcp_syncookies = SYNC_INIT; 
 int sysctl_tcp_stdurg;
 int sysctl_tcp_rfc1337;
@@ -120,6 +119,18 @@ static void tcp_delack_estimator(struct tcp_opt *tp)
        }
 }
 
+/* 
+ * Remember to send an ACK later.
+ */
+static __inline__ void tcp_remember_ack(struct tcp_opt *tp, struct tcphdr *th, 
+                                       struct sk_buff *skb)
+{
+       tp->delayed_acks++; 
+       /* Tiny-grams with PSH set make us ACK quickly. */
+       if(th->psh && (skb->len < (tp->mss_cache >> 1)))
+               tp->ato = HZ/50;
+} 
+
 /* Called to compute a smoothed rtt estimate. The data fed to this
  * routine either comes from timestamps, or from segments that were
  * known _not_ to have been retransmitted [see Karn/Partridge
@@ -693,7 +704,7 @@ static void tcp_ack_saw_tstamp(struct sock *sk, struct tcp_opt *tp,
        tcp_bound_rto(tp);
 }
 
-static void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
+static __inline__ void tcp_ack_packets_out(struct sock *sk, struct tcp_opt *tp)
 {
        struct sk_buff *skb = skb_peek(&sk->write_queue);
        long when = tp->rto - (jiffies - TCP_SKB_CB(skb)->when);
@@ -1153,6 +1164,10 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        struct tcp_sack_block *sp = &tp->selective_acks[0];
+       int cur_sacks = tp->num_sacks;
+
+       if (!cur_sacks)
+               goto new_sack;
 
        /* Optimize for the common case, new ofo frames arrive
         * "in order". ;-)  This also satisfies the requirements
@@ -1168,34 +1183,36 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
                sp->start_seq = TCP_SKB_CB(skb)->seq;
                tcp_sack_maybe_coalesce(tp, sp);
        } else {
-               int cur_sacks = tp->num_sacks;
-               int max_sacks = (tp->tstamp_ok ? 3 : 4);
+               struct tcp_sack_block *swap = sp + 1;
+               int this_sack, max_sacks = (tp->tstamp_ok ? 3 : 4);
 
                /* Oh well, we have to move things around.
                 * Try to find a SACK we can tack this onto.
                 */
-               if(cur_sacks > 1) {
-                       struct tcp_sack_block *swap = sp + 1;
-                       int this_sack;
-
-                       for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) {
-                               if((swap->end_seq == TCP_SKB_CB(skb)->seq) ||
-                                  (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) {
-                                       if(swap->end_seq == TCP_SKB_CB(skb)->seq)
-                                               swap->end_seq = TCP_SKB_CB(skb)->end_seq;
-                                       else
-                                               swap->start_seq = TCP_SKB_CB(skb)->seq;
-                                       tcp_sack_swap(sp, swap);
-                                       tcp_sack_maybe_coalesce(tp, sp);
-                                       return;
-                               }
+
+               for(this_sack = 1; this_sack < cur_sacks; this_sack++, swap++) {
+                       if((swap->end_seq == TCP_SKB_CB(skb)->seq) ||
+                          (swap->start_seq == TCP_SKB_CB(skb)->end_seq)) {
+                               if(swap->end_seq == TCP_SKB_CB(skb)->seq)
+                                       swap->end_seq = TCP_SKB_CB(skb)->end_seq;
+                               else
+                                       swap->start_seq = TCP_SKB_CB(skb)->seq;
+                               tcp_sack_swap(sp, swap);
+                               tcp_sack_maybe_coalesce(tp, sp);
+                               return;
                        }
                }
 
                /* Could not find an adjacent existing SACK, build a new one,
                 * put it at the front, and shift everyone else down.  We
                 * always know there is at least one SACK present already here.
+                *
+                * If the sack array is full, forget about the last one.
                 */
+               if (cur_sacks >= max_sacks) {
+                       cur_sacks--;
+                       tp->num_sacks--;
+               }
                while(cur_sacks >= 1) {
                        struct tcp_sack_block *this = &tp->selective_acks[cur_sacks];
                        struct tcp_sack_block *prev = (this - 1);
@@ -1204,11 +1221,11 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, struct sk_buff *skb)
                        cur_sacks--;
                }
 
-               /* Build head SACK, and we're done. */
+       new_sack:
+               /* Build the new head SACK, and we're done. */
                sp->start_seq = TCP_SKB_CB(skb)->seq;
                sp->end_seq = TCP_SKB_CB(skb)->end_seq;
-               if(tp->num_sacks < max_sacks)
-                       tp->num_sacks++;
+               tp->num_sacks++;
        }
 }
 
@@ -1313,16 +1330,14 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
                if(skb->h.th->fin) {
                        tcp_fin(skb, sk, skb->h.th);
                } else {
-                       tp->delayed_acks++;
-
-                       /* Tiny-grams with PSH set make us ACK quickly. */
-                       if(skb->h.th->psh && (skb->len < (tp->mss_cache >> 1)))
-                               tp->ato = HZ/50;
+                       tcp_remember_ack(tp, skb->h.th, skb); 
                }
                /* This may have eaten into a SACK block. */
                if(tp->sack_ok && tp->num_sacks)
                        tcp_sack_remove_skb(tp, skb);
                tcp_ofo_queue(sk);
+
+               /* Turn on fast path. */ 
                if (skb_queue_len(&tp->out_of_order_queue) == 0)
                        tp->pred_flags = htonl(((tp->tcp_header_len >> 2) << 28) |
                                               (0x10 << 16) |
@@ -1453,23 +1468,28 @@ static int tcp_data(struct sk_buff *skb, struct sock *sk, unsigned int len)
        return(1);
 }
 
-static void tcp_data_snd_check(struct sock *sk)
+static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       struct sk_buff *skb;
 
-       if ((skb = tp->send_head)) {
-               if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
-                   tcp_packets_in_flight(tp) < tp->snd_cwnd) {
-                       /* Put more data onto the wire. */
-                       tcp_write_xmit(sk);
-               } else if (tp->packets_out == 0 && !tp->pending) {
-                       /* Start probing the receivers window. */
-                       tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
-               }
+       if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) &&
+           tcp_packets_in_flight(tp) < tp->snd_cwnd) {
+               /* Put more data onto the wire. */
+               tcp_write_xmit(sk);
+       } else if (tp->packets_out == 0 && !tp->pending) {
+               /* Start probing the receivers window. */
+               tcp_reset_xmit_timer(sk, TIME_PROBE0, tp->rto);
        }
 }
 
+static __inline__ void tcp_data_snd_check(struct sock *sk)
+{
+       struct sk_buff *skb = sk->tp_pinfo.af_tcp.send_head;
+
+       if (skb != NULL)
+               __tcp_data_snd_check(sk, skb); 
+}
+
 /* 
  * Adapt the MSS value used to make delayed ack decision to the 
  * real world. 
@@ -1664,11 +1684,33 @@ static int prune_queue(struct sock *sk)
        return 0;
 }
 
+/*
+ *     TCP receive function for the ESTABLISHED state. 
+ *
+ *     It is split into a fast path and a slow path. The fast path is 
+ *     disabled when:
+ *     - A zero window was announced from us - zero window probing
+ *        is only handled properly in the slow path. 
+ *      - Out of order segments arrived.
+ *     - Urgent data is expected.
+ *     - There is no buffer space left
+ *     - Unexpected TCP flags/window values/header lengths are received
+ *       (detected by checking the TCP header against pred_flags) 
+ *     - Data is sent in both directions. Fast path only supports pure senders
+ *       or pure receivers (this means either the sequence number or the ack
+ *       value must stay constant)
+ *
+ *     When these conditions are not satisfied it drops into a standard 
+ *     receive procedure patterned after RFC793 to handle all cases.
+ *     The first three cases are guaranteed by proper pred_flags setting,
+ *     the rest is checked inline. Fast processing is turned on in 
+ *     tcp_data_queue when everything is OK.
+ */
 int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        struct tcphdr *th, unsigned len)
 {
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-       int queued = 0;
+       int queued;
        u32 flg;
 
        /*
@@ -1711,7 +1753,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
         *      '?' will be 0 else it will be !0
         *      (when there are holes in the receive 
         *       space for instance)
-        */
+         */
 
        if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
                if (len <= th->doff*4) {
@@ -1726,18 +1768,9 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                tcp_statistics.TcpInErrs++;
                                goto discard;
                        }
-               } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
-                       /* Bulk data transfer: receiver
-                        *
-                        * Check if the segment is out-of-window.
-                        * It may be a zero window probe.
-                        */
-                       if (!before(TCP_SKB_CB(skb)->seq,
-                                       tp->rcv_wup + tp->rcv_wnd))
-                               goto unacceptable_packet;
-                       if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
-                               goto discard;
-                       
+               } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una &&
+                       atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
+                       /* Bulk data transfer: receiver */
                        __skb_pull(skb,th->doff*4);
 
                        tcp_measure_rcv_mss(sk, skb); 
@@ -1754,16 +1787,17 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        sk->data_ready(sk, 0);
                        tcp_delack_estimator(tp);
 
-                       /* Tiny-grams with PSH set make us ACK quickly. */
-                       if(th->psh && (skb->len < (tp->mss_cache >> 1)))
-                               tp->ato = HZ/50;
+                       tcp_remember_ack(tp, th, skb); 
 
-                       tp->delayed_acks++;
                        __tcp_ack_snd_check(sk);
                        return 0;
                }
        }
 
+       /*
+        *      Standard slow path.
+        */
+
        if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
                /* RFC793, page 37: "In all states except SYN-SENT, all reset
                 * (RST) segments are validated by checking their SEQ-fields."
@@ -1778,7 +1812,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                                   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
                                   tp->rcv_wup, tp->rcv_wnd);
                }
-unacceptable_packet:
                tcp_send_ack(sk);
                goto discard;
        }
@@ -1838,7 +1871,8 @@ unacceptable_packet:
 }
 
 /* 
- *     Process an incoming SYN or SYN-ACK.
+ *     Process an incoming SYN or SYN-ACK for SYN_RECV sockets represented
+ *     as an open_request. 
  */
 
 struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, 
@@ -1903,7 +1937,8 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
 }
 
 /*
- *     This function implements the receiving procedure of RFC 793.
+ *     This function implements the receiving procedure of RFC 793 for
+ *     all states except ESTABLISHED and TIME_WAIT. 
  *     It's called from both tcp_v4_rcv and tcp_v6_rcv and should be
  *     address independent.
  */
index 104c59ee520cd7fff49062bce109a6802aa73d54..728bfdb5c365009e9fa6d3d83468e02269e55b74 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_ipv4.c,v 1.160 1998/09/15 02:11:27 davem Exp $
+ * Version:    $Id: tcp_ipv4.c,v 1.161 1998/10/03 09:38:05 davem Exp $
  *
  *             IPv4 specific functions
  *
@@ -594,7 +594,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        }
 
        tmp = ip_route_connect(&rt, nexthop, sk->saddr,
-                              RT_TOS(sk->ip_tos)|sk->localroute, sk->bound_dev_if);
+                              RT_TOS(sk->ip_tos)|RTO_CONN|sk->localroute, sk->bound_dev_if);
        if (tmp < 0)
                return tmp;
 
@@ -642,9 +642,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
        /* Reset mss clamp */
        tp->mss_clamp = ~0;
 
-       if ((sk->ip_pmtudisc == IP_PMTUDISC_DONT ||
-            (sk->ip_pmtudisc == IP_PMTUDISC_WANT &&
-             (rt->u.dst.mxlock&(1<<RTAX_MTU)))) &&
+       if (!ip_dont_fragment(sk, &rt->u.dst) &&
            rt->u.dst.pmtu > 576 && rt->rt_dst != rt->rt_gateway) {
                /* Clamp mss at maximum of 536 and user_mss.
                   Probably, user ordered to override tiny segment size
@@ -716,7 +714,11 @@ static struct open_request *tcp_v4_search_req(struct tcp_opt *tp,
        for (req = prev->dl_next; req; req = req->dl_next) {
                if (req->af.v4_req.rmt_addr == iph->saddr &&
                    req->af.v4_req.loc_addr == iph->daddr &&
-                   req->rmt_port == rport) {
+                   req->rmt_port == rport
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+                   && req->lcl_port == th->dest
+#endif
+                   ) {
                        *prevp = prev; 
                        return req; 
                }
@@ -776,6 +778,8 @@ static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *ip)
  * and for some paths there is no check at all.
  * A more general error queue to queue errors for later handling
  * is probably better.
+ *
+ * sk->err and sk->err_soft should be atomic_t.
  */
 
 void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
@@ -786,8 +790,8 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
        int type = skb->h.icmph->type;
        int code = skb->h.icmph->code;
        struct sock *sk;
-       int opening;
        __u32 seq;
+       int err;
 
        if (len < (iph->ihl << 2) + ICMP_MIN_LENGTH) { 
                icmp_statistics.IcmpInErrors++; 
@@ -804,13 +808,8 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
 
        tp = &sk->tp_pinfo.af_tcp;
        seq = ntohl(th->seq);
-       if (sk->state != TCP_LISTEN && 
-           !between(seq, tp->snd_una-16384, max(tp->snd_una+32768,tp->snd_nxt))) {
-               if (net_ratelimit()) 
-                       printk(KERN_WARNING 
-                               "icmp packet outside the tcp window:"
-                               " state:%d seq:%u win:%u,%u\n",
-                              (int)sk->state, seq, tp->snd_una, tp->snd_nxt); 
+       if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
+               net_statistics.OutOfWindowIcmps++;
                return; 
        }
 
@@ -824,24 +823,26 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
 #endif
                return;
        case ICMP_PARAMETERPROB:
-               sk->err=EPROTO;
-               sk->error_report(sk); /* This isn't serialized on SMP! */
+               err = EPROTO;
                break; 
        case ICMP_DEST_UNREACH:
+               if (code > NR_ICMP_UNREACH)
+                       return;
+
                if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
                        do_pmtu_discovery(sk, iph); 
-                       return; 
+                       return;
                }
-               break; 
-       }
 
-       /* If we've already connected we will keep trying
-        * until we time out, or the user gives up.
-        */
-       if (code > NR_ICMP_UNREACH)
+               err = icmp_err_convert[code].errno;
+               break;
+       case ICMP_TIME_EXCEEDED:
+               err = EHOSTUNREACH;
+               break;
+       default:
                return;
-       opening = 0; 
+       }
+
        switch (sk->state) {
                struct open_request *req, *prev;
        case TCP_LISTEN:
@@ -849,10 +850,10 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                 * ICMP is unreliable. 
                 */
                if (atomic_read(&sk->sock_readers)) {
-                       /* XXX: add a counter here to profile this. 
-                        * If too many ICMPs get dropped on busy
-                        * servers this needs to be solved differently.
-                        */
+                       net_statistics.LockDroppedIcmps++;
+                        /* If too many ICMPs get dropped on busy
+                         * servers this needs to be solved differently.
+                         */
                        return;
                }
 
@@ -869,10 +870,7 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                if (!req)
                        return;
                if (seq != req->snt_isn) {
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "icmp packet for openreq "
-                                      "with wrong seq number:%d:%d\n",
-                                      seq, req->snt_isn);
+                       net_statistics.OutOfWindowIcmps++;
                        return;
                }
                if (req->sk) {  
@@ -899,25 +897,43 @@ void tcp_v4_err(struct sk_buff *skb, unsigned char *dp, int len)
                }
                break;
        case TCP_SYN_SENT:
-       case TCP_SYN_RECV: 
+       case TCP_SYN_RECV:  /* Cannot happen */ 
                if (!th->syn)
-                       return; 
-               opening = 1; 
-               break;
+                       return;
+               tcp_statistics.TcpAttemptFails++;
+               sk->err = err;
+               sk->zapped = 1;
+               mb();
+               sk->error_report(sk);
+               return;
        }
-       
-       if(icmp_err_convert[code].fatal || opening) {
+
+       /* If we've already connected we will keep trying
+        * until we time out, or the user gives up.
+        *
+        * rfc1122 4.2.3.9 allows to consider as hard errors
+        * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too,
+        * but it is obsoleted by pmtu discovery).
+        *
+        * Note, that in modern internet, where routing is unreliable
+        * and in each dark corner broken firewalls sit, sending random
+        * errors ordered by their masters even this two messages finally lose
+        * their original sense (even Linux sends invalid PORT_UNREACHs)
+        *
+        * Now we are in compliance with RFCs.
+        *                                                      --ANK (980905)
+        */
+
+       if (sk->ip_recverr) {
                /* This code isn't serialized with the socket code */
-               sk->err = icmp_err_convert[code].errno;
-               if (opening) {
-                       tcp_statistics.TcpAttemptFails++;
-                       if (sk->state != TCP_LISTEN)
-                               tcp_set_state(sk,TCP_CLOSE);
-                       mb(); 
-                       sk->error_report(sk);           /* Wake people up to see the error (see connect in sock.c) */
-               }
+               /* ANK (980927) ... which is harmless now,
+                  sk->err's may be safely lost.
+                */
+               sk->err = err;
+               mb(); 
+               sk->error_report(sk);           /* Wake people up to see the error (see connect in sock.c) */
        } else  { /* Only an error on timeout */
-               sk->err_soft = icmp_err_convert[code].errno;
+               sk->err_soft = err;
                mb(); 
        }
 }
@@ -952,7 +968,16 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
 
        /* Never send a reset in response to a reset. */
        if (th->rst)
-               return; 
+               return;
+
+       if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL) {
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+               if (((struct rtable*)skb->dst)->rt_type == RTN_UNICAST)
+                       icmp_send(skb, ICMP_DEST_UNREACH,
+                                 ICMP_PORT_UNREACH, 0);
+#endif
+               return;
+       }
 
        /* Swap the send and the receive. */
        memset(&rth, 0, sizeof(struct tcphdr)); 
@@ -986,6 +1011,33 @@ static void tcp_v4_send_reset(struct sk_buff *skb)
 }
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
+
+/*
+   Seems, I never wrote nothing more stupid.
+   I hope Gods will forgive me, but I cannot forgive myself 8)
+                                                --ANK (981001)
+ */
+
+static struct sock *tcp_v4_search_proxy_openreq(struct sk_buff *skb)
+{
+       struct iphdr *iph = skb->nh.iph;
+       struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
+       struct sock *sk;
+       int i;
+
+       for (i=0; i<TCP_LHTABLE_SIZE; i++) {
+               for(sk = tcp_listening_hash[i]; sk; sk = sk->next) {
+                       struct open_request *dummy;
+                       if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, iph,
+                                             th, &dummy) &&
+                           (!sk->bound_dev_if ||
+                            sk->bound_dev_if == skb->dev->ifindex))
+                               return sk;
+               }
+       }
+       return NULL;
+}
+
 /*
  *     Check whether a received TCP packet might be for one of our
  *     connections.
@@ -997,10 +1049,20 @@ int tcp_chkaddr(struct sk_buff *skb)
        struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
        struct sock *sk;
 
-       sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr, th->dest, skb->dev->ifindex);
+       sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr,
+                          th->dest, skb->dev->ifindex);
 
        if (!sk)
-               return 0;
+               return tcp_v4_search_proxy_openreq(skb) != NULL;
+
+       if (sk->state == TCP_LISTEN) {
+               struct open_request *dummy;
+               if (tcp_v4_search_req(&sk->tp_pinfo.af_tcp, skb->nh.iph,
+                                     th, &dummy) &&
+                   (!sk->bound_dev_if ||
+                    sk->bound_dev_if == skb->dev->ifindex))
+                       return 1;
+       }
 
        /* 0 means accept all LOCAL addresses here, not all the world... */
 
@@ -1597,10 +1659,15 @@ int tcp_v4_rcv(struct sk_buff *skb, unsigned short len)
                sk = tcp_v4_proxy_lookup(th->dest, skb->nh.iph->saddr, th->source,
                                         skb->nh.iph->daddr, skb->dev,
                                         IPCB(skb)->redirport, skb->dev->ifindex);
-       else
+       else {
+#endif
+               sk = __tcp_v4_lookup(th, skb->nh.iph->saddr, th->source,
+                                    skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+               if (!sk)
+                       sk = tcp_v4_search_proxy_openreq(skb);
+       }
 #endif
-       sk = __tcp_v4_lookup(th, skb->nh.iph->saddr, th->source,
-                            skb->nh.iph->daddr, th->dest, skb->dev->ifindex);
        if (!sk)
                goto no_tcp_socket;
        if(!ipsec_sk_policy(sk,skb))
index 6b7eac22ac84c791af0b64e024cb6e1cf5f9f339..3e1ebfa4f201a844833d8ad52eaff0a5c42ec494 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_output.c,v 1.94 1998/09/15 02:11:36 davem Exp $
+ * Version:    $Id: tcp_output.c,v 1.95 1998/09/27 12:57:13 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -414,6 +414,7 @@ u32 __tcp_select_window(struct sock *sk, u32 cur_win)
        
        if ((free_space < (sk->rcvbuf/4)) && (free_space < ((int) (mss/2)))) {
                window = 0;
+               tp->pred_flags = 0; 
        } else {
                /* Get the largest window that is a nice multiple of mss.
                 * Window clamp already applied above.
index 5d9b7837ff9ff2b686cfbdc82adc28e81c4f0fa7..b03ed24cfd1c3480ce7bed5ac4c4b8f554032797 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             The User Datagram Protocol (UDP).
  *
- * Version:    $Id: udp.c,v 1.62 1998/09/15 02:11:32 davem Exp $
+ * Version:    $Id: udp.c,v 1.63 1998/10/03 09:38:16 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -481,6 +481,9 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
        int type = skb->h.icmph->type;
        int code = skb->h.icmph->code;
        struct sock *sk;
+       int harderr;
+       u32 info;
+       int err;
 
        if (len < (iph->ihl<<2)+sizeof(struct udphdr)) {
                icmp_statistics.IcmpInErrors++;
@@ -493,36 +496,40 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
                return; /* No socket for error */
        }
 
-       if (sk->ip_recverr && !atomic_read(&sk->sock_readers)) {
-               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
-               if (skb2 && sock_queue_err_skb(sk, skb2))
-                       kfree_skb(skb2);
-       }
-       
+       err = 0;
+       info = 0;
+       harderr = 0;
+
        switch (type) {
+       default:
        case ICMP_TIME_EXCEEDED:
+               err = EHOSTUNREACH;
+               break;
        case ICMP_SOURCE_QUENCH:
                return;
        case ICMP_PARAMETERPROB:
-               sk->err = EPROTO;
-               sk->error_report(sk);
-               return;
+               err = EPROTO;
+               info = ntohl(skb->h.icmph->un.gateway)>>24;
+               harderr = 1;
+               break;
        case ICMP_DEST_UNREACH:
                if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */
                        if (sk->ip_pmtudisc != IP_PMTUDISC_DONT) {
-                               /* 
-                                * There should be really a way to pass the
-                                * discovered MTU value back to the user (the
-                                * ICMP layer did all the work for us)
-                                */
-                               sk->err = EMSGSIZE;
-                               sk->error_report(sk);
+                               err = EMSGSIZE;
+                               info = ntohs(skb->h.icmph->un.frag.mtu);
+                               harderr = 1;
+                               break;
                        }
                        return;
                }
+               err = EHOSTUNREACH;
+               if (code <= NR_ICMP_UNREACH) {
+                       harderr = icmp_err_convert[code].fatal;
+                       err = icmp_err_convert[code].errno;
+               }
                break;
        }
-                       
+
        /*
         *      Various people wanted BSD UDP semantics. Well they've come 
         *      back out because they slow down response to stuff like dead
@@ -531,21 +538,25 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
         *      client code people.
         */
         
-       /* RFC1122: OK.  Passes ICMP errors back to application, as per */
-       /* 4.1.3.3. */
-       /* After the comment above, that should be no surprise. */
+       /*
+        *      RFC1122: OK.  Passes ICMP errors back to application, as per 
+        *      4.1.3.3. After the comment above, that should be no surprise. 
+        */
 
-       if (code < NR_ICMP_UNREACH && icmp_err_convert[code].fatal)
-       {
-               /*
-                *      4.x BSD compatibility item. Break RFC1122 to
-                *      get BSD socket semantics.
-                */
-               if(sk->bsdism && sk->state!=TCP_ESTABLISHED)
-                       return;
-               sk->err = icmp_err_convert[code].errno;
-               sk->error_report(sk);
-       }
+       if (!harderr && !sk->ip_recverr)
+               return;
+
+       /*
+        *      4.x BSD compatibility item. Break RFC1122 to
+        *      get BSD socket semantics.
+        */
+       if(sk->bsdism && sk->state!=TCP_ESTABLISHED)
+               return;
+
+       if (sk->ip_recverr)
+               ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1));
+       sk->err = err;
+       sk->error_report(sk);
 }
 
 
@@ -854,24 +865,17 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        /*
         *      Check any passed addresses
         */
-        
        if (addr_len) 
                *addr_len=sizeof(*sin);
 
-       if (sk->ip_recverr && (skb = skb_dequeue(&sk->error_queue)) != NULL) {
-               err = sock_error(sk);
-               if (msg->msg_controllen != 0) {
-                       put_cmsg(msg, SOL_IP, IP_RECVERR, skb->len, skb->data);
-                       err = 0;
-               }
-               goto out_free;
-       }
-  
+       if (flags & MSG_ERRQUEUE)
+               return ip_recv_error(sk, msg, len);
+
        /*
         *      From here the generic datagram does a lot of the work. Come
         *      the finished NET3, it will do _ALL_ the work!
         */
-               
+
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
                goto out;
@@ -1026,7 +1030,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
         *      Charge it to the socket, dropping if the queue is full.
         */
 
-       if (__sock_queue_rcv_skb(sk,skb)<0) {
+       if (sock_queue_rcv_skb(sk,skb)<0) {
                udp_statistics.UdpInErrors++;
                ip_statistics.IpInDiscards++;
                ip_statistics.IpInDelivers--;
@@ -1196,9 +1200,11 @@ csum_error:
         * RFC1122: OK.  Discards the bad packet silently (as far as 
         * the network is concerned, anyway) as per 4.1.3.4 (MUST). 
         */
-       NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
-                       ntohl(saddr),ntohs(uh->source),
-                       ntohl(daddr),ntohs(uh->dest),
+       NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n",
+                       NIPQUAD(saddr),
+                       ntohs(uh->source),
+                       NIPQUAD(daddr),
+                       ntohs(uh->dest),
                        ulen));
        udp_statistics.UdpInErrors++;
        kfree_skb(skb);
index 9cbb89a1bbe14ca6182d9b91a190bef4704b4f64..b40c35d00c3dc54fd5e9e0be940ed17055ac2765 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/af_inet.c
  *
- *     $Id: af_inet6.c,v 1.38 1998/09/15 02:11:45 davem Exp $
+ *     $Id: af_inet6.c,v 1.39 1998/10/03 09:38:23 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+#ifdef MODULE
 static int unloadable = 0; /* XX: Turn to one when all is ok within the
                              module for allowing unload */
+#endif
 
 #if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
 MODULE_AUTHOR("Cast of dozens");
@@ -132,6 +134,7 @@ static int inet6_create(struct socket *sock, int protocol)
        sk->net_pinfo.af_inet6.hop_limit  = -1;
        sk->net_pinfo.af_inet6.mcast_hops = -1;
        sk->net_pinfo.af_inet6.mc_loop    = 1;
+       sk->net_pinfo.af_inet6.pmtudisc   = IPV6_PMTUDISC_WANT;
 
        /* Init the ipv4 part of the socket since we can have sockets
         * using v6 API for ipv4.
index 51960bd266aec2f3cecce5d8c3aa217487b8a404..cd8725dedd7617a31f17f75f15403d9adf592b39 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: datagram.c,v 1.15 1998/08/26 12:04:47 davem Exp $
+ *     $Id: datagram.c,v 1.16 1998/10/03 09:38:25 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <net/addrconf.h>
 #include <net/transp_v6.h>
 
+#include <linux/errqueue.h>
+#include <asm/uaccess.h>
+
+void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 
+                    u16 port, u32 info, u8 *payload)
+{
+       struct icmp6hdr *icmph = (struct icmp6hdr *)skb->h.raw;
+       struct sock_exterr_skb *serr;
+
+       if (!sk->net_pinfo.af_inet6.recverr)
+               return;
+
+       skb = skb_clone(skb, GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       serr = SKB_EXT_ERR(skb);
+       serr->ee.ee_errno = err;
+       serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6;
+       serr->ee.ee_type = icmph->icmp6_type; 
+       serr->ee.ee_code = icmph->icmp6_code;
+       serr->ee.ee_pad = 0;
+       serr->ee.ee_info = info;
+       serr->ee.ee_data = 0;
+       serr->addr_offset = (u8*)&(((struct ipv6hdr*)(icmph+1))->daddr) - skb->nh.raw;
+       serr->port = port;
+
+       skb->h.raw = payload;
+       skb_pull(skb, payload - skb->data);
+
+       if (sock_queue_err_skb(sk, skb))
+               kfree_skb(skb);
+}
+
+void ipv6_local_error(struct sock *sk, int err, struct flowi *fl, u32 info)
+{
+       struct sock_exterr_skb *serr;
+       struct ipv6hdr *iph;
+       struct sk_buff *skb;
+
+       if (!sk->net_pinfo.af_inet6.recverr)
+               return;
+
+       skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC);
+       if (!skb)
+               return;
+
+       iph = (struct ipv6hdr*)skb_put(skb, sizeof(struct ipv6hdr));
+       skb->nh.ipv6h = iph;
+       memcpy(&iph->daddr, fl->fl6_dst, 16);
+
+       serr = SKB_EXT_ERR(skb);
+       serr->ee.ee_errno = err;
+       serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
+       serr->ee.ee_type = 0; 
+       serr->ee.ee_code = 0;
+       serr->ee.ee_pad = 0;
+       serr->ee.ee_info = info;
+       serr->ee.ee_data = 0;
+       serr->addr_offset = (u8*)&iph->daddr - skb->nh.raw;
+       serr->port = fl->uli_u.ports.dport;
+
+       skb->h.raw = skb->tail;
+       skb_pull(skb, skb->tail - skb->data);
+
+       if (sock_queue_err_skb(sk, skb))
+               kfree_skb(skb);
+}
+
+/* 
+ *     Handle MSG_ERRQUEUE
+ */
+int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
+{
+       struct sock_exterr_skb *serr;
+       struct sk_buff *skb, *skb2;
+       struct sockaddr_in6 *sin;
+       struct {
+               struct sock_extended_err ee;
+               struct sockaddr_in6      offender;
+       } errhdr;
+       int err;
+       int copied;
+
+       err = -EAGAIN;
+       skb = skb_dequeue(&sk->error_queue);
+       if (skb == NULL)
+               goto out;
+
+       copied = skb->len;
+       if (copied > len) {
+               msg->msg_flags |= MSG_TRUNC;
+               copied = len;
+       }
+       err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
+       if (err)
+               goto out_free_skb;
+
+       serr = SKB_EXT_ERR(skb);
+
+       sin = (struct sockaddr_in6 *)msg->msg_name;
+       if (sin) {
+               sin->sin6_family = AF_INET6;
+               sin->sin6_port = serr->port; 
+               if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6)
+                       memcpy(&sin->sin6_addr, skb->nh.raw + serr->addr_offset, 16);
+               else
+                       ipv6_addr_set(&sin->sin6_addr, 0, 0,
+                                     __constant_htonl(0xffff),
+                                     *(u32*)(skb->nh.raw + serr->addr_offset));
+       }
+
+       memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
+       sin = &errhdr.offender;
+       sin->sin6_family = AF_UNSPEC;
+       if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
+               sin->sin6_family = AF_INET6;
+               if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
+                       memcpy(&sin->sin6_addr, &skb->nh.ipv6h->saddr, 16);
+                       if (sk->net_pinfo.af_inet6.rxopt.all)
+                               datagram_recv_ctl(sk, msg, skb);
+               } else {
+                       ipv6_addr_set(&sin->sin6_addr, 0, 0,
+                                     __constant_htonl(0xffff),
+                                     skb->nh.iph->saddr);
+                       if (sk->ip_cmsg_flags)
+                               ip_cmsg_recv(msg, skb);
+               }
+       }
+
+       put_cmsg(msg, SOL_IPV6, IPV6_RECVERR, sizeof(errhdr), &errhdr);
+
+       /* Now we could try to dump offended packet options */
+
+       msg->msg_flags |= MSG_ERRQUEUE;
+       err = copied;
+
+       /* Reset and regenerate socket error */
+       sk->err = 0;
+       if ((skb2 = skb_peek(&sk->error_queue)) != NULL) {
+               sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno;
+               sk->error_report(sk);
+       }
+
+out_free_skb:  
+       kfree_skb(skb);
+out:
+       return err;
+}
+
+
+
 int datagram_recv_ctl(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
 {
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
index 89d58936d35f6ac10df6669029065bbfe13945a6..8a4f85b6c52f7e6dfa31507ec539b3fa21b8b87c 100644 (file)
@@ -7,7 +7,7 @@
  *     Andi Kleen              <ak@muc.de>
  *     Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
  *
- *     $Id: exthdrs.c,v 1.7 1998/08/26 12:04:49 davem Exp $
+ *     $Id: exthdrs.c,v 1.8 1998/10/03 09:38:27 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -368,9 +368,7 @@ ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
    what it does and calculates authentication data correctly.
    Certainly, it is possible only for udp and raw sockets, but not for tcp.
 
-   BTW I beg pardon, it is not good place for flames, but
-   I cannot be silent 8) It is very sad, but fools prevail 8)
-   AUTH header has 4byte granular length, what kills all the idea
+   AUTH header has 4byte granular length, which kills all the idea
    behind AUTOMATIC 64bit alignment of IPv6. Now we will loose
    cpu ticks, checking that sender did not something stupid
    and opt->hdrlen is even. Shit!              --ANK (980730)
@@ -383,6 +381,8 @@ static u8 *ipv6_auth_hdr(struct sk_buff **skb_ptr, u8 *nhptr)
        struct ipv6_opt_hdr *hdr = (struct ipv6_opt_hdr *)skb->h.raw;
        int len = (hdr->hdrlen+2)<<2;
 
+       if (len&7)
+               return NULL;
        opt->auth = (u8*)hdr - skb->nh.raw;
        if (skb->h.raw + len > skb->tail)
                return NULL;
index d43d1f98ddeb4c0177ba081e3c0b61f889b48fbd..8f49443e65136ce53b0ce465cef007ff3ff2c704 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>
  *
- *     $Id: icmp.c,v 1.19 1998/08/26 12:04:52 davem Exp $
+ *     $Id: icmp.c,v 1.20 1998/10/03 09:38:31 davem Exp $
  *
  *     Based on net/ipv4/icmp.c
  *
@@ -334,7 +334,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
        msg.daddr = &hdr->saddr;
 
        len = min((skb->tail - ((unsigned char *) hdr)) + sizeof(struct icmp6hdr), 
-                 IPV6_MIN_MTU - sizeof(struct icmp6hdr));
+                 IPV6_MIN_MTU - sizeof(struct ipv6hdr));
 
        if (len < 0) {
                printk(KERN_DEBUG "icmp: len problem\n");
@@ -396,7 +396,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
 }
 
 static void icmpv6_notify(struct sk_buff *skb,
-                         int type, int code, unsigned char *buff, int len)
+                         int type, int code, u32 info, unsigned char *buff, int len)
 {
        struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
        struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
@@ -404,7 +404,6 @@ static void icmpv6_notify(struct sk_buff *skb,
        struct inet6_protocol *ipprot;
        struct sock *sk;
        u8 *pb;
-       __u32 info = 0;
        int hash;
        u8 nexthdr;
 
@@ -436,11 +435,8 @@ static void icmpv6_notify(struct sk_buff *skb,
 
                if (ipprot->err_handler)
                        ipprot->err_handler(skb, hdr, NULL, type, code, pb, info);
-               return;
        }
 
-       /* delivery to upper layer protocols failed. try raw sockets */
-
        sk = raw_v6_htable[hash];
 
        if (sk == NULL)
@@ -468,6 +464,9 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len)
 
        icmpv6_statistics.Icmp6InMsgs++;
 
+       if (len < sizeof(struct icmp6hdr))
+               goto discard_it;
+
        /* Perform checksum. */
        switch (skb->ip_summed) {       
        case CHECKSUM_NONE:
@@ -538,7 +537,7 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len)
        case ICMPV6_DEST_UNREACH:
        case ICMPV6_TIME_EXCEED:
        case ICMPV6_PARAMPROB:
-               icmpv6_notify(skb, type, hdr->icmp6_code,
+               icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
                              (char *) (hdr + 1), ulen);
                break;
 
@@ -574,7 +573,7 @@ int icmpv6_rcv(struct sk_buff *skb, unsigned long len)
                 * must pass to upper level 
                 */
 
-               icmpv6_notify(skb, type, hdr->icmp6_code,
+               icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu,
                              (char *) (hdr + 1), ulen);
        };
        kfree_skb(skb);
@@ -586,7 +585,7 @@ discard_it:
        return 0;
 }
 
-__initfunc(int icmpv6_init(struct net_proto_family *ops))
+int __init icmpv6_init(struct net_proto_family *ops)
 {
        struct sock *sk;
        int err;
@@ -632,7 +631,7 @@ static struct icmp6_err {
 } tab_unreach[] = {
        { ENETUNREACH,  0},     /* NOROUTE              */
        { EACCES,       1},     /* ADM_PROHIBITED       */
-       { 0,            0},     /* Was NOT_NEIGHBOUR, now reserved */
+       { EHOSTUNREACH, 0},     /* Was NOT_NEIGHBOUR, now reserved */
        { EHOSTUNREACH, 0},     /* ADDR_UNREACH         */
        { ECONNREFUSED, 1},     /* PORT_UNREACH         */
 };
@@ -641,10 +640,11 @@ int icmpv6_err_convert(int type, int code, int *err)
 {
        int fatal = 0;
 
-       *err = 0;
+       *err = EPROTO;
 
        switch (type) {
        case ICMPV6_DEST_UNREACH:
+               fatal = 1;
                if (code <= ICMPV6_PORT_UNREACH) {
                        *err  = tab_unreach[code].err;
                        fatal = tab_unreach[code].fatal;
@@ -659,6 +659,10 @@ int icmpv6_err_convert(int type, int code, int *err)
                *err = EPROTO;
                fatal = 1;
                break;
+
+       case ICMPV6_TIME_EXCEED:
+               *err = EHOSTUNREACH;
+               break;
        };
 
        return fatal;
index 0555c1a2428bae464b88acb9a17b14dc9f1153f4..a9dfa97ba77387f68001d14d13b3dfbbc79a19b3 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: ip6_output.c,v 1.14 1998/08/26 12:05:01 davem Exp $
+ *     $Id: ip6_output.c,v 1.15 1998/10/03 09:38:34 davem Exp $
  *
  *     Based on linux/net/ipv4/ip_output.c
  *
@@ -291,8 +291,10 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
        frag_len = (mtu - unfrag_len) & ~0x7;
 
        /* Unfragmentable part exceeds mtu. */
-       if (frag_len <= 0)
+       if (frag_len <= 0) {
+               ipv6_local_error(sk, EMSGSIZE, fl, mtu);
                return -EMSGSIZE;
+       }
 
        nfrags = last_len / frag_len;
 
@@ -321,8 +323,10 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
           all the exthdrs will fit to the first fragment.
         */
        if (opt) {
-               if (frag_len < opt->opt_flen)
+               if (frag_len < opt->opt_flen) {
+                       ipv6_local_error(sk, EMSGSIZE, fl, mtu);
                        return -EMSGSIZE;
+               }
                data_off = frag_off - opt->opt_flen;
        }
 
@@ -520,12 +524,21 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
        }
 
        mtu = dst->pmtu;
+       if (np->frag_size < mtu) {
+               if (np->frag_size)
+                       mtu = np->frag_size;
+               else if (np->pmtudisc == IPV6_PMTUDISC_DONT)
+                       mtu = IPV6_MIN_MTU;
+       }
 
        /* Critical arithmetic overflow check.
           FIXME: may gcc optimize it out? --ANK (980726)
         */
-       if (pktlength < length)
-               return -EMSGSIZE;
+       if (pktlength < length) {
+               ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+               err = -EMSGSIZE;
+               goto out;
+       }
 
        if (pktlength <= mtu) {
                struct sk_buff *skb;
@@ -573,8 +586,12 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
                        kfree_skb(skb);
                }
        } else {
-               if (sk->ip_hdrincl || jumbolen)
-                       return -EMSGSIZE;
+               if (sk->ip_hdrincl || jumbolen ||
+                   np->pmtudisc == IPV6_PMTUDISC_DO) {
+                       ipv6_local_error(sk, EMSGSIZE, fl, mtu);
+                       err = -EMSGSIZE;
+                       goto out;
+               }
 
                err = ip6_frag_xmit(sk, getfrag, data, dst, fl, opt, final_dst, hlimit,
                                    flags, length, mtu);
index a246b996b58efe2d98bbd4446b438978082a6fed..4b8089d4a756ff4f3514860a4491d007f334b81a 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/net/ipv4/ip_sockglue.c
  *
- *     $Id: ipv6_sockglue.c,v 1.23 1998/08/26 12:05:04 davem Exp $
+ *     $Id: ipv6_sockglue.c,v 1.24 1998/10/03 09:38:37 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -275,33 +275,17 @@ done:
                break;
 
        case IPV6_MULTICAST_IF:
-       {
-               int oif = 0;
-               struct in6_addr addr;
-
-               if (copy_from_user(&addr, optval, sizeof(struct in6_addr)))
-                       return -EFAULT;
-                               
-               if (!ipv6_addr_any(&addr)) {
-                       struct inet6_ifaddr *ifp;
-
-                       ifp = ipv6_chk_addr(&addr, NULL, 0);
-
-                       if (ifp == NULL) {
-                               retv = -EADDRNOTAVAIL;
-                               break;
-                       }
-
-                       oif = ifp->idev->dev->ifindex;
-               }
-               if (sk->bound_dev_if && sk->bound_dev_if != oif) {
+               if (sk->bound_dev_if && sk->bound_dev_if != val) {
                        retv = -EINVAL;
                        break;
                }
-               np->mcast_oif = oif;
+               if (dev_get_by_index(val) == NULL) {
+                       retv = -ENODEV;
+                       break;
+               }
+               np->mcast_oif = val;
                retv = 0;
                break;
-       }
        case IPV6_ADD_MEMBERSHIP:
        case IPV6_DROP_MEMBERSHIP:
        {
@@ -319,6 +303,21 @@ done:
        case IPV6_ROUTER_ALERT:
                retv = ip6_ra_control(sk, val, NULL);
                break;
+       case IPV6_MTU_DISCOVER:
+               if (val<0 || val>2)
+                       return -EINVAL;
+               np->pmtudisc = val;
+               return 0;
+       case IPV6_MTU:
+               if (val && val < IPV6_MIN_MTU)
+                       return -EINVAL;
+               np->frag_size = val;
+               return 0;
+       case IPV6_RECVERR:
+               np->recverr = !!val;
+               if (!val)
+                       skb_queue_purge(&sk->error_queue);
+               return 0;
        };
 
 out:
@@ -330,6 +329,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
 {
        struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
        int len;
+       int val;
 
        if(level==SOL_IP && sk->type != SOCK_RAW)
                return udp_prot.getsockopt(sk, level, optname, optval, optlen);
@@ -364,9 +364,24 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
                        len = 0;
                return put_user(len, optlen);
        }
+       case IP_MTU:
+               val = 0;        
+               lock_sock(sk);
+               if (sk->dst_cache)              
+                       val = sk->dst_cache->pmtu;
+               release_sock(sk);
+               if (!val)
+                       return -ENOTCONN;
+               break;
        default:
+               return -EINVAL;
        }
-       return -EINVAL;
+       len=min(sizeof(int),len);
+       if(put_user(len, optlen))
+               return -EFAULT;
+       if(copy_to_user(optval,&val,len))
+               return -EFAULT;
+       return 0;
 }
 
 #if defined(MODULE) && defined(CONFIG_SYSCTL)
index 76339ff5879130e94a363fa7d57866cbdaa914c1..a47d10e82fe8ea1b53766f641f6961e664662545 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Adapted from linux/net/ipv4/raw.c
  *
- *     $Id: raw.c,v 1.21 1998/08/26 12:05:13 davem Exp $
+ *     $Id: raw.c,v 1.22 1998/10/03 09:38:40 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -185,8 +185,31 @@ void rawv6_err(struct sock *sk, struct sk_buff *skb, struct ipv6hdr *hdr,
               struct inet6_skb_parm *opt,
               int type, int code, unsigned char *buff, u32 info)
 {
-       if (sk == NULL)
+       int err;
+       int harderr;
+
+       if (buff > skb->tail)
                return;
+
+       /* Report error on raw socket, if:
+          1. User requested recverr.
+          2. Socket is connected (otherwise the error indication
+             is useless without recverr and error is hard.
+        */
+       if (!sk->net_pinfo.af_inet6.recverr && sk->state != TCP_ESTABLISHED)
+               return;
+
+       harderr = icmpv6_err_convert(type, code, &err);
+       if (type == ICMPV6_PKT_TOOBIG)
+               harderr = (sk->net_pinfo.af_inet6.pmtudisc == IPV6_PMTUDISC_DO);
+
+       if (sk->net_pinfo.af_inet6.recverr)
+               ipv6_icmp_error(sk, skb, err, 0, ntohl(info), buff);
+
+       if (sk->net_pinfo.af_inet6.recverr || harderr) {
+               sk->err = err;
+               sk->error_report(sk);
+       }
 }
 
 static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb)
@@ -234,16 +257,16 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        if (flags & MSG_OOB)
                return -EOPNOTSUPP;
                
-       if (sk->shutdown & RCV_SHUTDOWN) 
-               return(0);
-
        if (addr_len) 
                *addr_len=sizeof(*sin6);
 
+       if (flags & MSG_ERRQUEUE)
+               return ipv6_recv_error(sk, msg, len);
+
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
                goto out;
-       
+
        copied = skb->tail - skb->h.raw;
        if (copied > len) {
                copied = len;
index 8d1f59632bc5f7b9071844cb02aa4865310eda37..9ae8f63d7b45f2d291e2f594e9b08a41bd948545 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: route.c,v 1.33 1998/08/26 12:05:18 davem Exp $
+ *     $Id: route.c,v 1.34 1998/10/03 09:38:43 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -1025,6 +1025,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
         */
        if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
                nrt = rt6_cow(rt, daddr, saddr);
+               nrt->u.dst.pmtu = pmtu;
                nrt->rt6i_flags |= RTF_DYNAMIC;
                dst_release(&nrt->u.dst);
        } else {
@@ -1035,6 +1036,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
                nrt->rt6i_dst.plen = 128;
                nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);
                nrt->rt6i_flags |= (RTF_DYNAMIC | RTF_CACHE);
+               nrt->u.dst.pmtu = pmtu;
                rt6_ins(nrt);
        }
 
@@ -1063,10 +1065,10 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
                rt->u.dst.dev = ort->u.dst.dev;
                rt->u.dst.lastuse = jiffies;
                rt->rt6i_hoplimit = ort->rt6i_hoplimit;
-               rt->rt6i_expires = ort->rt6i_expires;
+               rt->rt6i_expires = 0;
 
                ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
-               rt->rt6i_flags = ort->rt6i_flags;
+               rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;
                rt->rt6i_metric = ort->rt6i_metric;
 
                memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));
index 0d6efd515d3400ab77d6cdd19ab5594596518213..850553d9dbcd3b8d32b4d969b301e8a872cd543a 100644 (file)
@@ -6,7 +6,7 @@
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *     Alexey Kuznetsov        <kuznet@ms2.inr.ac.ru>
  *
- *     $Id: sit.c,v 1.28 1998/08/26 12:05:22 davem Exp $
+ *     $Id: sit.c,v 1.29 1998/10/03 09:38:47 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -434,21 +434,21 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct device *dev)
                ip_rt_put(rt);
                goto tx_error;
        }
-       if (mtu >= IPV6_MIN_MTU) {
-               if (skb->dst && mtu < skb->dst->pmtu) {
-                       struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
-                       if (mtu < rt6->u.dst.pmtu) {
-                               if (tunnel->parms.iph.daddr || rt6->rt6i_dst.plen == 128) {
-                                       rt6->rt6i_flags |= RTF_MODIFIED;
-                                       rt6->u.dst.pmtu = mtu;
-                               }
+       if (mtu < IPV6_MIN_MTU)
+               mtu = IPV6_MIN_MTU;
+       if (skb->dst && mtu < skb->dst->pmtu) {
+               struct rt6_info *rt6 = (struct rt6_info*)skb->dst;
+               if (mtu < rt6->u.dst.pmtu) {
+                       if (tunnel->parms.iph.daddr || rt6->rt6i_dst.plen == 128) {
+                               rt6->rt6i_flags |= RTF_MODIFIED;
+                               rt6->u.dst.pmtu = mtu;
                        }
                }
-               if (skb->len > mtu) {
-                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
-                       ip_rt_put(rt);
-                       goto tx_error;
-               }
+       }
+       if (skb->len > mtu) {
+               icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+               ip_rt_put(rt);
+               goto tx_error;
        }
 
        if (tunnel->err_count > 0) {
@@ -554,6 +554,10 @@ ipip6_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
 
        case SIOCADDTUNNEL:
        case SIOCCHGTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                err = -EFAULT;
                if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
                        goto done;
@@ -580,6 +584,10 @@ ipip6_tunnel_ioctl (struct device *dev, struct ifreq *ifr, int cmd)
                break;
 
        case SIOCDELTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
                if (dev == &ipip6_fb_tunnel_dev) {
                        err = -EFAULT;
                        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
index 3ec55f7647fb32ec451010faf2c9f1348e886e82..a1402936d00bf1a1fea12630ce0494f9e8a9bbd1 100644 (file)
@@ -5,7 +5,7 @@
  *     Authors:
  *     Pedro Roque             <roque@di.fc.ul.pt>     
  *
- *     $Id: tcp_ipv6.c,v 1.92 1998/09/15 02:11:42 davem Exp $
+ *     $Id: tcp_ipv6.c,v 1.93 1998/10/03 09:38:50 davem Exp $
  *
  *     Based on: 
  *     linux/net/ipv4/tcp.c
@@ -53,6 +53,7 @@ static void   tcp_v6_xmit(struct sk_buff *skb);
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
                                              struct ipv6hdr *ip6h,
                                              struct tcphdr *th,
+                                             int iif,
                                              struct open_request **prevp);
 
 static struct tcp_func ipv6_mapped;
@@ -363,6 +364,12 @@ static int tcp_v6_unique_address(struct sock *sk)
        return retval;
 }
 
+static __inline__ int tcp_v6_iif(struct sk_buff *skb)
+{
+       struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+       return opt->iif;
+}
+
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
                          int addr_len)
 {
@@ -580,7 +587,6 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
        struct ipv6_pinfo *np;
        struct sock *sk;
        int err;
-       int opening;
        struct tcp_opt *tp; 
        __u32 seq; 
 
@@ -597,18 +603,18 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
        tp = &sk->tp_pinfo.af_tcp;
        seq = ntohl(th->seq); 
        if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) {
-               if (net_ratelimit()) 
-                       printk(KERN_DEBUG "icmp packet outside the tcp window:"
-                                         " s:%d %u,%u,%u\n",
-                              (int)sk->state, seq, tp->snd_una, tp->snd_nxt); 
+               net_statistics.OutOfWindowIcmps++;
                return; 
        }
 
        np = &sk->net_pinfo.af_inet6;
-       if (type == ICMPV6_PKT_TOOBIG && sk->state != TCP_LISTEN) {
+       if (type == ICMPV6_PKT_TOOBIG) {
                struct dst_entry *dst = NULL;
                /* icmp should have updated the destination cache entry */
 
+               if (sk->state == TCP_LISTEN)
+                       return;
+
                if (sk->dst_cache)
                        dst = dst_check(&sk->dst_cache, np->dst_cookie);
 
@@ -632,7 +638,7 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                        dst = dst_clone(dst);
 
                if (dst->error) {
-                       sk->err_soft = dst->error;
+                       sk->err_soft = -dst->error;
                } else if (tp->pmtu_cookie > dst->pmtu
                           && !atomic_read(&sk->sock_readers)) {
                        lock_sock(sk); 
@@ -644,26 +650,29 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                return;
        }
 
-       opening = 0; 
+       icmpv6_err_convert(type, code, &err);
+
        /* Might be for an open_request */
        switch (sk->state) {
                struct open_request *req, *prev;
                struct ipv6hdr hd;
        case TCP_LISTEN:
-               if (atomic_read(&sk->sock_readers))
-                       return;
+               if (atomic_read(&sk->sock_readers)) {
+                       net_statistics.LockDroppedIcmps++;
+                        /* If too many ICMPs get dropped on busy
+                         * servers this needs to be solved differently.
+                         */
+                       return;
+               }
 
                /* Grrrr - fix this later. */
                ipv6_addr_copy(&hd.saddr, saddr);
                ipv6_addr_copy(&hd.daddr, daddr); 
-               req = tcp_v6_search_req(tp, &hd,th, &prev);
+               req = tcp_v6_search_req(tp, &hd, th, tcp_v6_iif(skb), &prev);
                if (!req)
                        return;
                if (seq != req->snt_isn) {
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "icmp packet for openreq "
-                                      "with wrong seq number:%d:%d\n",
-                                      seq, req->snt_isn);
+                       net_statistics.OutOfWindowIcmps++;
                        return;
                }
                if (req->sk) {
@@ -676,21 +685,26 @@ void tcp_v6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
                }
                /* FALL THROUGH */ 
        case TCP_SYN_SENT:
-       case TCP_SYN_RECV: 
-               opening = 1;
-               break; 
+       case TCP_SYN_RECV:  /* Cannot happen */ 
+               tcp_statistics.TcpAttemptFails++;
+               sk->err = err;
+               sk->zapped = 1;
+               mb();
+               sk->error_report(sk);
+               return;
        }
 
-       if (icmpv6_err_convert(type, code, &err) || opening) {
+       if (np->recverr) {
+               /* This code isn't serialized with the socket code */
+               /* ANK (980927) ... which is harmless now,
+                  sk->err's may be safely lost.
+                */
                sk->err = err;
-
-               if (opening) {
-                       tcp_statistics.TcpAttemptFails++;
-                       tcp_set_state(sk,TCP_CLOSE);
-                       sk->error_report(sk);
-               }
+               mb();
+               sk->error_report(sk);
        } else {
                sk->err_soft = err;
+               mb();
        }
 }
 
@@ -853,7 +867,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, __u32 isn)
 
        /* So that link locals have meaning */
        if (!sk->bound_dev_if && ipv6_addr_type(&req->af.v6_req.rmt_addr)&IPV6_ADDR_LINKLOCAL)
-               req->af.v6_req.iif = skb->dev->ifindex;
+               req->af.v6_req.iif = tcp_v6_iif(skb);
 
        req->class = &or_ipv6;
        req->retrans = 0;
@@ -1035,6 +1049,9 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
        if (th->rst)
                return;
 
+       if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr))
+               return; 
+
        /*
         * We need to grab some memory, and put together an RST,
         * and then put it into the queue to be sent.
@@ -1076,7 +1093,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
                                    buff->csum);
 
        fl.proto = IPPROTO_TCP;
-       fl.oif = skb->dev->ifindex;
+       fl.oif = tcp_v6_iif(skb);
        fl.uli_u.ports.dport = t1->dest;
        fl.uli_u.ports.sport = t1->source;
 
@@ -1096,6 +1113,7 @@ static void tcp_v6_send_reset(struct sk_buff *skb)
 static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
                                              struct ipv6hdr *ip6h,
                                              struct tcphdr *th,
+                                             int iif,
                                              struct open_request **prevp)
 {
        struct open_request *req, *prev; 
@@ -1109,9 +1127,10 @@ static struct open_request *tcp_v6_search_req(struct tcp_opt *tp,
        for (req = prev->dl_next; req; req = req->dl_next) {
                if (!ipv6_addr_cmp(&req->af.v6_req.rmt_addr, &ip6h->saddr) &&
                    !ipv6_addr_cmp(&req->af.v6_req.loc_addr, &ip6h->daddr) &&
-                   req->rmt_port == rport) {
-                       *prevp = prev; 
-                       return req; 
+                   req->rmt_port == rport &&
+                   (!req->af.v6_req.iif || req->af.v6_req.iif == iif)) {
+                       *prevp = prev;
+                       return req;
                }
                prev = req; 
        }
@@ -1123,7 +1142,7 @@ static void tcp_v6_rst_req(struct sock *sk, struct sk_buff *skb)
        struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
        struct open_request *req, *prev;
 
-       req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,&prev);
+       req = tcp_v6_search_req(tp,skb->nh.ipv6h,skb->h.th,tcp_v6_iif(skb),&prev);
        if (!req)
                return;
        /* Sequence number check required by RFC793 */
@@ -1156,7 +1175,7 @@ static inline struct sock *tcp_v6_hnd_req(struct sock *sk, struct sk_buff *skb)
                struct open_request *req, *dummy;
                struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
                        
-               req = tcp_v6_search_req(tp, skb->nh.ipv6h,th, &dummy);
+               req = tcp_v6_search_req(tp, skb->nh.ipv6h, th, tcp_v6_iif(skb), &dummy);
                if (req) {
                        sk = tcp_check_req(sk, skb, req);
                }
@@ -1292,7 +1311,6 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
 {
        struct tcphdr *th;      
        struct sock *sk;
-       struct device *dev = skb->dev;
        struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
        struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
 
@@ -1330,7 +1348,7 @@ int tcp_v6_rcv(struct sk_buff *skb, unsigned long len)
                /* CHECKSUM_UNNECESSARY */
        };
 
-       sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, dev->ifindex);
+       sk = __tcp_v6_lookup(th, saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
 
        if (!sk)
                goto no_tcp_socket;
@@ -1412,7 +1430,7 @@ static struct sock * tcp_v6_get_sock(struct sk_buff *skb, struct tcphdr *th)
 
        saddr = &skb->nh.ipv6h->saddr;
        daddr = &skb->nh.ipv6h->daddr;
-       return tcp_v6_lookup(saddr, th->source, daddr, th->dest, skb->dev->ifindex);
+       return tcp_v6_lookup(saddr, th->source, daddr, th->dest, tcp_v6_iif(skb));
 }
 
 static void tcp_v6_xmit(struct sk_buff *skb)
@@ -1441,7 +1459,7 @@ static void tcp_v6_xmit(struct sk_buff *skb)
                dst = ip6_route_output(sk, &fl);
 
                if (dst->error) {
-                       sk->err_soft = dst->error;
+                       sk->err_soft = -dst->error;
                        dst_release(dst);
                        return;
                }
index fcd293f7bd322e47927d235f2d0ddd50dad8ef7a..3540f05952f91ead0afeb3096b5c65fdb3ab6755 100644 (file)
@@ -7,7 +7,7 @@
  *
  *     Based on linux/ipv4/udp.c
  *
- *     $Id: udp.c,v 1.35 1998/09/07 00:13:57 davem Exp $
+ *     $Id: udp.c,v 1.36 1998/10/03 09:38:54 davem Exp $
  *
  *     This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -332,32 +332,22 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
        struct sk_buff *skb;
        int copied, err;
 
-       /*
-        *      Check any passed addresses
-        */
-        
-       if (addr_len) 
+       if (addr_len)
                *addr_len=sizeof(struct sockaddr_in6);
   
-       /*
-        *      From here the generic datagram does a lot of the work. Come
-        *      the finished NET3, it will do _ALL_ the work!
-        */
+       if (flags & MSG_ERRQUEUE)
+               return ipv6_recv_error(sk, msg, len);
 
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
                goto out;
-  
+
        copied = skb->len - sizeof(struct udphdr);
        if (copied > len) {
                copied = len;
                msg->msg_flags |= MSG_TRUNC;
        }
 
-       /*
-        *      FIXME : should use udp header size info value 
-        */
-        
 #ifndef CONFIG_UDP_DELAY_CSUM
        err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), 
                                      msg->msg_iov, copied);
@@ -395,7 +385,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
 #endif
        if (err)
                goto out_free;
-       
+
        sk->stamp=skb->stamp;
 
        /* Copy the address. */
@@ -445,26 +435,25 @@ void udpv6_err(struct sk_buff *skb, struct ipv6hdr *hdr,
 
        sk = udp_v6_lookup(daddr, uh->dest, saddr, uh->source, dev->ifindex);
    
-       if (sk == NULL) {
-               if (net_ratelimit())
-                       printk(KERN_DEBUG "icmp for unknown sock\n");
+       if (sk == NULL)
                return;
-       }
 
-       if (icmpv6_err_convert(type, code, &err)) {
-               if(sk->bsdism && sk->state!=TCP_ESTABLISHED)
-                       return;
-               
-               sk->err = err;
-               sk->error_report(sk);
-       } else {
-               sk->err_soft = err;
-       }
+       if (!icmpv6_err_convert(type, code, &err) &&
+           !sk->net_pinfo.af_inet6.recverr)
+               return;
+
+       if (sk->bsdism && sk->state!=TCP_ESTABLISHED)
+               return;
+
+       if (sk->net_pinfo.af_inet6.recverr)
+               ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1));
+
+       sk->err = err;
+       sk->error_report(sk);
 }
 
 static inline int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
-
        if (sock_queue_rcv_skb(sk,skb)<0) {
                udp_stats_in6.UdpInErrors++;
                ipv6_statistics.Ip6InDiscards++;
@@ -768,6 +757,11 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
               
                udh.uh.dest = sin6->sin6_port;
                daddr = &sin6->sin6_addr;
+
+               /* Otherwise it will be difficult to maintain sk->dst_cache. */
+               if (sk->state == TCP_ESTABLISHED &&
+                   !ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
+                       daddr = &sk->net_pinfo.af_inet6.daddr;
        } else {
                if (sk->state != TCP_ESTABLISHED)
                        return(-ENOTCONN);
@@ -785,6 +779,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                sin.sin_addr.s_addr = daddr->s6_addr32[3];
                sin.sin_port = udh.uh.dest;
                msg->msg_name = (struct sockaddr *)(&sin);
+               msg->msg_namelen = sizeof(sin);
 
                return udp_sendmsg(sk, msg, ulen);
        }
@@ -806,7 +801,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
                udh.daddr = daddr;
 
        udh.uh.source = sk->sport;
-       udh.uh.len = len < 0x1000 ? htons(len) : 0;
+       udh.uh.len = len < 0x10000 ? htons(len) : 0;
        udh.uh.check = 0;
        udh.iov = msg->msg_iov;
        udh.wcheck = 0;
index de104813ea6d815e9b1ecdcebb3da25188406d68..23e94b5a5daea038c31fadc9043e8f610071c2be 100644 (file)
@@ -551,10 +551,6 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, int len,
        if (flags&(MSG_OOB|MSG_PEEK))
                return -EOPNOTSUPP;
 
-       err = -sock_error(sk);
-       if (err)
-               return err;
-
        skb = skb_recv_datagram(sk,flags,noblock,&err);
        if (skb==NULL)
                return err;
index 1b530fc1366d6cb82009add51eee2c6e1a742f8e..df4ffc37f4e05240560ed7592d679f333c417f07 100644 (file)
@@ -43,6 +43,8 @@ extern struct net_proto_family inet_family_ops;
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
+#include <linux/icmpv6.h>
+#include <net/ipv6.h>
 #include <net/ndisc.h>
 #include <net/dst.h>
 #include <net/transp_v6.h>
@@ -228,6 +230,10 @@ EXPORT_SYMBOL(__release_sock);
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
 
+#ifdef CONFIG_IPV6
+EXPORT_SYMBOL(ipv6_addr_type);
+EXPORT_SYMBOL(icmpv6_send);
+#endif
 #ifdef CONFIG_IPV6_MODULE
 /* inet functions common to v4 and v6 */
 EXPORT_SYMBOL(inet_stream_ops);
index 1e5a509d473c5ef3ec19421ed22562fb5f43fd96..c7e7a6733d9c83bcca487f8f16a83fadeabeb0dc 100644 (file)
@@ -5,10 +5,7 @@
  *
  *             PACKET - implements raw packet sockets.
  *
- *             Doesn't belong in IP but it's currently too hooked into ip
- *             to separate.
- *
- * Version:    @(#)packet.c    1.0.6   05/25/93
+ * Version:    $Id: af_packet.c,v 1.18 1998/10/03 15:55:24 freitag Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1245,7 +1242,7 @@ void cleanup_module(void)
 
 int init_module(void)
 #else
-__initfunc(void packet_proto_init(struct net_proto *pro))
+void __init packet_proto_init(struct net_proto *pro)
 #endif
 {
        sock_register(&packet_family_ops);
index 52512e87972f8d5d497343474a1f451fe20da813..9ae14c2434ce99ea7a79ae9125115ab4ad3007bf 100644 (file)
@@ -54,7 +54,7 @@
 
        -----------------------------------------------------------------------
 
-       Algorithm skeleton was taken from from NS simulator cbq.cc.
+       Algorithm skeleton was taken from NS simulator cbq.cc.
        If someone wants to check this code against the LBL version,
        he should take into account that ONLY the skeleton was borrowed,
        the implementation is different. Particularly:
index 80bc0a96f0bf1ec1071e2a4ae2472a432a30b1b8..eac678b837d5b14b465ebd105ba827928d29755a 100644 (file)
@@ -7,6 +7,9 @@
  *             2 of the License, or (at your option) any later version.
  *
  * Authors:    Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes:
+ * J Hadi Salim <hadi@nortel.com> 980914:      computation fixes
  */
 
 #include <linux/config.h>
@@ -156,9 +159,9 @@ red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
 
        if (!PSCHED_IS_PASTPERFECT(q->qidlestart)) {
                long us_idle;
-               PSCHED_SET_PASTPERFECT(q->qidlestart);
                PSCHED_GET_TIME(now);
                us_idle = PSCHED_TDIFF_SAFE(now, q->qidlestart, q->Scell_max, 0);
+               PSCHED_SET_PASTPERFECT(q->qidlestart);
 
 /*
    The problem: ideally, average length queue recalcultion should
@@ -177,10 +180,18 @@ red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
    but it is field for experiments.
 */
                q->qave >>= q->Stab[(us_idle>>q->Scell_log)&0xFF];
+       } else {
+               q->qave += sch->stats.backlog - (q->qave >> q->Wlog);
+               /* NOTE:
+                  q->qave is fixed point number with point at Wlog.
+                  The formulae above is equvalent to floating point
+                  version:
+
+                  qave = qave*(1-W) + sch->stats.backlog*W;
+                                                          --ANK (980924)
+                */
        }
 
-       q->qave += sch->stats.backlog - (q->qave >> q->Wlog);
-
        if (q->qave < q->qth_min) {
 enqueue:
                q->qcount = -1;
@@ -202,6 +213,22 @@ drop:
                goto drop;
        }
        if (++q->qcount) {
+               /* The formula used below causes questions.
+
+                  OK. qR is random number in the interval 0..Rmask
+                  i.e. 0..(2^Plog). If we used floating point
+                  arithmetics, it would be: (2^Plog)*rnd_num,
+                  where rnd_num is less 1.
+
+                  Taking into account, that qave have fixed
+                  point at Wlog, and Plog is related to max_P by
+                  max_P = (qth_max-qth_min)/2^Plog; two lines
+                  below have the following floating point equivalent:
+                  
+                  max_P*(qave - qth_min)/(qth_max-qth_min) < rnd/qcount
+
+                  Any questions? --ANK (980924)
+                */
                if (((q->qave - q->qth_min)>>q->Wlog)*q->qcount < q->qR)
                        goto enqueue;
                q->qcount = 0;
@@ -289,7 +316,7 @@ static int red_init(struct Qdisc *sch, struct rtattr *opt)
        q->Plog = ctl->Plog;
        q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
        q->Scell_log = ctl->Scell_log;
-       q->Scell_max = (256<<q->Scell_log)-1;
+       q->Scell_max = (255<<q->Scell_log);
        q->qth_min = ctl->qth_min<<ctl->Wlog;
        q->qth_max = ctl->qth_max<<ctl->Wlog;
        q->limit = ctl->limit;
index 01c8851689d38331d8e32c66a76770147ab110a9..bdd15f74411e2c6378c29e73dc4a92da575c6baa 100644 (file)
@@ -8,7 +8,7 @@
  *             as published by the Free Software Foundation; either version
  *             2 of the License, or (at your option) any later version.
  *
- * Version:    $Id: af_unix.c,v 1.69 1998/08/28 01:15:41 davem Exp $
+ * Version:    $Id: af_unix.c,v 1.71 1998/10/03 09:39:05 davem Exp $
  *
  * Fixes:
  *             Linus Torvalds  :       Assorted bug cures.
@@ -463,7 +463,7 @@ static int unix_autobind(struct socket *sock)
 
        addr = kmalloc(sizeof(*addr) + sizeof(short) + 16, GFP_KERNEL);
        if (!addr)
-               return -ENOBUFS;
+               return -ENOMEM;
        if (sk->protinfo.af_unix.addr || sk->protinfo.af_unix.dentry)
        {
                kfree(addr);
@@ -548,7 +548,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
        addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
        if (!addr)
-               return -ENOBUFS;
+               return -ENOMEM;
 
        /* We slept; recheck ... */
 
@@ -786,7 +786,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
        struct sk_buff *skb;
        
        if (sock->state != SS_UNCONNECTED)
-               return(-EINVAL);
+               return(-EINVAL); 
        if (!(sock->flags & SO_ACCEPTCON)) 
                return(-EINVAL);
 
@@ -1332,7 +1332,7 @@ static int unix_shutdown(struct socket *sock, int mode)
                                peer_mode |= SEND_SHUTDOWN;
                        if (mode&SEND_SHUTDOWN)
                                peer_mode |= RCV_SHUTDOWN;
-                       other->shutdown |= mode;
+                       other->shutdown |= peer_mode;
                        other->state_change(other);
                }
        }