summaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2001-03-09 20:33:35 +0000
committerRalf Baechle <ralf@linux-mips.org>2001-03-09 20:33:35 +0000
commit116674acc97ba75a720329996877077d988443a2 (patch)
tree6a3f2ff0b612ae2ee8a3f3509370c9e6333a53b3 /arch/s390
parent71118c319fcae4a138f16e35b4f7e0a6d53ce2ca (diff)
Merge with Linux 2.4.2.
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Makefile1
-rw-r--r--arch/s390/boot/Makefile3
-rw-r--r--arch/s390/boot/ipldump.S2
-rw-r--r--arch/s390/boot/ipleckd.S40
-rw-r--r--arch/s390/config.in17
-rw-r--r--arch/s390/defconfig87
-rw-r--r--arch/s390/kernel/Makefile42
-rw-r--r--arch/s390/kernel/cpcmd.c8
-rw-r--r--arch/s390/kernel/debug.c1167
-rw-r--r--arch/s390/kernel/ebcdic.c153
-rw-r--r--arch/s390/kernel/entry.S441
-rw-r--r--arch/s390/kernel/head.S645
-rw-r--r--arch/s390/kernel/irq.c10
-rw-r--r--arch/s390/kernel/mathemu.c575
-rw-r--r--arch/s390/kernel/process.c238
-rw-r--r--arch/s390/kernel/ptrace.c52
-rw-r--r--arch/s390/kernel/reipl.S17
-rw-r--r--arch/s390/kernel/s390_ext.c77
-rw-r--r--arch/s390/kernel/s390_ksyms.c80
-rw-r--r--arch/s390/kernel/s390dyn.c36
-rw-r--r--arch/s390/kernel/s390fpu.c5
-rw-r--r--arch/s390/kernel/s390io.c4605
-rw-r--r--arch/s390/kernel/s390mach.c157
-rw-r--r--arch/s390/kernel/semaphore.c2
-rw-r--r--arch/s390/kernel/setup.c65
-rw-r--r--arch/s390/kernel/signal.c83
-rw-r--r--arch/s390/kernel/smp.c283
-rw-r--r--arch/s390/kernel/sys_s390.c26
-rw-r--r--arch/s390/kernel/time.c14
-rw-r--r--arch/s390/kernel/traps.c322
-rw-r--r--arch/s390/lib/Makefile10
-rw-r--r--arch/s390/lib/delay.c37
-rw-r--r--arch/s390/lib/strcmp.S4
-rw-r--r--arch/s390/lib/strncpy.S6
-rw-r--r--arch/s390/lib/uaccess.S51
-rw-r--r--arch/s390/mm/Makefile3
-rw-r--r--arch/s390/mm/fault.c188
-rw-r--r--arch/s390/mm/init.c66
-rw-r--r--arch/s390/mm/ioremap.c4
-rw-r--r--arch/s390/tools/dasdfmt/Makefile2
-rw-r--r--arch/s390/tools/dasdfmt/dasdfmt.828
-rw-r--r--arch/s390/tools/dasdfmt/dasdfmt.c264
-rw-r--r--arch/s390/tools/silo/Makefile6
-rw-r--r--arch/s390/tools/silo/silo.c4
-rw-r--r--arch/s390/vmlinux.lds4
45 files changed, 3563 insertions, 6367 deletions
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 7af7bb937..3023d54a2 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -14,6 +14,7 @@
#
LD=$(CROSS_COMPILE)ld -m elf_s390
+CPP=$(CC) -E
OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
LDFLAGS=-e start
LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index 817152810..fb112b964 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -10,12 +10,11 @@
OBJCOPY = $(CROSS_COMPILE)objcopy
O_TARGET :=
-O_OBJS :=
include $(TOPDIR)/Rules.make
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
%.lnk: %.o
$(LD) -Ttext 0x0 -o $@ $<
diff --git a/arch/s390/boot/ipldump.S b/arch/s390/boot/ipldump.S
index 7868268af..3a09d1fea 100644
--- a/arch/s390/boot/ipldump.S
+++ b/arch/s390/boot/ipldump.S
@@ -38,7 +38,7 @@ _start:
#
# find out memory size
#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
+ mvc 104(8),.Lpcmem0 # setup program check handler
slr %r3,%r3
lhi %r2,1
sll %r2,20
diff --git a/arch/s390/boot/ipleckd.S b/arch/s390/boot/ipleckd.S
index 63b0330b2..d66a8d684 100644
--- a/arch/s390/boot/ipleckd.S
+++ b/arch/s390/boot/ipleckd.S
@@ -3,7 +3,7 @@
# IPL record for 3380/3390 DASD
#
# S390 version
-# Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
# Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
#
#
@@ -11,6 +11,8 @@
# FIXME: should insert zeroes into memory when filling holes
# FIXME: calculate blkpertrack from rdc data and blksize
+# change 09/20/00 removed obsolete store of ipldevice to textesegment
+
# Usage of registers
# r1: ipl subchannel ( general use, dont overload without save/restore !)
# r10:
@@ -39,7 +41,7 @@
.org 0xf0 # Lets start now...
_start: .globl _start
- l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore
+ l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore
st %r1,__LC_IPLDEV # keep it for reipl
stsch .Lrdcdata
oi .Lrdcdata+5,0x84 # enable ssch and multipath mode
@@ -111,10 +113,10 @@ _start: .globl _start
mvc 0x600(256,%r3),0x180(%r4)
mvc 0x700(256,%r3),0x280(%r4)
.Lrunkern:
- lhi %r2,17
- sll %r2,12
- st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
- st %r1,0xc6c # store iplsubchannel to lowcore
+# lhi %r2,17
+# sll %r2,12
+# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore
+# st %r1,0xc6c # store iplsubchannel to lowcore
br %r3
# This function does the start IO
# r2: number of first block to read ( input by caller )
@@ -140,17 +142,16 @@ _start: .globl _start
lr %r15,%r4 # save number or blocks
slr %r7,%r7
icm %r7,3,.Lrdcdata+14 # load heads to r7
+ lhi %r6,9
+ clc .Lrdcdata+3(2),.L9345
+ je .L011
+ lhi %r6,10
+ clc .Lrdcdata+3(2),.L3380
+ je .L011
+ lhi %r6,12
clc .Lrdcdata+3(2),.L3390
- jne .L010 # 3380 or 3390 ?
- lhi %r6,12 # setup r6 correct!
- j .L011
-.L010:
- clc .Lrdcdata+3(2),.L9343
- jne .L013
- lhi %r6,9
- j .L011
-.L013:
- lhi %r6,10
+ je .L011
+ bras %r14,.Ldisab
.L011:
# loop for nbl times
.Lrdloop:
@@ -245,10 +246,13 @@ _start: .globl _start
.long 0x00008000 # they are loaded with a LM
.L3390:
.word 0x3390
-.L9343:
- .word 0x9343
+.L9345:
+ .word 0x9345
+.L3380:
+ .word 0x3380
.Lnull:
.long 0x00000000,0x00000000
+ .align 4
.Lrdcdata:
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
diff --git a/arch/s390/config.in b/arch/s390/config.in
index 4415799ff..fc3b430a6 100644
--- a/arch/s390/config.in
+++ b/arch/s390/config.in
@@ -44,31 +44,20 @@ bool 'Networking support' CONFIG_NET
bool 'System V IPC' CONFIG_SYSVIPC
bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
bool 'Sysctl support' CONFIG_SYSCTL
+define CONFIG_KCORE ELF
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
endmenu
source drivers/s390/Config.in
-mainmenu_option next_comment
-comment 'Character devices'
-bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
- int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
-fi
-
-endmenu
-
if [ "$CONFIG_NET" = "y" ]; then
source net/Config.in
fi
source fs/Config.in
-# source drivers/char/Config.in
-
-# source drivers/media/Config.in
-
mainmenu_option next_comment
comment 'Kernel hacking'
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 459d51ebb..c4e590e75 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,6 +1,9 @@
#
# Automatically generated by make menuconfig: don't edit
#
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
CONFIG_UID16=y
CONFIG_ARCH_S390=y
@@ -20,7 +23,7 @@ CONFIG_IEEEFPU_EMULATION=y
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
#
# General setup
@@ -34,41 +37,60 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PROCESS_DEBUG is not set
#
-# S/390 block device drivers
+# Block device drivers
#
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=24576
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_MDISK is not set
+CONFIG_BLK_DEV_XPRAM=m
CONFIG_DASD=y
CONFIG_DASD_ECKD=y
-# CONFIG_DASD_MDSK is not set
+CONFIG_DASD_FBA=y
#
-# S/390 Network device support
+# Multi-device support (RAID and LVM)
#
-# CONFIG_CHANDEV is not set
-CONFIG_NETDEVICES=y
-CONFIG_CTC=y
-CONFIG_IUCV=y
-# CONFIG_DUMMY is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_TR=y
-# CONFIG_FDDI is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+CONFIG_BLK_DEV_LVM=m
+CONFIG_LVM_PROC_FS=y
#
-# S/390 Terminal and Console options
+# Character device drivers
#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
CONFIG_3215=y
CONFIG_3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_S390_TAPE=m
+CONFIG_S390_TAPE_CHAR=y
+CONFIG_S390_TAPE_BLOCK=y
+CONFIG_S390_TAPE_3490=y
+CONFIG_S390_TAPE_3480=y
+
+#
+# Network device drivers
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_TR=y
+# CONFIG_FDDI is not set
+# CONFIG_CHANDEV is not set
+CONFIG_CTC=m
+CONFIG_IUCV=m
#
# Networking options
@@ -82,25 +104,24 @@ CONFIG_NETLINK=y
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
-# CONFIG_IP_ROUTER is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
+# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-CONFIG_SKB_LARGE=y
# CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_BRIDGE is not set
# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
# CONFIG_NET_FASTROUTE is not set
@@ -118,6 +139,7 @@ CONFIG_SKB_LARGE=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
@@ -126,28 +148,37 @@ CONFIG_SKB_LARGE=y
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
+# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
@@ -155,6 +186,16 @@ CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_MOUNT_SUBDIR is not set
+# CONFIG_NCPFS_NDS_DOMAINS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
@@ -168,10 +209,10 @@ CONFIG_IBM_PARTITION=y
# CONFIG_MAC_PARTITION is not set
# CONFIG_MSDOS_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
# CONFIG_NLS is not set
#
# Kernel hacking
#
-# CONFIG_REMOTE_DEBUG is not set
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index f04b1cd74..dfaadc490 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -8,47 +8,25 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
-O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
+
+export-objs := s390_ksyms.o
+obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
- semaphore.o s390fpu.o s390io.o s390mach.o s390dyn.o reipl.o
-OX_OBJS := s390_ksyms.o
-MX_OBJS :=
-
-ifdef CONFIG_SMP
-O_OBJS += smp.o
-endif
-
-ifdef CONFIG_PCI
-O_OBJS += bios32.o
-endif
-
-ifdef CONFIG_MCA
-O_OBJS += mca.o
-endif
-
-ifeq ($(CONFIG_MTRR),y)
-OX_OBJS += mtrr.o
-else
- ifeq ($(CONFIG_MTRR),m)
- MX_OBJS += mtrr.o
- endif
-endif
-
-ifeq ($(CONFIG_IEEEFPU_EMULATION),y)
- O_OBJS += mathemu.o floatlib.o
-endif
+ semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
+
+obj-$(CONFIG_MODULES) += s390_ksyms.o
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o
#
# Kernel debugging
#
-ifdef CONFIG_REMOTE_DEBUG
-O_OBJS += gdb-stub.o #gdb-low.o
-endif
+obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 818958b4f..68abd7d50 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -8,7 +8,7 @@
#include <linux/stddef.h>
#include <linux/kernel.h>
-#include <asm/string.h>
+#include <linux/string.h>
#include <asm/ebcdic.h>
void cpcmd(char *cmd, char *response, int rlen)
@@ -22,10 +22,10 @@ void cpcmd(char *cmd, char *response, int rlen)
ASCEBC(obuffer,olen);
if (response != NULL && rlen > 0) {
- asm volatile ("LRA 2,0(0,%0)\n\t"
+ asm volatile ("LRA 2,0(%0)\n\t"
"LR 4,%1\n\t"
"O 4,%4\n\t"
- "LRA 3,0(0,%2)\n\t"
+ "LRA 3,0(%2)\n\t"
"LR 5,%3\n\t"
".long 0x83240008 # Diagnose 83\n\t"
: /* no output */
@@ -34,7 +34,7 @@ void cpcmd(char *cmd, char *response, int rlen)
: "2", "3", "4", "5" );
EBCASC(response, rlen);
} else {
- asm volatile ("LRA 2,0(0,%0)\n\t"
+ asm volatile ("LRA 2,0(%0)\n\t"
"LR 3,%1\n\t"
".long 0x83230008 # Diagnose 83\n\t"
: /* no output */
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
new file mode 100644
index 000000000..bb3dfe5de
--- /dev/null
+++ b/arch/s390/kernel/debug.c
@@ -0,0 +1,1167 @@
+/*
+ * arch/s390/kernel/debug.c
+ * S/390 debug facility
+ *
+ * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ * IBM Corporation
+ * Author(s): Michael Holzheu (holzheu@de.ibm.com),
+ * Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ *
+ * Bugreports to: <Linux390@de.ibm.com>
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
+#include <asm/debug.h>
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+#if defined(CONFIG_ARCH_S390X)
+#define DEBUG_PROC_HEADER_SIZE 46
+#else
+#define DEBUG_PROC_HEADER_SIZE 38
+#endif
+
+#define ADD_BUFFER 1000
+
+/* typedefs */
+
+typedef struct file_private_info {
+ loff_t len; /* length of output in byte */
+ int size; /* size of buffer for output */
+ char *data; /* buffer for output */
+ debug_info_t *debug_info; /* the debug information struct */
+ struct debug_view *view; /* used view of debug info */
+} file_private_info_t;
+
+extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
+
+/* internal function prototyes */
+
+static int debug_init(void);
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view);
+static ssize_t debug_output(struct file *file, char *user_buf,
+ size_t user_len, loff_t * offset);
+static ssize_t debug_input(struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset);
+static int debug_open(struct inode *inode, struct file *file);
+static int debug_close(struct inode *inode, struct file *file);
+static struct proc_dir_entry
+*debug_create_proc_dir_entry(struct proc_dir_entry *root,
+ const char *name, mode_t mode,
+ struct inode_operations *iops,
+ struct file_operations *fops);
+static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
+ struct proc_dir_entry *entry);
+static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
+static void debug_info_get(debug_info_t *);
+static void debug_info_put(debug_info_t *);
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf);
+
+/* globals */
+
+struct debug_view debug_raw_view = {
+ "raw",
+ NULL,
+ &debug_raw_header_fn,
+ &debug_raw_format_fn,
+ NULL
+};
+
+struct debug_view debug_hex_ascii_view = {
+ "hex_ascii",
+ NULL,
+ &debug_dflt_header_fn,
+ &debug_hex_ascii_format_fn,
+ NULL
+};
+
+struct debug_view debug_level_view = {
+ "level",
+ &debug_prolog_level_fn,
+ NULL,
+ NULL,
+ &debug_input_level_fn
+};
+
+/* static globals */
+
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+static struct semaphore debug_lock = MUTEX;
+#else
+DECLARE_MUTEX(debug_lock);
+#endif
+
+static int initialized = 0;
+
+static struct file_operations debug_file_ops = {
+ read: debug_output,
+ write: debug_input,
+ open: debug_open,
+ release: debug_close,
+};
+
+static struct inode_operations debug_inode_ops = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ default_file_ops: &debug_file_ops, /* file ops */
+#endif
+};
+
+
+static struct proc_dir_entry *debug_proc_root_entry;
+
+
+/* functions */
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t* debug_info_create(char *name, int page_order,
+ int nr_areas, int buf_size)
+{
+ debug_info_t* rc;
+ int i;
+
+ /* alloc everything */
+
+ rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+ if(!rc)
+ goto fail_malloc_rc;
+ rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
+ if(!rc->active_entry)
+ goto fail_malloc_active_entry;
+ memset(rc->active_entry, 0, nr_areas * sizeof(int));
+ rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+ sizeof(debug_entry_t *),
+ GFP_ATOMIC);
+ if (!rc->areas)
+ goto fail_malloc_areas;
+ for (i = 0; i < nr_areas; i++) {
+ rc->areas[i] =
+ (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+ page_order);
+ if (!rc->areas[i]) {
+ for (i--; i >= 0; i--) {
+ free_pages((unsigned long) rc->areas[i],
+ page_order);
+ }
+ goto fail_malloc_areas2;
+ } else {
+ memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+ }
+ }
+
+ /* initialize members */
+
+ spin_lock_init(&rc->lock);
+ rc->page_order = page_order;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = DEBUG_DEFAULT_LEVEL;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t) + buf_size;
+ strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+ rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+ memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+ memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
+ sizeof(struct proc_dir_entry*));
+ atomic_set(&(rc->ref_count), 0);
+ rc->proc_root_entry =
+ debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+ S_IFDIR | S_IRUGO | S_IXUGO |
+ S_IWUSR | S_IWGRP, NULL, NULL);
+
+ /* append new element to linked list */
+
+ if(debug_area_first == NULL){
+ /* first element in list */
+ debug_area_first = rc;
+ rc->prev = NULL;
+ }
+ else{
+ /* append element to end of list */
+ debug_area_last->next = rc;
+ rc->prev = debug_area_last;
+ }
+ debug_area_last = rc;
+ rc->next = NULL;
+
+ debug_info_get(rc);
+ return rc;
+
+fail_malloc_areas2:
+ kfree(rc->areas);
+fail_malloc_areas:
+ kfree(rc->active_entry);
+fail_malloc_active_entry:
+ kfree(rc);
+fail_malloc_rc:
+ return NULL;
+}
+
+/*
+ * debug_info_get
+ * - increments reference count for debug-info
+ */
+
+static void debug_info_get(debug_info_t * db_info)
+{
+ if (db_info)
+ atomic_inc(&db_info->ref_count);
+}
+
+/*
+ * debug_info_put:
+ * - decreases reference count for debug-info and frees it if necessary
+ */
+
+static void debug_info_put(debug_info_t *db_info)
+{
+ int i;
+
+ if (!db_info)
+ return;
+ if (atomic_dec_and_test(&db_info->ref_count)) {
+ printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
+ db_info, db_info->name);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (db_info->views[i] != NULL)
+ debug_delete_proc_dir_entry
+ (db_info->proc_root_entry,
+ db_info->proc_entries[i]);
+ }
+ debug_delete_proc_dir_entry(debug_proc_root_entry,
+ db_info->proc_root_entry);
+ for (i = 0; i < db_info->nr_areas; i++) {
+ free_pages((unsigned long) db_info->areas[i],
+ db_info->page_order);
+ }
+ kfree(db_info->areas);
+ kfree(db_info->active_entry);
+ if(db_info == debug_area_first)
+ debug_area_first = db_info->next;
+ if(db_info == debug_area_last)
+ debug_area_last = db_info->prev;
+ if(db_info->prev) db_info->prev->next = db_info->next;
+ if(db_info->next) db_info->next->prev = db_info->prev;
+ kfree(db_info);
+ }
+}
+
+
+/*
+ * debug_output:
+ * - called for user read()
+ * - copies formated output form private_data of the file
+ * handle to the user buffer
+ */
+
+static ssize_t debug_output(struct file *file, /* file descriptor */
+ char *user_buf, /* user buffer */
+ size_t user_len, /* length of buffer */
+ loff_t *offset /* offset in the file */ )
+{
+ loff_t len;
+ int rc;
+ file_private_info_t *p_info;
+
+ p_info = ((file_private_info_t *) file->private_data);
+ if (*offset >= p_info->len) {
+ return 0; /* EOF */
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
+ return rc;;
+ (*offset) += len;
+ return len; /* number of bytes "read" */
+ }
+}
+
+/*
+ * debug_input:
+ * - called for user write()
+ * - calls input function of view
+ */
+
+static ssize_t debug_input(struct file *file,
+ const char *user_buf, size_t length,
+ loff_t *offset)
+{
+ int rc = 0;
+ file_private_info_t *p_info;
+
+ down(&debug_lock);
+ p_info = ((file_private_info_t *) file->private_data);
+ if (p_info->view->input_proc)
+ rc = p_info->view->input_proc(p_info->debug_info,
+ p_info->view, file, user_buf,
+ length, offset);
+ up(&debug_lock);
+ return rc; /* number of input characters */
+}
+
+/*
+ * debug_format_output:
+ * - calls prolog, header and format functions of view to format output
+ */
+
+static int debug_format_output(debug_info_t * debug_area, char *buf,
+ int size, struct debug_view *view)
+{
+ int len = 0;
+ int i, j;
+ int nr_of_entries;
+ debug_entry_t *act_entry;
+
+ /* print prolog */
+ if (view->prolog_proc)
+ len += view->prolog_proc(debug_area, view, buf);
+ /* print debug records */
+ if (!(view->format_proc) && !(view->header_proc))
+ goto out;
+ nr_of_entries = PAGE_SIZE / debug_area->entry_size
+ << debug_area->page_order;
+ for (i = 0; i < debug_area->nr_areas; i++) {
+ act_entry = debug_area->areas[i];
+ for (j = 0; j < nr_of_entries; j++) {
+ if (act_entry->id.fields.used == 0)
+ break; /* empty entry */
+ if (view->header_proc)
+ len += view->header_proc(debug_area, view, i,
+ act_entry, buf + len);
+ if (view->format_proc)
+ len += view->format_proc(debug_area, view,
+ buf + len,
+ DEBUG_DATA(act_entry));
+ if (len > size) {
+ printk(KERN_ERR
+ "debug: error -- memory exceeded for (%s/%s)\n",
+ debug_area->name, view->name);
+ printk(KERN_ERR "debug: fix view %s!!\n",
+ view->name);
+ printk(KERN_ERR
+ "debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
+ i, debug_area->nr_areas - 1, j,
+ nr_of_entries - 1);
+ goto out;
+ }
+ act_entry = (debug_entry_t *) (((char *) act_entry) +
+ debug_area->entry_size);
+ }
+ }
+ out:
+ return len;
+}
+
+
+/*
+ * debug_open:
+ * - called for user open()
+ * - copies formated output to private_data area of the file
+ * handle
+ */
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ int i = 0, size = 0, rc = 0, f_entry_size = 0;
+ file_private_info_t *p_info;
+ debug_info_t* debug_info;
+
+#ifdef DEBUG
+ printk("debug_open\n");
+#endif
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ down(&debug_lock);
+
+ /* find debug log and view */
+
+ debug_info = debug_area_first;
+ while(debug_info != NULL){
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (debug_info->views[i] == NULL)
+ continue;
+ else if (debug_info->proc_entries[i]->low_ino ==
+ file->f_dentry->d_inode->i_ino) {
+ goto found; /* found view ! */
+ }
+ }
+ debug_info = debug_info->next;
+ }
+ /* no entry found */
+ rc = -EINVAL;
+ goto out;
+ found:
+ if ((file->private_data =
+ kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+ printk(KERN_ERR "debug_open: kmalloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ p_info = (file_private_info_t *) file->private_data;
+
+ /*
+ * the size for the formated output is calculated
+ * with the following formula:
+ *
+ * prolog-size
+ * +
+ * (record header size + record data field size)
+ * * number of entries per page
+ * * number of pages per area
+ * * number of areas
+ */
+
+ if (debug_info->views[i]->prolog_proc)
+ size +=
+ debug_info->views[i]->prolog_proc(debug_info,
+ debug_info->
+ views[i], NULL);
+
+ if (debug_info->views[i]->header_proc)
+ f_entry_size =
+ debug_info->views[i]->header_proc(debug_info,
+ debug_info->
+ views[i], 0, NULL,
+ NULL);
+ if (debug_info->views[i]->format_proc)
+ f_entry_size +=
+ debug_info->views[i]->format_proc(debug_info,
+ debug_info->
+ views[i], NULL,
+ NULL);
+
+ size += f_entry_size
+ * (PAGE_SIZE / debug_info->entry_size
+ << debug_info->page_order)
+ * debug_info->nr_areas + 1; /* terminating \0 */
+#ifdef DEBUG
+ printk("debug_open: size: %i\n", size);
+#endif
+
+ /* alloc some bytes more to be safe against bad views */
+ if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
+ printk(KERN_ERR "debug_open: vmalloc failed\n");
+ vfree(file->private_data);
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ p_info->size = size;
+ p_info->debug_info = debug_info;
+ p_info->view = debug_info->views[i];
+
+ spin_lock_irq(&debug_info->lock);
+
+ p_info->len =
+ debug_format_output(debug_info, p_info->data, size,
+ debug_info->views[i]);
+#ifdef DEBUG
+ {
+ int ilen = p_info->len;
+ printk("debug_open: len: %i\n", ilen);
+ }
+#endif
+
+ spin_unlock_irq(&debug_info->lock);
+ debug_info_get(debug_info);
+
+ out:
+ up(&debug_lock);
+#ifdef MODULE
+ if (rc != 0)
+ MOD_DEC_USE_COUNT;
+#endif
+ return rc;
+}
+
+/*
+ * debug_close:
+ * - called for user close()
+ * - deletes private_data area of the file handle
+ */
+
+static int debug_close(struct inode *inode, struct file *file)
+{
+ file_private_info_t *p_info;
+#ifdef DEBUG
+ printk("debug_close\n");
+#endif
+ down(&debug_lock);
+ p_info = (file_private_info_t *) file->private_data;
+ debug_info_put(p_info->debug_info);
+ if (p_info->data) {
+ vfree(p_info->data);
+ kfree(file->private_data);
+ }
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0; /* success */
+}
+
+/*
+ * debug_create_proc_dir_entry:
+ * - initializes proc-dir-entry and registers it
+ */
+
+static struct proc_dir_entry *debug_create_proc_dir_entry
+ (struct proc_dir_entry *root, const char *name, mode_t mode,
+ struct inode_operations *iops, struct file_operations *fops)
+{
+ struct proc_dir_entry *rc = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ const char *fn = name;
+ int len;
+ len = strlen(fn);
+
+ rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry)
+ + len + 1, GFP_ATOMIC);
+ if (!rc)
+ goto out;
+
+ memset(rc, 0, sizeof(struct proc_dir_entry));
+ memcpy(((char *) rc) + sizeof(*rc), fn, len + 1);
+ rc->name = ((char *) rc) + sizeof(*rc);
+ rc->namelen = len;
+ rc->low_ino = 0, rc->mode = mode;
+ rc->nlink = 1;
+ rc->uid = 0;
+ rc->gid = 0;
+ rc->size = 0;
+ rc->get_info = NULL;
+ rc->ops = iops;
+
+ proc_register(root, rc);
+#else
+ rc = create_proc_entry(name, mode, root);
+ if (!rc)
+ goto out;
+ if (fops)
+ rc->proc_fops = fops;
+#endif
+
+ out:
+ return rc;
+}
+
+
+/*
+ * delete_proc_dir_entry:
+ */
+
+static void debug_delete_proc_dir_entry
+ (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry)
+{
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+ proc_unregister(root, proc_entry->low_ino);
+ kfree(proc_entry);
+#else
+ remove_proc_entry(proc_entry->name, root);
+#endif
+}
+
+/*
+ * debug_register:
+ * - creates and initializes debug area for the caller
+ * - returns handle for debug area
+ */
+
+debug_info_t *debug_register
+ (char *name, int page_order, int nr_areas, int buf_size)
+{
+ debug_info_t *rc = NULL;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+ if (!initialized)
+ debug_init();
+ down(&debug_lock);
+
+ /* create new debug_info */
+
+ rc = debug_info_create(name, page_order, nr_areas, buf_size);
+ if(!rc)
+ goto out;
+ debug_register_view(rc, &debug_level_view);
+ printk(KERN_INFO
+ "debug: reserved %d areas of %d pages for debugging %s\n",
+ nr_areas, 1 << page_order, rc->name);
+ out:
+ if (rc == NULL){
+ printk(KERN_ERR "debug: debug_register failed for %s\n",name);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ }
+ up(&debug_lock);
+ return rc;
+}
+
+/*
+ * debug_unregister:
+ * - give back debug area
+ */
+
+void debug_unregister(debug_info_t * id)
+{
+ if (!id)
+ goto out;
+ down(&debug_lock);
+ printk(KERN_INFO "debug: unregistering %s\n", id->name);
+ debug_info_put(id);
+ up(&debug_lock);
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ out:
+ return;
+}
+
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void debug_set_level(debug_info_t* id, int new_level)
+{
+ long flags;
+ if(!id)
+ return;
+ spin_lock_irqsave(&id->lock,flags);
+ if(new_level == DEBUG_OFF_LEVEL){
+ id->level = DEBUG_OFF_LEVEL;
+ printk(KERN_INFO "debug: %s: switched off\n",id->name);
+ } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+ printk(KERN_INFO
+ "debug: %s: level %i is out of range (%i - %i)\n",
+ id->name, new_level, 0, DEBUG_MAX_LEVEL);
+ } else {
+ id->level = new_level;
+ printk(KERN_INFO
+ "debug: %s: new level %i\n",id->name,id->level);
+ }
+ spin_unlock_irqrestore(&id->lock,flags);
+}
+
+
+/*
+ * proceed_active_entry:
+ * - set active entry to next in the ring buffer
+ */
+
+static inline void proceed_active_entry(debug_info_t * id)
+{
+ if ((id->active_entry[id->active_area] += id->entry_size)
+ > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
+ id->active_entry[id->active_area] = 0;
+}
+
+/*
+ * proceed_active_area:
+ * - set active area to next in the ring buffer
+ */
+
+static inline void proceed_active_area(debug_info_t * id)
+{
+ id->active_area++;
+ id->active_area = id->active_area % id->nr_areas;
+}
+
+/*
+ * get_active_entry:
+ */
+
+static inline debug_entry_t *get_active_entry(debug_info_t * id)
+{
+ return (debug_entry_t *) ((char *) id->areas[id->active_area] +
+ id->active_entry[id->active_area]);
+}
+
+/*
+ * debug_common:
+ * - set timestamp, caller address, cpu number etc.
+ */
+
+static inline debug_entry_t *debug_common(debug_info_t * id)
+{
+ debug_entry_t *active;
+
+ active = get_active_entry(id);
+ STCK(active->id.stck);
+ active->id.fields.cpuid = smp_processor_id();
+ active->id.fields.used = 1;
+ active->caller = __builtin_return_address(0);
+ return active;
+}
+
+/*
+ * debug_event:
+ */
+
+debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_event:
+ */
+
+debug_entry_t *debug_int_event(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 0;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_event:
+ */
+
+debug_entry_t *debug_text_event(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 0;
+ proceed_active_entry(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_exception:
+ */
+
+debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
+ int len)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_int_exception:
+ */
+
+debug_entry_t *debug_int_exception(debug_info_t * id, int level,
+ unsigned int tag)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ active->id.fields.exception = 1;
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ memcpy(DEBUG_DATA(active), &tag,
+ MIN(sizeof(unsigned int), id->buf_size));
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+}
+
+/*
+ * debug_text_exception:
+ */
+
+debug_entry_t *debug_text_exception(debug_info_t * id, int level,
+ const char *txt)
+{
+ long flags;
+ debug_entry_t *active = NULL;
+
+ if ((!id) || (level > id->level))
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ active = debug_common(id);
+ memset(DEBUG_DATA(active), 0, id->buf_size);
+ strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size));
+ active->id.fields.exception = 1;
+ proceed_active_entry(id);
+ proceed_active_area(id);
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return active;
+
+}
+
+/*
+ * debug_init:
+ * - is called exactly once to initialize the debug feature
+ */
+
+int debug_init(void)
+{
+ int rc = 0;
+
+ down(&debug_lock);
+ if (!initialized) {
+ debug_proc_root_entry =
+ debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT,
+ S_IFDIR | S_IRUGO | S_IXUGO
+ | S_IWUSR | S_IWGRP, NULL,
+ NULL);
+ printk(KERN_INFO "debug: Initialization complete\n");
+ initialized = 1;
+ }
+ up(&debug_lock);
+
+ return rc;
+}
+
+/*
+ * debug_register_view:
+ */
+
+int debug_register_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+ mode_t mode = S_IFREG;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == NULL)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS) {
+ printk(KERN_WARNING "debug: cannot register view %s/%s\n",
+ id->name,view->name);
+ printk(KERN_WARNING
+ "debug: maximum number of views reached (%i)!\n", i);
+ rc = -1;
+ }
+ else {
+ id->views[i] = view;
+ if (view->prolog_proc || view->format_proc || view->header_proc)
+ mode |= S_IRUSR;
+ if (view->input_proc)
+ mode |= S_IWUSR;
+ id->proc_entries[i] =
+ debug_create_proc_dir_entry(id->proc_root_entry,
+ view->name, mode,
+ &debug_inode_ops,
+ &debug_file_ops);
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * debug_unregister_view:
+ */
+
+int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+{
+ int rc = 0;
+ int i;
+ long flags;
+
+ if (!id)
+ goto out;
+ spin_lock_irqsave(&id->lock, flags);
+ for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+ if (id->views[i] == view)
+ break;
+ }
+ if (i == DEBUG_MAX_VIEWS)
+ rc = -1;
+ else {
+ debug_delete_proc_dir_entry(id->proc_root_entry,
+ id->proc_entries[i]);
+ id->views[i] = NULL;
+ rc = 0;
+ }
+ spin_unlock_irqrestore(&id->lock, flags);
+ out:
+ return rc;
+}
+
+/*
+ * functions for debug-views
+ ***********************************
+*/
+
+/*
+ * prints out actual debug level
+ */
+
+static int debug_prolog_level_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf)
+{
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = 2;
+ goto out;
+ }
+ if(id->level == -1) rc = sprintf(out_buf,"-\n");
+ else rc = sprintf(out_buf, "%i\n", id->level);
+ out:
+ return rc;
+}
+
+/*
+ * reads new debug level
+ */
+
+static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char *user_buf,
+ size_t in_buf_size, loff_t * offset)
+{
+ char input_buf[1];
+ int rc = in_buf_size;
+
+ if (*offset != 0)
+ goto out;
+ if ((rc = copy_from_user(input_buf, user_buf, 1)))
+ goto out;
+ if (isdigit(input_buf[0])) {
+ int new_level = ((int) input_buf[0] - (int) '0');
+ debug_set_level(id, new_level);
+ } else if(input_buf[0] == '-') {
+ debug_set_level(id, DEBUG_OFF_LEVEL);
+ } else {
+ printk(KERN_INFO "debug: level `%c` is not valid\n",
+ input_buf[0]);
+ }
+ out:
+ *offset += in_buf_size;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints debug header in raw format
+ */
+
+int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ int rc;
+
+ rc = sizeof(debug_entry_t);
+ if (out_buf == NULL)
+ goto out;
+ memcpy(out_buf,entry,sizeof(debug_entry_t));
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in raw format
+ */
+
+static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int rc;
+
+ rc = id->buf_size;
+ if (out_buf == NULL || in_buf == NULL)
+ goto out;
+ memcpy(out_buf, in_buf, id->buf_size);
+ out:
+ return rc;
+}
+
+/*
+ * prints debug data in hex/ascii format
+ */
+
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
+{
+ int i, rc = 0;
+
+ if (out_buf == NULL || in_buf == NULL) {
+ rc = id->buf_size * 4 + 3;
+ goto out;
+ }
+ for (i = 0; i < id->buf_size; i++) {
+ rc += sprintf(out_buf + rc, "%02x ",
+ ((unsigned char *) in_buf)[i]);
+ }
+ rc += sprintf(out_buf + rc, "| ");
+ for (i = 0; i < id->buf_size; i++) {
+ unsigned char c = in_buf[i];
+ if (!isprint(c))
+ rc += sprintf(out_buf + rc, ".");
+ else
+ rc += sprintf(out_buf + rc, "%c", c);
+ }
+ rc += sprintf(out_buf + rc, "\n");
+ out:
+ return rc;
+}
+
+/*
+ * prints header for debug entry
+ */
+
+int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
+{
+ struct timeval time_val;
+ unsigned long long time;
+ char *except_str;
+ unsigned long caller;
+ int rc = 0;
+
+ if (out_buf == NULL) {
+ rc = DEBUG_PROC_HEADER_SIZE;
+ goto out;
+ }
+
+ time = entry->id.stck;
+ /* adjust todclock to 1970 */
+ time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
+ tod_to_timeval(time, &time_val);
+
+ if (entry->id.fields.exception)
+ except_str = "*";
+ else
+ except_str = "-";
+ caller = (unsigned long) entry->caller;
+#if defined(CONFIG_ARCH_S390X)
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#else
+ caller &= 0x7fffffff;
+ rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ",
+ area, time_val.tv_sec,
+ time_val.tv_usec, except_str,
+ entry->id.fields.cpuid, caller);
+#endif
+ out:
+ return rc;
+}
+
+/*
+ * init_module:
+ */
+
+#ifdef MODULE
+int init_module(void)
+{
+ int rc = 0;
+#ifdef DEBUG
+ printk("debug_module_init: \n");
+#endif
+ rc = debug_init();
+ if (rc)
+ printk(KERN_INFO "debug: an error occurred with debug_init\n");
+ return rc;
+}
+
+/*
+ * cleanup_module:
+ */
+
+void cleanup_module(void)
+{
+#ifdef DEBUG
+ printk("debug_cleanup_module: \n");
+#endif
+ debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+ return;
+}
+
+#endif /* MODULE */
diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c
index 3c70c4aa5..fc7740649 100644
--- a/arch/s390/kernel/ebcdic.c
+++ b/arch/s390/kernel/ebcdic.c
@@ -161,7 +161,156 @@ __u8 _ebcasc[256] =
/*
- * EBCDIC 037 conversion table:
+ * ASCII (IBM PC 437) -> EBCDIC 500
+ */
+__u8 _ascebc_500[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+/*
+ * EBCDIC 500 -> ASCII (IBM PC 437)
+ */
+__u8 _ebcasc_500[256] =
+{
+ /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48 [ . < ( + ! */
+ 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
+ /* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58 ß ] $ * ) ; ^ */
+ 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
+ /* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70 ---- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0 ---- § ---- */
+ 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8 ---- | ---- ---- ---- ---- */
+ 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+
+/*
+ * EBCDIC 037/500 conversion table:
* from upper to lower case
*/
__u8 _ebc_tolower[256] =
@@ -202,7 +351,7 @@ __u8 _ebc_tolower[256] =
/*
- * EBCDIC 037 conversion table:
+ * EBCDIC 037/500 conversion table:
* from lower to upper case
*/
__u8 _ebc_toupper[256] =
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index e39e18623..a1125e933 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -81,6 +81,7 @@ state = 0
flags = 4
sigpending = 8
need_resched = 24
+tsk_ptrace = 28
processor = 60
/* PSW related defines */
@@ -88,6 +89,13 @@ disable = 0xFC
enable = 0x03
daton = 0x04
+/*
+ * Base Address of this Module --- saved in __LC_ENTRY_BASE
+ */
+ .globl entry_base
+entry_base:
+
+#define BASED(name) name-entry_base(%r13)
#if 0
/* some code left lying around in case we need a
@@ -118,39 +126,37 @@ sysc_dn:
*/
#define SAVE_ALL(psworg) \
- st %r15,__LC_SAVE_AREA ; \
+ stm %r13,%r15,__LC_SAVE_AREA ; \
+ stam %a2,%a4,__LC_SAVE_AREA+12 ; \
+ basr %r13,0 ; /* temp base pointer */ \
+ l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \
tm psworg+1,0x01 ; /* test problem state bit */ \
- jz 0f ; /* skip stack setup save */ \
+ bz BASED(.+12) ; /* skip stack setup save */ \
l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \
-0: ahi %r15,-SP_SIZE ; /* make room for registers & psw */ \
- srl %r15,3 ; \
- sll %r15,3 ; /* align stack pointer to 8 */ \
- stm %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \
+ lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \
+ /* and access reg. 4 to home space */ \
+0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \
+ n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \
+ stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \
st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \
- mvc SP_RF(4,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \
stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \
mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \
- lhi %r0,psworg ; /* store trap indication */ \
+ la %r0,psworg ; /* store trap indication */ \
st %r0,SP_TRAP(%r15) ; \
- xc 0(4,%r15),0(%r15) ; /* clear back chain */ \
- tm psworg+1,0x01 ; /* kmod.c .wishes the set_fs & gs */ \
- jz 1f ; /* to work across syscalls */ \
- slr %r0,%r0 ; \
- sar %a2,%r0 ; /* set ac.reg. 2 to primary space */ \
- lhi %r0,1 ; \
- sar %a4,%r0 ; /* set access reg. 4 to home space */ \
-1:
+ xc 0(4,%r15),0(%r15) ; /* clear back chain */
#define RESTORE_ALL \
- mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
- lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
- lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
- ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
- lpsw __LC_RETURN_PSW /* back to caller */
+ mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
+ lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
+ lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \
+ ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \
+ lpsw __LC_RETURN_PSW /* back to caller */
#define GET_CURRENT /* load pointer to task_struct to R9 */ \
- lhi %r9,-8192 ; \
- nr %r9,15
+ lr %r9,%r15 ; \
+ n %r9,BASED(.Lc0xffffe000)
/*
@@ -162,22 +168,24 @@ sysc_dn:
*/
.globl resume
resume:
+ basr %r1,0
+resume_base:
l %r4,_TSS_PTREGS(%r3)
tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
- jz RES_DN1 # if not we're fine
- stctl %r9,%r11,24(%r15) # We are using per stuff
+ bz resume_noper-resume_base(%r1) # if not we're fine
+ stctl %r9,%r11,24(%r15) # We are using per stuff
clc _TSS_PER(12,%r3),24(%r15)
- je RES_DN1 # we got away without bashing TLB's
- lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
-RES_DN1:
+ be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
+ lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't
+resume_noper:
stm %r6,%r15,24(%r15) # store resume registers of prev task
st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
- lhi %r0,-8192
- nr %r0,%r15
+ lr %r0,%r15
+ n %r0,.Lc0xffffe000-resume_base(%r1)
l %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
- lhi %r1,8191
+ l %r1,.Lc8191-resume_base(%r1)
or %r1,%r15
- ahi %r1,1
+ la %r1,1(%r1)
st %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2
stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4
@@ -192,38 +200,19 @@ RES_DN1:
* are executed with interrupts enabled.
*/
-sysc_lit:
- sysc_do_signal: .long do_signal
- sysc_do_softirq: .long do_softirq
- sysc_schedule: .long schedule
- sysc_trace: .long syscall_trace
-#ifdef CONFIG_SMP
- sysc_schedtail: .long schedule_tail
-#endif
- sysc_clone: .long sys_clone
- sysc_fork: .long sys_fork
- sysc_vfork: .long sys_vfork
- sysc_sigreturn: .long sys_sigreturn
- sysc_rt_sigreturn: .long sys_rt_sigreturn
- sysc_execve: .long sys_execve
- sysc_sigsuspend: .long sys_sigsuspend
- sysc_rt_sigsuspend: .long sys_rt_sigsuspend
-
.globl system_call
system_call:
SAVE_ALL(0x20)
- XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
pgm_system_call:
- basr %r13,0
- ahi %r13,sysc_lit-. # setup base pointer R13 to sysc_lit
slr %r8,%r8 # gpr 8 is call save (-> tracesys)
ic %r8,0x8B # get svc number from lowcore
stosm 24(%r15),0x03 # reenable interrupts
GET_CURRENT # load pointer to task_struct to R9
sll %r8,2
- l %r8,sys_call_table-sysc_lit(8,%r13) # get address of system call
- tm flags+3(%r9),0x20 # PF_TRACESYS
- jnz sysc_tracesys
+ l %r8,sys_call_table-entry_base(8,%r13) # get address of system call
+ tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
+ bnz BASED(sysc_tracesys)
basr %r14,%r8 # call sys_xxxx
st %r2,SP_R2(%r15) # store return value (change R2 on stack)
# ATTENTION: check sys_execve_glue before
@@ -232,24 +221,24 @@ pgm_system_call:
sysc_return:
GET_CURRENT # load pointer to task_struct to R9
tm SP_PSW+1(%r15),0x01 # returning to user ?
- jno sysc_leave # no-> skip bottom half, resched & signal
+ bno BASED(sysc_leave) # no-> skip bottom half, resched & signal
#
# check, if bottom-half has to be done
#
l %r0,__LC_IRQ_STAT # get softirq_active
n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
- jnz sysc_handle_bottom_half
+ bnz BASED(sysc_handle_bottom_half)
#
# check, if reschedule is needed
#
sysc_return_bh:
icm %r0,15,need_resched(%r9) # get need_resched from task_struct
- jnz sysc_reschedule
+ bnz BASED(sysc_reschedule)
icm %r0,15,sigpending(%r9) # get sigpending from task_struct
- jnz sysc_signal_return
+ bnz BASED(sysc_signal_return)
sysc_leave:
icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct
- jnz pgm_svcret
+ bnz BASED(pgm_svcret)
stnsm 24(%r15),disable # disable I/O and ext. interrupts
RESTORE_ALL
@@ -259,24 +248,24 @@ sysc_leave:
sysc_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
- l %r1,sysc_do_signal-sysc_lit(%r13)
- la %r14,sysc_leave-sysc_lit(%r13)
+ l %r1,BASED(.Ldo_signal)
+ la %r14,BASED(sysc_leave)
br %r1 # return point is sysc_leave
#
# call trace before and after sys_call
#
sysc_tracesys:
- l %r1,sysc_trace-sysc_lit(%r13)
- lhi %r2,-ENOSYS
+ l %r1,BASED(.Ltrace)
+ l %r2,BASED(.Lc_ENOSYS)
st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval
basr %r14,%r1
lm %r3,%r6,SP_R3(%r15)
l %r2,SP_ORIG_R2(%r15)
basr %r14,%r8 # call sys_xxx
st %r2,SP_R2(%r15) # store return value
- l %r1,sysc_trace-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Ltrace)
+ la %r14,BASED(sysc_return)
br %r1 # return point is sysc_return
@@ -285,16 +274,16 @@ sysc_tracesys:
# is zero
#
sysc_handle_bottom_half:
- l %r1,sysc_do_softirq-sysc_lit(%r13)
- la %r14,sysc_return_bh-sysc_lit(%r13)
+ l %r1,BASED(.Ldo_softirq)
+ la %r14,BASED(sysc_return_bh)
br %r1 # call do_softirq
#
# call schedule with sysc_return as return-address
#
sysc_reschedule:
- l %r1,sysc_schedule-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(sysc_return)
br %r1 # call scheduler, return to sysc_return
#
@@ -303,17 +292,17 @@ sysc_reschedule:
.globl ret_from_fork
ret_from_fork:
basr %r13,0
- ahi %r13,sysc_lit-. # setup base pointer R13 to $SYSCDAT
+ l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base
GET_CURRENT # load pointer to task_struct to R9
stosm 24(%r15),0x03 # reenable interrupts
sr %r0,%r0 # child returns 0
st %r0,SP_R2(%r15) # store return value (change R2 on stack)
#ifdef CONFIG_SMP
- l %r1,sysc_schedtail-sysc_lit(%r13)
- la %r14,sysc_return-sysc_lit(%r13)
+ l %r1,BASED(.Lschedtail)
+ la %r14,BASED(sysc_return)
br %r1 # call schedule_tail, return to sysc_return
#else
- j sysc_return
+ b BASED(sysc_return)
#endif
#
@@ -324,22 +313,22 @@ ret_from_fork:
#
sys_clone_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_clone-sysc_lit(%r13)
+ l %r1,BASED(.Lclone)
br %r1 # branch to sys_clone
sys_fork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_fork-sysc_lit(%r13)
+ l %r1,BASED(.Lfork)
br %r1 # branch to sys_fork
sys_vfork_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_vfork-sysc_lit(%r13)
+ l %r1,BASED(.Lvfork)
br %r1 # branch to sys_vfork
sys_execve_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,sysc_execve-sysc_lit(%r13)
+ l %r1,BASED(.Lexecve)
lr %r12,%r14 # save return address
basr %r14,%r1 # call sys_execve
ltr %r2,%r2 # check if execve failed
@@ -349,12 +338,12 @@ sys_execve_glue:
sys_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,sysc_sigreturn-sysc_lit(%r13)
+ l %r1,BASED(.Lsigreturn)
br %r1 # branch to sys_sigreturn
sys_rt_sigreturn_glue:
la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,sysc_rt_sigreturn-sysc_lit(%r13)
+ l %r1,BASED(.Lrt_sigreturn)
br %r1 # branch to sys_sigreturn
#
@@ -369,7 +358,7 @@ sys_sigsuspend_glue:
lr %r4,%r3 # move history1 parameter
lr %r3,%r2 # move history0 parameter
la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
- l %r1,sysc_sigsuspend-sysc_lit(%r13)
+ l %r1,BASED(.Lsigsuspend)
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_sigsuspend
@@ -377,10 +366,15 @@ sys_rt_sigsuspend_glue:
lr %r4,%r3 # move sigsetsize parameter
lr %r3,%r2 # move unewset parameter
la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter
- l %r1,sysc_rt_sigsuspend-sysc_lit(%r13)
+ l %r1,BASED(.Lrt_sigsuspend)
la %r14,4(%r14) # skip store of return value
br %r1 # branch to sys_rt_sigsuspend
+sys_sigaltstack_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lsigaltstack)
+ br %r1 # branch to sys_sigreturn
+
.globl sys_call_table
sys_call_table:
.long sys_ni_syscall /* 0 */
@@ -459,7 +453,7 @@ sys_call_table:
.long sys_sigpending
.long sys_sethostname
.long sys_setrlimit /* 75 */
- .long sys_getrlimit
+ .long sys_old_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
@@ -569,13 +563,13 @@ sys_call_table:
.long sys_getcwd
.long sys_capget
.long sys_capset /* 185 */
- .long sys_sigaltstack
+ .long sys_sigaltstack_glue
.long sys_sendfile
.long sys_ni_syscall /* streams1 */
.long sys_ni_syscall /* streams2 */
.long sys_vfork_glue /* 190 */
.long sys_getrlimit
- .long sys_ni_syscall /* FIXME: problem with sys_mmap2: 6 parms */
+ .long sys_mmap2
.long sys_truncate64
.long sys_ftruncate64
.long sys_stat64 /* 195 */
@@ -604,7 +598,8 @@ sys_call_table:
.long sys_mincore
.long sys_madvise
.long sys_getdents64 /* 220 */
- .rept 255-220
+ .long sys_fcntl64
+ .rept 255-221
.long sys_ni_syscall
.endr
@@ -612,13 +607,6 @@ sys_call_table:
* Program check handler routine
*/
-pgm_lit:
- pgm_handle_per: .long handle_per_exception
- pgm_jump_table: .long pgm_check_table
- pgm_sysc_ret: .long sysc_return
- pgm_sysc_lit: .long sysc_lit
- pgm_do_signal: .long do_signal
-
.globl pgm_check_handler
pgm_check_handler:
/*
@@ -634,110 +622,131 @@ pgm_check_handler:
* we just ignore the PER event (FIXME: is there anything we have to do
* for LPSW?).
*/
+ stm %r13,%r15,__LC_SAVE_AREA
+ stam %a2,%a4,__LC_SAVE_AREA+12
+ basr %r13,0 # temp base pointer
+ l %r13,.Lentry_base-.(%r13)# load &entry_base to %r13
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
- jz pgm_sv # skip if not
+ bz BASED(pgm_sv) # skip if not
tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
- jnz pgm_sv # skip if it is
+ bnz BASED(pgm_sv) # skip if it is
# ok its one of the special cases, now we need to find out which one
clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
- je pgm_svcper
+ be BASED(pgm_svcper)
# no interesting special case, ignore PER event
- lpsw 0x28
+ lm %r13,%r15,__LC_SAVE_AREA
+ lpsw 0x28
# it was a single stepped SVC that is causing all the trouble
pgm_svcper:
- SAVE_ALL(0x20)
+ tm 0x21,0x01 # test problem state bit
+ bz BASED(.+12) # skip stack & access regs setup
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space
+ # and access reg. 4 to home space
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
+ stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack
+ st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+ mvc SP_PSW(8,%r15),0x20 # move user PSW to stack
+ la %r0,0x20 # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(4,%r15),0(%r15) # clear back chain
mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero
mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
- j pgm_system_call # now do the svc
+ b BASED(pgm_system_call) # now do the svc
pgm_svcret:
- lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
- lhi %r0,0x28
- st %r0,SP_TRAP(%r15) # set new trap indicator
+ mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk
+ lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
- basr %r13,0
- ahi %r13,pgm_lit-. # setup base pointer
- j pgm_no_sv
+ b BASED(pgm_no_sv)
pgm_sv:
- SAVE_ALL(0x28)
- XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
- basr %r13,0
- ahi %r13,pgm_lit-. # setup base pointer R13 to $PGMDAT
+ tm 0x29,0x01 # test problem state bit
+ bz BASED(.+12) # skip stack & access regs setup
+ l %r15,__LC_KERNEL_STACK # problem state -> load ksp
+ lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space
+ # and access reg. 4 to home space
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
+ n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
+ stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack
+ st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
+ mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
+ stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst.
+ mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
+ mvc SP_PSW(8,%r15),0x28 # move user PSW to stack
+ la %r0,0x28 # store trap indication
+ st %r0,SP_TRAP(%r15)
+ xc 0(4,%r15),0(%r15) # clear back chain
+ xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15)
lh %r7,__LC_PGM_ILC # load instruction length
pgm_no_sv:
lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it
stosm 24(%r15),0x03 # reenable interrupts
lr %r3,%r8
- lhi %r0,0x7f
+ la %r0,0x7f
nr %r3,%r0 # clear per-event-bit
- je pgm_dn # none of Martins exceptions occured bypass
- l %r9,pgm_jump_table-pgm_lit(%r13)
+ be BASED(pgm_dn) # none of Martins exceptions occured bypass
+ l %r9,BASED(.Ljump_table)
sll %r3,2
l %r9,0(%r3,%r9) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
srl %r3,2
- chi %r3,0x4 # protection-exception ?
- jne pgm_go # if not,
+ cl %r3,BASED(.Lc4) # protection-exception ?
+ bne BASED(pgm_go) # if not,
l %r5,SP_PSW+4(15) # load psw addr
sr %r5,%r7 # substract ilc from psw
st %r5,SP_PSW+4(15) # store corrected psw addr
pgm_go: basr %r14,%r9 # branch to interrupt-handler
-pgm_dn: lhi %r0,0x80
+pgm_dn: la %r0,0x80
nr %r8,%r0 # check for per exception
- je pgm_return
+ be BASED(pgm_return)
la %r2,SP_PTREGS(15) # address of register-save area
- l %r9,pgm_handle_per-pgm_lit(%r13) # load adr. of per handler
- l %r14,pgm_sysc_ret-pgm_lit(%r13) # load adr. of system return
- l %r13,pgm_sysc_lit-pgm_lit(%r13)
+ l %r9,BASED(.Lhandle_per) # load adr. of per handler
+ la %r14,BASED(sysc_return) # load adr. of system return
br %r9 # branch to handle_per_exception
+
#
# the backend code is the same as for sys-call
#
pgm_return:
- l %r14,pgm_sysc_ret-pgm_lit(%r13)
- l %r13,pgm_sysc_lit-pgm_lit(%r13)
- br %r14
+ b BASED(sysc_return)
/*
* IO interrupt handler routine
*/
-io_lit:
- io_do_IRQ: .long do_IRQ
- io_schedule: .long schedule
- io_do_signal: .long do_signal
- io_do_softirq: .long do_softirq
-
.globl io_int_handler
io_int_handler:
SAVE_ALL(0x38)
- basr %r13,0
- ahi %r13,io_lit-. # setup base pointer R13 to $IODAT
la %r2,SP_PTREGS(%r15) # address of register-save area
sr %r3,%r3
icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
- l %r4,__LC_IO_INT_PARM # load interuption parm
- l %r9,io_do_IRQ-io_lit(%r13) # load address of do_IRQ
+ l %r4,__LC_IO_INT_PARM # load interruption parm
+ l %r5,__LC_IO_INT_WORD # load interruption word
+ l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ
basr %r14,%r9 # branch to standard irq handler
io_return:
GET_CURRENT # load pointer to task_struct to R9
tm SP_PSW+1(%r15),0x01 # returning to user ?
- jz io_leave # no-> skip resched & signal
+ bz BASED(io_leave) # no-> skip resched & signal
stosm 24(%r15),0x03 # reenable interrupts
#
# check, if bottom-half has to be done
#
l %r0,__LC_IRQ_STAT # get softirq_active
n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
- jnz io_handle_bottom_half
+ bnz BASED(io_handle_bottom_half)
io_return_bh:
#
# check, if reschedule is needed
#
icm %r0,15,need_resched(%r9) # get need_resched from task_struct
- jnz io_reschedule
+ bnz BASED(io_reschedule)
icm %r0,15,sigpending(%r9) # get sigpending from task_struct
- jnz io_signal_return
+ bnz BASED(io_signal_return)
io_leave:
stnsm 24(%r15),disable # disable I/O and ext. interrupts
RESTORE_ALL
@@ -747,16 +756,16 @@ io_leave:
# is zero
#
io_handle_bottom_half:
- l %r1,io_do_softirq-io_lit(%r13)
- la %r14,io_return_bh-io_lit(%r13)
+ l %r1,BASED(.Ldo_softirq)
+ la %r14,BASED(io_return_bh)
br %r1 # call do_softirq
#
# call schedule with io_return as return-address
#
io_reschedule:
- l %r1,io_schedule-io_lit(%r13)
- la %r14,io_return-io_lit(%r13)
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(io_return)
br %r1 # call scheduler, return to io_return
#
@@ -765,103 +774,46 @@ io_reschedule:
io_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sr %r3,%r3 # clear *oldset
- l %r1,io_do_signal-io_lit(%r13)
- la %r14,io_leave-io_lit(%r13)
+ l %r1,BASED(.Ldo_signal)
+ la %r14,BASED(io_leave)
br %r1 # return point is io_leave
/*
* External interrupt handler routine
*/
-ext_lit:
- ext_timer_int: .long do_timer_interrupt
-#ifdef CONFIG_SMP
- ext_call_int: .long do_ext_call_interrupt
-#endif
-#ifdef CONFIG_HWC
- ext_hwc_int: .long do_hwc_interrupt
-#endif
-#ifdef CONFIG_MDISK
- ext_mdisk_int: .long do_mdisk_interrupt
-#endif
-#ifdef CONFIG_IUCV
- ext_iucv_int: .long do_iucv_interrupt
-#endif
- ext_io_lit: .long io_lit
- ext_io_return: .long io_return
-
.globl ext_int_handler
ext_int_handler:
SAVE_ALL(0x18)
- basr %r13,0
- ahi %r13,ext_lit-. # setup base pointer R13 to $EXTDAT
la %r2,SP_PTREGS(%r15) # address of register-save area
lh %r3,__LC_EXT_INT_CODE # error code
-#ifdef CONFIG_SMP
- chi %r3,0x1202 # EXTERNAL_CALL
- jne ext_no_extcall
- l %r9,ext_call_int-ext_lit(%r13) # load ext_call_interrupt
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_extcall:
-#endif
- chi %r3,0x1004 # CPU_TIMER
- jne ext_no_timer
- l %r9,ext_timer_int-ext_lit(%r13) # load timer_interrupt
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_timer:
-#ifdef CONFIG_HWC
- chi %r3,0x2401 # HWC interrupt
- jne ext_no_hwc
- l %r9,ext_hwc_int-ext_lit(%r13) # load addr. of hwc routine
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_hwc:
-#endif
-#ifdef CONFIG_MDISK
- chi %r3,0x2603 # diag 250 (VM) interrupt
- jne ext_no_mdisk
- l %r9,ext_mdisk_int-ext_lit(%r13)
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_mdisk:
-#endif
-#ifdef CONFIG_IUCV
- chi %r3,0x4000 # diag 250 (VM) interrupt
- jne ext_no_iucv
- l %r9,ext_iucv_int-ext_lit(%r13)
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r9 # branch to ext call handler
-ext_no_iucv:
-#endif
-
- l %r14,ext_io_return-ext_lit(%r13)
- l %r13,ext_io_lit-ext_lit(%r13)
- br %r14 # use backend code of io_int_handler
+ lr %r1,%r3 # calculate index = code & 0xff
+ n %r1,BASED(.Lc0xff)
+ sll %r1,2
+ l %r9,BASED(.Lext_hash)
+ l %r9,0(%r1,%r9) # get first list entry for hash value
+ ltr %r9,%r9 # == NULL ?
+ bz BASED(io_return) # yes, nothing to do, exit
+ext_int_loop:
+ ch %r3,8(%r9) # compare external interrupt code
+ be BASED(ext_int_found)
+ icm %r9,15,0(%r9) # next list entry
+ bnz BASED(ext_int_loop)
+ b BASED(io_return)
+ext_int_found:
+ l %r9,4(%r9) # get handler address
+ la %r14,BASED(io_return)
+ br %r9 # branch to ext call handler
/*
* Machine check handler routines
*/
-mcck_lit:
- mcck_crw_pending: .long do_crw_pending
-
.globl mcck_int_handler
mcck_int_handler:
SAVE_ALL(0x30)
- basr %r13,0
- ahi %r13,mcck_lit-. # setup base pointer R13 to $MCCKDAT
- tm __LC_MCCK_CODE+1,0x40
- jno mcck_no_crw
- l %r1,mcck_crw_pending-mcck_lit(%r13)
- basr %r14,%r1 # call do_crw_pending
-mcck_no_crw:
+ l %r1,BASED(.Ls390_mcck)
+ basr %r14,%r1 # call machine check handler
mcck_return:
RESTORE_ALL
@@ -876,11 +828,11 @@ restart_int_handler:
lam %a0,%a15,__LC_AREGS_SAVE_AREA
stosm 0(%r15),daton # now we can turn dat on
lm %r6,%r15,24(%r15) # load registers from clone
- bras %r14,restart_go
- .long start_secondary
-restart_go:
- l %r14,0(%r14)
+ basr %r14,0
+ l %r14,restart_addr-.(%r14)
br %r14 # branch to start_secondary
+restart_addr:
+ .long start_secondary
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
@@ -896,3 +848,48 @@ restart_crash:
restart_go:
#endif
+/*
+ * Integer constants
+ */
+ .align 4
+.Lc0xfffffff8: .long -8 # to align stack pointer to 8
+.Lc0xffffe000: .long -8192 # to round stack pointer to &task_struct
+.Lc8191: .long 8191
+.Lc_spsize: .long SP_SIZE
+.Lc_ac: .long 0,0,1
+.Lc_ENOSYS: .long -ENOSYS
+.Lc4: .long 4
+.Lc0x1202: .long 0x1202
+.Lc0x1004: .long 0x1004
+.Lc0x2401: .long 0x2401
+.Lc0x4000: .long 0x4000
+.Lc0xff: .long 0xff
+
+/*
+ * Symbol constants
+ */
+.Ls390_mcck: .long s390_do_machine_check
+.Ldo_IRQ: .long do_IRQ
+.Ldo_signal: .long do_signal
+.Ldo_softirq: .long do_softirq
+.Lentry_base: .long entry_base
+.Lext_hash: .long ext_int_hash
+.Lhandle_per: .long handle_per_exception
+.Ljump_table: .long pgm_check_table
+.Lschedule: .long schedule
+.Lclone: .long sys_clone
+.Lexecve: .long sys_execve
+.Lfork: .long sys_fork
+.Lrt_sigreturn:.long sys_rt_sigreturn
+.Lrt_sigsuspend:
+ .long sys_rt_sigsuspend
+.Lsigreturn: .long sys_sigreturn
+.Lsigsuspend: .long sys_sigsuspend
+.Lsigaltstack: .long sys_sigaltstack
+.Ltrace: .long syscall_trace
+.Lvfork: .long sys_vfork
+
+#ifdef CONFIG_SMP
+.Lschedtail: .long schedule_tail
+#endif
+
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index a3b5df25c..d41f398d8 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -2,20 +2,29 @@
* arch/s390/kernel/head.S
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Hartmut Penner (hp@de.ibm.com),
* Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Rob van der Heij (rvdhei@iae.nl)
*
- * There are 4 different IPL methods
+ * There are 5 different IPL methods
* 1) load the image directly into ram at address 0 and do an PSW restart
* 2) linload will load the image from address 0x10000 to memory 0x10000
* and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
* 3) generate the tape ipl header, store the generated image on a tape
* and ipl from it
+ * In case of SL tape you need to IPL 5 times to get past VOL1 etc
* 4) generate the vm reader ipl header, move the generated image to the
* VM reader (use option NOH!) and do a ipl from reader (VM only)
+ * 5) direct call of start by the SALIPL loader
* We use the cpuid to distinguish between VM and native ipl
* params for kernel are pushed to 0x10400 (see setup.h)
+
+ Changes:
+ Okt 25 2000 <rvdheij@iae.nl>
+ added code to skip HDR and EOF to allow SL tape IPL (5 retries)
+ changed first CCW from rewind to backspace block
+
*/
#include <linux/config.h>
@@ -24,40 +33,13 @@
#ifndef CONFIG_IPL
.org 0
- .long 0x00080000,0x80000000+iplstart # Just a restart PSW
-
-iplstart:
- l %r12,.Lparm # pointer to parameter area
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- slr %r2,%r2
- st %r2,INITRD_SIZE-PARMAREA(%r12) # null ramdisk
- st %r2,INITRD_START-PARMAREA(%r12)
- j start
-
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
- .align 8
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
-
+ .long 0x00080000,0x80000000+startup # Just a restart PSW
#else
#ifdef CONFIG_IPL_TAPE
#define IPL_BS 1024
.org 0
.long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
- .long 0x07000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
.long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
.long 0x00000000,0x00000000 # external old psw
.long 0x00000000,0x00000000 # svc old psw
@@ -74,92 +56,6 @@ iplstart:
.long 0x00080000,0x80000000+.Lioint # io new psw
.org 0x100
-iplstart:
- l %r1,0xb8 # load ipl subchannel number
- lhi %r2,IPL_BS # load start address
- bras %r14,.Lloader # load rest of ipl image
- st %r1,__LC_IPLDEV # store ipl device number
- l %r12,.Lparm # pointer to parameter area
-
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- c %r2,.Lbigmem # more than 64 MB of memory ?
- jl .Lmemok # if yes load ramdisk to 32 MB
- mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from tape
-#
- l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
- bras %r14,.Lloader # load parameter file
- ltr %r2,%r2 # got anything ?
- jz .Lnopf
- chi %r2,895
- jnh .Lnotrunc
- lhi %r2,895
-.Lnotrunc:
- l %r4,INITRD_START-PARMAREA(%r12)
- la %r5,0(%r4,%r2)
- lr %r3,%r2
-.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- jo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- brct %r3,.Lidebc
- j .Lnocv
-.Ldocv:
- l %r3,.Lcvtab
- tr 0(256,%r4),0(%r3) # convert parameters to ascii
- tr 256(256,%r4),0(%r3)
- tr 512(256,%r4),0(%r3)
- tr 768(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
- mvc 0(256,%r3),0(%r4)
- mvc 256(256,%r3),256(%r4)
- mvc 512(256,%r3),512(%r4)
- mvc 768(122,%r3),768(%r4)
- slr %r0,%r0
- j .Lcntlp
-.Ldelspc:
- ic %r0,0(%r2,%r3)
- chi %r0,0x20 # is it a space ?
- je .Lcntlp
- ahi %r2,1
- j .Leolp
-.Lcntlp:
- brct %r2,.Ldelspc
-.Leolp:
- slr %r0,%r0
- stc %r0,0(%r2,%r3) # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from tape
-#
- l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
- bras %r14,.Lloader # load ramdisk
- st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
- ltr %r2,%r2
- jnz .Lrdcont
- st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
-.Lrdcont:
-#
-# everything loaded, go for it
-#
- j start
#
# subroutine for loading from tape
# Paramters:
@@ -173,32 +69,32 @@ iplstart:
lctl %c6,%c6,.Lcr6
slr %r2,%r2
.Lldlp:
- lhi %r6,3 # 3 retries
+ la %r6,3 # 3 retries
.Lssch:
ssch 0(%r3) # load chunk of IPL_BS bytes
- jnz .Llderr
+ bnz .Llderr
.Lw4end:
- bras %r14,.Lwait4io
+ bas %r14,.Lwait4io
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Lrecov
+ bnz .Lrecov
slr %r7,%r7
icm %r7,3,10(%r5) # get residual count
lcr %r7,%r7
- ahi %r7,IPL_BS # IPL_BS-residual=#bytes read
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
ar %r2,%r7 # add to total size
tm 8(%r5),0x01 # found a tape mark ?
- jnz .Ldone
+ bnz .Ldone
l %r0,.Lccwread+4 # update CCW data addresses
ar %r0,%r7
st %r0,.Lccwread+4
- j .Lldlp
+ b .Lldlp
.Ldone:
l %r14,.Lldret
br %r14 # r2 contains the total size
.Lrecov:
- bras %r14,.Lsense # do the sensing
- brct %r6,.Lssch # dec. retry count & branch
- j .Llderr
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
#
# Sense subroutine
#
@@ -206,11 +102,11 @@ iplstart:
st %r14,.Lsnsret
la %r7,.Lorbsense
ssch 0(%r7) # start sense command
- jnz .Llderr
- bras %r14,.Lwait4io
+ bnz .Llderr
+ bas %r14,.Lwait4io
l %r14,.Lsnsret
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Llderr
+ bnz .Llderr
br %r14
#
# Wait for interrupt subroutine
@@ -219,13 +115,13 @@ iplstart:
lpsw .Lwaitpsw
.Lioint:
c %r1,0xb8 # compare subchannel number
- jne .Lwait4io
+ bne .Lwait4io
tsch 0(%r5)
slr %r0,%r0
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Lwtexit
+ bnz .Lwtexit
tm 8(%r5),0x04 # got device end ?
- jz .Lwait4io
+ bz .Lwait4io
.Lwtexit:
br %r14
.Llderr:
@@ -249,18 +145,12 @@ iplstart:
.Lcr6: .long 0xff000000
.align 8
.Lcrash:.long 0x000a0000,0x00000000
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
.Lldret:.long 0
.Lsnsret: .long 0
-.Lcvtab:.long _ebcasc # ebcdic to ascii table
-
#endif /* CONFIG_IPL_TAPE */
#ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
.org 0
.long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
.long 0x02000018,0x60000050 # by ipl to addresses 0-23.
@@ -287,103 +177,7 @@ iplstart:
.long 0x02000690,0x60000050
.long 0x020006e0,0x20000050
-
.org 0xf0
-iplstart:
- l %r1,0xb8 # load ipl subchannel number
- lhi %r2,0x730 # load start address
- bras %r14,.Lloader # load rest of ipl image
- st %r1,__LC_IPLDEV # store ipl device number
- l %r12,.Lparm # pointer to parameter area
-
-#
-# find out memory size
-#
- mvc 104(8,0),.Lpcmem0 # setup program check handler
- slr %r2,%r2
- lhi %r3,1
- sll %r3,20
-.Lloop0:
- l %r0,0(%r2) # test page
- ar %r2,%r3 # add 1M
- jnm .Lloop0 # r1 < 0x80000000 -> loop
-.Lchkmem0:
- n %r2,.L4malign0 # align to multiples of 4M
- st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size
- c %r2,.Lbigmem # more than 64 MB of memory ?
- jl .Lmemok # if yes load ramdisk to 32 MB
- mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from reader
-#
- l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
- bras %r14,.Lloader # load parameter file
- ltr %r2,%r2 # got anything ?
- jz .Lnopf
- chi %r2,895
- jnh .Lnotrunc
- lhi %r2,895
-.Lnotrunc:
- l %r4,INITRD_START-PARMAREA(%r12)
- la %r5,0(%r4,%r2)
- lr %r3,%r2
-.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- jo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- brct %r3,.Lidebc
- j .Lnocv
-.Ldocv:
- l %r3,.Lcvtab
- tr 0(256,%r4),0(%r3) # convert parameters to ascii
- tr 256(256,%r4),0(%r3)
- tr 512(256,%r4),0(%r3)
- tr 768(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
- mvc 0(256,%r3),0(%r4)
- mvc 256(256,%r3),256(%r4)
- mvc 512(256,%r3),512(%r4)
- mvc 768(122,%r3),768(%r4)
- slr %r0,%r0
- j .Lcntlp
-.Ldelspc:
- ic %r0,0(%r2,%r3)
- chi %r0,0x20 # is it a space ?
- je .Lcntlp
- ahi %r2,1
- j .Leolp
-.Lcntlp:
- brct %r2,.Ldelspc
-.Leolp:
- slr %r0,%r0
- stc %r0,0(%r2,%r3) # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from reader
-#
- l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
- bras %r14,.Lloader # load ramdisk
- st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
- ltr %r2,%r2
- jnz .Lrdcont
- st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
-.Lrdcont:
-
-#
-# everything loaded, reset files in reader, then go for it
-#
- stidp __LC_CPUID # store cpuid
- lh %r0,__LC_CPUID+4 # get cpu version
- chi %r0,0x7490 # running on P/390 ?
- je start # no -> skip reset
- la %r2,.Lreset
- lhi %r3,26
- .long 0x83230008
- j start
-
#
# subroutine for loading cards from the reader
#
@@ -394,29 +188,29 @@ iplstart:
la %r7,20
.Linit:
st %r2,4(%r6) # initialize CCW data addresses
- ahi %r2,0x50
- ahi %r6,8
- brct 7,.Linit
+ la %r2,0x50(%r2)
+ la %r6,8(%r6)
+ bct 7,.Linit
lctl %c6,%c6,.Lcr6 # set IO subclass mask
slr %r2,%r2
.Lldlp:
ssch 0(%r3) # load chunk of 1600 bytes
- jnz .Llderr
+ bnz .Llderr
.Lwait4irq:
mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw
lpsw .Lwaitpsw
.Lioint:
c %r1,0xb8 # compare subchannel number
- jne .Lwait4irq
+ bne .Lwait4irq
tsch 0(%r5)
slr %r0,%r0
ic %r0,8(%r5) # get device status
chi %r0,8 # channel end ?
- je .Lcont
+ be .Lcont
chi %r0,12 # channel end + device end ?
- je .Lcont
+ be .Lcont
l %r0,4(%r5)
s %r0,8(%r3) # r0/8 = number of ccws executed
@@ -436,9 +230,9 @@ iplstart:
ahi %r0,0x640
st %r0,4(%r6)
ahi %r6,8
- brct 7,.Lincr
+ bct 7,.Lincr
- j .Lldlp
+ b .Lldlp
.Llderr:
lpsw .Lcrash
@@ -447,16 +241,7 @@ iplstart:
.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.Lcr6: .long 0xff000000
.Lloadp:.long 0,0
-.Lparm: .long PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lcvtab:.long _ebcasc # ebcdic to ascii table
-.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
- .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
- .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
.align 8
-.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0
.Lcrash:.long 0x000a0000,0x00000000
.Lnewpsw:
.long 0x00080000,0x80000000+.Lioint
@@ -468,79 +253,330 @@ iplstart:
.long 0x02600050,0x00000000
.endr
.long 0x02200050,0x00000000
-
- .org 0x730 # end of the area loaded by the ipl channel program
#endif /* CONFIG_IPL_VM */
+iplstart:
+ lh %r1,0xb8 # test if subchannel number
+ bct %r1,.Lnoload # is valid
+ l %r1,0xb8 # load ipl subchannel number
+ la %r2,IPL_BS # load start address
+ bas %r14,.Lloader # load rest of ipl image
+ st %r1,__LC_IPLDEV # store ipl device number
+ l %r12,.Lparm # pointer to parameter area
+
+#
+# load parameter file from ipl device
+#
+.Lagain1:
+ l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp
+ bas %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ bz .Lnopf
+ chi %r2,895
+ bnh .Lnotrunc
+ la %r2,895
+.Lnotrunc:
+ l %r4,INITRD_START-PARMAREA(%r12)
+ clc 0(3,%r4),.L_hdr # if it is HDRx
+ bz .Lagain1 # skip dataset header
+ clc 0(3,%r4),.L_eof # if it is EOFx
+ bz .Lagain1 # skip dateset trailer
+ la %r5,0(%r4,%r2)
+ lr %r3,%r2
+.Lidebc:
+ tm 0(%r5),0x80 # high order bit set ?
+ bo .Ldocv # yes -> convert from EBCDIC
+ ahi %r5,-1
+ bct %r3,.Lidebc
+ b .Lnocv
+.Ldocv:
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(122,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(122,%r3),768(%r4)
+ slr %r0,%r0
+ b .Lcntlp
+.Ldelspc:
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ be .Lcntlp
+ ahi %r2,1
+ b .Leolp
+.Lcntlp:
+ brct %r2,.Ldelspc
+.Leolp:
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#
+.Lagain2:
+ l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk
+ bas %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk
+ ltr %r2,%r2
+ bnz .Lrdcont
+ st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it
+.Lrdcont:
+ l %r2,INITRD_START-PARMAREA(%r12)
+
+ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+ bz .Lagain2
+ clc 0(3,%r2),.L_eof
+ bz .Lagain2
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+ stidp __LC_CPUID # store cpuid
+ lh %r0,__LC_CPUID+4 # get cpu version
+ chi %r0,0x7490 # running on P/390 ?
+ be start # no -> skip reset
+ la %r2,.Lreset
+ lhi %r3,26
+ .long 0x83230008
+#endif
+
+#
+# everything loaded, go for it
+#
+.Lnoload:
+ l %r1,.Lstartup
+ br %r1
+
+.Lparm: .long PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+.L_eof: .long 0xc5d6c600 /* C'EOF' */
+.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+
#endif /* CONFIG_IPL */
#
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+ .org 0x800
+ .globl start
+start:
+ stm %r0,%r15,0x07b0 # store registers
+ basr %r12,%r0
+.base:
+ l %r11,.parm
+ l %r8,.cmd # pointer to command buffer
+
+ ltr %r9,%r9 # do we have SALIPL parameters?
+ bp .sk8x8
+
+ mvc 0(64,%r8),0x00b0 # copy saved registers
+ xc 64(240-64,%r8),0(%r8) # remainder of buffer
+ tr 0(64,%r8),.lowcase
+ b .gotr
+.sk8x8:
+ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+.gotr:
+ l %r10,.tbl # EBCDIC to ASCII table
+ tr 0(240,%r8),0(%r10)
+ stidp __LC_CPUID # Are we running on VM maybe
+ cli __LC_CPUID,0xff
+ bnz .test
+ .long 0x83300060 # diag 3,0,x'0060' - storage size
+ b .done
+.test:
+ mvc 0x68(8),.pgmnw # set up pgm check handler
+ l %r2,.fourmeg
+ lr %r3,%r2
+ bctr %r3,%r0 # 4M-1
+.loop: iske %r0,%r3
+ ar %r3,%r2
+.pgmx:
+ sr %r3,%r2
+ la %r3,1(%r3)
+.done:
+ st %r3,MEMORY_SIZE-PARMAREA(%r11)
+ slr %r0,%r0
+ st %r0,INITRD_SIZE-PARMAREA(%r11)
+ st %r0,INITRD_START-PARMAREA(%r11)
+ j startup # continue with startup
+.tbl: .long _ebcasc # translate table
+.cmd: .long COMMAND_LINE # address of command line buffer
+.parm: .long PARMAREA
+.fourmeg: .long 0x00400000 # 4M
+.pgmnw: .long 0x00080000,.pgmx
+.lowcase:
+ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
+ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
+ .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
+ .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
+ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+#
# startup-code at 0x10000, running in real mode
-# this is called either by the ipl loader or directly by PSW restart or linload
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
#
.org 0x10000
- .globl start
-start: basr %r13,0 # get base
-.LPG1: lctl %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd
- lctl %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd
- lctl %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd
- lctl %c0,%c0,.Lcr0-.LPG1(%r13) # set CR0
+startup:basr %r13,0 # get base
+.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
#
-# find out memory size. That is done in the ipl loader too but for
-# ipl from dasd the size of the memory has to be detected too...
+# find out memory size.
#
- icm %r0,15,MEMORY_SIZE-PARMAREA(%r12)
- jnz .Lsizeok
- mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
- slr %r1,%r1
+ mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler
lhi %r2,1
- sll %r2,20
+ sll %r2,17 # test in increments of 128KB
+ lr %r1,%r2
+ ahi %r1,-4 # test last word in the segment
.Lloop:
- l %r0,0(%r1) # test page
- ar %r1,%r2 # add 1M
- jnm .Lloop # r1 < 0x80000000 -> loop
+ l %r0,0(%r1) # test 128KB segment
+ st %r0,0(%r1)
+ ar %r1,%r2 # add 128KB
+ bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
.Lchkmem:
n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size
.Lsizeok:
#
+# Now we have to move the ramdisk to a location approriate for the
+# memory size. If we have more than 64 MB of memory we move it to 32MB
+# to make room for the page tables set up by paging_init.
+#
+ l %r1,MEMORY_SIZE-PARMAREA(%r12)
+ cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ?
+ bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok
+ icm %r4,15,INITRD_START-PARMAREA(%r12)
+ bz .Lnomove-.LPG1(%r13)
+ l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk
+ st %r2,INITRD_START-PARMAREA(%r12)
+ l %r1,INITRD_SIZE-PARMAREA(%r12)
+ ar %r2,%r1 # we start moving at the end
+ ar %r4,%r1 # because new location > old location
+.Lmove: lr %r0,%r2 # new - old is the maximum we can move
+ sr %r0,%r4 # because of overlapping
+ cr %r0,%r1 # we shouldn't move more than there is
+ bnh .Lnoend-.LPG1(%r13)
+ lr %r0,%r1
+.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go
+ bnh .Lchunk-.LPG1(%r13)
+ l %r0,.Lmaxchunk-.LPG1(%r13)
+.Lchunk:sr %r2,%r0 # make source & destination pointer
+ sr %r4,%r0
+ lr %r3,%r0 # set source & destination length
+ lr %r5,%r0
+ mvcl %r2,%r4
+ sr %r2,%r0 # substract length again, since
+ sr %r4,%r0 # mvcl added it to the pointers
+ sr %r1,%r0 # substract chunk size from length
+ bnz .Lmove-.LPG1(%r13)
+.Lnomove:
+
+#
# find out if we are running under VM
#
stidp __LC_CPUID # store cpuid
tm __LC_CPUID,0xff # running under VM ?
- jno .Lnovm
+ bno .Lnovm-.LPG1(%r13)
oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag
.Lnovm:
lh %r0,__LC_CPUID+4 # get cpu version
chi %r0,0x7490 # running on a P/390 ?
- jne .Lnop390
+ bne .Lnop390-.LPG1(%r13)
oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag
.Lnop390:
#
# find out if we have an IEEE fpu
#
- mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+ mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler
ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0
ldr %f2,%f0
adbr %f0,%f2 # test IEEE add instruction
oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag
.Lchkfpu:
+#
+# find out if we have the CSP instruction
+#
+ mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler
+ la %r0,0
+ lr %r1,%r0
+ la %r2,.Lflt0-.LPG1(%r13)
+ csp %r0,%r2 # Test CSP instruction
+ oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag
+.Lchkcsp:
+
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
-.Lentry:.long 0x04080000,0x80000000 + _stext
-.Lpstd: .long .Lpgd+0x7F # segment-table
-.Lcr0: .long 0x04b50002
+.Lentry:.long 0x00080000,0x80000000 + _stext
+.Lctl: .long 0x04b50002 # cr0: various things
+ .long 0 # cr1: primary space segment table
+ .long 0 # cr2: access register translation
+ .long 0 # cr3: instruction authorization
+ .long 0 # cr4: instruction authorization
+ .long 0 # cr5: various things
+ .long 0 # cr6: I/O interrupts
+ .long 0 # cr7: secondary space segment table
+ .long 0 # cr8: access registers translation
+ .long 0 # cr9: tracing off
+ .long 0 # cr10: tracing off
+ .long 0 # cr11: tracing off
+ .long 0 # cr12: tracing off
+ .long 0 # cr13: home space segment table
+ .long 0xc0000000 # cr14: machine check handling off
+ .long 0 # cr15: linkage stack operations
.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
+.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lflt0: .double 0
.Lparm1:.long PARMAREA
.L4malign:.long 0xffc00000
+.Lbigmem:.long 0x04000000
+.Lrdstart:.long 0x02000000
+.Lmaxchunk:.long 0x00ffffff
#
# params at 10400 (setup.h)
@@ -555,17 +591,8 @@ start: basr %r13,0 # get base
.word 0 # RAMDISK_FLAGS
.org COMMAND_LINE
-# .byte "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-# .byte "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
-# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-# .byte "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
-# .byte "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-# .byte "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
-# .byte "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
-# .byte "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
.byte "root=/dev/ram0 ro"
-# .byte 0
+ .byte 0
#
# startup-code, running in virtual mode
@@ -626,43 +653,3 @@ _stext: basr %r13,0 # get base
.align 8
.Ldw: .long 0x000a0000,0x00000000
-#
-# tempory segment-table at 0x11000
-#
- .org 0x11000
-.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff
- .long .Lpt1+0x1f # 00100000-001fffff
- .long .Lpt2+0x1f # 00200000-002fffff
- .long .Lpt3+0x1f # 00300000-003fffff
- .fill 2044,4,0x20 # 00400000-7fffffff
-
-#
-# tempory page-tables at 0x12000-0x15fff
-#
- .macro mktable from,to
- .long \from*0x10000
- .long \from*0x10000+0x1000
- .long \from*0x10000+0x2000
- .long \from*0x10000+0x3000
- .long \from*0x10000+0x4000
- .long \from*0x10000+0x5000
- .long \from*0x10000+0x6000
- .long \from*0x10000+0x7000
- .long \from*0x10000+0x8000
- .long \from*0x10000+0x9000
- .long \from*0x10000+0xa000
- .long \from*0x10000+0xb000
- .long \from*0x10000+0xc000
- .long \from*0x10000+0xd000
- .long \from*0x10000+0xe000
- .long \from*0x10000+0xf000
- .if \to-\from
- mktable "(\from+1)",\to
- .endif
- .endm
-
-.Lpt0: mktable 0,15
-.Lpt1: mktable 16,31
-.Lpt2: mktable 32,47
-.Lpt3: mktable 48,63
-
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index ba513325a..989aa0720 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -20,11 +20,11 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
-#include <linux/tasks.h>
+#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
@@ -205,6 +205,8 @@ static inline void wait_on_irq(int cpu)
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
+ /* this works even though global_irq_lock not
+ a long, but is arch-specific --RR */
if (!test_and_set_bit(0,&global_irq_lock))
break;
}
@@ -243,6 +245,8 @@ void synchronize_irq(void)
static inline void get_irqlock(int cpu)
{
+ /* this works even though global_irq_lock not a long, but is
+ arch-specific --RR */
if (test_and_set_bit(0,&global_irq_lock)) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
@@ -398,7 +402,7 @@ void enable_nop(int irq)
void __init init_IRQ(void)
{
- s390_init_IRQ();
+ s390_init_IRQ();
}
diff --git a/arch/s390/kernel/mathemu.c b/arch/s390/kernel/mathemu.c
index 78b6e5ec6..23c6c72a2 100644
--- a/arch/s390/kernel/mathemu.c
+++ b/arch/s390/kernel/mathemu.c
@@ -9,6 +9,7 @@
* that does not have the IEEE fpu
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
@@ -16,7 +17,59 @@
#include <asm/uaccess.h>
#include <asm/mathemu.h>
-static void set_CC_df(__u64 val1,__u64 val2) {
+#ifdef CONFIG_SYSCTL
+int sysctl_ieee_emulation_warnings=1;
+#endif
+
+#define mathemu_put_user(x, ptr) \
+{ \
+ if(put_user((x),(ptr))) \
+ return 1; \
+}
+
+#define mathemu_get_user(x, ptr) \
+{ \
+ if(get_user((x),(ptr))) \
+ return 1; \
+}
+
+
+#define mathemu_copy_from_user(to,from,n) \
+{ \
+ if(copy_from_user((to),(from),(n))==-EFAULT) \
+ return 1; \
+}
+
+
+#define mathemu_copy_to_user(to, from, n) \
+{ \
+ if(copy_to_user((to),(from),(n))==-EFAULT) \
+ return 1; \
+}
+
+
+
+static void display_emulation_not_implemented(char *instr)
+{
+ struct pt_regs *regs;
+ __u16 *location;
+
+#if CONFIG_SYSCTL
+ if(sysctl_ieee_emulation_warnings)
+#endif
+ {
+ regs=current->thread.regs;
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
+ instr,
+ current->comm, current->pid);
+ printk("%s's PSW: %08lx %08lx\n",instr,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) location);
+ }
+}
+
+static int set_CC_df(__u64 val1,__u64 val2) {
int rc;
rc = __cmpdf2(val1,val2);
current->thread.regs->psw.mask &= 0xFFFFCFFF;
@@ -28,9 +81,10 @@ static void set_CC_df(__u64 val1,__u64 val2) {
current->thread.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void set_CC_sf(__u32 val1,__u32 val2) {
+static int set_CC_sf(__u32 val1,__u32 val2) {
int rc;
rc = __cmpsf2(val1,val2);
current->thread.regs->psw.mask &= 0xFFFFCFFF;
@@ -42,384 +96,473 @@ static void set_CC_sf(__u32 val1,__u32 val2) {
current->thread.regs->psw.mask |= 0x00002000;
break;
}
+ return 0;
}
-static void emu_adb (int rx, __u64 val) {
+static int emu_adb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_adbr (int rx, int ry) {
+static int emu_adbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_aeb (int rx, __u32 val) {
+static int emu_aeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_aebr (int rx, int ry) {
+static int emu_aebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_axbr (int rx, int ry) {
- printk("axbr emulation not implemented!\n");
+static int emu_axbr (int rx, int ry) {
+ display_emulation_not_implemented("axbr");
+ return 0;
}
-static void emu_cdb (int rx, __u64 val) {
+static int emu_cdb (int rx, __u64 val) {
set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
+ return 0;
}
-static void emu_cdbr (int rx, int ry) {
+static int emu_cdbr (int rx, int ry) {
set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cdfbr (int rx, int ry) {
+static int emu_cdfbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__floatsidf(current->thread.regs->gprs[ry]);
+ return 0;
}
-static void emu_ceb (int rx, __u32 val) {
+static int emu_ceb (int rx, __u32 val) {
set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
+ return 0;
}
-static void emu_cebr (int rx, int ry) {
+static int emu_cebr (int rx, int ry) {
set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cefbr (int rx, int ry) {
+static int emu_cefbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f =
__floatsisf(current->thread.regs->gprs[ry]);
+ return 0;
}
-static void emu_cfdbr (int rx, int ry, int mask) {
+static int emu_cfdbr (int rx, int ry, int mask) {
current->thread.regs->gprs[rx] =
__fixdfsi(current->thread.fp_regs.fprs[ry].d);
+ return 0;
}
-static void emu_cfebr (int rx, int ry, int mask) {
+static int emu_cfebr (int rx, int ry, int mask) {
current->thread.regs->gprs[rx] =
__fixsfsi(current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_cfxbr (int rx, int ry, int mask) {
- printk("cfxbr emulation not implemented!\n");
+static int emu_cfxbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("cfxbr");
+ return 0;
}
-static void emu_cxbr (int rx, int ry) {
- printk("cxbr emulation not implemented!\n");
+static int emu_cxbr (int rx, int ry) {
+ display_emulation_not_implemented("cxbr");
+ return 0;
}
-static void emu_cxfbr (int rx, int ry) {
- printk("cxfbr emulation not implemented!\n");
+static int emu_cxfbr (int rx, int ry) {
+ display_emulation_not_implemented("cxfbr");
+ return 0;
}
-static void emu_ddb (int rx, __u64 val) {
+static int emu_ddb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ddbr (int rx, int ry) {
+static int emu_ddbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_deb (int rx, __u32 val) {
+static int emu_deb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_debr (int rx, int ry) {
+static int emu_debr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_didbr (int rx, int ry, int mask) {
- printk("didbr emulation not implemented!\n");
+static int emu_didbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("didbr");
+ return 0;
}
-static void emu_diebr (int rx, int ry, int mask) {
- printk("diebr emulation not implemented!\n");
+static int emu_diebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("diebr");
+ return 0;
}
-static void emu_dxbr (int rx, int ry) {
- printk("dxbr emulation not implemented!\n");
+static int emu_dxbr (int rx, int ry) {
+ display_emulation_not_implemented("dxbr");
+ return 0;
}
-static void emu_efpc (int rx, int ry) {
- printk("efpc emulation not implemented!\n");
+static int emu_efpc (int rx, int ry) {
+ current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc;
+ return 0;
}
-static void emu_fidbr (int rx, int ry, int mask) {
- printk("fidbr emulation not implemented!\n");
+static int emu_fidbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fidbr");
+ return 0;
}
-static void emu_fiebr (int rx, int ry, int mask) {
- printk("fiebr emulation not implemented!\n");
+static int emu_fiebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fiebr");
+ return 0;
}
-static void emu_fixbr (int rx, int ry, int mask) {
- printk("fixbr emulation not implemented!\n");
+static int emu_fixbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("fixbr");
+ return 0;
}
-static void emu_kdb (int rx, __u64 val) {
- printk("kdb emulation not implemented!\n");
+static int emu_kdb (int rx, __u64 val) {
+ display_emulation_not_implemented("kdb");
+ return 0;
}
-static void emu_kdbr (int rx, int ry) {
- printk("kdbr emulation not implemented!\n");
+static int emu_kdbr (int rx, int ry) {
+ display_emulation_not_implemented("kdbr");
+ return 0;
}
-static void emu_keb (int rx, __u32 val) {
- printk("keb emulation not implemented!\n");
+static int emu_keb (int rx, __u32 val) {
+ display_emulation_not_implemented("keb");
+ return 0;
}
-static void emu_kebr (int rx, int ry) {
- printk("kebr emulation not implemented!\n");
+static int emu_kebr (int rx, int ry) {
+ display_emulation_not_implemented("kebr");
+ return 0;
}
-static void emu_kxbr (int rx, int ry) {
- printk("kxbr emulation not implemented!\n");
+static int emu_kxbr (int rx, int ry) {
+ display_emulation_not_implemented("kxbr");
+ return 0;
}
-static void emu_lcdbr (int rx, int ry) {
+static int emu_lcdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__negdf2(current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_lcebr (int rx, int ry) {
+static int emu_lcebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f =
__negsf2(current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lcxbr (int rx, int ry) {
- printk("lcxbr emulation not implemented!\n");
+static int emu_lcxbr (int rx, int ry) {
+ display_emulation_not_implemented("lcxbr");
+ return 0;
}
-static void emu_ldeb (int rx, __u32 val) {
+static int emu_ldeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
+ return 0;
}
-static void emu_ldebr (int rx, int ry) {
+static int emu_ldebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d =
__extendsfdf2(current->thread.fp_regs.fprs[ry].f);
+ return 0;
}
-static void emu_ldxbr (int rx, int ry) {
- printk("ldxbr emulation not implemented!\n");
+static int emu_ldxbr (int rx, int ry) {
+ display_emulation_not_implemented("ldxbr");
+ return 0;
}
-static void emu_ledbr (int rx, int ry) {
+static int emu_ledbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lexbr (int rx, int ry) {
- printk("lexbr emulation not implemented!\n");
+static int emu_lexbr (int rx, int ry) {
+ display_emulation_not_implemented("lexbr");
+ return 0;
}
-static void emu_lndbr (int rx, int ry) {
- printk("lndbr emulation not implemented!\n");
+static int emu_lndbr (int rx, int ry) {
+ display_emulation_not_implemented("lndbr");
+ return 0;
}
-static void emu_lnebr (int rx, int ry) {
- printk("lnebr emulation not implemented!\n");
+static int emu_lnebr (int rx, int ry) {
+ display_emulation_not_implemented("lnebr");
+ return 0;
}
-static void emu_lnxbr (int rx, int ry) {
- printk("lnxbr emulation not implemented!\n");
+static int emu_lnxbr (int rx, int ry) {
+ display_emulation_not_implemented("lnxbr");
+ return 0;
}
-static void emu_lpdbr (int rx, int ry) {
+static int emu_lpdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
+ return 0;
}
-static void emu_lpebr (int rx, int ry) {
+static int emu_lpebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_lpxbr (int rx, int ry) {
- printk("lpxbr emulation not implemented!\n");
+static int emu_lpxbr (int rx, int ry) {
+ display_emulation_not_implemented("lpxbr");
+ return 0;
}
-static void emu_ltdbr (int rx, int ry) {
+static int emu_ltdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_ltebr (int rx, int ry) {
+static int emu_ltebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_ltxbr (int rx, int ry) {
- printk("ltxbr emulation not implemented!\n");
+static int emu_ltxbr (int rx, int ry) {
+ display_emulation_not_implemented("ltxbr");
+ return 0;
}
-static void emu_lxdb (int rx, __u64 val) {
- printk("lxdb emulation not implemented!\n");
+static int emu_lxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("lxdb");
+ return 0;
}
-static void emu_lxdbr (int rx, int ry) {
- printk("lxdbr emulation not implemented!\n");
+static int emu_lxdbr (int rx, int ry) {
+ display_emulation_not_implemented("lxdbr");
+ return 0;
}
-static void emu_lxeb (int rx, __u32 val) {
- printk("lxeb emulation not implemented!\n");
+static int emu_lxeb (int rx, __u32 val) {
+ display_emulation_not_implemented("lxeb");
+ return 0;
}
-static void emu_lxebr (int rx, int ry) {
- printk("lxebr emulation not implemented!\n");
+static int emu_lxebr (int rx, int ry) {
+ display_emulation_not_implemented("lxebr");
+ return 0;
}
-static void emu_madb (int rx, __u64 val, int mask) {
- printk("madb emulation not implemented!\n");
+static int emu_madb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("madb");
+ return 0;
}
-static void emu_madbr (int rx, int ry, int mask) {
- printk(" emulation not implemented!\n");
+static int emu_madbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("madbr");
+ return 0;
}
-static void emu_maeb (int rx, __u32 val, int mask) {
- printk("maeb emulation not implemented!\n");
+static int emu_maeb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("maeb");
+ return 0;
}
-static void emu_maebr (int rx, int ry, int mask) {
- printk("maebr emulation not implemented!\n");
+static int emu_maebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("maebr");
+ return 0;
}
-static void emu_mdb (int rx, __u64 val) {
+static int emu_mdb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdbr (int rx, int ry) {
+static int emu_mdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_mdeb (int rx, __u32 val) {
- printk("mdeb emulation not implemented!\n");
+static int emu_mdeb (int rx, __u32 val) {
+ display_emulation_not_implemented("mdeb");
+ return 0;
}
-static void emu_mdebr (int rx, int ry) {
- printk("mdebr emulation not implemented!\n");
+static int emu_mdebr (int rx, int ry) {
+ display_emulation_not_implemented("mdebr");
+ return 0;
}
-static void emu_meeb (int rx, __u32 val) {
+static int emu_meeb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_meebr (int rx, int ry) {
+static int emu_meebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_msdb (int rx, __u64 val, int mask) {
- printk("msdb emulation not implemented!\n");
+static int emu_msdb (int rx, __u64 val, int mask) {
+ display_emulation_not_implemented("msdb");
+ return 0;
}
-static void emu_msdbr (int rx, int ry, int mask) {
- printk("msdbr emulation not implemented!\n");
+static int emu_msdbr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msdbr");
+ return 0;
}
-static void emu_mseb (int rx, __u32 val, int mask) {
- printk("mseb emulation not implemented!\n");
+static int emu_mseb (int rx, __u32 val, int mask) {
+ display_emulation_not_implemented("mseb");
+ return 0;
}
-static void emu_msebr (int rx, int ry, int mask) {
- printk("msebr emulation not implemented!\n");
+static int emu_msebr (int rx, int ry, int mask) {
+ display_emulation_not_implemented("msebr");
+ return 0;
}
-static void emu_mxbr (int rx, int ry) {
- printk("mxbr emulation not implemented!\n");
+static int emu_mxbr (int rx, int ry) {
+ display_emulation_not_implemented("mxbr");
+ return 0;
}
-static void emu_mxdb (int rx, __u64 val) {
- printk("mxdb emulation not implemented!\n");
+static int emu_mxdb (int rx, __u64 val) {
+ display_emulation_not_implemented("mxdb");
+ return 0;
}
-static void emu_mxdbr (int rx, int ry) {
- printk("mxdbr emulation not implemented!\n");
+static int emu_mxdbr (int rx, int ry) {
+ display_emulation_not_implemented("mxdbr");
+ return 0;
}
-static void emu_sdb (int rx, __u64 val) {
+static int emu_sdb (int rx, __u64 val) {
current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_sdbr (int rx, int ry) {
+static int emu_sdbr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
current->thread.fp_regs.fprs[ry].d);
set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
+ return 0;
}
-static void emu_seb (int rx, __u32 val) {
+static int emu_seb (int rx, __u32 val) {
current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
val);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sebr (int rx, int ry) {
+static int emu_sebr (int rx, int ry) {
current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
current->thread.fp_regs.fprs[ry].f);
set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
+ return 0;
}
-static void emu_sfpc (int rx, int ry) {
- printk("sfpc emulation not implemented!\n");
+static int emu_sfpc (int rx, int ry) {
+ __u32 val=current->thread.regs->gprs[rx];
+ if(val==0)
+ current->thread.fp_regs.fpc=val;
+ else
+ display_emulation_not_implemented("sfpc");
+ return 0;
}
-static void emu_sqdb (int rx, __u64 val) {
- printk("sqdb emulation not implemented!\n");
+static int emu_sqdb (int rx, __u64 val) {
+ display_emulation_not_implemented("sqdb");
+ return 0;
}
-static void emu_sqdbr (int rx, int ry) {
- printk("sqdbr emulation not implemented!\n");
+static int emu_sqdbr (int rx, int ry) {
+ display_emulation_not_implemented("sqdbr");
+ return 0;
}
-static void emu_sqeb (int rx, __u32 val) {
- printk("sqeb emulation not implemented!\n");
+static int emu_sqeb (int rx, __u32 val) {
+ display_emulation_not_implemented("sqeb");
+ return 0;
}
-static void emu_sqebr (int rx, int ry) {
- printk("sqebr emulation not implemented!\n");
+static int emu_sqebr (int rx, int ry) {
+ display_emulation_not_implemented("sqebr");
+ return 0;
}
-static void emu_sqxbr (int rx, int ry) {
- printk("sqxbr emulation not implemented!\n");
+static int emu_sqxbr (int rx, int ry) {
+ display_emulation_not_implemented("sqxbr");
+ return 0;
}
-static void emu_sxbr (int rx, int ry) {
- printk("sxbr emulation not implemented!\n");
+static int emu_sxbr (int rx, int ry) {
+ display_emulation_not_implemented("sxbr");
+ return 0;
}
-static void emu_tcdb (int rx, __u64 val) {
- printk("tcdb emulation not implemented!\n");
+static int emu_tcdb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcdb");
+ return 0;
}
-static void emu_tceb (int rx, __u32 val) {
- printk("tceb emulation not implemented!\n");
+static int emu_tceb (int rx, __u32 val) {
+ display_emulation_not_implemented("tceb");
+ return 0;
}
-static void emu_tcxb (int rx, __u64 val) {
- printk("tcxb emulation not implemented!\n");
+static int emu_tcxb (int rx, __u64 val) {
+ display_emulation_not_implemented("tcxb");
+ return 0;
}
@@ -473,6 +616,7 @@ static inline void emu_store_rege(int reg) {
}
int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
static const __u8 format_table[] = {
2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -538,84 +682,82 @@ int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 2: /* RRE format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 3: /* RRF format, double operation */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_regd((opcode[3]>>4)&15);
- emu_load_regd(opcode[3]&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ emu_load_regd(opcode[3]&15);
+ return rc;
case 4: /* RRF format, float operation */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- emu_load_rege((opcode[3]>>4)&15);
- emu_load_rege(opcode[3]&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ emu_load_rege(opcode[3]&15);
+ return rc;
case 5: /* RRE format, cefbr instruction */
emu_store_rege((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
case 6: /* RRE format, cdfbr & cxfbr instruction */
emu_store_regd((opcode[3]>>4)&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
- /* FIXME !! */
- return 0;
- case 7: /* RRF format, cfebr instruction */
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
+ case 7: /* RRF format, cfebr instruction */
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 8: /* RRF format, cfdbr & cfxbr instruction */
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
- return 0;
+ return rc;
case 9: /* RRE format, ldebr & mdebr instruction */
/* float store but double load */
emu_store_rege((opcode[3]>>4)&15);
emu_store_rege(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_regd((opcode[3]>>4)&15);
- return 0;
+ emu_load_regd((opcode[3]>>4)&15);
+ return rc;
case 10: /* RRE format, ledbr instruction */
/* double store but float load */
emu_store_regd((opcode[3]>>4)&15);
emu_store_regd(opcode[3]&15);
/* call the emulation function */
- ((void (*)(int, int))jump_table[opcode[1]])
+ rc=((int (*)(int, int))jump_table[opcode[1]])
(opcode[3]>>4,opcode[3]&15);
- emu_load_rege((opcode[3]>>4)&15);
- return 0;
+ emu_load_rege((opcode[3]>>4)&15);
+ return rc;
default:
return 1;
}
@@ -632,6 +774,8 @@ static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
}
int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
+ int rc=0;
+
static const __u8 format_table[] = {
0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
@@ -669,13 +813,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u64))jump_table[opcode[5]])
+ rc=((int (*)(int, __u64))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 2: /* RXE format, __u32 constant */ {
__u32 *dxb, temp;
@@ -684,13 +827,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
- emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ emu_load_rege((opcode[1]>>4)&15);
+ return rc;
}
case 3: /* RXF format, __u64 constant */ {
__u32 *dxb, temp;
@@ -699,13 +841,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_regd((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&temp, dxb, 8);
+ mathemu_copy_from_user(&temp, dxb, 8);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
- emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ emu_load_regd((opcode[1]>>4)&15);
+ return rc;
}
case 4: /* RXF format, __u32 constant */ {
__u32 *dxb, temp;
@@ -714,29 +855,27 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32, int))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32, int))jump_table[opcode[5]])
(opcode[1]>>4,temp,opcode[4]>>4);
emu_load_rege((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
case 5: /* RXE format, __u32 constant */
/* store_rege and load_regd */
- {
+ {
__u32 *dxb, temp;
__u32 opc;
emu_store_rege((opcode[1]>>4)&15);
opc = *((__u32 *) opcode);
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
- get_user(temp, dxb);
+ mathemu_get_user(temp, dxb);
/* call the emulation function */
- ((void (*)(int, __u32))jump_table[opcode[5]])
+ rc=((int (*)(int, __u32))jump_table[opcode[5]])
(opcode[1]>>4,temp);
emu_load_regd((opcode[1]>>4)&15);
- return 0;
+ return rc;
}
default:
return 1;
@@ -746,7 +885,7 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
/*
* Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ldr(__u8 *opcode) {
+int math_emu_ldr(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
@@ -772,12 +911,13 @@ void math_emu_ldr(__u8 *opcode) {
current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
current->thread.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
*/
-void math_emu_ler(__u8 *opcode) {
+int math_emu_ler(__u8 *opcode) {
__u16 opc = *((__u16 *) opcode);
if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */
@@ -803,61 +943,68 @@ void math_emu_ler(__u8 *opcode) {
current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
current->thread.fp_regs.fprs[opc&0x000f];
}
+ return 0;
}
/*
* Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_from_user fails ? */
- copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ mathemu_copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
+ return 0;
}
/*
* Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if get_user fails ? */
mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
- get_user(mem[0], dxb);
+ mathemu_get_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u64 *dxb;
dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if copy_to_user fails ? */
- copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
+ mathemu_copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
+ return 0;
}
/*
* Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
*/
-void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
+int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
__u32 opc = *((__u32 *) opcode);
__u32 *mem, *dxb;
dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
- /* FIXME: how to react if put_user fails ? */
+ /* FIXME: how to react if mathemu_put_user fails ? */
mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
- put_user(mem[0], dxb);
+ mathemu_put_user(mem[0], dxb);
+ return 0;
}
/*
* Emulate LFPC D(B)
*/
int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb,temp;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_get_user(temp, dxb);
+ if(temp!=0)
+ display_emulation_not_implemented("lfpc");
return 0;
}
@@ -865,7 +1012,10 @@ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
* Emulate STFPC D(B)
*/
int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
- /* FIXME: how to do that ?!? */
+ __u32 *dxb;
+ __u32 opc = *((__u32 *) opcode);
+ dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc);
+ mathemu_put_user(current->thread.fp_regs.fpc, dxb);
return 0;
}
@@ -874,6 +1024,7 @@ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
*/
int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
/* FIXME: how to do that ?!? */
+ display_emulation_not_implemented("srnm");
return 0;
}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 2fc6d08fa..f8238de1e 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -28,7 +28,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
@@ -67,7 +67,9 @@ int cpu_idle(void *unused)
if (softirq_active(smp_processor_id()) &
softirq_mask(smp_processor_id())) {
do_softirq();
- continue;
+ __sti();
+ if (!current->need_resched)
+ continue;
}
if (current->need_resched) {
schedule();
@@ -92,12 +94,13 @@ idle_wakeup:
0 returned you know you've got all the lines
*/
-int sprintf_regs(int line, char *buff, struct task_struct * task,
- struct thread_struct *thread, struct pt_regs * regs)
-{
+static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+{
int linelen=0;
int regno,chaincnt;
u32 backchain,prev_backchain,endchain;
+ u32 ksp = 0;
+ char *mode = "???";
enum
{
@@ -118,106 +121,125 @@ int sprintf_regs(int line, char *buff, struct task_struct * task,
sp_kern_backchain1
};
- if(task)
- thread = &task->thread;
- if(thread)
- regs = thread->regs;
- switch (line) {
- case sp_linefeed:
+ if (task)
+ ksp = task->thread.ksp;
+ if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
+ ksp = regs->gprs[15];
+
+ if (regs)
+ mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
+ "User" : "Kernel";
+
+ switch(line)
+ {
+ case sp_linefeed:
linelen=sprintf(buff,"\n");
break;
case sp_psw:
if(regs)
- linelen = sprintf(buff,"User PSW: %08lx %08lx\n",
- (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
+ linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode,
+ (unsigned long) regs->psw.mask,
+ (unsigned long) regs->psw.addr);
else
- linelen = sprintf(buff,"pt_regs=NULL some info unavailable\n");
+ linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
break;
case sp_ksp:
- if (task)
- linelen += sprintf(&buff[linelen],
- "task: %08x ", (addr_t)task);
- if (thread)
- linelen += sprintf(&buff[linelen],
- "thread: %08x ksp: %08x ",
- (addr_t)thread,(addr_t)thread->ksp);
- if (regs)
- linelen += sprintf(&buff[linelen],
- "pt_regs: %08x\n", (addr_t)regs);
+ linelen=sprintf(&buff[linelen],
+ "task: %08x ksp: %08x pt_regs: %08x\n",
+ (addr_t)task, (addr_t)ksp, (addr_t)regs);
break;
case sp_gprs:
- if (regs)
- linelen = sprintf(buff,"User GPRS:\n");
+ if(regs)
+ linelen=sprintf(buff, "%s GPRS:\n", mode);
break;
case sp_gprs1 ... sp_gprs4:
- if (regs) {
- regno = (line-sp_gprs1)*4;
- linelen = sprintf(buff,"%08x %08x %08x %08x\n",
- regs->gprs[regno],
- regs->gprs[regno+1],
- regs->gprs[regno+2],
- regs->gprs[regno+3]);
+ if(regs)
+ {
+ regno=(line-sp_gprs1)*4;
+ linelen=sprintf(buff,"%08x %08x %08x %08x\n",
+ regs->gprs[regno],
+ regs->gprs[regno+1],
+ regs->gprs[regno+2],
+ regs->gprs[regno+3]);
}
break;
case sp_acrs:
- if (regs)
- linelen = sprintf(buff,"User ACRS:\n");
+ if(regs)
+ linelen=sprintf(buff, "%s ACRS:\n", mode);
break;
case sp_acrs1 ... sp_acrs4:
- if (regs) {
- regno = (line-sp_acrs1)*4;
- linelen = sprintf(buff,"%08x %08x %08x %08x\n",
- regs->acrs[regno],
- regs->acrs[regno+1],
- regs->acrs[regno+2],
- regs->acrs[regno+3]);
+ if(regs)
+ {
+ regno=(line-sp_acrs1)*4;
+ linelen=sprintf(buff,"%08x %08x %08x %08x\n",
+ regs->acrs[regno],
+ regs->acrs[regno+1],
+ regs->acrs[regno+2],
+ regs->acrs[regno+3]);
}
break;
case sp_kern_backchain:
- if (thread && thread->ksp && regs)
- linelen = sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n");
+ if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
+ break;
+ if (ksp)
+ linelen=sprintf(buff, "Kernel BackChain CallChain\n");
break;
default:
- if(thread && thread->ksp && regs) {
- backchain = (thread->ksp & PSW_ADDR_MASK);
- endchain = ((backchain & (-8192)) + 8192);
- prev_backchain = backchain - 1;
- line -= sp_kern_backchain1;
- for (chaincnt = 0; ; chaincnt++) {
- if ((backchain == 0) ||
- (backchain >= endchain) ||
- (chaincnt >= 8) ||
- (prev_backchain >= backchain))
+ if (ksp)
+ {
+
+ backchain=ksp&PSW_ADDR_MASK;
+ endchain=((backchain&(-8192))+8192);
+ prev_backchain=backchain-1;
+ line-=sp_kern_backchain1;
+ for(chaincnt=0;;chaincnt++)
+ {
+ if((backchain==0)||(backchain>=endchain)
+ ||(chaincnt>=8)||(prev_backchain>=backchain))
break;
- if ((chaincnt >> 1) == line) {
- linelen += sprintf(&buff[linelen],"%s%08x %08x ",
- (chaincnt&1) ? "":" ",
- backchain,*(u32 *)(backchain+56));
- }
- if ((chaincnt >> 1) > line)
+ if(chaincnt==line)
+ {
+ linelen+=sprintf(&buff[linelen]," %08x [<%08lx>]\n",
+ backchain,
+ *(u32 *)(backchain+56)&PSW_ADDR_MASK);
break;
- prev_backchain = backchain;
- backchain = (*((u32 *)backchain)) & PSW_ADDR_MASK;
+ }
+ prev_backchain=backchain;
+ backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
}
- if (linelen)
- linelen += sprintf(&buff[linelen],"\n");
}
}
- return linelen;
+ return(linelen);
}
-void show_regs(struct task_struct *task, struct thread_struct *thread,
- struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
{
char buff[80];
int line;
+
+ printk("CPU: %d\n",smp_processor_id());
+ printk("Process %s (pid: %d, stackpage=%08X)\n",
+ current->comm, current->pid, 4096+(addr_t)current);
- for (line = 0; sprintf_regs(line,buff,task,thread,regs); line++)
+ for (line = 0; sprintf_regs(line, buff, current, regs); line++)
printk(buff);
}
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+ int line, len;
+
+ for (line = 0; ; line++)
+ {
+ len = sprintf_regs(line, buffer, task, task->thread.regs);
+ if (!len) break;
+ buffer += len;
+ }
+ return buffer;
+}
+
+
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
int clone_arg = flags | CLONE_VM;
@@ -327,7 +349,7 @@ asmlinkage int sys_clone(struct pt_regs regs)
lock_kernel();
clone_flags = regs.gprs[3];
- newsp = regs.gprs[2];
+ newsp = regs.orig_gpr2;
if (!newsp)
newsp = regs.gprs[15];
ret = do_fork(clone_flags, newsp, &regs, 0);
@@ -365,7 +387,19 @@ asmlinkage int sys_execve(struct pt_regs regs)
goto out;
error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
if (error == 0)
- current->flags &= ~PF_DTRACE;
+ {
+ current->ptrace &= ~PT_DTRACE;
+ current->thread.fp_regs.fpc=0;
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ __volatile__
+ ("sr 0,0\n\t"
+ "sfpc 0,0\n\t"
+ :
+ :
+ :"0");
+ }
+ }
putname(filename);
out:
return error;
@@ -412,21 +446,77 @@ extern void scheduling_functions_end_here(void);
unsigned long get_wchan(struct task_struct *p)
{
- unsigned long r14, r15;
+ unsigned long r14, r15, bc;
unsigned long stack_page;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long) p;
r15 = p->thread.ksp;
+ if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page)
+ return 0;
+ bc = (*(unsigned long *) r15) & 0x7fffffff;
do {
- r14 = *(unsigned long *) (r15+56);
+ if (bc < stack_page || bc >= 8188+stack_page)
+ return 0;
+ r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff;
if (r14 < first_sched || r14 >= last_sched)
return r14;
- r15 = *(unsigned long *) (r15+60);
+ bc = (*(unsigned long *) bc) & 0x7fffffff;
} while (count++ < 16);
return 0;
}
#undef last_sched
#undef first_sched
+/*
+ * This should be safe even if called from tq_scheduler
+ * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
+ *
+ */
+void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
+{
+ struct fs_struct *fs;
+ extern struct task_struct *child_reaper;
+ struct task_struct *this_process=current;
+
+ /*
+ * If we were started as result of loading a module, close all of the
+ * user space pages. We don't need them, and if we didn't close them
+ * they would be locked into memory.
+ */
+ exit_mm(current);
+
+ this_process->session = 1;
+ this_process->pgrp = 1;
+ if(name)
+ {
+ strncpy(current->comm,name,15);
+ current->comm[15]=0;
+ }
+ else
+ current->comm[0]=0;
+ /* set signal mask to what we want to respond */
+ siginitsetinv(&current->blocked,mask);
+ /* exit_signal isn't set up */
+ /* if we inherit from cpu idle */
+ this_process->exit_signal=SIGCHLD;
+ /* if priority=0 schedule can go into a tight loop */
+ this_process->policy= SCHED_OTHER;
+ /* nice goes priority=20-nice; */
+ this_process->nice=10;
+ if(use_init_fs)
+ {
+ exit_fs(this_process); /* current->fs->count--; */
+ fs = init_task.fs;
+ current->fs = fs;
+ atomic_inc(&fs->count);
+ exit_files(current);
+ }
+ write_lock_irq(&tasklist_lock);
+ /* We want init as our parent */
+ REMOVE_LINKS(this_process);
+ this_process->p_opptr=this_process->p_pptr=child_reaper;
+ SET_LINKS(this_process);
+ write_unlock_irq(&tasklist_lock);
+}
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2643f100a..29a81418a 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -66,10 +66,16 @@ void FixPerRegisters(struct task_struct *task)
regs->psw.mask |=PSW_PER_MASK;
else
regs->psw.mask &= ~PSW_PER_MASK;
- if(per_info->control_regs.bits.storage_alt_space_ctl)
- task->thread.user_seg|=USER_STD_MASK;
+ if (per_info->control_regs.bits.em_storage_alteration)
+ {
+ per_info->control_regs.bits.storage_alt_space_ctl=1;
+ //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK;
+ }
else
- task->thread.user_seg&=~USER_STD_MASK;
+ {
+ per_info->control_regs.bits.storage_alt_space_ctl=0;
+ //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK;
+ }
}
void set_single_step(struct task_struct *task)
@@ -209,10 +215,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if (request == PTRACE_TRACEME)
{
/* are we already being traced? */
- if (current->flags & PF_PTRACED)
+ if (current->ptrace & PT_PTRACED)
goto out;
/* set the ptrace bit in the process flags. */
- current->flags |= PF_PTRACED;
+ current->ptrace |= PT_PTRACED;
ret = 0;
goto out;
}
@@ -237,9 +243,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
(current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE))
goto out;
/* the same process cannot be attached many times */
- if (child->flags & PF_PTRACED)
+ if (child->ptrace & PT_PTRACED)
goto out;
- child->flags |= PF_PTRACED;
+ child->ptrace |= PT_PTRACED;
write_lock_irqsave(&tasklist_lock, flags);
if (child->p_pptr != current)
@@ -256,16 +262,20 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
}
ret = -ESRCH;
// printk("child=%lX child->flags=%lX",child,child->flags);
- if (!(child->flags & PF_PTRACED))
- goto out;
- if (child->state != TASK_STOPPED)
+ /* I added child!=current line so we can get the */
+ /* ieee_instruction_pointer from the user structure DJB */
+ if(child!=current)
{
- if (request != PTRACE_KILL)
+ if (!(child->ptrace & PT_PTRACED))
+ goto out;
+ if (child->state != TASK_STOPPED)
+ {
+ if (request != PTRACE_KILL)
+ goto out;
+ }
+ if (child->p_pptr != current)
goto out;
}
- if (child->p_pptr != current)
- goto out;
-
switch (request)
{
/* If I and D space are separate, these will need to be fixed. */
@@ -303,9 +313,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if ((unsigned long) data >= _NSIG)
break;
if (request == PTRACE_SYSCALL)
- child->flags |= PF_TRACESYS;
+ child->ptrace |= PT_TRACESYS;
else
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
/* make sure the single step bit is not set. */
clear_single_step(child);
@@ -332,7 +342,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
if ((unsigned long) data >= _NSIG)
break;
- child->flags &= ~PF_TRACESYS;
+ child->ptrace &= ~PT_TRACESYS;
child->exit_code = data;
set_single_step(child);
/* give it a chance to run. */
@@ -344,7 +354,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = -EIO;
if ((unsigned long) data >= _NSIG)
break;
- child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+ child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
child->exit_code = data;
write_lock_irqsave(&tasklist_lock, flags);
REMOVE_LINKS(child);
@@ -374,11 +384,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
asmlinkage void syscall_trace(void)
{
lock_kernel();
- if ((current->flags & (PF_PTRACED|PF_TRACESYS))
- != (PF_PTRACED|PF_TRACESYS))
+ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
+ != (PT_PTRACED|PT_TRACESYS))
goto out;
current->exit_code = SIGTRAP;
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
/*
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index a77940905..c30fe433c 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -1,4 +1,13 @@
+/*
+ * arch/s390/kernel/reipl.S
+ *
+ * S390 version
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
+ */
+
#include <asm/lowcore.h>
+
.globl do_reipl
do_reipl: basr %r13,0
.Lpg0: lpsw .Lnewpsw-.Lpg0(%r13)
@@ -7,7 +16,7 @@ do_reipl: basr %r13,0
ni .Lctlsave-.Lpg0(%r13),0xef
lctl %c0,%c0,.Lctlsave-.Lpg0(%r13)
lr %r1,%r2
- mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13)
+ mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
stsch .Lschib-.Lpg0(%r13)
oi .Lschib+5-.Lpg0(%r13),0x84
.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
@@ -15,9 +24,9 @@ do_reipl: basr %r13,0
ssch .Liplorb-.Lpg0(%r13)
jz .L001
bas %r14,.Ldisab-.Lpg0(%r13)
-.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
-.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0)
+.Lcont: c %r1,__LC_SUBCHANNEL_ID
jnz .Ltpi
clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
jnz .Ltpi
@@ -29,7 +38,7 @@ do_reipl: basr %r13,0
jz .L003
bas %r14,.Ldisab-.Lpg0(%r13)
.L003: spx .Lnull-.Lpg0(%r13)
- st %r1,__LC_SUBCHANNEL_ID(%r0)
+ st %r1,__LC_SUBCHANNEL_ID
lpsw 0
sigp 0,0,0(6)
.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
new file mode 100644
index 000000000..6a7be9496
--- /dev/null
+++ b/arch/s390/kernel/s390_ext.c
@@ -0,0 +1,77 @@
+/*
+ * arch/s390/kernel/s390_ext.c
+ *
+ * S390 version
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
+ * Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <asm/lowcore.h>
+#include <asm/s390_ext.h>
+
+/*
+ * Simple hash strategy: index = code & 0xff;
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
+ * iucv) this is always the first element.
+ */
+ext_int_info_t *ext_int_hash[256] = { 0, };
+ext_int_info_t ext_int_info_timer;
+ext_int_info_t ext_int_info_hwc;
+
+int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p;
+ int index;
+
+ index = code & 0xff;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code)
+ return -EBUSY;
+ p = p->next;
+ }
+ if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
+ p = &ext_int_info_timer;
+ else if (code == 0x2401) /* hwc_init is done too early too */
+ p = &ext_int_info_hwc;
+ else
+ p = (ext_int_info_t *)
+ kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
+ if (p == NULL)
+ return -ENOMEM;
+ p->code = code;
+ p->handler = handler;
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+
+int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
+ ext_int_info_t *p, *q;
+ int index;
+
+ index = code & 0xff;
+ q = NULL;
+ p = ext_int_hash[index];
+ while (p != NULL) {
+ if (p->code == code && p->handler == handler)
+ break;
+ q = p;
+ p = p->next;
+ }
+ if (p == NULL)
+ return -ENOENT;
+ if (q != NULL)
+ q->next = p->next;
+ else
+ ext_int_hash[index] = p->next;
+ if (code != 0x1004 && code != 0x2401)
+ kfree(p);
+ return 0;
+}
+
+
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 85ecb5ce0..b0a6d0225 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -5,14 +5,27 @@
*/
#include <linux/config.h>
#include <linux/module.h>
+#include <linux/string.h>
+#include <asm/ccwcache.h>
+#include <asm/debug.h>
#include <asm/irq.h>
-#include <asm/string.h>
+#include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
+#include <asm/ebcdic.h>
#include <asm/checksum.h>
+#include <asm/delay.h>
+#if CONFIG_CHANDEV
+#include <asm/chandev.h>
+#endif
+#if CONFIG_IP_MULTICAST
+#include <net/arp.h>
+#endif
/*
* I/O subsystem
*/
EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
EXPORT_SYMBOL(do_IO);
EXPORT_SYMBOL(resume_IO);
EXPORT_SYMBOL(ioinfo);
@@ -22,6 +35,35 @@ EXPORT_SYMBOL(get_irq_by_devno);
EXPORT_SYMBOL(get_devno_by_irq);
EXPORT_SYMBOL(get_irq_first);
EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
+
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
+
+/*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_int_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_int_exception);
+EXPORT_SYMBOL(debug_text_exception);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
/*
* memory management
@@ -29,6 +71,16 @@ EXPORT_SYMBOL(get_irq_next);
EXPORT_SYMBOL(_oi_bitmap);
EXPORT_SYMBOL(_ni_bitmap);
EXPORT_SYMBOL(_zb_findmap);
+EXPORT_SYMBOL(__copy_from_user_fixup);
+EXPORT_SYMBOL(__copy_to_user_fixup);
+
+/*
+ * semaphore ops
+ */
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
/*
* string functions
@@ -36,6 +88,7 @@ EXPORT_SYMBOL(_zb_findmap);
EXPORT_SYMBOL_NOVERS(memcmp);
EXPORT_SYMBOL_NOVERS(memset);
EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(strlen);
EXPORT_SYMBOL_NOVERS(strchr);
EXPORT_SYMBOL_NOVERS(strcmp);
EXPORT_SYMBOL_NOVERS(strncat);
@@ -46,19 +99,42 @@ EXPORT_SYMBOL_NOVERS(strrchr);
EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
/*
* misc.
*/
+EXPORT_SYMBOL(module_list);
+EXPORT_SYMBOL(__udelay);
#ifdef CONFIG_SMP
#include <asm/smplock.h>
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(lowcore_ptr);
EXPORT_SYMBOL(global_bh_lock);
EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
#endif
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(csum_fold);
-
+#if CONFIG_CHANDEV
+EXPORT_SYMBOL(chandev_register_and_probe);
+EXPORT_SYMBOL(chandev_request_irq);
+EXPORT_SYMBOL(chandev_unregister);
+EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_initnetdevice);
+#endif
+#if CONFIG_IP_MULTICAST
+/* Required for lcs gigabit ethernet multicast support */
+EXPORT_SYMBOL(arp_mc_map);
+#endif
+EXPORT_SYMBOL(s390_daemonize);
diff --git a/arch/s390/kernel/s390dyn.c b/arch/s390/kernel/s390dyn.c
deleted file mode 100644
index 0a5625830..000000000
--- a/arch/s390/kernel/s390dyn.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/s390/kernel/s390dyn.c
- * S/390 dynamic device attachment
- *
- * S390 version
- * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-
-int s390_device_register( devreg_t *drinfo )
-{
- return -EOPNOTSUPP;
-}
-
-
-int s390_device_deregister ( devreg_t *dreg )
-{
- return -EOPNOTSUPP;
-}
-
-int s390_request_irq_special( int irq,
- io_handler_func_t io_handler,
- not_oper_handler_func_t not_oper_handler,
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- return -EOPNOTSUPP;
-}
-
diff --git a/arch/s390/kernel/s390fpu.c b/arch/s390/kernel/s390fpu.c
index 42048abbc..c56c50d66 100644
--- a/arch/s390/kernel/s390fpu.c
+++ b/arch/s390/kernel/s390fpu.c
@@ -81,6 +81,11 @@ int restore_fp_regs1(s390_fp_regs *fpregs)
{
int has_ieee=MACHINE_HAS_IEEE;
+ /* If we don't mask with the FPC_VALID_MASK here
+ * we've got a very quick shutdown -h now command
+ * via a kernel specification exception.
+ */
+ fpregs->fpc&=FPC_VALID_MASK;
asm volatile ("LD 0,8(%0)\n\t"
"LD 2,24(%0)\n\t"
"LD 4,40(%0)\n\t"
diff --git a/arch/s390/kernel/s390io.c b/arch/s390/kernel/s390io.c
deleted file mode 100644
index b1db16707..000000000
--- a/arch/s390/kernel/s390io.c
+++ /dev/null
@@ -1,4605 +0,0 @@
-/*
- * arch/s390/kernel/s390io.c
- * S/390 common I/O routines
- *
- * S390 version
- * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/tasks.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/smp.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
-#include <asm/lowcore.h>
-
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#undef CONFIG_DEBUG_IO
-
-#define REIPL_DEVID_MAGIC 0x87654321
-
-struct irqaction init_IRQ_action;
-unsigned int highest_subchannel;
-ioinfo_t *ioinfo_head = NULL;
-ioinfo_t *ioinfo_tail = NULL;
-ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
- [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
-};
-
-static spinlock_t sync_isc; // synchronous irq processing lock
-static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc
-static psw_t io_new_psw; // save I/O new PSW, prot. by sync_isc
-static int cons_dev = -1; // identify console device
-static int init_IRQ_complete = 0;
-static schib_t init_schib;
-static __u64 irq_IPL_TOD;
-
-/*
- * Dummy controller type for unused interrupts
- */
-int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}
-int enable_none(unsigned int irq) { return(-ENODEV); }
-int disable_none(unsigned int irq) { return(-ENODEV); }
-
-struct hw_interrupt_type no_irq_type = {
- "none",
- do_none,
- enable_none,
- disable_none
-};
-
-static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static int s390_setup_irq(unsigned int irq, struct irqaction * new);
-static void s390_process_subchannels( void);
-static void s390_device_recognition( void);
-static int s390_validate_subchannel( int irq);
-static int s390_SenseID( int irq, senseid_t *sid);
-static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_process_IRQ( unsigned int irq );
-static int s390_DevicePathVerification( int irq );
-
-extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int enable_none(unsigned int irq);
-extern int disable_none(unsigned int irq);
-extern void tod_wait(unsigned long usecs);
-
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm );
-
-void s390_displayhex(char *str,void *ptr,s32 cnt);
-
-void s390_displayhex(char *str,void *ptr,s32 cnt)
-{
- s32 cnt1,cnt2,maxcnt2;
- u32 *currptr=(__u32 *)ptr;
-
- printk("\n%s\n",str);
-
- for(cnt1=0;cnt1<cnt;cnt1+=16)
- {
- printk("%08lX ",(unsigned long)currptr);
- maxcnt2=cnt-cnt1;
- if(maxcnt2>16)
- maxcnt2=16;
- for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
- printk("%08X ",*currptr++);
- printk("\n");
- }
-}
-
-int s390_request_irq( unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- int retval;
- struct irqaction *action;
-
- if (irq >= __MAX_SUBCHANNELS)
- return -EINVAL;
-
- if ( !handler || !dev_id )
- return -EINVAL;
-
- /*
- * during init_IRQ() processing we don't have memory
- * management yet, thus need to use a statically
- * allocated irqaction control block
- */
- if ( init_IRQ_complete )
- {
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- }
- else
- {
- action = &init_IRQ_action;
-
- } /* endif */
-
- if (!action)
- {
- return -ENOMEM;
-
- } /* endif */
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- retval = s390_setup_irq( irq, action);
-
- if ( !retval )
- {
- retval = s390_DevicePathVerification( irq );
- }
- else if ( retval && init_IRQ_complete )
- {
- kfree(action);
-
- } /* endif */
-
- return retval;
-}
-
-void s390_free_irq(unsigned int irq, void *dev_id)
-{
- unsigned int flags;
- int ret;
-
- unsigned int count = 0;
-
- if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return;
-
- } /* endif */
-
- s390irq_spin_lock_irqsave( irq, flags);
-
-#ifdef CONFIG_KERNEL_DEBUG
- if ( irq != cons_dev )
- {
- printk("Trying to free IRQ%d\n",irq);
-
- } /* endif */
-#endif
-
- /*
- * disable the device and reset all IRQ info if
- * the IRQ is actually owned by the handler ...
- */
- if ( ioinfo[irq]->irq_desc.action )
- {
- if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id )
- || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) )
- {
- /* start deregister */
- ioinfo[irq]->ui.flags.unready = 1;
-
- do
- {
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
-
- count++;
-
- if ( ret == -EBUSY )
- {
- int iret;
-
- /*
- * kill it !
- * ... we first try sync and eventually
- * try terminating the current I/O by
- * an async request, twice halt, then
- * clear.
- */
- if ( count < 3 )
- {
- iret = halt_IO( irq,
- 0xC8C1D3E3,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- halt_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 200000 ); /* 200 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
- }
- else
- {
- iret = clear_IO( irq,
- 0x40C3D3D9,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- clear_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 1000000 ); /* 1000 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
-
- } /* endif */
-
- if ( count == 3 )
- {
- /* give it a very last try ... */
- ioinfo[irq]->irq_desc.handler->disable(irq);
-
- if ( ioinfo[irq]->ui.flags.busy )
- {
- printk( KERN_CRIT"free_irq(%04X) "
- "- device %04X busy, retry "
- "count exceeded\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- break; /* sigh, let's give up ... */
-
- } /* endif */
-
- } /* endif */
-
- } while ( ret == -EBUSY );
-
- if ( init_IRQ_complete )
- kfree( ioinfo[irq]->irq_desc.action );
-
- ioinfo[irq]->irq_desc.action = NULL;
- ioinfo[irq]->ui.flags.ready = 0;
-
- ioinfo[irq]->irq_desc.handler->enable = &enable_none;
- ioinfo[irq]->irq_desc.handler->disable = &disable_none;
-
- ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
-
- s390irq_spin_unlock_irqrestore( irq, flags);
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, dev_id does not match !");
-
- } /* endif */
-
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, no action block ... !");
-
- } /* endif */
-
-}
-
-/*
- * Generic enable/disable code
- */
-int disable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- /*
- * At this point we may actually have a pending interrupt being active
- * on another CPU. So don't touch the IRQ_INPROGRESS bit..
- */
- ioinfo[irq]->irq_desc.status |= IRQ_DISABLED;
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- synchronize_irq();
-
- return( ret);
-}
-
-int enable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- ioinfo[irq]->irq_desc.status = 0;
- ret = ioinfo[irq]->irq_desc.handler->enable(irq);
-
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- return(ret);
-}
-
-/*
- * Enable IRQ by modifying the subchannel
- */
-static int enable_subchannel( unsigned int irq)
-{
- int ret;
- int ccode;
- int retry = 5;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- /*
- * If a previous disable request is pending we reset it. However, this
- * status implies that the device may (still) be not-operational.
- */
- if ( ioinfo[irq]->ui.flags.d_disable )
- {
- ioinfo[irq]->ui.flags.d_disable = 0;
- ret = 0;
- }
- else
- {
-
- ccode = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- ioinfo[irq]->schib.pmcw.ena = 1;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (ccode) {
- case 0:
- ret = 0;
- break;
-
- case 1:
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parameter for interface compatibility
- * only. Bottom-half handling cannot be
- * required as this must be an
- * unsolicited interrupt (!busy).
- */
-
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EIO; /* might be overwritten */
- /* ... on re-driving */
- /* ... the msch() */
- retry--;
- break;
-
- case 3:
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- break;
-
- default:
- printk( KERN_CRIT"enable_subchannel(%04X) "
- " : ccode 2 on msch() for device "
- "%04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
- ret = -ENODEV; // never reached
- }
-
- } while ( (ccode == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * Disable IRQ by modifying the subchannel
- */
-static int disable_subchannel( unsigned int irq)
-{
- int cc; /* condition code */
- int ret; /* function return value */
- int retry = 5;
-
- if ( irq > highest_subchannel )
- {
- ret = -ENODEV;
- }
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else if ( ioinfo[irq]->ui.flags.busy )
- {
- /*
- * the disable function must not be called while there are
- * requests pending for completion !
- */
- ret = -EBUSY;
- }
- else
- {
- /*
- * If device isn't operational we have to perform delayed
- * disabling when the next interrupt occurs - unless the
- * irq is re-requested prior to the interrupt to occur.
- */
- cc = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( cc == 3 )
- {
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0;
- }
- else // cc == 0
- {
- ioinfo[irq]->schib.pmcw.ena = 0;
-
- do
- {
- cc = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (cc) {
- case 0 :
- ret = 0; /* done */
- break;
-
- case 1 :
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parm for interface compatibility
- * only. Bottom-half handling cannot
- * be required as this must be an
- * unsolicited interrupt (!busy).
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- s390_process_IRQ( irq );
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EBUSY; /* might be overwritten */
- /* ... on re-driving the */
- /* ... msch() call */
- retry--;
- break;
-
- case 2 :
- /*
- * *** must not occur ! ***
- * *** ***
- * *** indicates our internal ***
- * *** interrupt accounting is out ***
- * *** of sync ===> panic() ***
- */
- printk( KERN_CRIT"disable_subchannel(%04X) "
- "- unexpected busy condition for "
- "device %04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- ret = -ENODEV; // never reached
- break;
-
- case 3 :
- /*
- * should hardly occur ?!
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0; /* if the device has gone we */
- /* ... don't need to disable */
- /* ... it anymore ! */
- break;
-
- default :
- ret = -ENODEV; // never reached ...
- break;
-
- } /* endswitch */
-
- } while ( (cc == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret);
-}
-
-
-
-int s390_setup_irq( unsigned int irq, struct irqaction * new)
-{
- unsigned long flags;
- int rc = 0;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- s390irq_spin_lock_irqsave( irq, flags);
-
- if ( ioinfo[irq]->irq_desc.action == NULL )
- {
- ioinfo[irq]->irq_desc.action = new;
- ioinfo[irq]->irq_desc.status = 0;
- ioinfo[irq]->irq_desc.handler->enable = &enable_subchannel;
- ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel;
- ioinfo[irq]->irq_desc.handler->handle = &handle_IRQ_event;
-
- ioinfo[irq]->ui.flags.ready = 1;
-
- ioinfo[irq]->irq_desc.handler->enable(irq);
- }
- else
- {
- /*
- * interrupt already owned, and shared interrupts
- * aren't supported on S/390.
- */
- rc = -EBUSY;
-
- } /* endif */
-
- s390irq_spin_unlock_irqrestore(irq,flags);
-
- return( rc);
-}
-
-void s390_init_IRQ( void )
-{
- unsigned long flags; /* PSW flags */
- long cr6 __attribute__ ((aligned (8)));
-
- // Hopefully bh_count's will get set when we copy the prefix lowcore
- // structure to other CPI's ( DJB )
- softirq_active(smp_processor_id()) = 0;
- softirq_mask(smp_processor_id()) = 0;
- local_bh_count(smp_processor_id()) = 0;
- local_irq_count(smp_processor_id()) = 0;
- syscall_count(smp_processor_id()) = 0;
-
- asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
-
- /*
- * As we don't know about the calling environment
- * we assure running disabled. Before leaving the
- * function we resestablish the old environment.
- *
- * Note : as we don't need a system wide lock, therefore
- * we shouldn't use cli(), but __cli() as this
- * affects the current CPU only.
- */
- __save_flags(flags);
- __cli();
-
- /*
- * disable all interrupts
- */
- cr6 = 0;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_process_subchannels();
-
- /*
- * enable default I/O-interrupt sublass 3
- */
- cr6 = 0x10000000;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_device_recognition();
-
- init_IRQ_complete = 1;
-
- s390_init_machine_check();
-
- __restore_flags(flags);
-
- return;
-}
-
-
-/*
- * dummy handler, used during init_IRQ() processing for compatibility only
- */
-void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
-{
- /* this is a dummy handler only ... */
-}
-
-
-int s390_start_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* logical channel prog addr */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags */
-{
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
- int ret = 0;
-
- /*
- * The flag usage is mutal exclusive ...
- */
- if ( (flag & DOIO_RETURN_CHAN_END)
- && (flag & DOIO_REPORT_ALL ) )
- {
- return( -EINVAL );
-
- } /* endif */
-
- memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) );
-
- /*
- * setup ORB
- */
- ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm;
- ioinfo[irq]->orb.fmt = 1;
-
- ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
- ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND);
- ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND )
- && (flag & DOIO_SUPPRESS_INTER) );
-
- if ( flag & DOIO_VALID_LPM )
- {
- ioinfo[irq]->orb.lpm = lpm;
- }
- else
- {
- ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
-
- } /* endif */
-
- ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
-
- /*
- * If sync processing was requested we lock the sync ISC, modify the
- * device to present interrupts for this ISC only and switch the
- * CPU to handle this ISC + the console ISC exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc, psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Start subchannel" and process condition code
- */
- ccode = ssch( irq, &(ioinfo[irq]->orb) );
-
- switch ( ccode ) {
- case 0:
-
- if ( !ioinfo[irq]->ui.flags.w4sense )
- {
- /*
- * init the device driver specific devstat irb area
- *
- * Note : don´t clear saved irb info in case of sense !
- */
- memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
- } /* endif */
-
- /*
- * initialize device status information
- */
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
-
- /*
- * Check for either early (FAST) notification requests
- * or if we are to return all interrupt info.
- * Default is to call IRQ handler at secondary status only
- */
- if ( flag & DOIO_RETURN_CHAN_END )
- {
- ioinfo[irq]->ui.flags.fast = 1;
- }
- else if ( flag & DOIO_REPORT_ALL )
- {
- ioinfo[irq]->ui.flags.repall = 1;
-
- } /* endif */
-
- ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- // __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- int io_sub = -1;
- struct _lowcore *lc = NULL;
- int count = 30000;
-
- /*
- * We shouldn't perform a TPI loop, waiting for an
- * interrupt to occur, but should load a WAIT PSW
- * instead. Otherwise we may keep the channel subsystem
- * busy, not able to present the interrupt. When our
- * sync. interrupt arrived we reset the I/O old PSW to
- * its original value.
- */
- memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "start_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&io_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
- if ( flag & DOIO_TIMEOUT )
- {
- tpi_info_t tpi_info;
-
- do
- {
- if ( tpi(&tpi_info) == 1 )
- {
- io_sub = tpi_info.irq;
- break;
- }
- else
- {
- count--;
- tod_wait(100); /* usecs */
-
- } /* endif */
-
- } while ( count );
- }
- else
- {
- asm volatile ("lpsw %0" : : "m" (io_sync_wait));
-
-io_wakeup:
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- } /* endif */
-
- if ( count )
- ready = s390_process_IRQ( io_sub );
-
- /*
- * surrender when retry count's exceeded ...
- */
-
- } while ( !( ( io_sub == irq )
- && ( ready == 1 ))
- && count );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- if ( !count )
- ret = -ETIMEDOUT;
-
- } /* endif */
-
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending status.
- * However, we must avoid calling the user action handler, as
- * it won't be prepared to handle a pending status during
- * do_IO() processing inline. This also implies that process_IRQ
- * must terminate synchronously - especially if device sensing
- * is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last path
- * has gone, except we have previously restricted the I/O to
- * a particular path. A condition code 1 (0 won't occur)
- * results in return code EIO as well as 3 with another path
- * than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - irb for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib) ,
- sizeof(schib_t));
-
-
- if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
- {
- sprintf( buffer, "s390_start_IO(%04X) - sense "
- "data for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
-
- }
- }
-#endif
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- ioinfo[irq]->ui.flags.oper = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-
- memcpy( ioinfo[irq]->irq_desc.action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after 'not oper' status\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib),
- sizeof(schib_t));
- }
-#endif
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- } /* endif */
-
- return( ret);
-}
-
-int do_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* channel program address */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags : see above */
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /* handler registered ? or free_irq() in process already ? */
- if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Note: We ignore the device operational status - if not operational,
- * the SSCH will lead to an -ENODEV condition ...
- */
- if ( !ioinfo[irq]->ui.flags.busy ) /* last I/O completed ? */
- {
- ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
- }
- else if ( ioinfo[irq]->ui.flags.fast )
- {
- /*
- * If primary status was received and ending status is missing,
- * the device driver won't be notified on the ending status
- * if early (fast) interrupt notification was requested.
- * Therefore we have to queue the next incoming request. If
- * halt_IO() is issued while there is a request queued, a HSCH
- * needs to be issued and the queued request must be deleted
- * but its intparm must be returned (see halt_IO() processing)
- */
- if ( ioinfo[irq]->ui.flags.w4final
- && !ioinfo[irq]->ui.flags.doio_q )
- {
- ioinfo[irq]->qflag = flag;
- ioinfo[irq]->qcpa = cpa;
- ioinfo[irq]->qintparm = user_intparm;
- ioinfo[irq]->qlpm = lpm;
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
-
- return( ret );
-
-}
-
-/*
- * resume suspended I/O operation
- */
-int resume_IO( int irq)
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * We allow for 'resume' requests only for active I/O operations
- */
- if ( ioinfo[irq]->ui.flags.busy )
- {
- int ccode;
-
- ccode = rsch( irq);
-
- switch (ccode) {
- case 0 :
- break;
-
- case 1 :
- s390_process_IRQ( irq );
- ret = -EBUSY;
- break;
-
- case 2 :
- ret = -EINVAL;
- break;
-
- case 3 :
- /*
- * useless to wait for request completion
- * as device is no longer operational !
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- }
- else
- {
- ret = -ENOTCONN;
-
- } /* endif */
-
- return( ret);
-}
-
-/*
- * Note: The "intparm" parameter is not used by the halt_IO() function
- * itself, as no ORB is built for the HSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the halt_IO() request.
- */
-int halt_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = hsch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-hio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Note: The "intparm" parameter is not used by the clear_IO() function
- * itself, as no ORB is built for the CSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the clear_IO() request.
- */
-int clear_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- * Concurrent I/O is possible in SMP environments only, but the
- * sync. I/O request can be gated to one CPU at a time only.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = csch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-cio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm )
-{
-#ifdef CONFIG_FAST_IRQ
- int ccode;
- tpi_info_t tpi_info;
- int new_irq;
-#endif
- int use_irq = irq;
-// __u32 use_intparm = s390_intparm;
-
- //
- // fix me !!!
- //
- // We need to schedule device recognition, the interrupt stays
- // pending. We need to dynamically allocate an ioinfo structure.
- //
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return; /* this keeps the device boxed ... */
- }
-
- /*
- * take fast exit if CPU is in sync. I/O state
- *
- * Note: we have to turn off the WAIT bit and re-disable
- * interrupts prior to return as this was the initial
- * entry condition to synchronous I/O.
- */
- if ( *(__u32 *)__LC_SYNC_IO_WORD )
- {
- regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
-
- return;
-
- } /* endif */
-
- s390irq_spin_lock(use_irq);
-
-#ifdef CONFIG_FAST_IRQ
- do {
-#endif /* CONFIG_FAST_IRQ */
-
- s390_process_IRQ( use_irq );
-
-#ifdef CONFIG_FAST_IRQ
-
- /*
- * more interrupts pending ?
- */
- ccode = tpi( &tpi_info );
-
- if ( ! ccode )
- break; // no, leave ...
-
- new_irq = tpi_info.irq;
-// use_intparm = tpi_info.intparm;
-
- /*
- * if the interrupt is for a different irq we
- * release the current irq lock and obtain
- * a new one ...
- */
- if ( new_irq != use_irq )
- {
- s390irq_spin_unlock(use_irq);
- use_irq = new_irq;
- s390irq_spin_lock(use_irq);
-
- } /* endif */
-
- } while ( 1 );
-
-#endif /* CONFIG_FAST_IRQ */
-
- s390irq_spin_unlock(use_irq);
-
- return;
-}
-
-/*
- * s390_process_IRQ() handles status pending situations and interrupts
- *
- * Called by : do_IRQ() - for "real" interrupts
- * s390_start_IO, halt_IO()
- * - status pending cond. after SSCH, or HSCH
- * disable_subchannel() - status pending conditions (after MSCH)
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-int s390_process_IRQ( unsigned int irq )
-{
- int ccode; /* condition code from tsch() operation */
- int irb_cc; /* condition code from irb */
- int sdevstat; /* effective struct devstat size to copy */
- unsigned int fctl; /* function control */
- unsigned int stctl; /* status control */
- unsigned int actl; /* activity control */
- struct irqaction *action;
- struct pt_regs regs; /* for interface compatibility only */
-
- int issense = 0;
- int ending_status = 0;
- int allow4handler = 1;
- int chnchk = 0;
-#if 0
- int cpu = smp_processor_id();
-
- kstat.irqs[cpu][irq]++;
-#endif
- action = ioinfo[irq]->irq_desc.action;
-
- /*
- * It might be possible that a device was not-oper. at the time
- * of free_irq() processing. This means the handler is no longer
- * available when the device possibly becomes ready again. In
- * this case we perform delayed disable_subchannel() processing.
- */
- if ( action == NULL )
- {
- if ( !ioinfo[irq]->ui.flags.d_disable )
- {
- printk( KERN_CRIT"s390_process_IRQ(%04X) "
- "- no interrupt handler registered"
- "for device %04X !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- } /* endif */
-
- /*
- * retrieve the i/o interrupt information (irb),
- * update the device specific status information
- * and possibly call the interrupt handler.
- *
- * Note 1: At this time we don't process the resulting
- * condition code (ccode) from tsch(), although
- * we probably should.
- *
- * Note 2: Here we will have to check for channel
- * check conditions and call a channel check
- * handler.
- *
- * Note 3: If a start function was issued, the interruption
- * parameter relates to it. If a halt function was
- * issued for an idle device, the intparm must not
- * be taken from lowcore, but from the devstat area.
- */
- ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
-
- //
- // We must only accumulate the status if initiated by do_IO() or halt_IO()
- //
- if ( ioinfo[irq]->ui.flags.busy )
- {
- ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
- }
- else
- {
- ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-
- ioinfo[irq]->devstat.flag = 0; // reset status flags
-
- } /* endif */
-
- ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
-
- if ( ioinfo[irq]->ui.flags.busy)
- {
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm;
-
- } /* endif */
-
- /*
- * reset device-busy bit if no longer set in irb
- */
- if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY )
- && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
- {
- ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;
-
- } /* endif */
-
- /*
- * Save residual count and CCW information in case primary and
- * secondary status are presented with different interrupts.
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
- {
- ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "residual count from irb after tsch() %d\n",
- irq, ioinfo[irq]->devstat.rescnt );
-#endif
- } /* endif */
-
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )
- {
- ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
-
- } /* endif */
-
- irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;
-
- //
- // check for any kind of channel or interface control check but don't
- // issue the message for the console device
- //
- if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat
- & ( SCHN_STAT_CHN_DATA_CHK
- | SCHN_STAT_CHN_CTRL_CHK
- | SCHN_STAT_INTF_CTRL_CHK ) )
- && (irq != cons_dev ) )
- {
- printk( "Channel-Check or Interface-Control-Check "
- "received\n"
- " ... device %04X on subchannel %04X, dev_stat "
- ": %02X sch_stat : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- chnchk = 1;
-
- } /* endif */
-
- issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;
-
- if ( issense )
- {
- ioinfo[irq]->devstat.scnt =
- ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;
- ioinfo[irq]->devstat.flag |=
- DEVSTAT_FLAG_SENSE_AVAIL;
-
- sdevstat = sizeof( devstat_t);
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "concurrent sense bytes avail %d\n",
- irq, ioinfo[irq]->devstat.scnt );
-#endif
- }
- else
- {
- /* don't copy the sense data area ! */
- sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
-
- } /* endif */
-
- switch ( irb_cc ) {
- case 1: /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- case 0: /* normal i/o interruption */
-
- fctl = ioinfo[irq]->devstat.ii.irb.scsw.fctl;
- stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl;
- actl = ioinfo[irq]->devstat.ii.irb.scsw.actl;
-
- if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088))
- {
- char buffer[80];
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X after channel check\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
- } /* endif */
-
- ioinfo[irq]->stctl |= stctl;
-
- ending_status = ( stctl & SCSW_STCTL_SEC_STATUS )
- || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) )
- || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
-
- /*
- * Check for unsolicited interrupts - for debug purposes only
- *
- * We only consider an interrupt as unsolicited, if the device was not
- * actively in use (busy) and an interrupt other than an ALERT status
- * was received.
- *
- * Note: We must not issue a message to the console, if the
- * unsolicited interrupt applies to the console device
- * itself !
- */
-#if CONFIG_DEBUG_IO
- if ( ( irq != cons_dev )
- && !( stctl & SCSW_STCTL_ALERT_STATUS )
- && ( ioinfo[irq]->ui.flags.busy == 0 ) )
- {
- char buffer[80];
-
- printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
- " ... device status : %02X subchannel status : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X, ending_status %d\n",
- irq,
- ioinfo[irq]->devstat.devno,
- ending_status);
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- } /* endif */
-
- /*
- * take fast exit if no handler is available
- */
- if ( !action )
- return( ending_status );
-
-#endif
- /*
- * Check whether we must issue a SENSE CCW ourselves if there is no
- * concurrent sense facility installed for the subchannel.
- *
- * Note: We should check for ioinfo[irq]->ui.flags.consns but VM
- * violates the ESA/390 architecture and doesn't present an
- * operand exception for virtual devices without concurrent
- * sense facility available/supported when enabling the
- * concurrent sense facility.
- */
- if ( ( ( ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
- && ( !issense ) )
- || ( ioinfo[irq]->ui.flags.delsense && ending_status ) )
- {
- int ret_io;
- ccw1_t *s_ccw = &ioinfo[irq]->senseccw;
- unsigned long s_flag = 0;
-
- if ( ending_status )
- {
- /*
- * We copy the current status information into the device driver
- * status area. Then we can use the local devstat area for device
- * sensing. When finally calling the IRQ handler we must not overlay
- * the original device status but copy the sense data only.
- */
- memcpy( action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
-
- s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
- s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data);
- s_ccw->count = SENSE_MAX_COUNT;
- s_ccw->flags = CCW_FLAG_SLI;
-
- /*
- * If free_irq() or a sync do_IO/s390_start_IO() is in
- * process we have to sense synchronously
- */
- if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio )
- {
- s_flag = DOIO_WAIT_FOR_INTERRUPT;
-
- } /* endif */
-
- /*
- * Reset status info
- *
- * It does not matter whether this is a sync. or async.
- * SENSE request, but we have to assure we don't call
- * the irq handler now, but keep the irq in busy state.
- * In sync. mode s390_process_IRQ() is called recursively,
- * while in async. mode we re-enter do_IRQ() with the
- * next interrupt.
- *
- * Note : this may be a delayed sense request !
- */
- allow4handler = 0;
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
- ioinfo[irq]->ui.flags.delsense = 0;
-
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.rescnt = SENSE_MAX_COUNT;
-
- ioinfo[irq]->ui.flags.w4sense = 1;
-
- ret_io = s390_start_IO( irq,
- s_ccw,
- 0xE2C5D5E2, // = SENSe
- 0, // n/a
- s_flag);
- }
- else
- {
- /*
- * we received an Unit Check but we have no final
- * status yet, therefore we must delay the SENSE
- * processing. However, we must not report this
- * intermediate status to the device interrupt
- * handler.
- */
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
-
- ioinfo[irq]->ui.flags.delsense = 1;
- allow4handler = 0;
-
- } /* endif */
-
- } /* endif */
-
- /*
- * we allow for the device action handler if .
- * - we received ending status
- * - the action handler requested to see all interrupts
- * - we received a PCI
- * - fast notification was requested (primary status)
- * - unsollicited interrupts
- *
- */
- if ( allow4handler )
- {
- allow4handler = ending_status
- || ( ioinfo[irq]->ui.flags.repall )
- || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI )
- || ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
- || ( ioinfo[irq]->ui.flags.oper == 0 );
-
- } /* endif */
-
- /*
- * We used to copy the device status information right before
- * calling the device action handler. However, in status
- * pending situations during do_IO() or halt_IO(), as well as
- * enable_subchannel/disable_subchannel processing we must
- * synchronously return the status information and must not
- * call the device action handler.
- *
- */
- if ( allow4handler )
- {
- /*
- * if we were waiting for sense data we copy the sense
- * bytes only as the original status information was
- * saved prior to sense already.
- */
- if ( ioinfo[irq]->ui.flags.w4sense )
- {
- int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "BASIC SENSE bytes avail %d\n",
- irq, sense_count );
-#endif
- ioinfo[irq]->ui.flags.w4sense = 0;
- ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
- ((devstat_t *)(action->dev_id))->scnt = sense_count;
-
- if ( sense_count >= 0 )
- {
- memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data,
- &(ioinfo[irq]->devstat.ii.sense.data),
- sense_count);
- }
- else
- {
-#if 1
- panic( "s390_process_IRQ(%04x) encountered "
- "negative sense count\n",
- irq);
-#else
- printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
- "negative sense count\n",
- irq);
-#endif
- } /* endif */
- }
- else
- {
- memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat );
-
- } /* endif */
-
- } /* endif */
-
- /*
- * for status pending situations other than deferred interrupt
- * conditions detected by s390_process_IRQ() itself we must not
- * call the handler. This will synchronously be reported back
- * to the caller instead, e.g. when detected during do_IO().
- */
- if ( ioinfo[irq]->ui.flags.s_pend || ioinfo[irq]->ui.flags.unready )
- allow4handler = 0;
-
- /*
- * Call device action handler if applicable
- */
- if ( allow4handler )
- {
-
- /*
- * We only reset the busy condition when we are sure that no further
- * interrupt is pending for the current I/O request (ending_status).
- */
- if ( ending_status || !ioinfo[irq]->ui.flags.oper )
- {
- ioinfo[irq]->ui.flags.oper = 1; /* dev IS oper */
-
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.haltio = 0;
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
- ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS;
-
- action->handler( irq, action->dev_id, &regs);
-
- //
- // reset intparm after final status or we will badly present unsolicited
- // interrupts with a intparm value possibly no longer valid.
- //
- ioinfo[irq]->devstat.intparm = 0;
-
- //
- // Was there anything queued ? Start the pending channel program
- // if there is one.
- //
- if ( ioinfo[irq]->ui.flags.doio_q )
- {
- int ret;
-
- ret = s390_start_IO( irq,
- ioinfo[irq]->qcpa,
- ioinfo[irq]->qintparm,
- ioinfo[irq]->qlpm,
- ioinfo[irq]->qflag);
-
- ioinfo[irq]->ui.flags.doio_q = 0;
-
- /*
- * If s390_start_IO() failed call the device's interrupt
- * handler, the IRQ related devstat area was setup by
- * s390_start_IO() accordingly already (status pending
- * condition).
- */
- if ( ret )
- {
- action->handler( irq, action->dev_id, &regs);
-
- } /* endif */
-
- } /* endif */
-
- }
- else
- {
- ioinfo[irq]->ui.flags.w4final = 1;
- action->handler( irq, action->dev_id, &regs);
-
- } /* endif */
-
- } /* endif */
-
- break;
-
- case 3: /* device not operational */
-
- ioinfo[irq]->ui.flags.oper = 0;
-
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.haltio = 0;
-
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * When we find a device "not oper" we save the status
- * information into the device status area and call the
- * device specific interrupt handler.
- *
- * Note: currently we don't have any way to reenable
- * the device unless an unsolicited interrupt
- * is presented. We don't check for spurious
- * interrupts on "not oper" conditions.
- */
-
- if ( ( ioinfo[irq]->ui.flags.fast )
- && ( ioinfo[irq]->ui.flags.w4final ) )
- {
- /*
- * If a new request was queued already, we have
- * to simulate the "not oper" status for the
- * queued request by switching the "intparm" value
- * and notify the interrupt handler.
- */
- if ( ioinfo[irq]->ui.flags.doio_q )
- {
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
-
- } /* endif */
-
- } /* endif */
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat );
-
- ioinfo[irq]->devstat.intparm = 0;
-
- if ( !ioinfo[irq]->ui.flags.s_pend )
- action->handler( irq, action->dev_id, &regs);
-
- ending_status = 1;
-
- break;
-
- } /* endswitch */
-
- return( ending_status );
-}
-
-/*
- * Set the special i/o-interruption sublass 7 for the
- * device specified by parameter irq. There can only
- * be a single device been operated on this special
- * isc. This function is aimed being able to check
- * on special device interrupts in disabled state,
- * without having to delay I/O processing (by queueing)
- * for non-console devices.
- *
- * Setting of this isc is done by set_cons_dev(), while
- * reset_cons_dev() resets this isc and re-enables the
- * default isc3 for this device. wait_cons_dev() allows
- * to actively wait on an interrupt for this device in
- * disabed state. When the interrupt condition is
- * encountered, wait_cons_dev(9 calls do_IRQ() to have
- * the console device driver processing the interrupt.
- */
-int set_cons_dev( int irq )
-{
- int ccode;
- unsigned long cr6 __attribute__ ((aligned (8)));
- int rc = 0;
-
- if ( cons_dev != -1 )
- {
- rc = -EBUSY;
- }
- else if ( (irq > highest_subchannel) || (irq < 0) )
- {
- rc = -ENODEV;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- /*
- * modify the indicated console device to operate
- * on special console interrupt sublass 7
- */
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- }
- else
- {
- ioinfo[irq]->schib.pmcw.isc = 7;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
- cons_dev = irq;
-
- /*
- * enable console I/O-interrupt sublass 7
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 |= 0x01000000;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- return( rc);
-}
-
-int reset_cons_dev( int irq)
-{
- int rc = 0;
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- if ( cons_dev != -1 )
- {
- rc = -EBUSY;
- }
- else if ( (irq > highest_subchannel) || (irq < 0) )
- {
- rc = -ENODEV;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- /*
- * reset the indicated console device to operate
- * on default console interrupt sublass 3
- */
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- }
- else
- {
-
- ioinfo[irq]->schib.pmcw.isc = 3;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
- cons_dev = -1;
-
- /*
- * disable special console I/O-interrupt sublass 7
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 &= 0xFEFFFFFF;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- return( rc);
-}
-
-int wait_cons_dev( int irq )
-{
- int rc = 0;
- long save_cr6;
-
- if ( irq == cons_dev )
- {
-
- /*
- * before entering the spinlock we may already have
- * processed the interrupt on a different CPU ...
- */
- if ( ioinfo[irq]->ui.flags.busy == 1 )
- {
- long cr6 __attribute__ ((aligned (8)));
-
- /*
- * disable all, but isc 7 (console device)
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- save_cr6 = cr6;
- cr6 &= 0x01FFFFFF;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- do {
- tpi_info_t tpi_info;
- if (tpi(&tpi_info) == 1) {
- s390_process_IRQ( tpi_info.irq );
- } else {
- s390irq_spin_unlock(irq);
- tod_wait(100);
- s390irq_spin_lock(irq);
- }
- eieio();
- } while (ioinfo[irq]->ui.flags.busy == 1);
-
- /*
- * restore previous isc value
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 = save_cr6;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- }
- else
- {
- rc = EINVAL;
-
- } /* endif */
-
-
- return(rc);
-}
-
-
-int enable_cpu_sync_isc( int irq )
-{
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- int count = 0;
- int rc = 0;
-
- if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if ( !ccode )
- {
- ioinfo[irq]->schib.pmcw.isc = 5;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode == 0 )
- {
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 |= 0x04000000; // enable sync isc 5
- cr6 &= 0xEFFFFFFF; // disable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
- }
- else if (ccode == 3)
- {
- rc = -ENODEV; // device not-oper - very unlikely
-
- }
- else if (ccode == 2)
- {
- rc = -EBUSY; // device busy - should not happen
-
- }
- else if (ccode == 1)
- {
- //
- // process pending status
- //
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- count++;
-
- } /* endif */
-
- } while ( ccode == 1 && count < 3 );
-
- if ( count == 3)
- {
- rc = -EIO;
-
- } /* endif */
- }
- else
- {
- rc = -ENODEV; // device is not-operational
-
- } /* endif */
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-int disable_cpu_sync_isc( int irq)
-{
- int rc = 0;
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- ioinfo[irq]->schib.pmcw.isc = 3;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
-
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 &= 0xFBFFFFFF; // disable sync isc 5
- cr6 |= 0x10000000; // enable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-//
-// Input :
-// devno - device number
-// ps - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16 devno,
- senseid_t *ps )
-{
- diag210_t diag_data;
- int ccode;
-
- int error = 0;
-
- diag_data.vrdcdvno = devno;
- diag_data.vrdclen = sizeof( diag210_t);
- ccode = diag210( (diag210_t *)virt_to_phys( &diag_data ) );
- ps->reserved = 0xff;
-
- switch (diag_data.vrdcvcla) {
- case 0x80:
-
- switch (diag_data.vrdcvtyp) {
- case 00:
-
- ps->cu_type = 0x3215;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x40:
-
- switch (diag_data.vrdcvtyp) {
- case 0xC0:
-
- ps->cu_type = 0x5080;
-
- break;
-
- case 0x80:
-
- ps->cu_type = 0x2250;
-
- break;
-
- case 0x04:
-
- ps->cu_type = 0x3277;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3278;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x20:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3505;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x2501;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x10:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3525;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x4F:
- case 0x4E:
- case 0x48:
-
- ps->cu_type = 0x3820;
-
- break;
-
- case 0x4D:
- case 0x49:
- case 0x45:
-
- ps->cu_type = 0x3800;
-
- break;
-
- case 0x4B:
-
- ps->cu_type = 0x4248;
-
- break;
-
- case 0x4A:
-
- ps->cu_type = 0x4245;
-
- break;
-
- case 0x47:
-
- ps->cu_type = 0x3262;
-
- break;
-
- case 0x43:
-
- ps->cu_type = 0x3203;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3211;
-
- break;
-
- case 0x41:
-
- ps->cu_type = 0x1403;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x08:
-
- switch (diag_data.vrdcvtyp) {
- case 0x82:
-
- ps->cu_type = 0x3422;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x3490;
-
- break;
-
- case 0x10:
-
- ps->cu_type = 0x3420;
-
- break;
-
- case 0x02:
-
- ps->cu_type = 0x3430;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3480;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3424;
-
- break;
-
- case 0x44:
-
- ps->cu_type = 0x9348;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- if ( error )
- {printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, "
- "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
- devno,
- ccode,
- diag_data.vrdcvcla,
- diag_data.vrdcvtyp,
- diag_data.vrdcrccl,
- diag_data.vrdccrty,
- diag_data.vrdccrmd );
-
- } /* endif */
-
-}
-
-/*
- * This routine returns the characteristics for the device
- * specified. Some old devices might not provide the necessary
- * command code information during SenseID processing. In this
- * case the function returns -EINVAL. Otherwise the function
- * allocates a decice specific data buffer and provides the
- * device characteristics together with the buffer size. Its
- * the callers responability to release the kernel memory if
- * not longer needed. In case of persistent I/O problems -EBUSY
- * is returned.
- *
- * The function may be called enabled or disabled. However, the
- * caller must have locked the irq it is requesting data for.
- *
- * Note : It would have been nice to collect this information
- * during init_IRQ() processing but this is not possible
- *
- * a) without statically pre-allocation fixed size buffers
- * as virtual memory management isn't available yet.
- *
- * b) without unnecessarily increase system startup by
- * evaluating devices eventually not used at all.
- */
-int read_dev_chars( int irq, void **buffer, int length )
-{
- unsigned int flags;
- ccw1_t *rdc_ccw;
- devstat_t devstat;
- char *rdc_buf;
- int devflag;
-
- int ret = 0;
- int emulated = 0;
- int retry = 5;
-
- if ( !buffer || !length )
- {
- return( -EINVAL );
-
- } /* endif */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Before playing around with irq locks we should assure
- * running disabled on (just) our CPU. Sync. I/O requests
- * also require to run disabled.
- *
- * Note : as no global lock is required, we must not use
- * cli(), but __cli() instead.
- */
- __save_flags(flags);
- __cli();
-
- rdc_ccw = &ioinfo[irq]->senseccw;
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RDC", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- if ( ! *buffer )
- {
- rdc_buf = kmalloc( length, GFP_KERNEL);
- }
- else
- {
- rdc_buf = *buffer;
-
- } /* endif */
-
- if ( !rdc_buf )
- {
- ret = -ENOMEM;
- }
- else
- {
- do
- {
- rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf );
- rdc_ccw->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rdc_ccw,
- 0x00524443, // RDC
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
- retry--;
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- } /* endif */
-
- if ( !retry )
- {
- ret = -EBUSY;
-
- } /* endif */
-
- __restore_flags(flags);
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *buffer = rdc_buf;
-
- } /* endif */
-
- if ( emulated )
- {
- free_irq( irq, &devstat);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Read Configuration data
- */
-int read_conf_data( int irq, void **buffer, int *length )
-{
- int found = 0;
- int ciw_cnt = 0;
- unsigned int flags;
-
- int ret = 0;
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * scan for RCD command in extended SenseID data
- */
- for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
- {
- if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
- {
- found = 1;
- break;
- } /* endif */
-
- } /* endfor */
-
- if ( found )
- {
- ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
- devstat_t devstat;
- char *rcd_buf;
- int devflag;
-
- int emulated = 0;
- int retry = 5;
-
- __save_flags(flags);
- __cli();
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RCD", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
- GFP_KERNEL);
-
- do
- {
- rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
- rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf );
- rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- rcd_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rcd_ccw,
- 0x00524344, // == RCD
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
-
- retry--;
-
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- if ( !retry )
- ret = -EBUSY;
-
- __restore_flags(flags);
-
- } /* endif */
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- *buffer = rcd_buf;
-
- } /* endif */
-
- if ( emulated )
- free_irq( irq, &devstat);
- }
- else
- {
- ret = -EINVAL;
-
- } /* endif */
-
- return( ret );
-
-}
-
-int get_dev_info( int irq, dev_info_t * pdi)
-{
- return( get_dev_info_by_irq( irq, pdi));
-}
-
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
-{
- int ret_val;
-
- while ( TRUE )
- {
- if ( pi->ui.flags.oper )
- {
- ret_val = pi->irq;
- break;
- }
- else
- {
- pi = pi->next;
-
- //
- // leave at end of list unconditionally
- //
- if ( pi == NULL )
- {
- ret_val = -ENODEV;
- break;
- }
-
- } /* endif */
-
- } /* endwhile */
-
- return ret_val;
-}
-
-
-int get_irq_first( void )
-{
- int ret_irq;
-
- if ( ioinfo_head )
- {
- if ( ioinfo_head->ui.flags.oper )
- {
- ret_irq = ioinfo_head->irq;
- }
- else if ( ioinfo_head->next )
- {
- ret_irq = get_next_available_irq( ioinfo_head->next );
-
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_irq_next( int irq )
-{
- int ret_irq;
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- if ( ioinfo[irq]->next )
- {
- if ( ioinfo[irq]->next->ui.flags.oper )
- {
- ret_irq = ioinfo[irq]->next->irq;
- }
- else
- {
- ret_irq = get_next_available_irq( ioinfo[irq]->next );
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -EINVAL;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_dev_info_by_irq( int irq, dev_info_t *pdi)
-{
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- pdi->devno = ioinfo[irq]->schib.pmcw.dev;
- pdi->irq = irq;
-
- if ( ioinfo[irq]->ui.flags.oper )
- {
- pdi->status = 0;
- memcpy( &(pdi->sid_data),
- &ioinfo[irq]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- memcpy( &(pdi->sid_data),
- '\0',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- return 0;
-
- } /* endif */
-
-}
-
-
-int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi)
-{
- int i;
- int rc = -ENODEV;
-
- if ( devno > 0x0000ffff )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else
- {
-
- for ( i=0; i <= highest_subchannel; i++ )
- {
-
- if ( ioinfo[i] != INVALID_STORAGE_AREA
- && ioinfo[i]->schib.pmcw.dev == devno )
- {
- if ( ioinfo[i]->ui.flags.oper )
- {
- pdi->status = 0;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data),
- &ioinfo[i]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[i]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- rc = 0; /* found */
- break;
-
- } /* endif */
-
- } /* endfor */
-
- return( rc);
-
- } /* endif */
-
-}
-
-int get_irq_by_devno( __u16 devno )
-{
- int i;
- int rc = -1;
-
- if ( devno <= 0x0000ffff )
- {
- for ( i=0; i <= highest_subchannel; i++ )
- {
- if ( (ioinfo[i] != INVALID_STORAGE_AREA )
- && (ioinfo[i]->schib.pmcw.dev == devno)
- && (ioinfo[i]->schib.pmcw.dnv == 1 ) )
- {
- rc = i;
- break;
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return( rc);
-}
-
-unsigned int get_devno_by_irq( int irq )
-{
-
- if ( ( irq > highest_subchannel )
- || ( irq < 0 )
- || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
- {
- return -1;
-
- } /* endif */
-
- /*
- * we don't need to check for the device be operational
- * as the initial STSCH will always present the device
- * number defined by the IOCDS regardless of the device
- * existing or not. However, there could be subchannels
- * defined who's device number isn't valid ...
- */
- if ( ioinfo[irq]->schib.pmcw.dnv )
- return( ioinfo[irq]->schib.pmcw.dev );
- else
- return -1;
-}
-
-/*
- * s390_device_recognition
- *
- * Used for system wide device recognition. Issues the device
- * independant SenseID command to obtain info the device type.
- *
- */
-void s390_device_recognition( void)
-{
-
- int irq = 0; /* let's start with subchannel 0 ... */
-
- do
- {
- /*
- * We issue the SenseID command on I/O subchannels we think are
- * operational only.
- */
- if ( ( ioinfo[irq] != INVALID_STORAGE_AREA )
- && ( ioinfo[irq]->schib.pmcw.st == 0 )
- && ( ioinfo[irq]->ui.flags.oper == 1 ) )
- {
- s390_SenseID( irq, &ioinfo[irq]->senseid );
-
- } /* endif */
-
- irq ++;
-
- } while ( irq <= highest_subchannel );
-
-}
-
-
-/*
- * s390_search_devices
- *
- * Determines all subchannels available to the system.
- *
- */
-void s390_process_subchannels( void)
-{
- int isValid;
- int irq = 0; /* Evaluate all subchannels starting with 0 ... */
-
- do
- {
- isValid = s390_validate_subchannel( irq);
-
- irq++;
-
- } while ( isValid && irq < __MAX_SUBCHANNELS );
-
- highest_subchannel = --irq;
-
- printk( "\nHighest subchannel number detected: %u\n",
- highest_subchannel);
-}
-
-/*
- * s390_validate_subchannel()
- *
- * Process the subchannel for the requested irq. Returns 1 for valid
- * subchannels, otherwise 0.
- */
-int s390_validate_subchannel( int irq )
-{
-
- int retry; /* retry count for status pending conditions */
- int ccode; /* condition code for stsch() only */
- int ccode2; /* condition code for other I/O routines */
- schib_t *p_schib;
-
- /*
- * The first subchannel that is not-operational (ccode==3)
- * indicates that there aren't any more devices available.
- */
- if ( ( init_IRQ_complete )
- && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
- {
- p_schib = &ioinfo[irq]->schib;
- }
- else
- {
- p_schib = &init_schib;
-
- } /* endif */
-
- ccode = stsch( irq, p_schib);
-
- if ( ccode == 0)
- {
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if ( p_schib->pmcw.st )
- {
- printk( "Subchannel %04X reports "
- "non-I/O subchannel type %04X\n",
- irq,
- p_schib->pmcw.st);
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- if ( p_schib->pmcw.dnv )
- {
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
-
- if ( !init_IRQ_complete )
- {
- ioinfo[irq] =
- (ioinfo_t *)alloc_bootmem( sizeof(ioinfo_t));
- }
- else
- {
- ioinfo[irq] =
- (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
- GFP_KERNEL );
-
- } /* endif */
-
- memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
- memcpy( &ioinfo[irq]->schib,
- &init_schib,
- sizeof( schib_t));
- ioinfo[irq]->irq_desc.status = IRQ_DISABLED;
- ioinfo[irq]->irq_desc.handler = &no_irq_type;
-
- /*
- * We have to insert the new ioinfo element
- * into the linked list, either at its head,
- * its tail or insert it.
- */
- if ( ioinfo_head == NULL ) /* first element */
- {
- ioinfo_head = ioinfo[irq];
- ioinfo_tail = ioinfo[irq];
- }
- else if ( irq < ioinfo_head->irq ) /* new head */
- {
- ioinfo[irq]->next = ioinfo_head;
- ioinfo_head->prev = ioinfo[irq];
- ioinfo_head = ioinfo[irq];
- }
- else if ( irq > ioinfo_tail->irq ) /* new tail */
- {
- ioinfo_tail->next = ioinfo[irq];
- ioinfo[irq]->prev = ioinfo_tail;
- ioinfo_tail = ioinfo[irq];
- }
- else /* insert element */
- {
- ioinfo_t *pi = ioinfo_head;
-
- do
- {
- if ( irq < pi->next->irq )
- {
- ioinfo[irq]->next = pi->next;
- ioinfo[irq]->prev = pi;
- pi->next->prev = ioinfo[irq];
- pi->next = ioinfo[irq];
- break;
-
- } /* endif */
-
- pi = pi->next;
-
- } while ( 1 );
-
- } /* endif */
-
- } /* endif */
-
- // initialize some values ...
- ioinfo[irq]->ui.flags.pgid_supp = 1;
-
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- printk( "Detected device %04X on subchannel %04X"
- " - PIM = %02X, PAM = %02X, POM = %02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- ioinfo[irq]->schib.pmcw.pim,
- ioinfo[irq]->schib.pmcw.pam,
- ioinfo[irq]->schib.pmcw.pom);
-
- /*
- * We should have at least one CHPID ...
- */
- if ( ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom )
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- /*
- * We now have to initially ...
- * ... set "interruption sublass"
- * ... enable "concurrent sense"
- * ... enable "multipath mode" if more than one
- * CHPID is available. This is done regardless
- * whether multiple paths are available for us.
- *
- * Note : we don't enable the device here, this is temporarily
- * done during device sensing below.
- */
- ioinfo[irq]->schib.pmcw.isc = 3; /* could be smth. else */
- ioinfo[irq]->schib.pmcw.csense = 1; /* concurrent sense */
- ioinfo[irq]->schib.pmcw.ena = 0; /* force disable it */
- ioinfo[irq]->schib.pmcw.intparm =
- ioinfo[irq]->schib.pmcw.dev;
-
- if ( ( ioinfo[irq]->schib.pmcw.pim != 0 )
- && ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- } /* endif */
-
- /*
- * initialize ioinfo structure
- */
- ioinfo[irq]->irq = irq;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.ready = 0;
- ioinfo[irq]->ui.flags.oper = 1;
- ioinfo[irq]->devstat.intparm = 0;
- ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
-
- retry = 5;
-
- do
- {
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- switch (ccode2) {
- case 0: // successful completion
- //
- // concurrent sense facility available ...
- //
- ioinfo[irq]->ui.flags.consns = 1;
- break;
-
- case 1: // status pending
- //
- // How can we have a pending status as device is
- // disabled for interrupts ? Anyway, clear it ...
- //
- tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
- retry--;
- break;
-
- case 2: // busy
- retry--;
- break;
-
- case 3: // not operational
- ioinfo[irq]->ui.flags.oper = 0;
- retry = 0;
- break;
-
- default:
-#define PGMCHK_OPERAND_EXC 0x15
-
- if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
- {
- /*
- * re-issue the modify subchannel without trying to
- * enable the concurrent sense facility
- */
- ioinfo[irq]->schib.pmcw.csense = 0;
-
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- if ( ccode2 != 0 )
- {
- printk( " ... modify subchannel (2) failed with CC = %X\n",
- ccode2 );
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ioinfo[irq]->ui.flags.consns = 0;
-
- } /* endif */
- }
- else
- {
- printk( " ... modify subchannel (1) failed with CC = %X\n",
- ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- retry = 0;
- break;
-
- } /* endswitch */
-
- } while ( ccode2 && retry );
-
- if ( (ccode2 < 3) && (!retry) )
- {
- printk( " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %d\n",
- irq,
- ccode2);
-
- } /* endif */
-
- }
- else
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * indicate whether the subchannel is valid
- */
- if ( ccode == 3)
- return(0);
- else
- return(1);
-}
-
-/*
- * s390_SenseID
- *
- * Try to obtain the 'control unit'/'device type' information
- * associated with the subchannel.
- *
- * The function is primarily meant to be called without irq
- * action handler in place. However, it also allows for
- * use with an action handler in place. If there is already
- * an action handler registered assure it can handle the
- * s390_SenseID() related device interrupts - interruption
- * parameter used is 0x00E2C9C4 ( SID ).
- */
-int s390_SenseID( int irq, senseid_t *sid )
-{
- ccw1_t sense_ccw; /* ccw area for SenseID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- sense_ccw.cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw.cda = (__u32)virt_to_phys( sid );
- sense_ccw.count = sizeof( senseid_t);
- sense_ccw.flags = CCW_FLAG_SLI;
-
- ioinfo[irq]->senseid.cu_type = 0xFFFF; /* initialize fields ... */
- ioinfo[irq]->senseid.cu_model = 0;
- ioinfo[irq]->senseid.dev_type = 0;
- ioinfo[irq]->senseid.dev_model = 0;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &sense_ccw,
- 0x00E2C9C4, // == SID
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_TIMEOUT );
-
- if ( irq_ret == -ETIMEDOUT )
- {
- halt_IO( irq,
- 0x80E2C9C4,
- DOIO_WAIT_FOR_INTERRUPT);
- devstat.flag |= DEVSTAT_NOT_OPER;
-
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF && devstat.flag != DEVSTAT_NOT_OPER )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "Device %04X on Subchannel %04X "
- "reports pending status, retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * if the device doesn't support the SenseID
- * command further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "Device %04X,"
- " UC/SenseID,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "Device %04X on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else // we got it or the device is not-operational ...
- {
- retry = 0;
-
- } /* endif */
-
- retry--;
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- /*
- * if running under VM check there ... perhaps we should do
- * only if we suffered a command reject, but it doesn't harm
- */
- if ( ( sid->cu_type == 0xFFFF )
- && ( MACHINE_IS_VM ) )
- {
- VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
- sid );
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF )
- {
- /*
- * SenseID CU-type of 0xffff indicates that no device
- * information could be retrieved (pre-init value).
- *
- * If we can't couldn't identify the device type we
- * consider the device "not operational".
- */
- printk( "Unknown device %04X on subchannel %04X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- /*
- * Issue device info message if unit was operational .
- */
- if ( ioinfo[irq]->ui.flags.oper )
- {
- if ( sid->dev_type != 0 )
- {
- printk( "Device %04X reports: CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- }
- else
- {
- printk( "Device %04X reports:"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
-
- } /* endif */
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper )
- irq_ret = 0;
- else
- irq_ret = -ENODEV;
-
- } /* endif */
-
- return( irq_ret );
-}
-
-static int __inline__ s390_SetMultiPath( int irq )
-{
- int cc;
-
- cc = stsch( irq, &ioinfo[irq]->schib );
-
- if ( !cc )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- cc = msch( irq, &ioinfo[irq]->schib );
-
- } /* endif */
-
- return( cc);
-}
-
-/*
- * Device Path Verification
- *
- * Path verification is accomplished by checking which paths (CHPIDs) are
- * available. Further, a path group ID is set, if possible in multipath
- * mode, otherwise in single path mode.
- *
- */
-int s390_DevicePathVerification( int irq )
-{
-#if 0
- int ccode;
- __u8 pathmask;
-
- int ret = 0;
-
- if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
- {
- ret = -EOPNOTSUPP;
-
- } /* endif */
-
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- int i;
- pgid_t pgid;
-
- int first = 1;
- __u8 dev_path = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- /*
- * let's build a path group ID if we don't have one yet
- */
- if ( ioinfo[irq]->ui.flags.pgid == 0)
- {
- struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
-
- ioinfo->pgid.cpu_addr = lowcore->cpu_data.cpu_addr;
- ioinfo->pgid.cpu_id = lowcore->cpu_data.cpu_id.ident;
- ioinfo->pgid.cpu_model = lowcore->cpu_data.cpu_id.machine;
- ioinfo->pgid.tod_high = *(__u32 *)&irq_IPL_TOD;
-
- ioinfo[irq]->ui.flags.pgid = 1;
-
- } /* endif */
-
- memcpy( &pgid, ioinfo[irq]->pgid, sizeof(pgid_t));
-
- for ( i = 0; i < 8 && !ret ; i++)
- {
- pathmask = 0x80 >> i;
-
- if ( dev_path & pathmask )
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- /*
- * For the *first* path we are prepared
- * for recovery
- *
- * - If we fail setting the PGID we assume its
- * using a different PGID already (VM) we
- * try to sense.
- */
- if ( ret == -EOPNOTSUPP && first )
- {
- *(int *)&pgid = 0;
-
- ret = s390_SensePGID( irq, pathmask, &pgid);
- first = 0;
-
- if ( !ret )
- {
- /*
- * Check whether we retrieved
- * a reasonable PGID ...
- */
- if ( !ret && (*(int *)&pgid == 0) )
- {
- ret = -EOPNOTSUPP;
- }
- else
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- } /* endif */
-
- } /* endif */
-
- if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- printk( "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path grouping",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- } /* endif */
- }
- else if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return ret;
-#else
- return 0;
-#endif
-}
-
-/*
- * s390_SetPGID
- *
- * Set Path Group ID
- *
- */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t spid_ccw; /* ccw area for SPID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
- int mpath = 1; /* try multi-path first */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SPID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- spid_ccw.cmd_code = CCW_CMD_SET_PGID;
- spid_ccw.cda = (__u32)virt_to_phys( pgid );
- spid_ccw.count = sizeof( pgid_t);
- spid_ccw.flags = CCW_FLAG_SLI;
-
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &spid_ccw,
- 0xE2D7C9C4, // == SPID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag == ( DEVSTAT_START_FUNCTION
- | DEVSTAT_FINAL_STATUS ) )
- {
- retry = 0; // successfully set ...
- }
- else if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- if ( mpath )
- {
- pgid->inf.fc = SPID_FUNC_ESTABLISH;
- mpath = 0;
- retry--;
- }
- else
- {
- irq_ret = -EOPNOTSUPP;
- retry = 0;
-
- } /* endif */
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SPID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-/*
- * s390_SensePGID
- *
- * Sense Path Group ID
- *
- */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t snid_ccw; /* ccw area for SNID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SNID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- snid_ccw.cmd_code = CCW_CMD_SENSE_PGID;
- snid_ccw.cda = (__u32)virt_to_phys( pgid );
- snid_ccw.count = sizeof( pgid_t);
- snid_ccw.flags = CCW_FLAG_SLI;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &snid_ccw,
- 0xE2D5C9C4, // == SNID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- irq_ret = -EOPNOTSUPP;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SNID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-void do_crw_pending( void )
-{
- return;
-}
-
-
-/* added by Holger Smolinski for reipl support in reipl.S */
-void
-reipl ( int sch )
-{
- int i;
-
- for ( i = 0; i < highest_subchannel; i ++ ) {
- free_irq ( i, (void*)REIPL_DEVID_MAGIC );
- }
- do_reipl( 0x10000 | sch );
-}
-
diff --git a/arch/s390/kernel/s390mach.c b/arch/s390/kernel/s390mach.c
deleted file mode 100644
index 750e50c30..000000000
--- a/arch/s390/kernel/s390mach.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * arch/s390/kernel/s390mach.c
- * S/390 machine check handler,
- * currently only channel-reports are supported
- *
- * S390 version
- * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/lowcore.h>
-#include <asm/semaphore.h>
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-
-#define S390_MACHCHK_DEBUG
-
-static mchchk_queue_element_t *mchchk_queue_head = NULL;
-static mchchk_queue_element_t *mchchk_queue_tail = NULL;
-static mchchk_queue_element_t *mchchk_queue_free = NULL;
-static spinlock_t mchchk_queue_lock;
-static struct semaphore s_sem[2];
-
-//
-// initialize machine check handling
-//
-void s390_init_machine_check( void )
-{
- init_MUTEX_LOCKED( &s_sem[0] );
- init_MUTEX_LOCKED( &s_sem[1] );
-
-#if 0
- //
- // fix me ! initialize a machine check queue with 100 elements
- //
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : starting kernel thread\n");
-#endif
-
- kernel_thread( s390_machine_check_handler, s_sem, 0);
-
- //
- // wait for the machine check handler to be ready
- //
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : waiting for kernel thread\n");
-#endif
-
- down( &sem[0]);
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "init_mach : kernel thread ready\n");
-#endif
-
- //
- // fix me ! we have to initialize CR14 to allow for CRW pending
- // conditions
-
- //
- // fix me ! enable machine checks in the PSW
- //
-#endif
- return;
-}
-
-//
-// machine check pre-processor
-//
-void __init s390_do_machine_check( void )
-{
- // fix me ! we have to check for machine check and
- // post the handler eventually
-
- return;
-}
-
-//
-// machine check handler
-//
-static void __init s390_machine_check_handler( struct semaphore *sem )
-{
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : kernel thread up\n");
-#endif
-
- up( &sem[0] );
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : kernel thread ready\n");
-#endif
-
- do {
-
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : waiting for wakeup\n");
-#endif
-
- down_interruptible( &sem[1] );
-#ifdef S390_MACHCHK_DEBUG
- printk( "mach_handler : wakeup\n");
-#endif
-
- break; // fix me ! unconditional surrender ...
-
- // fix me ! check for machine checks and
- // call do_crw_pending() eventually
-
- } while (1);
-
- return;
-}
-
-mchchk_queue_element_t *s390_get_mchchk( void )
-{
- unsigned long flags;
- mchchk_queue_element_t *qe;
-
- spin_lock_irqsave( &mchchk_queue_lock, flags );
-
- // fix me ! dequeue first element if available
- qe = NULL;
-
- spin_unlock_irqrestore( &mchchk_queue_lock, flags );
-
- return qe;
-}
-
-void s390_free_mchchk( mchchk_queue_element_t *mchchk )
-{
- unsigned long flags;
-
- if ( mchchk != NULL)
- {
- spin_lock_irqsave( &mchchk_queue_lock, flags );
-
- mchchk->next = mchchk_queue_free;
-
- if ( mchchk_queue_free != NULL )
- {
- mchchk_queue_free->prev = mchchk;
-
- } /* endif */
-
- mchchk->prev = NULL;
- mchchk_queue_free = mchchk;
-
- spin_unlock_irqrestore( &mchchk_queue_lock, flags );
-
- } /* endif */
-
- return;
-}
-
diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
index a0a434581..8af6d8277 100644
--- a/arch/s390/kernel/semaphore.c
+++ b/arch/s390/kernel/semaphore.c
@@ -2,7 +2,7 @@
* linux/arch/S390/kernel/semaphore.c
*
* S390 version
- * Copyright (C) 1998 IBM Corporation
+ * Copyright (C) 1998-2000 IBM Corporation
* Author(s): Martin Schwidefsky
*
* Derived from "linux/arch/i386/kernel/semaphore.c
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 109af4e76..628d7bcf7 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -21,7 +21,7 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/tty.h>
@@ -45,6 +45,7 @@
__u16 boot_cpu_addr;
int cpus_initialized = 0;
unsigned long cpu_initialized = 0;
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
/*
* Setup options
@@ -80,6 +81,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
void __init cpu_init (void)
{
int nr = smp_processor_id();
+ int addr = hard_smp_processor_id();
if (test_and_set_bit(nr,&cpu_initialized)) {
printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
@@ -91,7 +93,7 @@ void __init cpu_init (void)
* Store processor id in lowcore (used e.g. in timer_interrupt)
*/
asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
- S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id();
+ S390_lowcore.cpu_data.cpu_addr = addr;
S390_lowcore.cpu_data.cpu_nr = nr;
/*
@@ -158,33 +160,18 @@ void machine_halt(void)
{
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_power_off(void)
{
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
#endif
/*
- * Waits for 'delay' microseconds using the tod clock
- */
-void tod_wait(unsigned long delay)
-{
- uint64_t start_cc, end_cc;
-
- if (delay == 0)
- return;
- asm volatile ("STCK %0" : "=m" (start_cc));
- do {
- asm volatile ("STCK %0" : "=m" (end_cc));
- } while (((end_cc - start_cc)/4096) < delay);
-}
-
-/*
* Setup function called from init/main.c just after the banner
* was printed.
*/
@@ -192,12 +179,11 @@ void __init setup_arch(char **cmdline_p)
{
unsigned long bootmap_size;
unsigned long memory_start, memory_end;
- char c = ' ', *to = command_line, *from = COMMAND_LINE;
+ char c = ' ', cn, *to = command_line, *from = COMMAND_LINE;
struct resource *res;
unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0;
unsigned long delay = 0;
- int len = 0;
if (smptrap)
return;
@@ -210,6 +196,7 @@ void __init setup_arch(char **cmdline_p)
*/
cpu_init();
boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+ __cpu_logical_map[0] = boot_cpu_addr;
/*
* print what head.S has found out about the machine
@@ -227,10 +214,15 @@ void __init setup_arch(char **cmdline_p)
rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
#endif
- /* nasty stuff with PARMAREAs. we use head.S or parameterline
- if (!MOUNT_ROOT_RDONLY)
- root_mountflags &= ~MS_RDONLY;
- */
+ memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
+ memory_end = MEMORY_SIZE;
+ /*
+ * We need some free virtual space to be able to do vmalloc.
+ * On a machine with 2GB memory we make sure that we have at
+ * least 128 MB free space for vmalloc.
+ */
+ if (memory_end > 1920*1024*1024)
+ memory_end = 1920*1024*1024;
memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/
memory_end = MEMORY_SIZE; /* detected in head.s */
init_mm.start_code = PAGE_OFFSET;
@@ -252,7 +244,6 @@ void __init setup_arch(char **cmdline_p)
* "mem=XXX[kKmM]" sets memsize
*/
if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
- if (to != command_line) to--;
memory_end = simple_strtoul(from+4, &from, 0);
if ( *from == 'K' || *from == 'k' ) {
memory_end = memory_end << 10;
@@ -275,16 +266,22 @@ void __init setup_arch(char **cmdline_p)
delay = delay*60*1000000;
from++;
}
- /* now wait for the requestion amount of time */
- tod_wait(delay);
+ /* now wait for the requestedn amount of time */
+ udelay(delay);
}
- c = *(from++);
- if (!c)
+ cn = *(from++);
+ if (!cn)
break;
- if (COMMAND_LINE_SIZE <= ++len)
+ if (cn == '\n')
+ cn = ' '; /* replace newlines with space */
+ if (cn == ' ' && c == ' ')
+ continue; /* remove additional spaces */
+ c = cn;
+ if (to - command_line >= COMMAND_LINE_SIZE)
break;
*(to++) = c;
}
+ if (c == ' ' && to > command_line) to--;
*to = '\0';
*cmdline_p = command_line;
@@ -317,7 +314,7 @@ void __init setup_arch(char **cmdline_p)
paging_init();
#ifdef CONFIG_BLK_DEV_INITRD
if (INITRD_START) {
- if (INITRD_START + INITRD_SIZE < memory_end) {
+ if (INITRD_START + INITRD_SIZE <= memory_end) {
reserve_bootmem(INITRD_START, INITRD_SIZE);
initrd_start = INITRD_START;
initrd_end = initrd_start + INITRD_SIZE;
@@ -368,8 +365,8 @@ int get_cpuinfo(char * buffer)
p += sprintf(p,"vendor_id : IBM/S390\n"
"# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n",
- smp_num_cpus, loops_per_sec/500000,
- (loops_per_sec/5000)%100);
+ smp_num_cpus, loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ))%100);
for (i = 0; i < smp_num_cpus; i++) {
cpuinfo = &safe_get_cpu_lowcore(i).cpu_data;
p += sprintf(p,"processor %i: "
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 7809a4a2b..de05ec764 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/signal.c
*
* S390 version
- * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* Based on Intel version
@@ -37,7 +37,7 @@
#define SIGFRAME_COMMON \
__u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \
struct sigcontext sc; \
-sigregs sregs; \
+_sigregs sregs; \
__u8 retcode[S390_SYSCALL_SIZE];
typedef struct
@@ -54,6 +54,41 @@ typedef struct
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
+int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from)
+{
+ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t)))
+ return -EFAULT;
+ if (from->si_code < 0)
+ return __copy_to_user(to, from, sizeof(siginfo_t));
+ else {
+ int err;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ /* First 32bits of unions are always present. */
+ err |= __put_user(from->si_pid, &to->si_pid);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ /* case __SI_RT: This is not generated by the kernel as of now. */
+ }
+ return err;
+ }
+}
+
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -71,7 +106,7 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -99,7 +134,7 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
regs->gprs[2] = -EINTR;
while (1) {
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
if (do_signal(regs, &saveset))
return -EINTR;
@@ -139,16 +174,15 @@ sys_sigaction(int sig, const struct old_sigaction *act,
}
asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
{
- struct pt_regs *regs = (struct pt_regs *) &uss;
return do_sigaltstack(uss, uoss, regs->gprs[15]);
}
-static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -163,7 +197,7 @@ static int save_sigregs(struct pt_regs *regs,sigregs *sregs)
}
-static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
+static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
@@ -185,13 +219,13 @@ static int restore_sigregs(struct pt_regs *regs,sigregs *sregs)
static int
restore_sigcontext(struct sigcontext *sc, pt_regs *regs,
- sigregs *sregs,sigset_t *set)
+ _sigregs *sregs,sigset_t *set)
{
unsigned int err;
err=restore_sigregs(regs,sregs);
if(!err)
- err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE);
+ err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE);
return(err);
}
@@ -227,15 +261,12 @@ badframe:
asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
- stack_t st;
if (sigreturn_common(regs,sizeof(rt_sigframe)))
goto badframe;
- if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
- goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->gprs[15]);
+ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
return regs->gprs[2];
badframe:
@@ -290,7 +321,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
err=__put_user(&frame->sregs,&frame->sc.sregs);
if(!err)
- err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE);
+ err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE);
if(!err)
{
regs->gprs[2]=(current->exec_domain
@@ -316,14 +347,17 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
static void setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs * regs)
{
+ sigframe *frame;
- if(!setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
- (S390_SYSCALL_OPCODE|__NR_sigreturn)))
+ if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe),
+ (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0)
goto give_sigsegv;
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->eip, frame->pretcode);
#endif
+ /* Martin wants this for pthreads */
+ regs->gprs[3] = (addr_t)&frame->sc;
return;
give_sigsegv:
@@ -343,7 +377,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
(S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0)
goto give_sigsegv;
- err = __copy_to_user(&frame->info, info, sizeof(*info));
+ err = copy_siginfo_to_user(&frame->info, info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
@@ -352,8 +386,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(sas_ss_flags(orig_sp),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- regs->gprs[3] = (u32)&frame->info;
- regs->gprs[4] = (u32)&frame->uc;
+ err |= __put_user(&frame->sc,&frame->uc.sc);
+ regs->gprs[3] = (addr_t)&frame->info;
+ regs->gprs[4] = (addr_t)&frame->uc;
if (err)
goto give_sigsegv;
@@ -452,10 +487,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!signr)
break;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {
/* Let the debugger run. */
current->exit_code = signr;
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
notify_parent(current, SIGCHLD);
schedule();
@@ -511,7 +546,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* FALLTHRU */
case SIGSTOP:
- current->state = TASK_STOPPED;
+ set_current_state(TASK_STOPPED);
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
notify_parent(current, SIGCHLD);
@@ -540,7 +575,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
}
/* Did we come from a system call? */
- if ( regs->trap == 0x20 /* System Call! */ ) {
+ if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) {
/* Restart the system call - no handlers present */
if (regs->gprs[2] == -ERESTARTNOHAND ||
regs->gprs[2] == -ERESTARTSYS ||
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 6cf2e6918..4b15b5501 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -32,16 +32,15 @@
#include <asm/sigp.h>
#include <asm/pgalloc.h>
#include <asm/irq.h>
+#include <asm/s390_ext.h>
#include "cpcmd.h"
/* prototypes */
-extern void update_one_process( struct task_struct *p,
- unsigned long ticks, unsigned long user,
- unsigned long system, int cpu);
extern int cpu_idle(void * unused);
extern __u16 boot_cpu_addr;
+extern volatile int __cpu_logical_map[];
/*
* An array with a pointer the lowcore of every CPU.
@@ -52,10 +51,8 @@ struct _lowcore *lowcore_ptr[NR_CPUS];
unsigned int prof_multiplier[NR_CPUS];
unsigned int prof_old_multiplier[NR_CPUS];
unsigned int prof_counter[NR_CPUS];
-volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
cycles_t cacheflush_time=0;
int smp_threads_ready=0; /* Set when the idlers are all forked. */
-unsigned long ipi_count=0; /* Number of IPIs delivered. */
static atomic_t smp_commenced = ATOMIC_INIT(0);
spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
@@ -104,7 +101,7 @@ void do_machine_restart(void)
void machine_restart(char * __unused)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_restart);
+ smp_ext_bitcall(0, ec_restart);
for (;;);
} else
do_machine_restart();
@@ -115,13 +112,13 @@ void do_machine_halt(void)
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
cpcmd(vmhalt_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_halt(void)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_halt);
+ smp_ext_bitcall(0, ec_halt);
for (;;);
} else
do_machine_halt();
@@ -132,13 +129,13 @@ void do_machine_power_off(void)
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
cpcmd(vmpoff_cmd, NULL, 0);
- disabled_wait(0);
+ signal_processor(smp_processor_id(), sigp_stop_and_store_status);
}
void machine_power_off(void)
{
if (smp_processor_id() != 0) {
- smp_ext_call_async(0, ec_power_off);
+ smp_ext_bitcall(0, ec_power_off);
for (;;);
} else
do_machine_power_off();
@@ -149,7 +146,7 @@ void machine_power_off(void)
* cpus are handled.
*/
-void do_ext_call_interrupt(__u16 source_cpu_addr)
+void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
{
ec_ext_call *ec, *next;
int bits;
@@ -172,6 +169,8 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
do_machine_halt();
if (test_bit(ec_power_off, &bits))
do_machine_power_off();
+ if (test_bit(ec_ptlb, &bits))
+ local_flush_tlb();
/*
* Handle external call commands with a parameter area
@@ -184,7 +183,7 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
return; /* no command signals */
/* Make a fifo out of the lifo */
- next = ec;
+ next = ec->next;
ec->next = NULL;
while (next != NULL) {
ec_ext_call *tmp = next->next;
@@ -196,61 +195,21 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
/* Execute every sigp command on the queue */
while (ec != NULL) {
switch (ec->cmd) {
- case ec_get_ctl: {
- ec_creg_parms *pp;
- pp = (ec_creg_parms *) ec->parms;
+ case ec_callback_async: {
+ void (*func)(void *info);
+ void *info;
+
+ func = ec->func;
+ info = ec->info;
atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " stctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (pp->cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- atomic_set(&ec->status,ec_done);
+ (func)(info);
return;
}
- case ec_set_ctl: {
- ec_creg_parms *pp;
- pp = (ec_creg_parms *) ec->parms;
+ case ec_callback_sync:
atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " lctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (pp->cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
+ (ec->func)(ec->info);
atomic_set(&ec->status,ec_done);
return;
- }
- case ec_set_ctl_masked: {
- ec_creg_mask_parms *pp;
- u32 cregs[16];
- int i;
-
- pp = (ec_creg_mask_parms *) ec->parms;
- atomic_set(&ec->status,ec_executing);
- asm volatile (
- " bras 1,0f\n"
- " stctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- for (i = pp->start_ctl; i <= pp->end_ctl; i++)
- cregs[i] = (cregs[i] & pp->andvals[i])
- | pp->orvals[i];
- asm volatile (
- " bras 1,0f\n"
- " lctl 0,0,0(%0)\n"
- "0: ex %1,0(1)\n"
- : : "a" (cregs+pp->start_ctl),
- "a" ((pp->start_ctl<<4) + pp->end_ctl)
- : "memory", "1" );
- atomic_set(&ec->status,ec_done);
- return;
- }
default:
}
ec = ec->next;
@@ -258,17 +217,19 @@ void do_ext_call_interrupt(__u16 source_cpu_addr)
}
/*
- * Send an external call sigp to another cpu and wait for its completion.
+ * Send a callback sigp to another cpu.
*/
-sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms)
+sigp_ccode
+smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait)
{
struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
sigp_ccode ccode;
ec_ext_call ec;
- ec.cmd = cmd;
+ ec.cmd = wait ? ec_callback_sync : ec_callback_async;
atomic_set(&ec.status, ec_pending);
- ec.parms = parms;
+ ec.func = func;
+ ec.info = info;
do {
ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue);
} while (atomic_compare_and_swap((int) ec.next, (int)(&ec),
@@ -288,34 +249,15 @@ sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms)
if (ccode != sigp_not_operational)
/* wait for completion, FIXME: possible seed of a deadlock */
- while (atomic_read(&ec.status) != ec_done);
+ while (atomic_read(&ec.status) != (wait?ec_done:ec_executing));
return ccode;
}
/*
- * Send an external call sigp to another cpu and return without waiting
- * for its completion. Currently we do not support parameters with
- * asynchronous sigps.
+ * Send a callback sigp to every other cpu in the system.
*/
-sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig)
-{
- struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
- sigp_ccode ccode;
-
- /*
- * Set signaling bit in lowcore of target cpu and kick it
- */
- atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
- ccode = signal_processor(cpu, sigp_external_call);
- return ccode;
-}
-
-/*
- * Send an external call sigp to every other cpu in the system and
- * wait for the completion of the sigps.
- */
-void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
+void smp_ext_call_others(void (*func)(void *info), void *info, int wait)
{
struct _lowcore *lowcore;
ec_ext_call ec[NR_CPUS];
@@ -326,9 +268,10 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
if (smp_processor_id() == i)
continue;
lowcore = &get_cpu_lowcore(i);
- ec[i].cmd = cmd;
- atomic_set(&ec[i].status, ec_pending);
- ec[i].parms = parms;
+ ec[i].cmd = wait ? ec_callback_sync : ec_callback_async;
+ atomic_set(&ec[i].status, ec_pending);
+ ec[i].func = func;
+ ec[i].info = info;
do {
ec[i].next = (ec_ext_call *)
atomic_read(&lowcore->ext_call_queue);
@@ -341,16 +284,33 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms)
for (i = 0; i < smp_num_cpus; i++) {
if (smp_processor_id() == i)
continue;
- while (atomic_read(&ec[i].status) != ec_done);
+ while (atomic_read(&ec[i].status) !=
+ (wait ? ec_done:ec_executing));
}
}
/*
+ * Send an external call sigp to another cpu and return without waiting
+ * for its completion.
+ */
+sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
+{
+ struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+ sigp_ccode ccode;
+
+ /*
+ * Set signaling bit in lowcore of target cpu and kick it
+ */
+ atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
+ ccode = signal_processor(cpu, sigp_external_call);
+ return ccode;
+}
+
+/*
* Send an external call sigp to every other cpu in the system and
- * return without waiting for the completion of the sigps. Currently
- * we do not support parameters with asynchronous sigps.
+ * return without waiting for its completion.
*/
-void smp_ext_call_async_others(ec_bit_sig sig)
+void smp_ext_bitcall_others(ec_bit_sig sig)
{
struct _lowcore *lowcore;
sigp_ccode ccode;
@@ -420,7 +380,46 @@ int smp_signal_others(sigp_order_code order_code, u32 parameter,
void smp_send_stop(void)
{
- smp_signal_others(sigp_stop, 0, 1, NULL);
+ int i;
+ u32 dummy;
+ unsigned long low_core_addr;
+
+ /* write magic number to zero page (absolute 0) */
+
+ get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
+
+ /* stop all processors */
+
+ smp_signal_others(sigp_stop, 0, TRUE, NULL);
+
+ /* store status of all processors in their lowcores (real 0) */
+
+ for (i = 0; i < smp_num_cpus; i++) {
+ if (smp_processor_id() != i) {
+ int ccode;
+ low_core_addr = (unsigned long)&get_cpu_lowcore(i);
+ do {
+ ccode = signal_processor_ps(
+ &dummy,
+ low_core_addr,
+ i,
+ sigp_store_status_at_address);
+ } while(ccode == sigp_busy);
+ }
+ }
+}
+
+/*
+ * this function sends a 'purge tlb' signal to another CPU.
+ */
+void smp_ptlb_callback(void *info)
+{
+ local_flush_tlb();
+}
+
+void smp_ptlb_all(void)
+{
+ smp_ext_call_others(smp_ptlb_callback, NULL, 1);
}
/*
@@ -431,7 +430,44 @@ void smp_send_stop(void)
void smp_send_reschedule(int cpu)
{
- smp_ext_call_async(cpu, ec_schedule);
+ smp_ext_bitcall(cpu, ec_schedule);
+}
+
+/*
+ * parameter area for the set/clear control bit callbacks
+ */
+typedef struct
+{
+ __u16 start_ctl;
+ __u16 end_ctl;
+ __u32 orvals[16];
+ __u32 andvals[16];
+} ec_creg_mask_parms;
+
+/*
+ * callback for setting/clearing control bits
+ */
+void smp_ctl_bit_callback(void *info) {
+ ec_creg_mask_parms *pp;
+ u32 cregs[16];
+ int i;
+
+ pp = (ec_creg_mask_parms *) info;
+ asm volatile (" bras 1,0f\n"
+ " stctl 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+ for (i = pp->start_ctl; i <= pp->end_ctl; i++)
+ cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
+ asm volatile (" bras 1,0f\n"
+ " lctl 0,0,0(%0)\n"
+ "0: ex %1,0(1)\n"
+ : : "a" (cregs+pp->start_ctl),
+ "a" ((pp->start_ctl<<4) + pp->end_ctl)
+ : "memory", "1" );
+ return;
}
/*
@@ -445,7 +481,7 @@ void smp_ctl_set_bit(int cr, int bit) {
parms.end_ctl = cr;
parms.orvals[cr] = 1 << bit;
parms.andvals[cr] = 0xFFFFFFFF;
- smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
}
__ctl_set_bit(cr, bit);
}
@@ -461,11 +497,35 @@ void smp_ctl_clear_bit(int cr, int bit) {
parms.end_ctl = cr;
parms.orvals[cr] = 0x00000000;
parms.andvals[cr] = ~(1 << bit);
- smp_ext_call_sync_others(ec_set_ctl_masked,&parms);
+ smp_ext_call_others(smp_ctl_bit_callback, &parms, 1);
}
__ctl_clear_bit(cr, bit);
}
+/*
+ * Call a function on all other processors
+ */
+
+int
+smp_call_function(void (*func)(void *info), void *info, int retry, int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <retry> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler, you may call it from a bottom half handler.
+ */
+{
+ if (atomic_read(&smp_commenced) != 0)
+ smp_ext_call_others(func, info, 1);
+ (func)(info);
+ return 0;
+}
/*
* Lets check how many CPUs we have.
@@ -475,7 +535,6 @@ void smp_count_cpus(void)
{
int curr_cpu;
- __cpu_logical_map[0] = boot_cpu_addr;
current->processor = 0;
smp_num_cpus = 1;
for (curr_cpu = 0;
@@ -527,7 +586,7 @@ static int __init fork_by_hand(void)
struct pt_regs regs;
/* don't care about the psw and regs settings since we'll never
reschedule the forked task. */
- memset(&regs,sizeof(pt_regs),0);
+ memset(&regs,0,sizeof(pt_regs));
return do_fork(CLONE_VM|CLONE_PID, 0, &regs, 0);
}
@@ -594,7 +653,10 @@ void __init smp_boot_cpus(void)
struct _lowcore *curr_lowcore;
sigp_ccode ccode;
int i;
-
+
+ /* request the 0x1202 external interrupt */
+ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x1202");
smp_count_cpus();
memset(lowcore_ptr,0,sizeof(lowcore_ptr));
@@ -705,24 +767,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs)
*/
irq_enter(cpu, 0);
- update_one_process(p, 1, user, system, cpu);
- if (p->pid) {
- p->counter -= 1;
- if (p->counter <= 0) {
- p->counter = 0;
- p->need_resched = 1;
- }
- if (p->nice > 0) {
- kstat.cpu_nice += user;
- kstat.per_cpu_nice[cpu] += user;
- } else {
- kstat.cpu_user += user;
- kstat.per_cpu_user[cpu] += user;
- }
- kstat.cpu_system += system;
- kstat.per_cpu_system[cpu] += system;
-
- }
+ update_process_times(user);
irq_exit(cpu, 0);
}
}
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index b00d88a62..cc7700864 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -71,18 +71,10 @@ out:
return error;
}
-/* FIXME: 6 parameters is one too much ... */
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff)
-{
- return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
/*
* Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
+ * calls. Linux for S/390 isn't able to handle more than 5
+ * system call parameters, so these system calls used a memory
* block for parameter passing..
*/
@@ -95,6 +87,18 @@ struct mmap_arg_struct {
unsigned long offset;
};
+asmlinkage long sys_mmap2(struct mmap_arg_struct *arg)
+{
+ struct mmap_arg_struct a;
+ int error = -EFAULT;
+
+ if (copy_from_user(&a, arg, sizeof(a)))
+ goto out;
+ error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
+out:
+ return error;
+}
+
asmlinkage int old_mmap(struct mmap_arg_struct *arg)
{
struct mmap_arg_struct a;
@@ -239,7 +243,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
asmlinkage int sys_pause(void)
{
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule();
return -ERESTARTNOHAND;
}
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 8cd84ee54..f4bde27b3 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -11,7 +11,6 @@
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -27,15 +26,14 @@
#include <asm/uaccess.h>
#include <asm/delay.h>
+#include <asm/s390_ext.h>
-#include <linux/mc146818rtc.h>
#include <linux/timex.h>
+#include <linux/config.h>
#include <asm/irq.h>
-extern volatile unsigned long lost_ticks;
-
/* change this if you have some constant time drift */
#define USECS_PER_JIFFY ((signed long)1000000/HZ)
#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
@@ -45,6 +43,7 @@ extern volatile unsigned long lost_ticks;
static uint64_t init_timer_cc, last_timer_cc;
extern rwlock_t xtime_lock;
+extern unsigned long wall_jiffies;
void tod_to_timeval(uint64_t todval, struct timeval *xtime)
{
@@ -94,9 +93,9 @@ unsigned long do_gettimeoffset(void)
*/
void do_gettimeofday(struct timeval *tv)
{
- extern volatile unsigned long lost_ticks;
unsigned long flags;
unsigned long usec, sec;
+ unsigned long lost_ticks = jiffies - wall_jiffies;
read_lock_irqsave(&xtime_lock, flags);
usec = do_gettimeoffset();
@@ -149,7 +148,7 @@ void do_settimeofday(struct timeval *tv)
extern __u16 boot_cpu_addr;
#endif
-void do_timer_interrupt(struct pt_regs *regs,int error_code)
+void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
{
unsigned long flags;
@@ -242,6 +241,9 @@ void __init time_init(void)
printk("time_init: TOD clock stopped/non-operational\n");
break;
}
+ /* request the 0x1004 external interrupt */
+ if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
+ panic("Couldn't request external interrupts 0x1004");
init_100hz_timer();
init_timer_cc = S390_lowcore.jiffy_timer_cc;
init_timer_cc -= 0x8126d60e46000000LL -
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 4af4f6565..fc774a7db 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -42,122 +42,15 @@ extern void handle_per_exception(struct pt_regs *regs);
typedef void pgm_check_handler_t(struct pt_regs *, long);
pgm_check_handler_t *pgm_check_table[128];
-extern pgm_check_handler_t default_trap_handler;
-extern pgm_check_handler_t do_page_fault;
-
-asmlinkage int system_call(void);
-
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void name(struct pt_regs * regs, long error_code) \
-{ \
- tsk->thread.error_code = error_code; \
- tsk->thread.trap_no = trapnr; \
- die_if_no_fixup(str,regs,error_code); \
- force_sig(signr, tsk); \
-}
-
-/* TODO: define these as 'pgm_check_handler_t xxx;'
-asmlinkage void divide_error(void);
-asmlinkage void debug(void);
-asmlinkage void nmi(void);
-asmlinkage void int3(void);
-asmlinkage void overflow(void);
-asmlinkage void bounds(void);
-asmlinkage void invalid_op(void);
-asmlinkage void device_not_available(void);
-asmlinkage void double_fault(void);
-asmlinkage void coprocessor_segment_overrun(void);
-asmlinkage void invalid_TSS(void);
-asmlinkage void segment_not_present(void);
-asmlinkage void stack_segment(void);
-asmlinkage void general_protection(void);
-asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
-asmlinkage void alignment_check(void);
-asmlinkage void spurious_interrupt_bug(void);
-*/
-
-int kstack_depth_to_print = 24;
-
-/*
- * These constants are for searching for possible module text
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
- * a guess of how much space is likely to be vmalloced.
- */
-#define VMALLOC_OFFSET (8*1024*1024)
-#define MODULE_RANGE (8*1024*1024)
-
-void show_crashed_task_info(void)
-{
- printk("CPU: %d\n",smp_processor_id());
- printk("Process %s (pid: %d, stackpage=%08X)\n",
- current->comm, current->pid, 4096+(addr_t)current);
- show_regs(current,NULL,NULL);
-}
-#if 0
-static void show_registers(struct pt_regs *regs)
-{
- printk("CPU: %d\nPSW: %08lx %08lx\n",
- smp_processor_id(), (unsigned long) regs->psw.mask,
- (unsigned long) regs->psw.addr);
- printk("GPRS:\n");
-
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[0], regs->gprs[1],
- regs->gprs[2], regs->gprs[3]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[4], regs->gprs[5],
- regs->gprs[6], regs->gprs[7]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[8], regs->gprs[9],
- regs->gprs[10], regs->gprs[11]);
- printk("%08lx %08lx %08lx %08lx\n",
- regs->gprs[12], regs->gprs[13],
- regs->gprs[14], regs->gprs[15]);
- printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ",
- current->comm, current->pid, 4096+(unsigned long)current);
-/*
- stack = (unsigned long *) esp;
- for(i=0; i < kstack_depth_to_print; i++) {
- if (((long) stack & 4095) == 0)
- break;
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("%08lx ", get_seg_long(ss,stack++));
- }
- printk("\nCall Trace: ");
- stack = (unsigned long *) esp;
- i = 1;
- module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
- module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
- module_end = module_start + MODULE_RANGE;
- while (((long) stack & 4095) != 0) {
- addr = get_seg_long(ss, stack++); */
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
-/* if (((addr >= (unsigned long) &_stext) &&
- (addr <= (unsigned long) &_etext)) ||
- ((addr >= module_start) && (addr <= module_end))) {
- if (i && ((i % 8) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
- printk("\nCode: ");
- for(i=0;i<20;i++)
- printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip)));
- printk("\n");
-*/
-}
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+int sysctl_userprocess_debug = 1;
+#else
+int sysctl_userprocess_debug = 0;
+#endif
#endif
+extern pgm_check_handler_t do_page_fault;
spinlock_t die_lock;
@@ -166,29 +59,65 @@ void die(const char * str, struct pt_regs * regs, long err)
console_verbose();
spin_lock_irq(&die_lock);
printk("%s: %04lx\n", str, err & 0xffff);
- show_crashed_task_info();
+ show_regs(regs);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
-int check_for_fixup(struct pt_regs * regs)
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+ siginfo_t info; \
+ info.si_signo = signr; \
+ info.si_errno = 0; \
+ info.si_code = sicode; \
+ info.si_addr = (void *)siaddr; \
+ do_trap(interruption_code, signr, str, regs, &info); \
+}
+
+static void inline do_trap(long interruption_code, int signr, char *str,
+ struct pt_regs *regs, siginfo_t *info)
{
- if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
- unsigned long fixup;
- fixup = search_exception_table(regs->psw.addr);
- if (fixup) {
- regs->psw.addr = fixup;
- return 1;
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
+ struct task_struct *tsk = current;
+ tsk->thread.trap_no = interruption_code;
+ if (info)
+ force_sig_info(signr, info, tsk);
+ else
+ force_sig(signr, tsk);
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ interruption_code);
+ show_regs(regs);
}
- }
- return 0;
+#endif
+ } else {
+ unsigned long fixup = search_exception_table(regs->psw.addr);
+ if (fixup)
+ regs->psw.addr = fixup;
+ else
+ die(str, regs, interruption_code);
+ }
}
int do_debugger_trap(struct pt_regs *regs,int signal)
{
if(regs->psw.mask&PSW_PROBLEM_STATE)
{
- if(current->flags & PF_PTRACED)
+ if(current->ptrace & PT_PTRACED)
force_sig(signal,current);
else
return 1;
@@ -207,50 +136,16 @@ int do_debugger_trap(struct pt_regs *regs,int signal)
return 0;
}
-static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
-{
- if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
- unsigned long fixup;
- fixup = search_exception_table(regs->psw.addr);
- if (fixup) {
- regs->psw.addr = fixup;
- return;
- }
- die(str, regs, err);
- }
-}
-
-asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code)
-{
- current->thread.error_code = error_code;
- current->thread.trap_no = error_code;
- die_if_no_fixup("Unknown program exception",regs,error_code);
- force_sig(SIGSEGV, current);
-}
-
-DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current)
-DO_ERROR(3, SIGILL, "execute exception", execute_exception, current)
-DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current)
-DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current)
-DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current)
-DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current)
-DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current)
+DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
+DO_ERROR(SIGILL, "privileged operation", privileged_op)
+DO_ERROR(SIGILL, "execute exception", execute_exception)
+DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
+DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGILL, "translation exception", translation_exception)
+DO_ERROR(SIGILL, "special operand exception", special_op_exception)
+DO_ERROR(SIGILL, "operand exception", operand_exception)
-/* need to define
-DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current)
-DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current)
-DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math)
-DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current)
-DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current)
-DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current)
-DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
-DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
-*/
-
-#ifdef CONFIG_IEEEFPU_EMULATION
-
-asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
+asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
@@ -268,6 +163,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
if(do_debugger_trap(regs,SIGTRAP))
do_sig=1;
}
+#ifdef CONFIG_IEEEFPU_EMULATION
else if (problem_state )
{
if (opcode[0] == 0xb3) {
@@ -288,18 +184,19 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code)
do_sig = math_emu_lfpc(opcode, regs);
} else
do_sig = 1;
- } else
- do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
}
+#endif
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
unlock_kernel();
}
-asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
+
+
+#ifdef CONFIG_IEEEFPU_EMULATION
+asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
@@ -311,26 +208,26 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
default:
do_sig = 1;
@@ -338,47 +235,59 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code)
}
} else
do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
- }
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "specification exception", regs, NULL);
unlock_kernel();
}
+#else
+DO_ERROR(SIGILL, "specification exception", specification_exception)
+#endif
-asmlinkage void data_exception(struct pt_regs * regs, long error_code)
+asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
__u16 *location;
int do_sig = 0;
lock_kernel();
- if (regs->psw.mask & 0x00010000L) {
- location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+ if(MACHINE_HAS_IEEE)
+ {
+ __asm__ volatile ("stfpc %0\n\t"
+ : "=m" (current->thread.fp_regs.fpc));
+ }
+ /* Same code should work when we implement fpu emulation */
+ /* provided we call data exception from the fpu emulator */
+ if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
+ {
+ current->thread.ieee_instruction_pointer=(addr_t)location;
+ force_sig(SIGFPE, current);
+ }
+#ifdef CONFIG_IEEEFPU_EMULATION
+ else if (regs->psw.mask & 0x00010000L) {
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
- math_emu_ldr(opcode);
+ do_sig=math_emu_ldr(opcode);
break;
case 0x38: /* LER Rx,Ry */
- math_emu_ler(opcode);
+ do_sig=math_emu_ler(opcode);
break;
case 0x60: /* STD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_std(opcode, regs);
+ do_sig=math_emu_std(opcode, regs);
break;
case 0x68: /* LD R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ld(opcode, regs);
+ do_sig=math_emu_ld(opcode, regs);
break;
case 0x70: /* STE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_ste(opcode, regs);
+ do_sig=math_emu_ste(opcode, regs);
break;
case 0x78: /* LE R,D(X,B) */
get_user(*((__u16 *) (opcode+2)), location+1);
- math_emu_le(opcode, regs);
+ do_sig=math_emu_le(opcode, regs);
break;
case 0xb3:
get_user(*((__u16 *) (opcode+2)), location+1);
@@ -406,22 +315,15 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code)
do_sig = 1;
break;
}
- } else
- do_sig = 1;
- if (do_sig) {
- current->thread.error_code = error_code;
- current->thread.trap_no = 1;
- force_sig(SIGILL, current);
- die_if_no_fixup("illegal operation", regs, error_code);
}
+#endif
+ else
+ do_sig = 1;
+ if (do_sig)
+ do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
unlock_kernel();
}
-#else
-DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current)
-DO_ERROR(6, SIGILL, "specification exception", specification_exception, current)
-DO_ERROR(7, SIGILL, "data exception", data_exception, current)
-#endif /* CONFIG_IEEEFPU_EMULATION */
/* init is done in lowcore.S and head.S */
@@ -463,7 +365,7 @@ void handle_per_exception(struct pt_regs *regs)
/* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n");
- show_crashed_task_info();
+ show_regs(regs);
/* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK;
}
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index aa8b0e5da..40ae70e8c 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -2,11 +2,17 @@
# Makefile for s390-specific library files..
#
+ifdef SMP
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
+else
+.S.o:
+ $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
+endif
L_TARGET = lib.a
-L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o
+
+obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index ec3274487..012a95308 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -21,25 +21,30 @@
void __delay(unsigned long loops)
{
- __asm__ __volatile__(
- "0: ahi %0,-1\n"
- " jnm 0b"
- : /* no outputs */ : "r" (loops) );
+ /*
+ * To end the bloody studid and useless discussion about the
+ * BogoMips number I took the liberty to define the __delay
+ * function in a way that that resulting BogoMips number will
+ * yield the megahertz number of the cpu. The important function
+ * is udelay and that is done using the tod clock. -- martin.
+ */
+ __asm__ __volatile__(
+ "0: brct %0,0b"
+ : /* no outputs */ : "r" (loops/2) );
}
-inline void __const_udelay(unsigned long xloops)
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
{
+ uint64_t start_cc, end_cc;
- __asm__("LR 3,%1\n\t"
- "MR 2,%2\n\t"
- "LR %0,2\n\t"
- : "=r" (xloops)
- : "r" (xloops) , "r" (loops_per_sec)
- : "2" , "3");
- __delay(xloops);
+ if (usecs == 0)
+ return;
+ asm volatile ("STCK %0" : "=m" (start_cc));
+ do {
+ asm volatile ("STCK %0" : "=m" (end_cc));
+ } while (((end_cc - start_cc)/4096) < usecs);
}
-void __udelay(unsigned long usecs)
-{
- __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */
-}
diff --git a/arch/s390/lib/strcmp.S b/arch/s390/lib/strcmp.S
index d3f63942f..340edffb5 100644
--- a/arch/s390/lib/strcmp.S
+++ b/arch/s390/lib/strcmp.S
@@ -18,8 +18,8 @@ strcmp:
CLST 2,3
JO .-4
JE strcmp_equal
- IC 0,0(0,3)
- IC 1,0(0,2)
+ IC 0,0(3)
+ IC 1,0(2)
SR 1,0
strcmp_equal:
LR 2,1
diff --git a/arch/s390/lib/strncpy.S b/arch/s390/lib/strncpy.S
index 83578909c..3065be2b4 100644
--- a/arch/s390/lib/strncpy.S
+++ b/arch/s390/lib/strncpy.S
@@ -20,9 +20,9 @@ strncpy:
SR 0,0
strncpy_loop:
ICM 0,1,0(3) # ICM sets the cc, IC does not
- LA 3,1(0,3)
- STC 0,0(0,1)
- LA 1,1(0,1)
+ LA 3,1(3)
+ STC 0,0(1)
+ LA 1,1(1)
JZ strncpy_exit # ICM inserted a 0x00
BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0
strncpy_exit:
diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
new file mode 100644
index 000000000..8044d156d
--- /dev/null
+++ b/arch/s390/lib/uaccess.S
@@ -0,0 +1,51 @@
+/*
+ * arch/s390/lib/uaccess.S
+ * fixup routines for copy_{from|to}_user functions.
+ *
+ * s390
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ * These functions have a non-standard call interface
+ */
+
+#include <asm/lowcore.h>
+
+ .text
+ .align 4
+ .globl __copy_from_user_fixup
+__copy_from_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 3,-4096
+ sll 3,1
+ srl 3,1
+ n 3,__LC_TRANS_EXC_ADDR
+ sr 3,4
+ bm 4(1)
+1: mvcle 2,4,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
+ .align 4
+ .text
+ .globl __copy_to_user_fixup
+__copy_to_user_fixup:
+ l 1,__LC_PGM_OLD_PSW+4
+ sll 4,1
+ srl 4,1
+0: lhi 5,-4096
+ sll 5,1
+ srl 5,1
+ n 5,__LC_TRANS_EXC_ADDR
+ sr 5,4
+ bm 4(1)
+1: mvcle 4,2,0
+ b 4(1)
+ .section __ex_table,"a"
+ .long 1b,0b
+ .previous
+
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index cee7d4e6d..73e25bd30 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -8,6 +8,7 @@
# Note 2! The CFLAGS definition is now in the main makefile...
O_TARGET := mm.o
-O_OBJS := init.o fault.o ioremap.o extable.o
+
+obj-y := init.o fault.o ioremap.o extable.o
include $(TOPDIR)/Rules.make
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index f20a9d49e..2c75918af 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -9,6 +9,7 @@
* Copyright (C) 1995 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -26,6 +27,10 @@
#include <asm/pgtable.h>
#include <asm/hardirq.h>
+#ifdef CONFIG_SYSCTL
+extern int sysctl_userprocess_debug;
+#endif
+
extern void die(const char *,struct pt_regs *,long);
/*
@@ -48,6 +53,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
int write;
unsigned long psw_mask;
unsigned long psw_addr;
+ int si_code = SEGV_MAPERR;
+ int kernel_address = 0;
/*
* get psw mask of Program old psw to find out,
@@ -65,58 +72,106 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
address = S390_lowcore.trans_exc_code&0x7ffff000;
- if (in_irq())
- die("page fault from irq handler",regs,error_code);
-
tsk = current;
mm = tsk->mm;
+ if (in_interrupt() || !mm)
+ goto no_context;
+
+
+ /*
+ * Check which address space the address belongs to
+ */
+ switch (S390_lowcore.trans_exc_code & 3)
+ {
+ case 0: /* Primary Segment Table Descriptor */
+ kernel_address = 1;
+ goto no_context;
+
+ case 1: /* STD determined via access register */
+ if (S390_lowcore.exc_access_id == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
+ {
+ if (regs->acrs[S390_lowcore.exc_access_id] == 0)
+ {
+ kernel_address = 1;
+ goto no_context;
+ }
+ if (regs->acrs[S390_lowcore.exc_access_id] == 1)
+ {
+ /* user space address */
+ break;
+ }
+ }
+ die("page fault via unknown access register", regs, error_code);
+ break;
+
+ case 2: /* Secondary Segment Table Descriptor */
+ case 3: /* Home Segment Table Descriptor */
+ /* user space address */
+ break;
+ }
+
+
+ /*
+ * When we get here, the fault happened in the current
+ * task's user address space, so we search the VMAs
+ */
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
- if (!vma) {
- printk("no vma for address %lX\n",address);
+ if (!vma)
goto bad_area;
- }
if (vma->vm_start <= address)
goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN)) {
- printk("VM_GROWSDOWN not set, but address %lX \n",address);
- printk("not in vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (!(vma->vm_flags & VM_GROWSDOWN))
goto bad_area;
- }
- if (expand_stack(vma, address)) {
- printk("expand of vma failed address %lX\n",address);
- printk("vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (expand_stack(vma, address))
goto bad_area;
- }
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
write = 0;
+ si_code = SEGV_ACCERR;
+
switch (error_code & 0xFF) {
case 0x04: /* write, present*/
write = 1;
break;
case 0x10: /* not present*/
case 0x11: /* not present*/
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
- printk("flags %X of vma for address %lX wrong \n",
- vma->vm_flags,address);
- printk("vma %p (start %lX end %lX)\n",vma,
- vma->vm_start,vma->vm_end);
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
- }
break;
default:
printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);
goto bad_area;
}
- handle_mm_fault(tsk, vma, address, write);
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ switch (handle_mm_fault(mm, vma, address, write)) {
+ case 1:
+ tsk->min_flt++;
+ break;
+ case 2:
+ tsk->maj_flt++;
+ break;
+ case 0:
+ goto do_sigbus;
+ default:
+ goto out_of_memory;
+ }
up(&mm->mmap_sem);
return;
@@ -130,19 +185,32 @@ bad_area:
/* User mode accesses just cause a SIGSEGV */
if (psw_mask & PSW_PROBLEM_STATE) {
+ struct siginfo si;
tsk->thread.prot_addr = address;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 14;
-
+ tsk->thread.trap_no = error_code;
+#ifndef CONFIG_SYSCTL
+#ifdef CONFIG_PROCESS_DEBUG
printk("User process fault: interruption code 0x%lX\n",error_code);
printk("failing address: %lX\n",address);
- show_crashed_task_info();
- force_sig(SIGSEGV, tsk);
+ show_regs(regs);
+#endif
+#else
+ if (sysctl_userprocess_debug) {
+ printk("User process fault: interruption code 0x%lX\n",
+ error_code);
+ printk("failing address: %lX\n", address);
+ show_regs(regs);
+ }
+#endif
+ si.si_signo = SIGSEGV;
+ si.si_code = si_code;
+ si.si_addr = (void*) address;
+ force_sig_info(SIGSEGV, &si, tsk);
return;
}
+no_context:
/* Are we prepared to handle this kernel fault? */
-
if ((fixup = search_exception_table(regs->psw.addr)) != 0) {
regs->psw.addr = fixup;
return;
@@ -151,53 +219,47 @@ bad_area:
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
- *
- * First we check if it was the bootup rw-test, though..
*/
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+
+ if (kernel_address)
+ printk(KERN_ALERT "Unable to handle kernel pointer dereference"
+ " at virtual kernel address %08lx\n", address);
else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
+ printk(KERN_ALERT "Unable to handle kernel paging request"
+ " at virtual user address %08lx\n", address);
/*
* need to define, which information is useful here
*/
- lock_kernel();
die("Oops", regs, error_code);
do_exit(SIGKILL);
- unlock_kernel();
-}
-/*
- {
- char c;
- int i,j;
- char *addr;
- addr = ((char*) psw_addr)-0x20;
- for (i=0;i<16;i++) {
- if (i == 2)
- printk("\n");
- printk ("%08X: ",(unsigned long) addr);
- for (j=0;j<4;j++) {
- printk("%08X ",*(unsigned long*)addr);
- addr += 4;
- }
- addr -=0x10;
- printk(" | ");
- for (j=0;j<16;j++) {
- printk("%c",(c=*addr++) < 0x20 ? '.' : c );
- }
-
- printk("\n");
- }
- printk("\n");
- }
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
*/
+out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if (psw_mask & PSW_PROBLEM_STATE)
+ do_exit(SIGKILL);
+ goto no_context;
+do_sigbus:
+ up(&mm->mmap_sem);
+ /*
+ * Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ tsk->thread.prot_addr = address;
+ tsk->thread.trap_no = error_code;
+ force_sig(SIGBUS, tsk);
-
+ /* Kernel mode? Handle exceptions or die */
+ if (!(psw_mask & PSW_PROBLEM_STATE))
+ goto no_context;
+}
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 177e5e8f2..e1acfa063 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -52,10 +52,10 @@ static unsigned long totalram_pages;
* data and COW.
*/
-pgd_t swapper_pg_dir[512] __attribute__ ((__aligned__ (4096)));
-unsigned long empty_bad_page[1024] __attribute__ ((__aligned__ (4096)));
-unsigned long empty_zero_page[1024] __attribute__ ((__aligned__ (4096)));
-pte_t empty_bad_pte_table[1024] __attribute__ ((__aligned__ (4096)));
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE)));
static int test_access(unsigned long loc)
{
@@ -104,47 +104,6 @@ static inline void invalidate_page(pte_t *pte)
pte_clear(pte++);
}
-void __handle_bad_pmd(pmd_t *pmd)
-{
- pmd_ERROR(*pmd);
- pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table());
-}
-
-void __handle_bad_pmd_kernel(pmd_t *pmd)
-{
- pmd_ERROR(*pmd);
- pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table());
-}
-
-pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset)
-{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL);
- if (pmd_none(*pmd)) {
- if (pte) {
- invalidate_page(pte);
- pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte);
- pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024;
- pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048;
- pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072;
- return pte + offset;
- }
- pte = get_bad_pte_table();
- pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte);
- pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024;
- pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048;
- pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072;
- return NULL;
- }
- free_page((unsigned long)pte);
- if (pmd_bad(*pmd)) {
- __handle_bad_pmd_kernel(pmd);
- return NULL;
- }
- return (pte_t *) pmd_page(*pmd) + offset;
-}
-
pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
{
unsigned long pte;
@@ -167,10 +126,8 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
return NULL;
}
free_page(pte);
- if (pmd_bad(*pmd)) {
- __handle_bad_pmd(pmd);
- return NULL;
- }
+ if (pmd_bad(*pmd))
+ BUG();
return (pte_t *) pmd_page(*pmd) + offset;
}
@@ -180,7 +137,7 @@ int do_check_pgt_cache(int low, int high)
if(pgtable_cache_size > high) {
do {
if(pgd_quicklist)
- free_pgd_slow(get_pgd_fast()), freed++;
+ free_pgd_slow(get_pgd_fast()), freed += 2;
if(pmd_quicklist)
free_pmd_slow(get_pmd_fast()), freed++;
if(pte_quicklist)
@@ -245,6 +202,7 @@ void __init paging_init(void)
unsigned long address=0;
unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE);
+ static const int ssm_mask = 0x04000000L;
/* unmap whole virtual address space */
@@ -283,8 +241,9 @@ void __init paging_init(void)
/* enable virtual mapping in kernel mode */
__asm__ __volatile__(" LCTL 1,1,%0\n"
" LCTL 7,7,%0\n"
- " LCTL 13,13,%0"
- : :"m" (pgdir_k));
+ " LCTL 13,13,%0\n"
+ " SSM %1"
+ : : "m" (pgdir_k), "m" (ssm_mask));
local_flush_tlb();
@@ -378,6 +337,7 @@ void si_meminfo(struct sysinfo *val)
val->sharedram = 0;
val->freeram = nr_free_pages();
val->bufferram = atomic_read(&buffermem_pages);
+ val->totalhigh = 0;
+ val->freehigh = 0;
val->mem_unit = PAGE_SIZE;
- return;
}
diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c
index f9f0024c4..38acc4a22 100644
--- a/arch/s390/mm/ioremap.c
+++ b/arch/s390/mm/ioremap.c
@@ -33,8 +33,8 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned l
printk("remap_area_pte: page already exists\n");
BUG();
}
- set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT |
- _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
+ set_pte(pte, mk_pte_phys(phys_addr,
+ __pgprot(_PAGE_PRESENT | flags)));
address += PAGE_SIZE;
phys_addr += PAGE_SIZE;
pte++;
diff --git a/arch/s390/tools/dasdfmt/Makefile b/arch/s390/tools/dasdfmt/Makefile
index f63ff468b..b60641bbc 100644
--- a/arch/s390/tools/dasdfmt/Makefile
+++ b/arch/s390/tools/dasdfmt/Makefile
@@ -1,7 +1,7 @@
all: dasdfmt
dasdfmt: dasdfmt.c
- $(CROSS_COMPILE)gcc -o $@ $^
+ $(CC) -o $@ $^
$(STRIP) $@
clean:
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.8 b/arch/s390/tools/dasdfmt/dasdfmt.8
index b08244322..9e6a4e89e 100644
--- a/arch/s390/tools/dasdfmt/dasdfmt.8
+++ b/arch/s390/tools/dasdfmt/dasdfmt.8
@@ -3,8 +3,7 @@
.SH NAME
dasdfmt \- formatting of DSAD (ECKD) disk drives.
.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI]
- \fIdiskSpec\fR
+\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
.SH DESCRIPTION
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
@@ -25,6 +24,10 @@ Increases verbosity.
Start formatting without further user-confirmation.
.TP
+\fB-L\fR
+Omit the writing of a disk label after formatting.
+
+.TP
\fB-V\fR
Print version number and exit.
@@ -35,26 +38,17 @@ and always be a power of two. Due due some limitations in the driver,
it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
.TP
-\fIblockRange\fR
-This parameter specifies the number of the first and last block to be
-formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk
-is assumed. The \fIblockRange\fR can be specified in two different formats:
-.sp
- \fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR
-.br
-or
-.br
- \fB-r\fR \fIstartBlock\fR-\fIendBlock\fR
-.sp
-If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If
-\fIendBlock\fR is omitted, the last block of the disk is assumed.
+\fB-l\fR \fIdiskLabel\fR
+Specify the label to be written to disk after formatting. If no label is
+specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
+ASCII string and is automatically converted to EBCDIC.
.TP
\fIdiskSpec\fR
This parameter specified the device to be formatted. It also can be
given in two variants:
.sp
- \fB-f\fR \fB/dev/dd\fR\fIX\fR
+ \fB-f\fR \fB/dev/dasd\fR\fIX\fR
.br
or
.br
@@ -63,7 +57,7 @@ or
The first form uses the commonly used
.SM UNIX
device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the VM vdev number.
+The second form uses simply the device number.
.SH BUGS
None so far ;-)
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c
index 1726e7061..2820fc91d 100644
--- a/arch/s390/tools/dasdfmt/dasdfmt.c
+++ b/arch/s390/tools/dasdfmt/dasdfmt.c
@@ -12,6 +12,8 @@
* detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them
*/
+/* #define _LINUX_BLKDEV_H */
+
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
@@ -25,19 +27,25 @@
#include <string.h>
#include <dirent.h>
#include <mntent.h>
-#include "../../../drivers/s390/block/dasd.h" /* uses DASD_PARTN_BITS */
#define __KERNEL__ /* we want to use kdev_t and not have to define it */
#include <linux/kdev_t.h>
#undef __KERNEL__
+#include <linux/fs.h>
+#include <asm/dasd.h>
+#include <linux/hdreg.h>
+
#define EXIT_MISUSE 1
#define EXIT_BUSY 2
#define TEMPFILENAME "/tmp/ddfXXXXXX"
#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */
-#define IOCTL_COMMAND 'D' << 8
#define SLASHDEV "/dev/"
#define PROC_DASD_DEVICES "/proc/dasd/devices"
+/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
+#define PROC_MOUNTS _PATH_MOUNTED
+#define PROC_SWAPS "/proc/swaps"
#define DASD_DRIVER_NAME "dasd"
+#define LABEL_LENGTH 10
#define PROC_LINE_LENGTH 80
#define ERR_LENGTH 80
@@ -66,24 +74,108 @@
ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
"is in invalid format\n",prog_name);}
-typedef struct {
- int start_unit;
- int stop_unit;
- int blksize;
-} format_data_t;
-
-char prog_name[]="dasd_format";
+char *prog_name;/*="dasdfmt";*/
char tempfilename[]=TEMPFILENAME;
+__u8 _ascebc[256] =
+{
+ /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ /* ->NL */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN EM SUB ESC FS GS RS US */
+ /* ->IGS ->IRS ->IUS */
+ 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0 sz */
+ 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+ 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+void convert_label(char *str)
+{
+ int i;
+ for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
+}
+
void
exit_usage(int exitcode)
{
- printf("Usage: %s [-htvyV] [-b blocksize] <range> <diskspec>\n\n",
- prog_name);
- printf(" where <range> is either\n");
- printf(" -s start_track -e end_track\n");
+#ifdef RANGE_FORMATTING
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+ "<diskspec>\n\n",prog_name);
+#else /* RANGE_FORMATTING */
+ printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+ "<diskspec>\n\n",prog_name);
+#endif /* RANGE_FORMATTING */
+ printf(" -t means testmode\n");
+ printf(" -v means verbose mode\n");
+ printf(" -V means print version\n");
+ printf(" -L means don't write disk label\n");
+ printf(" <label> is a label which is converted to EBCDIC and " \
+ "written to disk\n");
+ printf(" <blocksize> has to be power of 2 and at least 512\n");
+#ifdef RANGE_FORMATTING
+ printf(" <range> is either\n");
+ printf(" -s <start_track> -e <end_track>\n");
printf(" or\n");
- printf(" -r start_track-end_track\n");
+ printf(" -r <start_track>-<end_track>\n");
+#endif /* RANGE_FORMATTING */
printf(" and <diskspec> is either\n");
printf(" -f /dev/dasdX\n");
printf(" or\n");
@@ -106,9 +198,9 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
PROC_DASD_DEVICES ": %s (do you have the /proc " \
"filesystem enabled?)\n",prog_name,strerror(errno));
- fgets(line,sizeof(line),file); /* omit first line */
+ /* fgets(line,sizeof(line),file); omit first line */
while (fgets(line,sizeof(line),file)!=NULL) {
- rc=sscanf(line,"%X%d%d",&d,&ma_i,&mi_i);
+ rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
ma=ma_i;
mi=mi_i;
if ( (rc==3) &&
@@ -253,6 +345,7 @@ ask_user_for_data(format_data_t params)
char *str;
char output[60],o2[12];
+#ifdef RANGE_FORMATTING
i=params.start_unit;
do {
params.start_unit=i;
@@ -284,6 +377,7 @@ ask_user_for_data(format_data_t params)
ASK_CHECK_PARAM(CHECK_END);
}
} while (rc!=1);
+#endif /* RANGE_FORMATTING */
i=params.blksize;
do {
@@ -320,8 +414,8 @@ check_mounted(int major, int minor)
/*
* first, check filesystems
*/
- if (!(f = fopen(_PATH_MOUNTED, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", _PATH_MOUNTED,
+ if (!(f = fopen(PROC_MOUNTS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
strerror(errno));
while ((ment = getmntent(f))) {
if (stat(ment->mnt_fsname, &stbuf) == 0)
@@ -337,8 +431,8 @@ check_mounted(int major, int minor)
/*
* second, check active swap spaces
*/
- if (!(f = fopen("/proc/swaps", "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "/proc/swaps: %s", strerror(errno));
+ if (!(f = fopen(PROC_SWAPS, "r")))
+ ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
/*
* skip header line
*/
@@ -362,12 +456,15 @@ check_mounted(int major, int minor)
void
do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
- int verbosity,int withoutprompt)
+ int verbosity,int writenolabel,int labelspec,
+ char *label,int withoutprompt,int devno)
{
int fd,rc;
struct stat stat_buf;
kdev_t minor_no,major_no;
- int devno;
+ int new_blksize;
+ unsigned int label_position;
+ struct hd_geometry new_geometry;
char inp_buffer[5]; /* to contain yes */
fd=open(dev_name,O_RDWR);
@@ -390,6 +487,10 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
minor_no=MINOR(stat_buf.st_rdev);
}
check_mounted(major_no, minor_no);
+
+ if ((!writenolabel) && (!labelspec)) {
+ sprintf(label,"LNX1 x%04x",devno);
+ }
if ( ((withoutprompt)&&(verbosity>=1)) ||
(!withoutprompt) ) {
@@ -400,6 +501,11 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
printf(" Device number of device : 0x%x\n",devno);
printf(" Major number of device : %u\n",major_no);
printf(" Minor number of device : %u\n",minor_no);
+ printf(" Labelling device : %s\n",(writenolabel)?
+ "no":"yes");
+ if (!writenolabel)
+ printf(" Disk label : %s\n",label);
+#ifdef RANGE_FORMATTING
printf(" Start track : %d\n" \
,format_params.start_unit);
printf(" End track : ");
@@ -407,6 +513,7 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
printf("last track of disk\n");
else
printf("%d\n",format_params.stop_unit);
+#endif /* RANGE_FORMATTING */
printf(" Blocksize : %d\n" \
,format_params.blksize);
if (testmode) printf("Test mode active, omitting ioctl.\n");
@@ -416,8 +523,8 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
if (!withoutprompt) {
printf("\n--->> ATTENTION! <<---\n");
printf("All data in the specified range of that " \
- "device will be lost.\nType yes to continue" \
- ", no will leave the disk untouched: ");
+ "device will be lost.\nType \"yes\" to " \
+ "continue, no will leave the disk untouched: ");
fgets(inp_buffer,sizeof(inp_buffer),stdin);
if (strcasecmp(inp_buffer,"yes") &&
strcasecmp(inp_buffer,"yes\n")) {
@@ -430,13 +537,70 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
if ( !( (withoutprompt)&&(verbosity<1) ))
printf("Formatting the device. This may take a " \
"while (get yourself a coffee).\n");
- rc=ioctl(fd,IOCTL_COMMAND,format_params);
+ rc=ioctl(fd,BIODASDFORMAT,format_params);
if (rc)
ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
"returned with the following error " \
"message:\n%s\n",prog_name,strerror(errno));
printf("Finished formatting the device.\n");
+ if (!writenolabel) {
+ if (verbosity>0)
+ printf("Retrieving disk geometry... ");
+
+ rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get geometry " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+
+ rc=ioctl(fd,BLKGETSIZE,&new_blksize);
+ if (rc) {
+ ERRMSG("%s: the ioctl call to get blocksize " \
+ "returned with the following error " \
+ "message:\n%s\n",prog_name,
+ strerror(errno));
+ goto reread;
+ }
+
+ if (verbosity>0) printf("done\n");
+
+ label_position=new_geometry.start*new_blksize;
+
+ if (verbosity>0) printf("Writing label... ");
+ convert_label(label);
+ rc=lseek(fd,label_position,SEEK_SET);
+ if (rc!=label_position) {
+ ERRMSG("%s: lseek on the device to %i " \
+ "failed with the following error " \
+ "message:\n%s\n",prog_name,
+ label_position,strerror(errno));
+ goto reread;
+ }
+ rc=write(fd,label,LABEL_LENGTH);
+ if (rc!=LABEL_LENGTH) {
+ ERRMSG("%s: writing the label only wrote %d " \
+ "bytes.\n",prog_name,rc);
+ goto reread;
+ }
+
+ sync();
+ sync();
+
+ if (verbosity>0) printf("done\n");
+ }
+ reread:
+ printf("Rereading the partition table... ");
+ rc=ioctl(fd,BLKRRPART,NULL);
+ if (rc) {
+ ERRMSG("%s: error during rereading the partition " \
+ "table: %s.\n",prog_name,strerror(errno));
+ } else printf("done.\n");
+
break;
}
@@ -452,11 +616,13 @@ int main(int argc,char *argv[]) {
int verbosity;
int testmode;
int withoutprompt;
+ int writenolabel,labelspec;
char *dev_name;
int devno;
char *dev_filename,*devno_param_str,*range_param_str;
char *start_param_str,*end_param_str,*blksize_param_str;
+ char label[LABEL_LENGTH+1];
format_data_t format_params;
@@ -465,23 +631,30 @@ int main(int argc,char *argv[]) {
char *endptr;
char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
- int i1,i2;
+ int i,i1,i2;
char *str;
int start_specified,end_specified,blksize_specified;
int devfile_specified,devno_specified,range_specified;
/******************* initialization ********************/
+ prog_name=argv[0];
endptr=NULL;
/* set default values */
- format_params.start_unit=0;
- format_params.stop_unit=-1;
- format_params.blksize=4096;
+ format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
+ format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
+ format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
+ format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
testmode=0;
verbosity=0;
withoutprompt=0;
+ writenolabel=0;
+ labelspec=0;
+ for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
+ label[LABEL_LENGTH]=0;
+
start_specified=end_specified=blksize_specified=0;
devfile_specified=devno_specified=range_specified=0;
@@ -490,7 +663,10 @@ int main(int argc,char *argv[]) {
/* avoid error message generated by getopt */
opterr=0;
- while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) {
+#ifdef RANGE_FORMATTING
+ while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+#endif /* RANGE_FORMATTING */
+ while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
switch (oc) {
case 'y':
withoutprompt=1;
@@ -515,6 +691,18 @@ int main(int argc,char *argv[]) {
printf("%s version 0.99\n",prog_name);
exit(0);
+ case 'l':
+ strncpy(label,optarg,LABEL_LENGTH);
+ if (strlen(optarg)<LABEL_LENGTH)
+ label[strlen(optarg)]=' ';
+ labelspec++;
+ break;
+
+ case 'L':
+ writenolabel++;
+ break;
+
+#ifdef RANGE_FORMATTING
case 's' :
start_param_str=optarg;
start_specified++;
@@ -525,6 +713,12 @@ int main(int argc,char *argv[]) {
end_specified++;
break;
+ case 'r' :
+ range_param_str=optarg;
+ range_specified++;
+ break;
+#endif /* RANGE_FORMATTING */
+
case 'b' :
blksize_param_str=optarg;
blksize_specified++;
@@ -539,10 +733,6 @@ int main(int argc,char *argv[]) {
dev_filename=optarg;
devfile_specified++;
break;
- case 'r' :
- range_param_str=optarg;
- range_specified++;
- break;
}
}
@@ -594,6 +784,8 @@ int main(int argc,char *argv[]) {
CHECK_SPEC_MAX_ONCE(start_specified,"start track");
CHECK_SPEC_MAX_ONCE(end_specified,"end track");
CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+ CHECK_SPEC_MAX_ONCE(labelspec,"label");
+ CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
if (devno_specified)
PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
@@ -616,9 +808,9 @@ int main(int argc,char *argv[]) {
str=check_param(CHECK_ALL,format_params);
if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
- /*************** issue the real command *****************/
+ /******* issue the real command and reread part table *******/
do_format_dasd(dev_name,format_params,testmode,verbosity,
- withoutprompt);
+ writenolabel,labelspec,label,withoutprompt,devno);
/*************** cleanup ********************************/
if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
diff --git a/arch/s390/tools/silo/Makefile b/arch/s390/tools/silo/Makefile
index fb100e1b9..62b11d7da 100644
--- a/arch/s390/tools/silo/Makefile
+++ b/arch/s390/tools/silo/Makefile
@@ -1,13 +1,13 @@
all: silo
silo.o: silo.c
- $(CROSS_COMPILE)gcc -c -o silo.o -O2 silo.c
+ $(CC) -c -o silo.o -O2 silo.c
cfg.o: cfg.c
- $(CROSS_COMPILE)gcc -c -o cfg.o -O2 cfg.c
+ $(CC) -c -o cfg.o -O2 cfg.c
silo: silo.o cfg.o
- $(CROSS_COMPILE)gcc -o $@ $^
+ $(CC) -o $@ $^
$(STRIP) $@
clean:
diff --git a/arch/s390/tools/silo/silo.c b/arch/s390/tools/silo/silo.c
index 827082f5c..9ac04ac2b 100644
--- a/arch/s390/tools/silo/silo.c
+++ b/arch/s390/tools/silo/silo.c
@@ -45,7 +45,7 @@ CONFIG cf_options[] = {
/* from dasd.h */
#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',5,int)
+#define BIODASDRWTB _IOWR('D',0,int)
/* end */
#define SILO_CFG "/etc/silo.conf"
@@ -554,7 +554,7 @@ int
main (int argct, char *argv[])
{
int rc = 0;
- char *save;
+ char *save=NULL;
char *tmpdir=getenv("TMPDIR");
if (tmpdir) {
NTRY( save=(char*)malloc(strlen(tmpdir)));
diff --git a/arch/s390/vmlinux.lds b/arch/s390/vmlinux.lds
index b1b556d14..4d93bcc7a 100644
--- a/arch/s390/vmlinux.lds
+++ b/arch/s390/vmlinux.lds
@@ -26,6 +26,10 @@ SECTIONS
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
+ __start___kallsyms = .; /* All kernel symbols */
+ __kallsyms : { *(__kallsyms) }
+ __stop___kallsyms = .;
+
_etext = .; /* End of text section */
.data : { /* Data */