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
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
======
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
====
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
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
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
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).
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).
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
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
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.
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
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
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
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
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!
--- /dev/null
+/*
+ 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"));
+}
+
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....
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
# Console drivers
#
CONFIG_VGA_CONSOLE=y
+# CONFIG_VIDEO_SELECT is not set
#
# Sound
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);
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)
{
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)
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));
}
/* Must be done before calibration delay is computed */
mtrr_init_secondary_cpu ();
#endif
+ stts();
smp_callin();
while (!smp_commenced)
barrier();
static volatile int calibration_lock;
- save_flags(flags);
- cli();
+ __save_flags(flags);
+ __cli();
SMP_PRINTK(("setup_APIC_clock() called.\n"));
ack_APIC_irq ();
-
- restore_flags(flags);
+ __restore_flags(flags);
}
/*
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);
* 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)
* 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>
* /Roman Zippel
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
* 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>
*
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <asm/residual.h>
#include <asm/pnp.h>
-# $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
# 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 \
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
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
-# $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
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
-/* $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;
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))
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 */
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
if (!*rr) fatal();
(*rr)->offset = offset;
(*rr)->f = NULL;
- if (buffer[30] == 'f') {
+ if (buffer[nbase+3] == 'f') {
lastf = f;
lastfoffset = offset;
lastfrelno = k;
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)
-# $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.
#
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'
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
#
# 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
CONFIG_INET_RARP=m
CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
-CONFIG_IPV6=m
+CONFIG_IPV6=y
# CONFIG_IPV6_EUI64 is not set
#
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
-# $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
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
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
#include <linux/stddef.h>
#include <linux/init.h>
+#include <linux/config.h>
#include <asm/oplib.h>
#include <asm/io.h>
#include <asm/auxio.h>
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;
}
prom_printf("Cannot find auxio node, cannot continue...\n");
prom_halt();
+#endif
}
}
prom_getproperty(auxio_nd, "reg", (char *) auxregs, sizeof(auxregs));
--- /dev/null
+/* $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, ®s[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, ®s[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
+}
-/* $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
*
* 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)
*/
#include <asm/spinlock.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
+#include <asm/pcic.h>
/*
* Dave Redman (djhr@tadpole.co.uk)
break;
case sun4m:
+#ifdef CONFIG_PCI
+ pcic_probe();
+ if (pci_present()) {
+ sun4m_pci_init_IRQ();
+ break;
+ }
+#endif
sun4m_init_IRQ();
break;
--- /dev/null
+/* $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 *)®s[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
-/* $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)
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;
/* 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();
}
}
void machine_power_off(void)
{
+#ifdef CONFIG_SUN_AUXIO
if (auxio_power_register)
*auxio_power_register |= AUXIO_POWER_OFF;
+#endif
machine_halt();
}
*/
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(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ current->flags &= ~(PF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->tss.float_regs[0], ¤t->tss.fsr,
+ ¤t->tss.fpqueue[0], ¤t->tss.fpqdepth);
+ last_task_used_math = 0;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ memcpy(&fpregs->pr_fr.pr_regs[0],
+ ¤t->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],
+ ¤t->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;
}
/*
-/* $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)
switch(sparc_cpu_model) {
case sun4:
printk("SUN4\n");
-#ifdef CONFIG_SUN4_FORCECONSOLE
- register_console(&prom_console);
-#endif
packed = 0;
break;
case sun4c:
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();
}
}
-/* $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
{
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);
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],
- ¤t->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= copy_to_user(&sc->sigc_wbuf[window],
+ ¤t->tss.reg_window[window],
+ sizeof(struct reg_window));
}
else
- 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);
/* 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);
regs->psr &= ~(PSR_EF);
}
#endif
- copy_to_user(&fpu->si_float_regs[0], ¤t->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], ¤t->tss.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->tss.fsr, &fpu->si_fsr);
+ err |= __put_user(current->tss.fpqdepth, &fpu->si_fpqdepth);
if (current->tss.fpqdepth != 0)
- copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
+ err |= copy_to_user(&fpu->si_fpqueue[0], ¤t->tss.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
current->used_math = 0;
+ return err;
}
static inline void
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();
}
/* 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;
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]));
sigill_and_return:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
static inline void
struct rt_signal_frame *sf;
int sigframe_size;
unsigned int psr;
- int i;
+ int i, err;
synchronize_user_stack();
sigframe_size = RT_ALIGNEDSZ;
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;
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]));
sigill:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/* Setup a Solaris stack frame */
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);
}
/* 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;
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], ®s->u_regs [UREG_G1], sizeof (long) * 7);
- copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8);
+ err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (long) * 7);
+ err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (long) * 8);
/* Setup sigaltstack */
- __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.
* 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], ¤t->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],
+ ¤t->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 */
* 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;
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;
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)
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;
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], ®s->u_regs [UREG_G1], sizeof (uint) * 7);
- copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8);
+ err |= copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs [UREG_G1], sizeof (uint) * 7);
+ err |= copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs [UREG_I0], sizeof (uint) * 8);
/* Setup sigaltstack */
- __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();
spin_unlock_irq(¤t->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(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
- copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
- return 0;
+ err |= copy_from_user(®s->u_regs [UREG_G1], &(*gr)[SVR4_G1],
+ sizeof (long) * 7);
+ err |= copy_from_user(®s->u_regs [UREG_I0], &(*gr)[SVR4_O0],
+ sizeof (long) * 8);
+ return (err ? -EFAULT : 0);
sigsegv_and_return:
lock_kernel();
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());
}
}
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;
+}
-/* $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)
/* 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);
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);
#endif
EXPORT_SYMBOL(page_offset);
+
+#ifndef CONFIG_SUN4
EXPORT_SYMBOL(stack_top);
+#endif
/* Atomic operations. */
EXPORT_SYMBOL_PRIVATE(_atomic_add);
/* sparc library symbols */
EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL_NOVERS(memscan);
EXPORT_SYMBOL(strlen);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strcpy);
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);
{
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
* 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
prom_halt();
}
+#if 0
+ /* This does not work on 4/330 */
sun4c_enable_irq(10);
+#endif
claim_ticker14(NULL, PROFILE_IRQ, 0);
}
-/* $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.
*
/* 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),
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;
#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" :
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();
/* 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)
{
}
}
+#endif
+
extern unsigned int prof_multiplier[NR_CPUS];
extern unsigned int prof_counter[NR_CPUS];
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) {
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++) {
*
* 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
};
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;
#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" :
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]);
if(!--prof_counter[cpu]) {
int user = user_mode(regs);
+
if(current->pid) {
update_one_process(current, 1, user, !user, cpu);
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);
}
-/* $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
}
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
out_putf:
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)))
-/* $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)
}
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
if(!ret_type)
retval = ((retval < PAGE_OFFSET) ? 0 : retval);
-/* $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
-/* $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)
* 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>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/init.h>
+#include <linux/pci.h>
#include <asm/oplib.h>
#include <asm/segment.h>
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;
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();
/* 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.
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;
#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);
#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");
__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;
}
void do_settimeofday(struct timeval *tv)
+{
+ bus_do_settimeofday(tv);
+}
+
+static void sbus_do_settimeofday(struct timeval *tv)
{
cli();
#if !CONFIG_AP1000
-/* $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)
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
* 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; \
.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; \
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,#)
.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
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
-/* $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;
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;
__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();
-# $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
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
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
-/* $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.
-/* $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)
(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,
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.
*/
}
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..
regs->u_regs[UREG_G2] = g2;
regs->pc = fixup;
regs->npc = regs->pc + 4;
- goto out;
+ return;
}
}
if(from_user) {
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,
-/* $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)
-/* $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)
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);
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
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))
{
#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 */
/* 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 */
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);
-/* $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)
_unused = sun4c_get_context();
sun4c_set_context(_unused);
+#ifdef CONFIG_SUN_AUXIO
_unused = *AUXREG;
+#endif
}
/* Bootup utility functions. */
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:
~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) {
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);
{
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);
{
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);
+++ /dev/null
-/* $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
-/* $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>
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.
*/
i = 0;
}
#endif
-
break;
default:
i = -1;
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;
return PROMDEV_I_UNK;
case PROM_AP1000:
return PROMDEV_I_UNK;
- };
+ }
}
/* Query for output device type */
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]==':') {
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;
break;
case PROM_AP1000:
default:
- return PROMDEV_I_UNK;
- };
+ }
return PROMDEV_O_UNK;
}
-/* $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.
*
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/ctype.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
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)
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
+ __start___fixup = .;
.fixup : { *(.fixup) }
+ __stop___fixup = .;
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
-# $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
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
-# $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.
#
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
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
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
-CONFIG_PCI_CONSOLE=y
#
# Misc Linux/SPARC drivers
# 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
# 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
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
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
# Kernel hacking
#
# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_EC_FLUSH_TRAP is not set
-# $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
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
#
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
@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>
@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>
# 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(¤t->mm->count) != 1)
return 0;
current->dumpable = 0;
* 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;
-/* 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
#!/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
-/* $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.
*
-/* $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)
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);
}
}
-extern void sun4u_start_timers(void);
extern void clock_probe(void);
__initfunc(void ebus_init(void))
++num_ebus;
}
-#ifndef CONFIG_FB
- pci_console_init();
-#endif
-
#ifdef CONFIG_SUN_OPENPROMIO
openprom_init();
#endif
#ifdef CONFIG_OBP_FLASH
flash_init();
#endif
- sun4u_start_timers();
clock_probe();
}
-/* $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)
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
.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
.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
-/* $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)
#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;
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;
}
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;
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;
}
__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;
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) {
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;
}
}
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;
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;
}
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:
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)
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;
}
}
};
-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];
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);
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;
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;
}
#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;
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;
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;
}
#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;
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;
}
__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;
void *karg;
int err = 0;
+ memset(&cmap, 0, sizeof(cmap));
switch (cmd) {
case FBIOGET_FSCREENINFO:
karg = &fix;
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;
set_fs(old_fs);
if(error == 0) {
- uvp = (unsigned int *)A(arg);
+ uvp = (unsigned int *)arg;
if(put_user(kval, uvp))
error = -EFAULT;
}
#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;
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:
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:
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:
{
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 {
};
#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;
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)
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);
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:
#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;
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);
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 {
__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;
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)
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)
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 {
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;
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);
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;
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;
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) {
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:
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
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:
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;
}
-/* $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)
* 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... */
*/
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);
#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;
}
/*
-/* $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)
#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];
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)
-/* $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)
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
-/* $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)
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
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
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
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();
"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
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
-/* $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
/* 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)
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;
}
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();
mcontext_t *mcp;
unsigned long fp, i7;
unsigned char fenab;
+ int err;
synchronize_user_stack();
if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
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, ¤t->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, ¤t->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();
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)
/* 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);
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();
}
/* 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;
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);
sigill:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
static inline void
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();
}
/* 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;
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);
sigill:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
static inline void handle_signal(unsigned long signr, struct k_sigaction *ka,
}
}
+#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.
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:
-/* $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
/* #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):
*
recalc_sigpending(current);
spin_unlock_irq(¤t->sigmask_lock);
return;
+
segv:
- send_sig(SIGSEGV, current, 1);
+ lock_kernel();
+ do_exit(SIGSEGV);
}
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)
spin_unlock_irq(¤t->sigmask_lock);
return;
segv:
- send_sig(SIGSEGV, current, 1);
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/* Checks if the fp is valid */
struct signal_sframe32 *sframep;
struct sigcontext32 *sc;
unsigned seta[_NSIG_WORDS32];
+ int err = 0;
#if 0
int window = 0;
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);
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],
- ¤t->tss.reg_window[window],
- sizeof(struct reg_window));
+ err |= copy_to_user(&sc->sigc_wbuf[window],
+ ¤t->tss.reg_window[window],
+ sizeof(struct reg_window));
}
else
#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,
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 */
}
/* 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) {
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;
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);
sigill:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
/* Setup a Solaris stack frame */
int window = 0;
#endif
unsigned psr;
- int i;
+ int i, err;
synchronize_user_stack();
save_and_clear_fpu();
}
/* 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;
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.
*/
#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], ¤t->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],
+ ¤t->tss.reg_window [window],
+ sizeof (svr4_rwindow_t));
+ err |= __put_user(0, (int *)gw->winptr + window);
}
#endif
* 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;
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
svr4_gregset_t *gr;
svr4_mcontext_t *mc;
svr4_sigset_t setv;
- int i;
+ int i, err;
synchronize_user_stack();
save_and_clear_fpu();
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;
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);
}
spin_unlock_irq(¤t->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
#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:
struct rt_signal_frame32 *sf;
int sigframe_size;
u32 psr;
- int i;
+ int i, err;
sigset_t32 seta;
/* 1. Make sure everything is clean */
}
/* 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);
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;
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);
sigill:
lock_kernel();
do_exit(SIGILL);
+sigsegv:
+ lock_kernel();
+ do_exit(SIGSEGV);
}
static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka,
/* 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);
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;
}
{
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);
{
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);
{
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.
-/* $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)
#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);
/* sparc library symbols */
EXPORT_SYMBOL(bcopy);
-EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(__strlen);
EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strcpy);
EXPORT_SYMBOL(strncpy);
-/* $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
-/* $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
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
-/* $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
}
}
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
retval = do_mmap(file, addr, len, prot, flags, off);
out_putf:
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)
-/* $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;
*
* 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;
return retval;
}
-char * getname32(u32 filename)
+char * getname32(const char *filename)
{
char *tmp, *result;
*
* 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)
{
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;
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;
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:
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;
}
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;
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;
}
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;
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;
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;
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, ×->actime) ||
+ __get_user (t.modtime, ×->modtime))
return -EFAULT;
filenam = getname32 (filename);
ret = PTR_ERR(filenam);
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;
goto out;
ret = do_readv_writev32(VERIFY_WRITE, file,
- (struct iovec32 *)A(vector), count);
+ vector, count);
out:
fput(file);
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;
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);
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;
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)
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;
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;
*/
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;
}
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;
__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;
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;
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;
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;
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;
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;
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;
}
#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;
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) {
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)
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);
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;
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;
}
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;
}
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;
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;
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;
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);
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;
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;
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;
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;
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;
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);
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;
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);
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;
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;
}
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;
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;
}
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;
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;
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);
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;
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;
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;
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;
}
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. */
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];
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;
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;
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;
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);
}
}
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];
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;
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;
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;
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);
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);
/* 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 {
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;
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;
}
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;
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;
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);
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))
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;
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;
}
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;
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));
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;
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];
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;
}
(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)
(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,
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);
}
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;
-/* $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
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,
-/* $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.
*
.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
.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
-/* $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)
#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);
}
/* 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;
}
/* 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;
/* 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;
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;
}
kick_start_clock();
set_system_time();
+
+ __restore_flags(flags);
}
#ifndef BCD_TO_BIN
#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);
-/* $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)
}
#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 ();
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. */
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();
unlock_kernel();
}
-void instruction_access_exception (struct pt_regs *regs)
+void do_iae(struct pt_regs *regs)
{
clean_and_reenable_l1_caches();
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) {
-/* $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)
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)
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)
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)
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)
-/* $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.
*
}
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();
}
}
{
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));
}
}
{
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++) {
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))) {
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)
-/* $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.
*
* 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
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.
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
+
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
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
#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
-/* $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.
-/* $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)
(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 (®s, 0, sizeof (regs));
- regs.tpc = pc;
- regs.tnpc = pc + 4;
- /* FIXME: Should set up regs->tstate? */
- unhandled_fault (address, current, ®s);
- /* 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;
}
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..
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();
}
-/* $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)
/* 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;
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));
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;
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++) {
pte_clear(ptep);
}
-#ifdef NOTUSED
void sparc_ultra_dump_itlb(void)
{
int slot;
{
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 */
-/* $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)
__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
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:
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.
-/* $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[];
-/* $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)
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:
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
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,
#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);
static void do_update_region(int currcons, unsigned long start, int count)
{
+#ifndef VT_BUF_VRAM_ONLY
unsigned int xx, yy, offset;
u16 *p;
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);
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
a <<= 1;
return a;
}
+#else
+ return 0;
+#endif
}
static void update_attr(int currcons)
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;
}
}
}
- if (IS_VISIBLE)
+#endif
+ if (DO_UPDATE)
do_update_region(currcons, (unsigned long) p, count);
}
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)
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);
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);
}
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);
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);
}
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;
}
{
/* ++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;
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);
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);
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);
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;
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;
}
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;
((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;
}
goto quit;
}
+ if (vcmode != KD_TEXT)
+ return;
+
/* undraw cursor first */
if (IS_FG)
hide_cursor(currcons);
return kmem_start;
}
+#ifndef VT_SINGLE_DRIVER
+
static void clear_buffer_attributes(int currcons)
{
unsigned short *p = (unsigned short *) origin;
con_driver_map[i] = NULL;
}
+#endif
+
/*
* Screen blanking
*/
EXPORT_SYMBOL(video_scan_lines);
EXPORT_SYMBOL(vc_resize);
+#ifndef VT_SINGLE_DRIVER
EXPORT_SYMBOL(take_over_console);
EXPORT_SYMBOL(give_up_console);
+#endif
#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)
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
/* 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. */
#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) */
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
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
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 *);
#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
int entry, skblen, len;
int status = 0;
static int outs;
+ unsigned long flags;
/* Transmitter timeout, serious problems */
if (dev->tbusy) {
}
/* 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 */
if (TX_BUFFS_AVAIL)
dev->tbusy = 0;
+ restore_flags(flags);
return status;
}
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();
}
--- /dev/null
+/*
+ * 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 */
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
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;
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);
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;
}
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)
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;
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;
}
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);
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)
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;
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);
* 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) {
++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) {
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);
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];
}
/* This card is _fucking_ hot... */
- if(!~(csum))
+ if(!(csum ^ 0xffff))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
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;
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)
return -EAGAIN;
}
} else
-#else
+#endif
#ifdef CONFIG_PCI
if(hp->happy_flags & HFLAG_PCI) {
if(request_irq(dev->irq, &pci_happy_meal_interrupt,
return -EAGAIN;
}
} else
-#endif
#endif
if(request_irq(dev->irq, &happy_meal_interrupt,
SA_SHIRQ, "HAPPY MEAL", (void *)dev)) {
}
#ifdef CONFIG_PCI
+#ifdef __sparc_v9__
extern inline void pcihme_write_rxd(struct happy_meal_rxd *rp,
unsigned int flags,
unsigned int addr)
: "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) */
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
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
/* 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;
cs4231_init();
#endif
+#ifdef CONFIG_SPARCAUDIO_DBRI
+ dbri_init();
+#endif
+
return 0;
}
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 */
#include <asm/delay.h>
#include <asm/sbus.h>
-#include "audio.h"
+#include <asm/audioio.h>
#include "dbri.h"
/* 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 */
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
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;
}
-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;
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
*/
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);
/*
*/
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;
}
* 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);
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);
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;
/* 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)
if(dbri->mm.version == 0xff)
return -EIO;
- /*
- mmcodec_init_data(dbri, &n);
- */
+ mmcodec_init_data(dbri);
return 0;
}
* 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) ) {
/*
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;
}
+/*
+****************************************************************************
+******************** 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)
return err;
}
- dbri_init(drv);
+ dbri_initialize(drv);
err = mmcodec_init(drv);
if(err) {
dbri_detach(drv);
}
}
#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:
+ */
#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 */
/* 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 */
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
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
#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); }
{
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;
}
-/* $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)
-/* $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)
-/* $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;
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);
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;
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)
{
outl(0, pcibeep_iobase);
restore_flags(flags);
}
+#endif
static void nop_kd_mksound(unsigned int hz, unsigned int ticks)
{
__initfunc(static char *do_pcikbd_init_hw(void))
{
+
while(pcikbd_wait_for_input() != -1)
;
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) {
/*
* 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;
printk("8042(speaker): iobase[%016lx]%s\n", pcibeep_iobase,
edev ? "" : " (forced)");
}
+#endif
disable_irq(pcikbd_irq);
msg = do_pcikbd_init_hw();
* Here begins the Mouse Driver.
*/
-static int ms_node;
-
static unsigned long pcimouse_iobase = 0;
static unsigned int pcimouse_irq;
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);
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
*/
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;
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();
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",
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);
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");
* 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;
}
-/* $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)
-/* $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)
#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);
/*
* 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 */
}
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:
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)
__initfunc(static inline void show_serial_version(void))
{
- char *revision = "$Revision: 1.20 $";
+ char *revision = "$Revision: 1.23 $";
char *version, *p;
version = strchr(revision, ' ');
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;
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;
}
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')
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;
/*
if (i & CBAUDEX) {
i &= ~(CBAUDEX);
if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
- info->tty->termios->c_cflag &= ~CBAUDEX;
+ cflag &= ~CBAUDEX;
else
i += 15;
}
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 */
+
--- /dev/null
+/* $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 *)®0, sizeof(reg0)) == -1) {
+ prom_printf("su: no \"reg\" property\n");
+ return;
+ }
+ prom_apply_obio_ranges(®0, 1);
+ if ((info->port = (unsigned long) sparc_alloc_io(reg0.phys_addr,
+ 0, reg0.reg_size, "su-regs", reg0.which_io, 0)) == 0) {
+ prom_printf("su: cannot map\n");
+ return;
+ }
+ /*
+ * There is no intr property on MrCoffee, so hardwire it. Krups?
+ */
+ info->irq = 13;
+#endif
+
+ info->magic = SERIAL_MAGIC;
+
+ save_flags(flags); cli();
+
+ /*
+ * Do a simple existence test first; if we fail this, there's
+ * no point trying anything else.
+ *
+ * 0x80 is used as a nonsense port to prevent against false
+ * positives due to ISA bus float. The assumption is that
+ * 0x80 is a non-existent port; which should be safe since
+ * include/asm/io.h also makes this assumption.
+ */
+ scratch = serial_in(info, UART_IER);
+ su_outb(info, UART_IER, 0);
+ scratch2 = serial_in(info, UART_IER);
+ su_outb(info, UART_IER, scratch);
+ if (scratch2) {
+ restore_flags(flags);
+ return; /* We failed; there's nothing here */
+ }
+
+#if 0 /* P3 You will never beleive but SuperIO fails this test in MrCoffee. */
+ scratch = serial_in(info, UART_MCR);
+ su_outb(info, UART_MCR, UART_MCR_LOOP | scratch);
+ scratch2 = serial_in(info, UART_MSR);
+ su_outb(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_in(info, UART_MSR) & 0xF0;
+ su_outb(info, UART_MCR, scratch);
+ su_outb(info, UART_MSR, scratch2);
+ if (status1 != 0x90) {
+ restore_flags(flags);
+ return;
+ }
+#endif
+
+ scratch2 = serial_in(info, UART_LCR);
+ su_outb(info, UART_LCR, 0xBF); /* set up for StarTech test */
+ su_outb(info, UART_EFR, 0); /* EFR is the same as FCR */
+ su_outb(info, UART_LCR, 0);
+ su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ scratch = serial_in(info, UART_IIR) >> 6;
+ switch (scratch) {
+ case 0:
+ info->type = PORT_16450;
+ break;
+ case 1:
+ info->type = PORT_UNKNOWN;
+ break;
+ case 2:
+ info->type = PORT_16550;
+ break;
+ case 3:
+ info->type = PORT_16550A;
+ break;
+ }
+ if (info->type == PORT_16550A) {
+ /* Check for Startech UART's */
+ su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+ if (su_inb(info, UART_EFR) == 0) {
+ info->type = PORT_16650;
+ } else {
+ su_outb(info, UART_LCR, 0xBF);
+ if (su_inb(info, UART_EFR) == 0)
+ info->type = PORT_16650V2;
+ }
+ }
+ if (info->type == PORT_16550A) {
+ /* Check for TI 16750 */
+ su_outb(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+ su_outb(info, UART_FCR,
+ UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
+ scratch = su_inb(info, UART_IIR) >> 5;
+ if (scratch == 7) {
+ su_outb(info, UART_LCR, 0);
+ su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ scratch = su_inb(info, UART_IIR) >> 5;
+ if (scratch == 6)
+ info->type = PORT_16750;
+ }
+ su_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ }
+ su_outb(info, UART_LCR, scratch2);
+ if (info->type == PORT_16450) {
+ scratch = su_inb(info, UART_SCR);
+ su_outb(info, UART_SCR, 0xa5);
+ status1 = su_inb(info, UART_SCR);
+ su_outb(info, UART_SCR, 0x5a);
+ status2 = su_inb(info, UART_SCR);
+ su_outb(info, UART_SCR, scratch);
+
+ if ((status1 != 0xa5) || (status2 != 0x5a))
+ info->type = PORT_8250;
+ }
+ info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size;
+
+ if (info->type == PORT_UNKNOWN) {
+ restore_flags(flags);
+ return;
+ }
+
+#ifdef __sparc_v9__
+ sprintf(info->name, "su(%s)", info->ms_node ? "mouse" : "kbd");
+ request_region(info->port, 8, info->name);
+#else
+ strcpy(info->name, "su(serial)");
+#endif
+
+ /*
+ * Reset the UART.
+ */
+ su_outb(info, UART_MCR, 0x00);
+ su_outb(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT));
+ su_inb(info, UART_RX);
+
+ restore_flags(flags);
+}
+
+/*
+ * The serial driver boot-time initialization code!
+ */
+__initfunc(int su_init(void))
+{
+ int i;
+ struct su_struct *info;
+ extern void atomwide_serial_init (void);
+ extern void dualsp_serial_init (void);
+
+#ifdef CONFIG_ATOMWIDE_SERIAL
+ atomwide_serial_init ();
+#endif
+#ifdef CONFIG_DUALSP_SERIAL
+ dualsp_serial_init ();
+#endif
+
+ init_bh(SERIAL_BH, do_serial_bh);
+ timer_table[RS_TIMER].fn = su_timer;
+ timer_table[RS_TIMER].expires = 0;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ IRQ_ports[i] = 0;
+ IRQ_timeout[i] = 0;
+#ifdef CONFIG_SERIAL_MULTIPORT
+ memset(&rs_multiport[i], 0,
+ sizeof(struct rs_multiport_struct));
+#endif
+ }
+#if 0 /* Must be shared with keyboard on MrCoffee. */
+#ifdef CONFIG_SERIAL_CONSOLE
+ /*
+ * The interrupt of the serial console port
+ * can't be shared.
+ */
+ if (sercons.flags & CON_CONSDEV) {
+ for(i = 0; i < NR_PORTS; i++)
+ if (i != sercons.index &&
+ su_table[i].irq == su_table[sercons.index].irq)
+ su_table[i].irq = 0;
+ }
+#endif
+#endif
+ show_su_version();
+
+ /* Initialize the tty_driver structure */
+
+ memset(&serial_driver, 0, sizeof(struct tty_driver));
+ serial_driver.magic = TTY_DRIVER_MAGIC;
+ serial_driver.driver_name = "su";
+ serial_driver.name = "ttyS";
+ serial_driver.major = TTY_MAJOR;
+ serial_driver.minor_start = 64;
+ serial_driver.num = NR_PORTS;
+ serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver.subtype = SERIAL_TYPE_NORMAL;
+ serial_driver.init_termios = tty_std_termios;
+ serial_driver.init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver.flags = TTY_DRIVER_REAL_RAW;
+ serial_driver.refcount = &serial_refcount;
+ serial_driver.table = serial_table;
+ serial_driver.termios = serial_termios;
+ serial_driver.termios_locked = serial_termios_locked;
+
+ serial_driver.open = su_open;
+ serial_driver.close = su_close;
+ serial_driver.write = su_write;
+ serial_driver.put_char = su_put_char;
+ serial_driver.flush_chars = su_flush_chars;
+ serial_driver.write_room = su_write_room;
+ serial_driver.chars_in_buffer = su_chars_in_buffer;
+ serial_driver.flush_buffer = su_flush_buffer;
+ serial_driver.ioctl = su_ioctl;
+ serial_driver.throttle = su_throttle;
+ serial_driver.unthrottle = su_unthrottle;
+ serial_driver.send_xchar = su_send_xchar;
+ serial_driver.set_termios = su_set_termios;
+ serial_driver.stop = su_stop;
+ serial_driver.start = su_start;
+ serial_driver.hangup = su_hangup;
+ serial_driver.break_ctl = su_break;
+ serial_driver.wait_until_sent = su_wait_until_sent;
+ serial_driver.read_proc = su_read_proc;
+
+ /*
+ * The callout device is just like normal device except for
+ * major number and the subtype code.
+ */
+ callout_driver = serial_driver;
+ callout_driver.name = "cua";
+ callout_driver.major = TTYAUX_MAJOR;
+ callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ callout_driver.read_proc = 0;
+ callout_driver.proc_entry = 0;
+
+ if (tty_register_driver(&serial_driver))
+ panic("Couldn't register regular su\n");
+ if (tty_register_driver(&callout_driver))
+ panic("Couldn't register callout su\n");
+
+ for (i = 0, info = su_table; i < NR_PORTS; i++, info++) {
+ info->magic = SSTATE_MAGIC;
+ info->line = i;
+ info->type = PORT_UNKNOWN;
+ info->baud_base = BAUD_BASE;
+ /* info->flags = 0; */
+ info->custom_divisor = 0;
+ info->close_delay = 5*HZ/10;
+ info->closing_wait = 30*HZ;
+ info->callout_termios = callout_driver.init_termios;
+ info->normal_termios = serial_driver.init_termios;
+ info->icount.cts = info->icount.dsr =
+ info->icount.rng = info->icount.dcd = 0;
+ info->icount.rx = info->icount.tx = 0;
+ info->icount.frame = info->icount.parity = 0;
+ info->icount.overrun = info->icount.brk = 0;
+ info->tqueue.routine = do_softint;
+ info->tqueue.data = info;
+
+ if (info->kbd_node)
+ info->cflag = B1200 | CS8 | CREAD;
+ else if (info->ms_node)
+ info->cflag = B4800 | CS8 | CREAD;
+ else
+ info->cflag = B9600 | CS8 | CREAD;
+
+ autoconfig(info);
+ if (info->type == PORT_UNKNOWN)
+ continue;
+
+ printk(KERN_INFO "%s at %16lx (irq = %s) is a %s\n",
+ info->name, info->port, __irq_itoa(info->irq),
+ uart_config[info->type].name);
+
+ /*
+ * We want startup here because we want mouse and keyboard
+ * working without opening. On SPARC console will work
+ * without startup.
+ */
+ if (info->kbd_node) {
+ startup(info);
+ keyboard_zsinit(su_put_char_kbd);
+ } else if (info->ms_node) {
+ startup(info);
+ sun_mouse_zsinit();
+ }
+ }
+
+ return 0;
+}
+
+__initfunc(int su_probe (unsigned long *memory_start))
+{
+ struct su_struct *info = su_table;
+ int node, enode, tnode, sunode;
+ int kbnode = 0, msnode = 0;
+ int devices = 0;
+ char prop[128];
+ int len;
+
+ /*
+ * Find su on MrCoffee. We return OK code if find any.
+ * Then su_init finds every one and initializes them.
+ * We do this early because MrCoffee got no aliases.
+ */
+ node = prom_getchild(prom_root_node);
+ if ((node = prom_searchsiblings(node, "obio")) != 0) {
+ if ((sunode = prom_getchild(node)) != 0) {
+ if ((sunode = prom_searchsiblings(sunode, "su")) != 0) {
+ info->port_node = sunode;
+#ifdef CONFIG_SERIAL_CONSOLE
+ /*
+ * Console must be initiated after the generic initialization.
+ * sunserial_setinitfunc inverts order, so call this before next one.
+ */
+ sunserial_setinitfunc(memory_start, su_serial_console_init);
+#endif
+ sunserial_setinitfunc(memory_start, su_init);
+ return 0;
+ }
+ }
+ }
+
+ /*
+ * Get the nodes for keyboard and mouse from 'aliases'...
+ */
+ node = prom_getchild(prom_root_node);
+ node = prom_searchsiblings(node, "aliases");
+ if (!node)
+ return -ENODEV;
+
+ len = prom_getproperty(node, "keyboard", prop, sizeof(prop));
+ if (len > 0) {
+ prop[len] = 0;
+ kbnode = prom_finddevice(prop);
+ }
+ if (!kbnode)
+ return -ENODEV;
+
+ len = prom_getproperty(node, "mouse", prop, sizeof(prop));
+ if (len > 0) {
+ prop[len] = 0;
+ msnode = prom_finddevice(prop);
+ }
+ if (!msnode)
+ return -ENODEV;
+
+ /*
+ * Find matching EBus nodes...
+ */
+ node = prom_getchild(prom_root_node);
+ if ((node = prom_searchsiblings(node, "pci")) == 0) {
+ return -ENODEV; /* Plain sparc */
+ }
+
+ /*
+ * Check for SUNW,sabre on Ultra 5/10/AXi.
+ */
+ len = prom_getproperty(node, "model", prop, sizeof(prop));
+ if ((len > 0) && !strncmp(prop, "SUNW,sabre", len)) {
+ node = prom_getchild(node);
+ node = prom_searchsiblings(node, "pci");
+ }
+
+ /*
+ * For each PCI bus...
+ */
+ while (node) {
+ enode = prom_getchild(node);
+ enode = prom_searchsiblings(enode, "ebus");
+
+ /*
+ * For each EBus on this PCI...
+ */
+ while (enode) {
+ sunode = prom_getchild(enode);
+ tnode = prom_searchsiblings(sunode, "su");
+ if (!tnode)
+ tnode = prom_searchsiblings(sunode, "su_pnp");
+ sunode = tnode;
+
+ /*
+ * For each 'su' on this EBus...
+ */
+ while (sunode) {
+ /*
+ * Does it match?
+ */
+ if (sunode == kbnode) {
+ info->kbd_node = sunode;
+ ++info;
+ ++devices;
+ }
+ if (sunode == msnode) {
+ info->ms_node = sunode;
+ ++info;
+ ++devices;
+ }
+
+ /*
+ * Found everything we need?
+ */
+ if (devices == NR_PORTS)
+ goto found;
+
+ sunode = prom_getsibling(sunode);
+ tnode = prom_searchsiblings(sunode, "su");
+ if (!tnode)
+ tnode = prom_searchsiblings(sunode,
+ "su_pnp");
+ sunode = tnode;
+ }
+ enode = prom_getsibling(enode);
+ enode = prom_searchsiblings(enode, "ebus");
+ }
+ node = prom_getsibling(node);
+ node = prom_searchsiblings(node, "pci");
+ }
+ return -ENODEV;
+
+found:
+ sunserial_setinitfunc(memory_start, su_init);
+ rs_ops.rs_change_mouse_baud = su_change_mouse_baud;
+ sunkbd_setinitfunc(memory_start, sun_kbd_init);
+ kbd_ops.compute_shiftstate = sun_compute_shiftstate;
+ kbd_ops.setledstate = sun_setledstate;
+ kbd_ops.getledstate = sun_getledstate;
+ kbd_ops.setkeycode = sun_setkeycode;
+ kbd_ops.getkeycode = sun_getkeycode;
+#ifdef CONFIG_PCI
+ sunkbd_install_keymaps(memory_start, sun_key_maps, sun_keymap_count,
+ sun_func_buf, sun_func_table,
+ sun_funcbufsize, sun_funcbufleft,
+ sun_accent_table, sun_accent_table_size);
+#endif
+ return 0;
+}
+
+#if 0
+#ifdef MODULE
+int init_module(void)
+{
+ return su_init(); /* rs_init? su_probe? XXX */
+}
+
+void cleanup_module(void)
+{
+ unsigned long flags;
+ int e1, e2;
+ int i;
+
+ /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
+ save_flags(flags);
+ cli();
+ timer_active &= ~(1 << RS_TIMER);
+ timer_table[RS_TIMER].fn = NULL;
+ timer_table[RS_TIMER].expires = 0;
+ remove_bh(SERIAL_BH);
+ if ((e1 = tty_unregister_driver(&serial_driver)))
+ printk("SERIAL: failed to unregister serial driver (%d)\n",
+ e1);
+ if ((e2 = tty_unregister_driver(&callout_driver)))
+ printk("SERIAL: failed to unregister callout driver (%d)\n",
+ e2);
+ restore_flags(flags);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ if (su_table[i].type != PORT_UNKNOWN)
+ release_region(su_table[i].port, 8);
+ }
+ if (tmp_buf) {
+ free_page((unsigned long) tmp_buf);
+ tmp_buf = NULL;
+ }
+}
+#endif /* MODULE */
+#endif /* deadwood */
+
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+/*
+ * Wait for transmitter & holding register to empty
+ */
+static inline void wait_for_xmitr(struct su_struct *info)
+{
+ int lsr;
+ unsigned int tmout = 1000000;
+
+ do {
+ lsr = su_inb(info, UART_LSR);
+ if (--tmout == 0)
+ break;
+ } while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void serial_console_write(struct console *co, const char *s,
+ unsigned count)
+{
+ struct su_struct *info;
+ int ier;
+ unsigned i;
+
+ info = su_table + co->index;
+ /*
+ * First save the IER then disable the interrupts
+ */
+ ier = su_inb(info, UART_IER);
+ su_outb(info, UART_IER, 0x00);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++, s++) {
+ wait_for_xmitr(info);
+
+ /*
+ * Send the character out.
+ * If a LF, also do CR...
+ */
+ su_outb(info, UART_TX, *s);
+ if (*s == 10) {
+ wait_for_xmitr(info);
+ su_outb(info, UART_TX, 13);
+ }
+ }
+
+ /*
+ * Finally, Wait for transmitter & holding register to empty
+ * and restore the IER
+ */
+ wait_for_xmitr(info);
+ su_outb(info, UART_IER, ier);
+}
+
+/*
+ * Receive character from the serial port
+ */
+static int serial_console_wait_key(struct console *co)
+{
+ struct su_struct *info;
+ int ier;
+ int lsr;
+ int c;
+
+ info = su_table + co->index;
+
+ /*
+ * First save the IER then disable the interrupts so
+ * that the real driver for the port does not get the
+ * character.
+ */
+ ier = su_inb(info, UART_IER);
+ su_outb(info, UART_IER, 0x00);
+
+ do {
+ lsr = su_inb(info, UART_LSR);
+ } while (!(lsr & UART_LSR_DR));
+ c = su_inb(info, UART_RX);
+
+ /*
+ * Restore the interrupts
+ */
+ su_outb(info, UART_IER, ier);
+
+ return c;
+}
+
+static kdev_t serial_console_device(struct console *c)
+{
+ return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+/*
+ * Setup initial baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first su_open()
+ * - initialize the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+__initfunc(static int serial_console_setup(struct console *co, char *options))
+{
+ struct su_struct *info;
+ unsigned cval;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int cflag = CREAD | HUPCL | CLOCAL;
+ int quot = 0;
+ char *s;
+
+ if (options) {
+ baud = simple_strtoul(options, NULL, 10);
+ s = options;
+ while(*s >= '0' && *s <= '9')
+ s++;
+ if (*s) parity = *s++;
+ if (*s) bits = *s - '0';
+ }
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch(baud) {
+ case 1200:
+ cflag |= B1200;
+ break;
+ case 2400:
+ cflag |= B2400;
+ break;
+ case 4800:
+ cflag |= B4800;
+ break;
+ case 19200:
+ cflag |= B19200;
+ break;
+ case 38400:
+ cflag |= B38400;
+ break;
+ case 57600:
+ cflag |= B57600;
+ break;
+ case 115200:
+ cflag |= B115200;
+ break;
+ case 9600:
+ default:
+ cflag |= B9600;
+ break;
+ }
+ switch(bits) {
+ case 7:
+ cflag |= CS7;
+ break;
+ default:
+ case 8:
+ cflag |= CS8;
+ break;
+ }
+ switch(parity) {
+ case 'o': case 'O':
+ cflag |= PARODD;
+ break;
+ case 'e': case 'E':
+ cflag |= PARENB;
+ break;
+ }
+ co->cflag = cflag;
+
+ /*
+ * Divisor, bytesize and parity
+ */
+ info = su_table + co->index;
+ quot = BAUD_BASE / baud;
+ cval = cflag & (CSIZE | CSTOPB);
+#if defined(__powerpc__) || defined(__alpha__)
+ cval >>= 8;
+#else /* !__powerpc__ && !__alpha__ */
+ cval >>= 4;
+#endif /* !__powerpc__ && !__alpha__ */
+ if (cflag & PARENB)
+ cval |= UART_LCR_PARITY;
+ if (!(cflag & PARODD))
+ cval |= UART_LCR_EPAR;
+
+ /*
+ * Disable UART interrupts, set DTR and RTS high
+ * and set speed.
+ */
+ su_outb(info, UART_IER, 0);
+ su_outb(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+ su_outb(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+ su_outb(info, UART_DLL, quot & 0xff); /* LS of divisor */
+ su_outb(info, UART_DLM, quot >> 8); /* MS of divisor */
+ su_outb(info, UART_LCR, cval); /* reset DLAB */
+ info->quot = quot;
+
+ /*
+ * If we read 0xff from the LSR, there is no UART here.
+ */
+ if (su_inb(info, UART_LSR) == 0xff)
+ return -1;
+
+ return 0;
+}
+
+static struct console sercons = {
+ "ttyS",
+ serial_console_write,
+ NULL,
+ serial_console_device,
+ serial_console_wait_key,
+ NULL,
+ serial_console_setup,
+ CON_PRINTBUFFER,
+ -1,
+ 0,
+ NULL
+};
+
+/*
+ * Register console.
+ */
+__initfunc(int su_serial_console_init(void))
+{
+ extern int con_is_present(void);
+
+ if (con_is_present())
+ return 0;
+ if (serial_console == 0)
+ return 0;
+ if (su_table[0].port == 0 || su_table[0].port_node == 0)
+ return 0;
+ sercons.index = 0;
+ register_console(&sercons);
+ return 0;
+}
+
+#endif /* CONFIG_SERIAL_CONSOLE */
}
/* 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;
kbd_redirected = 0;
kbd_opened = 0;
- kbd_fasync (f, 0);
+ kbd_fasync (-1, f, 0);
return 0;
}
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;
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;
-/* $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)
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)
return kbd_ops.getkeycode(scancode);
}
-
void
sunserial_setinitfunc(unsigned long *memory_start, int (*init) (void))
{
}
#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.
*
return memory_start;
}
#endif
+
if (!ret)
return memory_start;
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
-#include <linux/uaccess.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/delay.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/uaccess.h>
#define VFC_MAJOR (60)
-/* $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"
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 */
static void show_serial_version(void)
{
- char *revision = "$Revision: 1.26 $";
+ char *revision = "$Revision: 1.29 $";
char *version, *p;
version = strchr(revision, ' ');
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;
}
}
-/* $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)
#include <linux/config.h>
#include <linux/init.h>
#include <linux/malloc.h>
+#include <linux/pci.h>
#include <asm/system.h>
#include <asm/sbus.h>
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);
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");
#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
}
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))
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,
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;
}
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
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);
}
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;
}
#endif /* CONFIG_FB_COMPAT_XPMAC) */
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
if (register_framebuffer(&fb_info) < 0)
return;
break;
#endif
default:
- display->dispsw = NULL;
+ display->dispsw = &fbcon_dummy;
break;
}
}
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),
break;
#endif
default:
- display->dispsw = NULL;
+ display->dispsw = &fbcon_dummy;
}
if (fb_info.changevar)
(*fb_info.changevar)(con);
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+
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]);
-/* $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
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:
info->dispsw.cursor = atyfb_cursor;
info->dispsw.set_font = atyfb_set_font;
}
- restore_flags(flags);
}
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];
-/* $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)
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;
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.
*/
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);
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;
#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;
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;
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);
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;
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
}
#ifdef FBCON_HAS_CFB8
disp->dispsw = &fbcon_cfb8;
#else
- disp->dispsw = NULL;
+ disp->dispsw = &fbcon_dummy;
#endif
}
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;
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];
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;
default:
printk("unsupported color depth\n");
- disp->dispsw = NULL;
+ disp->dispsw = &fbcon_dummy;
break;
}
}
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);
control_par_to_all(p, 1);
+ p->info.flags = FBINFO_FLAG_DEFAULT;
if (register_framebuffer(&p->info) < 0) {
kfree(p);
return;
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,
&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,
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);
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);
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;
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 */
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);
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;
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);
* more details.
*/
-
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
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);
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);
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();
#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>
*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;
{
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];
oldxres = disp->var.xres;
oldyres = disp->var.yres;
oldgreenlen = disp->var.green.length;
+ oldaccel = disp->var.accel_flags;
disp->var = *var;
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) {
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 */
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;
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;
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;
};
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];
}
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;
}
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;
{
__u32 i, tmp;
struct imstt_regvals *init;
+ unsigned int accel;
tmp = in_le32(&p->dc_regs[SSTATUS]);
/* printk("chip version %ld, ", (tmp & 0x0F00) >> 8); */
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) {
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 */
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;
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;
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;
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;
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);
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];
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);
* more details.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
#endif
#include <asm/io.h>
#include <asm/prom.h>
+#include <asm/bootx.h>
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
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
__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) */
}
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];
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;
#include <linux/vt_kern.h>
#include <asm/uaccess.h>
+#include <asm/pgtable.h> /* io_remap_page_range() */
#include <video/sbusfb.h>
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);
/*
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];
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;
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);
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);
}
}
-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 */
info->switch_con = &valkyriefb_switch;
info->updatevar = &valkyriefb_updatevar;
info->blank = &valkyriefb_blank;
+ info->flags = FBINFO_FLAG_DEFAULT;
}
* 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>
#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)
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
#endif
+#ifdef FBCON_HAS_CFB24
+ u32 cfb24[16];
+#endif
#ifdef FBCON_HAS_CFB32
u32 cfb32[16];
#endif
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);
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;
#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
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)
{
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);
}
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)
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);
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);
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 *
*/
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;
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;
inode->i_nlink);
return;
}
- if (!inode->i_sb) {
+ if (!sb) {
printk("ext2_free_inode: inode on nonexistent device\n");
return;
}
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);
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.. */
-/* $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>
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
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];
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;
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;
}
}
}
+
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;
-/* $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>
__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;
* 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__ */
-/* $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)
: "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)
: "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)
: "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)
--- /dev/null
+/* $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) */
-/* $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.
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
/* 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 */
-/* $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
#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)
"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;
#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__ */
-/* $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
#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__
--- /dev/null
+/* $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) */
-/* $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)
-/* $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
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) */
-/* $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.
*
*/
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);
--- /dev/null
+/* $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) */
--- /dev/null
+/* $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) */
-/* $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
* 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) */ \
-/* $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:
*/
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)
#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); }
#define SMP_FROM_INT 1
#define SMP_FROM_SYSCALL 2
-
-#else /* !(__SMP__) */
+#endif /* !(__SMP__) */
#define NO_PROC_ID 0xFF
#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; \
#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 {
#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 */
-/* $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
__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
__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
__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
__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
-/* $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
-/* $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)
#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.
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) */
-/* $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.
*
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)
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)
-/* $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)
__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; })
-/* $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
* 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 */
#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)
#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__ */
-/* $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
#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.
*/
#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
/*
-/* $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
-/* $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
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. */
};
/* 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;
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
#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);
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
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)
{
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];
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"))
}
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;
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;
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) */
#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__) */
-/* $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)
#ifdef __KERNEL__
+#include <asm/pgtable.h>
+
typedef unsigned long ide_ioreg_t;
#undef MAX_HWIFS
#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;
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,
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 */
-/* $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
#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.
#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,
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);
-/* $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
/* 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;
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__) */
-/* $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).
*
#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
/* 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 */
/* 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__
-/* $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)
#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);
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);
}
}
/* 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) */
* 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;
-/* $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
* 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) */ \
#define PROC_CHANGE_PENALTY 20
-#else /* !(__SMP__) */
+#endif /* !(__SMP__) */
#define NO_PROC_ID 0xFF
#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; \
-/* $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.
*
/* 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);
-/* $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
#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
*/
#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" \
"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)), \
"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)
-/* $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
-/* $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;
-/* $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
#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 (); \
} \
spitfire_set_secondary_context(current->tss.ctx); \
__asm__ __volatile__("flush %g6"); \
+ __restore_flags(flags); \
spin_unlock(&scheduler_lock); \
} \
} while(0)
-/* $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
* 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__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)
-/* $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
#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 */
--- /dev/null
+#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
#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" */
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 */
/* 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
#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
#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
#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
#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 */
#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];
#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"
* 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);
/*
#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 */
--- /dev/null
+/*
+ * 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 */
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,
ip_finish_output(skb);
}
-static __inline__
+extern __inline__
int ip_decrease_ttl(struct iphdr *iph)
{
u16 check = iph->check;
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.
*/
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 */
+++ /dev/null
-#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 */
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;
};
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;
* 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).
};
/*
- * timeout values
+ * Timeout values
+ * ipchains holds a copy of this definition
*/
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
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
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
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); \
/*
* /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);
/*
#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 */
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
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 ...
*/
+++ /dev/null
-#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
* 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
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 */
unsigned long PruneCalled;
unsigned long RcvPruned;
unsigned long OfoPruned;
+ unsigned long OutOfWindowIcmps;
+ unsigned long LockDroppedIcmps;
};
#endif
struct in6_addr *daddr_cache;
__u32 flow_lbl;
+ __u32 frag_size;
int hop_limit;
int mcast_hops;
int mcast_oif;
} 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;
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
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;
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);
*
* (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>
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))
}
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:
{
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);
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 */
{
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;
/* writable? */
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ else
+ sk->socket->flags |= SO_NOSPACE;
return mask;
}
-- 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)
* 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>
__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);
/*
int valbool;
int err;
struct linger ling;
- struct ifreq req;
int ret = 0;
#ifdef CONFIG_FILTER
#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
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;
}
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);
/*
* 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) {
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) {
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) {
return NULL;
}
+/*
+ * Free an option memory block.
+ */
void sock_kfree_s(struct sock *sk, void *mem, int size)
{
kfree_s(mem, size);
* 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);
* 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)
{
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;
{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},
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
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
*
* 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);
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)
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);
}
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)
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;
}
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);
*
* 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>
*
#include <net/sock.h>
#include <net/ip_fib.h>
-#define FTprint(a...)
+#define FTprint(a...)
/*
-printk(KERN_DEBUG a)
+ printk(KERN_DEBUG a)
*/
/*
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
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;
}
}
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 */
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;
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;
}
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)
#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,
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;
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 ?
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) &&
* 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;
}
}
#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));
*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;
}
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
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) {
}
#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
*
* 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>
*
* 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>
(!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;
}
*
* 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>
*
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 &&
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))
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);
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;
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);
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) {
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
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);
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",
*
* 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)
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;
}
}
/* 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) */
*
* 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
*
#endif
-#ifdef CONFIG_TRANSPARENT_PROXY
- if (ip_chk_sock(skb))
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
+ if (ip_chksock(skb))
goto local_pkt;
#endif
ip_send(skb);
return 0;
-#ifdef CONFIG_TRANSPARENT_PROXY
+#ifdef CONFIG_IP_TRANSPARENT_PROXY
local_pkt:
return ip_local_deliver(skb);
#endif
#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;
#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");
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
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;
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)))
*
* 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>
{
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)
#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
*
* 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;
return sysctl_ip_masq_debug;
}
+struct ip_masq_hook *ip_masq_user_hook = NULL;
+
/*
* Timeout table[state]
*/
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]
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!";
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);
}
*/
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)
{
return ms->timeout;
}
-#define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */
-
/*
* Dynamic address rewriting
*/
/*
* 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
* 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)
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);
/*
* 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
/*
* 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;
/*
* Hashes ip_masq by its proto,addrs,ports.
- * should be called with masked interrupts.
+ * should be called with locked tables.
* returns bool success.
*/
/*
* UNhashes ip_masq from ip_masq_[ms]_tables.
- * should be called with masked interrupts.
+ * should be called with locked tables.
* returns bool success.
*/
* 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)) &&
d_port);
out:
- ip_masq_unlock(&__ip_masq_lock, 0);
return ms;
}
* 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;
*/
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 &&
d_port);
out:
- ip_masq_unlock(&__ip_masq_lock, 0);
return ms;
}
/*
* 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)
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)) {
}
out:
- ip_masq_unlock(&__ip_masq_lock, 0);
return ms;
}
#endif
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;
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;
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 ...
*/
goto masq_expire_later;
}
+#endif
/*
* do I control anybody?
*/
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);
}
*/
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)
int ports_tried;
atomic_t *free_ports_p = NULL;
static int n_fails = 0;
+ int prio;
if (masq_proto_num(proto)!=-1 && mport == 0) {
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;
/*
* 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",
(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);
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;
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);
}
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) {
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);
}
/*
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));
* 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;
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;
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;
/* 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;
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,
*/
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 */
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;
/* 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;
return 1;
}
-
/*
* Check if it's an masqueraded port, look it up,
* and send it on its way...
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:
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...
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)
{
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));
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.
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;
return ms->control;
}
+
#ifdef CONFIG_PROC_FS
/*
* /proc/net entries
int idx = 0;
int len=0;
- ip_masq_lockz(&__ip_masq_lock, &masq_wait, 0);
if (offset < 128)
{
}
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
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;
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
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
#endif
#ifdef CONFIG_IP_MASQUERADE_IPPORTFW
ip_portfw_init();
+#endif
+#ifdef CONFIG_IP_MASQUERADE_IPMARKFW
+ ip_markfw_init();
#endif
ip_masq_app_init();
* 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>
*
#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
__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;
}
* 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
-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");
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;
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;
* 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();
}
}
-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 ...
*/
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
}
#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))) {
* 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
*
/*
* 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)
/*
* 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;
/*
* 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");
/*
*
* 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
#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
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
*/
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;
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
}
{
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;
}
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)
/*
* 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);
* 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
* 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>
*
* 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)
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);
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;
}
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];
}
}
- 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)
{
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) {
}
n = NULL;
out:
- ip_masq_unlock(&portfw_lock, 0);
return n;
}
int count = 0;
- ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
+ read_lock_bh(&portfw_lock);
l = &portfw_list[prot];
}
}
- ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+ read_unlock_bh(&portfw_lock);
return count;
}
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;
-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;
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;
int ind;
int len=0;
- ip_masq_lockz(&portfw_lock, &portfw_wait, 0);
if (offset < 64)
{
}
pos = 64;
+ read_lock_bh(&portfw_lock);
+
for(ind = 0; ind < 2; ind++)
{
l = &portfw_list[ind];
{
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",
}
}
done:
- ip_masq_unlockz(&portfw_lock, &portfw_wait, 0);
+ read_unlock_bh(&portfw_lock);
begin = len - (pos - offset);
*start = buffer + begin;
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
#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
__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,
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...
*/
*/
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;
}
* 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
/*
* 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
--- /dev/null
+/*
+ * 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 */
* 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
/*
* 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)
*
* 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>
*
* 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.
#include <net/checksum.h>
#include <linux/route.h>
#include <net/route.h>
+#include <net/ip_fib.h>
int
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);
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:
*
* 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
*
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;
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;
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;
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;
}
}
case IPOPT_SEC:
case IPOPT_SID:
default:
- if (!skb) {
+ if (!skb && !capable(CAP_NET_RAW)) {
pp_ptr = optptr;
goto error;
}
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;
- }
}
}
*
* 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>
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;
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. */
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.
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);
* 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.
*/
if (offset > 0 && df) {
+ ip_local_error(sk, EMSGSIZE, rt->rt_dst, sk->dport, mtu);
return(-EMSGSIZE);
}
/*
* 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.
*
* 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))
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)
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.
#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;
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)
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:
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)
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;
case IP_MULTICAST_LOOP:
val=sk->ip_mc_loop;
break;
-#if 0
case IP_MULTICAST_IF:
{
struct ip_mreqn mreq;
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);
}
/*
* 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
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;
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)))
* 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.
((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);
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
*/
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
return -EADDRNOTAVAIL;
break;
default:
+#if 0
printk(KERN_DEBUG "ipmr_add_vif: flags %02x\n", vif.vifc_flags);
+#endif
return -EINVAL;
}
len=length;
if (len < 0) {
len = 0;
- printk(KERN_CRIT "Yep, guys... our template for proc_*_read is crappy :-)\n");
}
return len;
}
* 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>
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)
{
*
* 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>
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);
}
}
{
/* 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);
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)
*
* 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>
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)
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)
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;
}
}
}
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);
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;
flags |= RTCF_DIRECTSRC;
}
flags |= RTCF_BROADCAST;
+ res.type = RTN_BROADCAST;
local_input:
rth = dst_alloc(sizeof(struct rtable), &ipv4_dst_ops);
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;
}
(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
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);
}
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);
/*
* 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]
/* 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;
*
* 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)
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;
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.
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. */
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)
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;
}
/* 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) {
skb->csum = csum_and_copy_from_user(from,
skb_put(skb, copy), copy, 0, &err);
+ if (err)
+ goto do_fault;
+
from += copy;
copied += copy;
}
}
sk->err = 0;
- if (err)
- return -EFAULT;
return copied;
do_sock_err:
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().
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".
*/
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;
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;
* 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:
*
* 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>
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;
}
}
+/*
+ * 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
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);
{
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
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);
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++;
}
}
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) |
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.
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;
/*
* '?' 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) {
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);
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."
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;
}
}
/*
- * 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,
}
/*
- * 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.
*/
*
* 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
*
}
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;
/* 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
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;
}
* 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)
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++;
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;
}
#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:
* 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;
}
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) {
}
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();
}
}
/* 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));
}
#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.
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... */
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))
*
* 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>
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.
*
* 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>
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++;
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
* 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);
}
/*
* 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;
* 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--;
* 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);
*
* 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");
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.
* 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;
* 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
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)
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;
* 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
*
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");
}
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;
struct inet6_protocol *ipprot;
struct sock *sk;
u8 *pb;
- __u32 info = 0;
int hash;
u8 nexthdr;
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)
icmpv6_statistics.Icmp6InMsgs++;
+ if (len < sizeof(struct icmp6hdr))
+ goto discard_it;
+
/* Perform checksum. */
switch (skb->ip_summed) {
case CHECKSUM_NONE:
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;
* 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);
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;
} 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 */
};
{
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;
*err = EPROTO;
fatal = 1;
break;
+
+ case ICMPV6_TIME_EXCEED:
+ *err = EHOSTUNREACH;
+ break;
};
return fatal;
* 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
*
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;
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;
}
}
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;
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);
*
* 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
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:
{
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:
{
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);
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)
*
* 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
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)
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;
* 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
*/
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 {
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);
}
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));
* 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
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) {
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;
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)))
* 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
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;
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)
{
struct ipv6_pinfo *np;
struct sock *sk;
int err;
- int opening;
struct tcp_opt *tp;
__u32 seq;
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);
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);
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) {
}
/* 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();
}
}
/* 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;
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.
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;
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;
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;
}
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 */
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);
}
{
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;
/* 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;
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)
dst = ip6_route_output(sk, &fl);
if (dst->error) {
- sk->err_soft = dst->error;
+ sk->err_soft = -dst->error;
dst_release(dst);
return;
}
*
* 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
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);
#endif
if (err)
goto out_free;
-
+
sk->stamp=skb->stamp;
/* Copy the address. */
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++;
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);
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);
}
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;
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;
#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>
/* 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);
*
* 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>
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);
-----------------------------------------------------------------------
- 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:
* 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>
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
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;
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;
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;
* 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.
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);
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
if (!addr)
- return -ENOBUFS;
+ return -ENOMEM;
/* We slept; recheck ... */
struct sk_buff *skb;
if (sock->state != SS_UNCONNECTED)
- return(-EINVAL);
+ return(-EINVAL);
if (!(sock->flags & SO_ACCEPTCON))
return(-EINVAL);
peer_mode |= SEND_SHUTDOWN;
if (mode&SEND_SHUTDOWN)
peer_mode |= RCV_SHUTDOWN;
- other->shutdown |= mode;
+ other->shutdown |= peer_mode;
other->state_change(other);
}
}