From 167b5dd21394f926b93ba5abc70925166aecc1a1 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:22:47 -0500 Subject: [PATCH] Linux 2.2.18pre21 o Environment controller update for sparc (Eric Brower) o No italian translation for config.help (Andrea Ferraris) o Fix type error in buz driver (Pete Zaitcev) o Resnchronize Apple PowerMac codebase (Paul Mackerras & co) o Merge powermac tree fixes into usb o Powermac input device handling changes o Fix console switch fonts o S/390 merge (IBM S/390 folks) (Merge grunt work done by Kurt Roeckx) o Make knfsd TCP an option (Alan Cox) o Drop cisco info packets (0x2000) (Ivan Passos) o Add belkin USB serial cable (William Greathouse) --- CREDITS | 9 + Documentation/Configure.help | 4 +- Documentation/s390/xpram.txt | 133 + Documentation/usb/usb-serial.txt | 31 + Makefile | 6 +- arch/i386/kernel/smp.c | 27 +- arch/ppc/boot/Makefile | 2 +- arch/ppc/boot/vreset.c | 2 +- arch/ppc/coffboot/Makefile | 11 +- arch/ppc/coffboot/chrpmain.c | 63 +- arch/ppc/config.in | 39 +- arch/ppc/kernel/Makefile | 42 +- arch/ppc/kernel/apus_setup.c | 2 +- arch/ppc/kernel/chrp_pci.c | 3 +- arch/ppc/kernel/chrp_setup.c | 97 +- arch/ppc/kernel/chrp_time.c | 5 +- arch/ppc/kernel/feature.c | 557 +++- arch/ppc/kernel/gemini_setup.c | 17 +- arch/ppc/kernel/head.S | 243 +- arch/ppc/kernel/irq.c | 48 +- arch/ppc/kernel/mbx_pci.c | 2 + arch/ppc/kernel/mbx_setup.c | 17 +- arch/ppc/kernel/misc.S | 260 +- arch/ppc/kernel/open_pic.c | 124 +- arch/ppc/kernel/open_pic.h | 1 + arch/ppc/kernel/openpic.c | 93 +- arch/ppc/kernel/pci.c | 158 + arch/ppc/kernel/pmac_pci.c | 169 +- arch/ppc/kernel/pmac_pic.c | 92 +- arch/ppc/kernel/pmac_setup.c | 146 +- arch/ppc/kernel/pmac_support.c | 151 +- arch/ppc/kernel/pmac_time.c | 22 +- arch/ppc/kernel/ppc_htab.c | 5 +- arch/ppc/kernel/ppc_ksyms.c | 52 +- arch/ppc/kernel/prep_pci.c | 18 +- arch/ppc/kernel/prep_setup.c | 20 +- arch/ppc/kernel/process.c | 2 +- arch/ppc/kernel/prom.c | 159 +- arch/ppc/kernel/setup.c | 42 +- arch/ppc/kernel/signal.c | 223 +- arch/ppc/kernel/sleep.S | 78 +- arch/ppc/kernel/smp.c | 203 +- arch/ppc/kernel/syscalls.c | 11 + arch/ppc/kernel/time.c | 14 +- arch/ppc/kernel/traps.c | 51 +- arch/ppc/mm/extable.c | 41 +- arch/ppc/mm/init.c | 15 +- arch/ppc/xmon/start.c | 12 + arch/ppc/xmon/xmon.c | 5 + arch/s390/boot/ipleckd.S | 22 +- arch/s390/config.in | 1 + arch/s390/defconfig | 3 +- arch/s390/kernel/cpcmd.c | 2 +- arch/s390/kernel/debug.c | 1369 +++++++-- arch/s390/kernel/entry.S | 77 +- arch/s390/kernel/head.S | 47 +- arch/s390/kernel/irq.c | 29 +- arch/s390/kernel/mathemu.c | 485 +-- arch/s390/kernel/process.c | 116 +- arch/s390/kernel/ptrace.c | 18 +- arch/s390/kernel/s390_ext.c | 6 +- arch/s390/kernel/s390_ksyms.c | 25 +- arch/s390/kernel/s390dyn.c | 2 +- arch/s390/kernel/s390fpu.c | 5 + arch/s390/kernel/s390io.c | 1149 ++++--- arch/s390/kernel/s390mach.c | 53 +- arch/s390/kernel/setup.c | 8 +- arch/s390/kernel/signal.c | 63 +- arch/s390/kernel/smp.c | 27 +- arch/s390/kernel/traps.c | 273 +- arch/s390/lib/Makefile | 2 +- arch/s390/lib/delay.c | 2 +- arch/s390/lib/uaccess.S | 51 + arch/s390/mm/fault.c | 72 +- arch/s390/mm/init.c | 5 +- arch/s390/tools/dasdfmt/dasdfmt.8 | 114 +- arch/s390/tools/dasdfmt/dasdfmt.c | 14 +- arch/s390/tools/hwc/Makefile | 12 + .../{hwc_cntl_key => hwc}/hwc_cntl_key.c | 0 arch/s390/tools/hwc/hwc_measure.c | 79 + arch/s390/tools/hwc_cntl_key/Makefile | 11 - arch/s390/tools/silo/silo.c | 26 +- arch/sparc64/kernel/ioctl32.c | 3 +- drivers/Makefile | 2 +- drivers/block/Config.in | 2 +- drivers/block/genhd.c | 130 +- drivers/block/ide-pmac.c | 286 +- drivers/block/rd.c | 2 + drivers/char/Config.in | 2 +- drivers/char/buz.c | 22 +- drivers/char/console.c | 6 +- drivers/char/keyboard.c | 4 +- drivers/char/mem.c | 12 - drivers/char/misc.c | 2 +- drivers/char/tty_io.c | 5 + drivers/macintosh/Makefile | 20 +- drivers/macintosh/adb.c | 19 +- drivers/macintosh/adbhid.c | 875 ++++++ drivers/macintosh/mac_hid.c | 492 +++ drivers/macintosh/mac_keyb.c | 120 +- drivers/macintosh/macserial.c | 130 +- drivers/macintosh/macserial.h | 1 + drivers/macintosh/mediabay.c | 13 +- drivers/macintosh/nvram.c | 27 +- drivers/macintosh/via-pmu.c | 652 ++-- drivers/net/bmac.c | 10 +- drivers/net/de4x5.c | 4 +- drivers/net/gmac.c | 314 +- drivers/net/gmac.h | 34 +- drivers/net/hdlc.c | 8 +- drivers/s390/Config.in | 2 +- drivers/s390/Makefile | 8 +- drivers/s390/block/Makefile | 2 +- drivers/s390/block/dasd.c | 923 +++--- drivers/s390/block/dasd.h | 3 +- drivers/s390/block/dasd_3990_erp.c | 19 +- drivers/s390/block/dasd_diag.c | 65 +- drivers/s390/block/dasd_eckd.c | 564 ++-- drivers/s390/block/dasd_fba.c | 66 +- drivers/s390/block/xpram.c | 2 +- drivers/s390/ccwcache.c | 40 +- drivers/s390/char/con3215.c | 189 +- drivers/s390/char/hwc.h | 86 +- drivers/s390/char/hwc_con.c | 46 +- drivers/s390/char/hwc_rw.c | 1412 ++++----- drivers/s390/char/hwc_rw.h | 22 +- drivers/s390/char/hwc_tty.c | 88 +- drivers/s390/idals.c | 79 + drivers/s390/net/Makefile | 4 + drivers/s390/net/ctc.c | 2627 ++++++++++------- drivers/s390/net/iucv.c | 9 +- drivers/sbus/char/envctrl.c | 135 +- drivers/sound/awacs_defs.h | 10 +- drivers/sound/dmasound.c | 45 +- drivers/usb/Config.in | 1 + drivers/usb/keybdev.c | 61 +- drivers/usb/serial/Makefile | 1 + drivers/usb/serial/belkin_sa.c | 561 ++++ drivers/usb/serial/belkin_sa.h | 113 + drivers/usb/usb-ohci.c | 110 +- drivers/usb/usb-ohci.h | 1 + drivers/video/aty128.h | 45 +- drivers/video/aty128fb.c | 223 +- drivers/video/atyfb.c | 52 +- drivers/video/chipsfb.c | 9 +- drivers/video/offb.c | 29 +- fs/Config.in | 1 + fs/nfsd/nfssvc.c | 2 + fs/proc/array.c | 12 +- include/asm-ppc/backlight.h | 28 + include/asm-ppc/delay.h | 32 +- include/asm-ppc/dma.h | 2 + include/asm-ppc/feature.h | 23 + include/asm-ppc/heathrow.h | 6 + include/asm-ppc/irq.h | 2 - include/asm-ppc/keyboard.h | 4 +- include/asm-ppc/keylargo.h | 119 + include/asm-ppc/machdep.h | 10 +- include/asm-ppc/nvram.h | 13 +- include/asm-ppc/pci-bridge.h | 18 + include/asm-ppc/pci.h | 13 + include/asm-ppc/pmu.h | 56 +- include/asm-ppc/processor.h | 9 + include/asm-ppc/system.h | 11 +- include/asm-ppc/uaccess.h | 2 +- include/asm-ppc/ucontext.h | 1 + include/asm-ppc/uninorth.h | 83 + include/asm-ppc/unistd.h | 8 +- include/asm-s390/atomic.h | 85 +- include/asm-s390/bitops.h | 20 +- include/asm-s390/ccwcache.h | 15 +- include/asm-s390/checksum.h | 23 +- include/asm-s390/dasd.h | 5 +- include/asm-s390/debug.h | 157 +- include/asm-s390/idals.h | 25 + include/asm-s390/irq.h | 378 +-- include/asm-s390/lowcore.h | 2 +- include/asm-s390/mathemu.h | 15 +- include/asm-s390/pgtable.h | 8 +- include/asm-s390/processor.h | 2 +- include/asm-s390/ptrace.h | 8 +- include/asm-s390/s390-regs-common.h | 6 +- include/asm-s390/s390dyn.h | 2 +- include/asm-s390/s390io.h | 2 +- include/asm-s390/s390mach.h | 7 +- include/asm-s390/sigcontext.h | 38 +- include/asm-s390/sigp.h | 10 + include/asm-s390/spinlock.h | 4 +- include/asm-s390/system.h | 17 +- include/asm-s390/termios.h | 2 +- include/asm-s390/uaccess.h | 218 +- include/asm-s390/unistd.h | 2 +- include/asm-sparc64/envctrl.h | 3 +- include/linux/genhd.h | 12 + include/linux/input.h | 28 +- include/linux/openpic.h | 1 + include/linux/pci.h | 21 + include/linux/sysctl.h | 14 +- init/main.c | 8 + kernel/sysctl.c | 15 +- scripts/Lindent | 2 + 201 files changed, 14075 insertions(+), 6079 deletions(-) create mode 100644 Documentation/s390/xpram.txt create mode 100644 arch/s390/lib/uaccess.S create mode 100644 arch/s390/tools/hwc/Makefile rename arch/s390/tools/{hwc_cntl_key => hwc}/hwc_cntl_key.c (100%) create mode 100644 arch/s390/tools/hwc/hwc_measure.c delete mode 100644 arch/s390/tools/hwc_cntl_key/Makefile create mode 100644 drivers/macintosh/adbhid.c create mode 100644 drivers/macintosh/mac_hid.c create mode 100644 drivers/s390/idals.c create mode 100644 drivers/usb/serial/belkin_sa.c create mode 100644 drivers/usb/serial/belkin_sa.h create mode 100644 include/asm-ppc/backlight.h create mode 100644 include/asm-ppc/keylargo.h create mode 100644 include/asm-ppc/pci.h create mode 100644 include/asm-ppc/uninorth.h create mode 100644 include/asm-s390/idals.h create mode 100644 scripts/Lindent diff --git a/CREDITS b/CREDITS index 285986308b3c..54b012ba7ea1 100644 --- a/CREDITS +++ b/CREDITS @@ -763,6 +763,15 @@ S: 8124 Constitution Apt. 7 S: Sterling Heights, Michigan 48313 S: USA +N: William Greathouse +E: wgreathouse@smva.com +E: wgreathouse@myfavoritei.com +D: Current Belkin USB Serial Adapter F5U103 hacker +D: Kernel hacker, embedded systems +S: 7802 Fitzwater Road +S: Brecksville, OH 44141-1334 +S: USA + N: Tristan Greaves E: Tristan.Greaves@icl.com E: tmg296@ecs.soton.ac.uk diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 88eb5d379d92..042c3726d85c 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -13,8 +13,6 @@ # http://www.traduc.org/kernelfr # - Spanish, by Carlos Perelló Marín (fperllo@ehome.encis.es), at # http://visar.csustan.edu/~carlos/ -# - Italian, by Alessandro Rubini (rubini@linux.it), at -# ftp://ftp-pavia1.linux.it/pub/linux/Configure.help # - Polish, by Cezar Cichocki (cezar@cs.net.pl), at # http://www.cs.net.pl/~cezar/Kernel # - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder @@ -13518,7 +13516,7 @@ CONFIG_DISPLAY7SEG # # LocalWords: CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab # LocalWords: unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz -# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd +# LocalWords: cdrom diskless netboot nfs xzvf ATAPI MB ide pavia pl pd # LocalWords: HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN # LocalWords: ISA EISA Microchannel VESA BIOSes IPC SYSVIPC ipc Ctrl dmesg hlt # LocalWords: BINFMT Linkable http ac uk jo html GCC SPARC AVANTI CABRIOLET EB diff --git a/Documentation/s390/xpram.txt b/Documentation/s390/xpram.txt new file mode 100644 index 000000000000..8693be48508e --- /dev/null +++ b/Documentation/s390/xpram.txt @@ -0,0 +1,133 @@ +XPRAM +===== + +The S/390 architecture supports more RAM than can be accessed as main memory. +The LINUX for S/390 main memory is limited to 2 GB. However, additional +memory can be declared as expanded storage. The S/390 architecture allows +applications to access up to 16 TB of expanded storage (although the current +hardware can only be equipped with up to 32 GB memory). Memory in the +expanded storage range can be copied in 4 KB blocks to, or from, the main +memory. + +An interesting feature of expanded storage is that is persistent with respect +to IPLs (booting) but volatile with respect to IMLs (power off/on). + +The XPRAM device driver is a block device driver that supports LINUX for S/390 +allowing it to access the expanded storage. Thus XPRAM can be used as a basis +for fast swap devices and/or fast file systems. + +Features +++++++++ +XPRAM automatically detects whether expanded storage is available on the +system. The expanded storage can be subdivided into up to 32 partitions, the +default being a single partition. The XPRAM device driver has major number 35. +The partitions have minor numbers 0 through 31. The hard sector size of XPRAM +is set to 4096 bytes. + +Limitations ++++++++++++ +If expanded storage is not available, XPRAM cannot be used. Its initialization +fails gracefully with a log message reporting the lack of expanded storage. + +Configuration option +++++++++++++++++++++ + +CONFIG_XPRAM + +Module name ++++++++++++ + +XPRAM can be used as module. Its moduel name is xpram.o. + +Kernel parameter syntax ++++++++++++++++++++++++ +The kernel parameter is optional. The default defines the whole expanded +storage to be one partition. + +xpram_parts=[,[,...]] + +where defines how many partitions the expanded storage +is split into. The i-th defines the size of the i-th +partition. + +The syntax for sizes is: + +[0x][k|K|m|M|g|G] + +If the 0x prefix is used the subsequent number is interpreted as a hexadecimal +value, otherwise it is interpreted as a decimal value (default). The +non-negative_integer value may be followed by a magnitude: + +- k or K for kilo (1024) is the default +- m or M for Mega (1024*1024) +- g or G for Giga (1024*1024*1024) + +The value multiplied by its magnitude defines the +partition's size in bytes. The default size is 0. + +Any partition defined with a non-zero size is allocated the amount of memory +specified by its non-negative_integer parameter. + +You can automatically allocate the remaining memory between a set of partitions +by specifying zero for the size of each partition in the set. The following +formula is used to calculate the size for each of these partitions: + + (available exp. storage - sum of all non-zero sizes specified) +computed size = -------------------------------------------------------------- + number of partitions with zero sizes + +This formula is only a good approximation of the actual size allocated to each +partition. Because of the requirement to assign blocks in multiples of 4K, +partitions can be larger or smaller than the estimate produced by the +calculation. In addition, there might be an amount of memory left as a "guard +space" between two partitions. + +Example +------- + +xpram_parts=4,0x800M,0,0,0x1000M + +This allocates the extended storage into four partitions. Partition 1 has 2 GB, +partition 4 has x 4 GB, and partitions 2 and 3 use equal parts of the remaining +storage. If the total amount of extended storage was 16 GB, then partitions 3 +and 4 would each have approximately 5 GB. + +Module parameter syntax ++++++++++++++++++++++++ +XPRAM may be used as module. The syntax of the module parameters passed to +insmod differs from the kernel parameter syntax: + +[devs= [sizes=[,,...]]] + +where: +- number_of_devices is used to define the number of partitions. +- size is a non-negative integer that defines the partition's size. + Only decimal values are allowed and no magnitudes are accepted. + The size will be interpretedin KB. + +Example +------- + +devs=4 sizes=2097152,8388608,4194304,2097152 + +This allocates a total of 16 GB of extended storage into four partitions, of +(respectively) size 2 GB, 8 GB, 4 GB, and 2 GB. + +Usage ++++++ + +XPRAM is a block device driver with major 35. +Using the standard naming scheme (see devices.txt) the partitions of XPRAM +can be accessed through /dev/slram0, ... , /dev/slram31. + +XPRAM does not require any formatting. Partitioning is only possible during +device initialization by kernel or module parameters. Note that if both the +expanded storage and the partitioning parameters are left unchanged between +two device initializations (even if LINUX was IPLed in the meantime) then +XPRAM behaves like a persistent storage. This is not true if the system is +IMLed. + +You can make a files system on a XPRAM partition (e.g. mke2fs) with a block +size that is a multiple of 4096 byte and mount this file system. + +Alternativly an XPRAM partition can be used as a swap device (mkswap, swapon). \ No newline at end of file diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index 4ffe021a7404..a6efeefa57d1 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -151,6 +151,37 @@ Digi AccelePort Driver driver. +Belkin USB Serial Adapter F5U103 + + Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. + +Current status: + The following have been tested and work: + Baud rate 300-230400 + Data bits 5-8 + Stop bits 1-2 + Parity N,E,O,M,S + Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)* + Break Set and clear + Line contrl Input/Output query and control ** + + * Hardware input flow control is only enabled for firmware + levels above 2.06. Read source code comments describing Belkin + firmware errata. Hardware output flow control is working for all + firmware versions. + ** Queries of inputs (CTS,DSR,CD,RI) show the last + reported state. Queries of outputs (DTR,RTS) show the last + requested state and may not reflect current state as set by + automatic hardware flow control. + +TO DO List: + -- Add true modem contol line query capability. Currently tracks the + states reported by the interrupt and the states requested. + -- Add error reporting back to application for UART error conditions. + -- Add support for flush ioctls. + -- Add everything else that is missing :) + + Generic Serial driver If your device is not one of the above listed devices, compatible with diff --git a/Makefile b/Makefile index b84d817a1492..2e646ce411b9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 18 -EXTRAVERSION = pre20 +EXTRAVERSION = pre21 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) @@ -170,8 +170,8 @@ ifeq ($(CONFIG_NET_FC),y) DRIVERS := $(DRIVERS) drivers/net/fc/fc.a endif -ifdef CONFIG_PPC -DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a +ifdef CONFIG_POWERMAC +DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.o endif ifdef CONFIG_PNP diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index cbc09a5a5972..004ada11f9fb 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -364,13 +364,20 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) (struct mpc_config_ioapic *)mpt; if (m->mpc_flags&MPC_APIC_USABLE) { - ioapics++; - printk("I/O APIC #%d Version %d at 0x%lX.\n", - m->mpc_apicid,m->mpc_apicver, - m->mpc_apicaddr); - mp_apics [mp_apic_entries] = *m; - if (++mp_apic_entries > MAX_IO_APICS) - --mp_apic_entries; + if(m->mpc_apicaddr == 0) + { + printk(KERN_ERR "Error - Non MP compliant BIOS. Skipping invalid io-apic!\n"); + } + else + { + ioapics++; + printk("I/O APIC #%d Version %d at 0x%lX.\n", + m->mpc_apicid,m->mpc_apicver, + m->mpc_apicaddr); + mp_apics [mp_apic_entries] = *m; + if (++mp_apic_entries > MAX_IO_APICS) + --mp_apic_entries; + } } mpt+=sizeof(*m); count+=sizeof(*m); @@ -408,6 +415,12 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) printk("Warning: switching to non APIC mode.\n"); skip_ioapic_setup=1; } + if (ioapics == 0) + { + printk("Warning: BIOS table gives no I/O APIC.\n"); + printk("Warning: switching to non APIC mode.\n"); + skip_ioapic_setup=1; + } return num_processors; } diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile index 7152bace7c44..5febfc31cea1 100644 --- a/arch/ppc/boot/Makefile +++ b/arch/ppc/boot/Makefile @@ -10,7 +10,7 @@ # modified by Cort (cort@cs.nmt.edu) # .c.s: - $(CC) $(CFLAGS) -S -o $*.s $< + $(CC) $(CFLAGS) -I$(HPATH) -S -o $*.s $< .s.o: $(AS) -o $*.o $< .c.o: diff --git a/arch/ppc/boot/vreset.c b/arch/ppc/boot/vreset.c index c01361dc6721..bd44cd9d71e4 100644 --- a/arch/ppc/boot/vreset.c +++ b/arch/ppc/boot/vreset.c @@ -24,7 +24,7 @@ extern char *vidmem; extern int lines, cols; /* estimate for delay */ -unsigned long loops_per_sec = 50000000;; +unsigned long loops_per_jiffy = 50000000/HZ; /* * VGA Register */ diff --git a/arch/ppc/coffboot/Makefile b/arch/ppc/coffboot/Makefile index 68b1255c63e6..ad0389d3c256 100644 --- a/arch/ppc/coffboot/Makefile +++ b/arch/ppc/coffboot/Makefile @@ -7,11 +7,11 @@ HOSTCFLAGS = -O -I$(TOPDIR)/include CC = $(CROSS_COMPILE)gcc LD = $(CROSS_COMPILE)ld -CFLAGS = $(CPPFLAGS) -O -fno-builtin +CFLAGS = $(CPPFLAGS) -O -fno-builtin -I$(HPATH) OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic -CHRP_LD_ARGS = -Ttext 0x00400000 +CHRP_LD_ARGS = -Ttext 0x01000000 GZ = gzip -9 COFFOBJS = coffcrt0.o start.o coffmain.o misc.o string.o zlib.o image.o @@ -24,18 +24,13 @@ else MSIZE= endif -ifeq ($(CONFIG_ALL_PPC),y) -# yes, we want to build pmac stuff -CONFIG_PMAC = y -endif - ifeq ($(CONFIG_SMP),y) TFTPIMAGE=/tftpboot/zImage.pmac.smp$(MSIZE) else TFTPIMAGE=/tftpboot/zImage.pmac$(MSIZE) endif -ifeq ($(CONFIG_PMAC),y) +ifeq ($(CONFIG_POWERMAC),y) hack-coff: hack-coff.c $(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c diff --git a/arch/ppc/coffboot/chrpmain.c b/arch/ppc/coffboot/chrpmain.c index 254ced627768..b1f09efdd8d6 100644 --- a/arch/ppc/coffboot/chrpmain.c +++ b/arch/ppc/coffboot/chrpmain.c @@ -18,13 +18,18 @@ void stop_imac_usb(void); #define get_16be(x) (*(unsigned short *)(x)) #define get_32be(x) (*(unsigned *)(x)) -#define RAM_START 0x00000000 -#define RAM_END (8<<20) +#define RAM_END (16 << 20) #define PROG_START 0x00010000 +#define PROG_SIZE 0x003f0000 + +#define SCRATCH_SIZE (128 << 10) char *avail_ram; -char *end_avail; +char *begin_avail, *end_avail; +char *avail_high; +unsigned int heap_use; +unsigned int heap_max; extern char _end[]; extern char image_data[]; @@ -56,23 +61,28 @@ boot(int a1, int a2, void *prom) im = image_data; len = image_len; /* claim 3MB starting at PROG_START */ - claim(PROG_START, 3 << 20, 0); + claim(PROG_START, PROG_SIZE, 0); dst = (void *) PROG_START; if (im[0] == 0x1f && im[1] == 0x8b) { - /* claim 512kB for scratch space */ - avail_ram = (char *) claim(0, 512 << 10, 0x10); - end_avail = avail_ram + (512 << 10); - printf("avail_ram = %x\n", avail_ram); + /* claim some memory for scratch space */ + avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10); + begin_avail = avail_high = avail_ram; + end_avail = avail_ram + SCRATCH_SIZE; + printf("heap at 0x%x\n", avail_ram); printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len); - gunzip(dst, 3 << 20, im, &len); + gunzip(dst, PROG_SIZE, im, &len); printf("done %u bytes\n", len); + printf("%u bytes of heap consumed, max in use %u\n", + avail_high - begin_avail, heap_max); } else { memmove(dst, im, len); } flush_cache(dst, len); +#if 0 stop_imac_ethernet(); stop_imac_usb(); +#endif sa = (unsigned long)PROG_START; printf("start address = 0x%x\n", sa); @@ -84,6 +94,7 @@ boot(int a1, int a2, void *prom) pause(); } +#if 0 #define eieio() asm volatile("eieio"); void stop_imac_ethernet(void) @@ -134,14 +145,35 @@ void stop_imac_usb(void) *usb_ctrl = 0x01000000; /* cpu_to_le32(1) */ eieio(); } +#endif + +struct memchunk { + unsigned int size; + struct memchunk *next; +}; + +static struct memchunk *freechunks; void *zalloc(void *x, unsigned items, unsigned size) { - void *p = avail_ram; + void *p; + struct memchunk **mpp, *mp; size *= items; size = (size + 7) & -8; + heap_use += size; + if (heap_use > heap_max) + heap_max = heap_use; + for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) { + if (mp->size == size) { + *mpp = mp->next; + return mp; + } + } + p = avail_ram; avail_ram += size; + if (avail_ram > avail_high) + avail_high = avail_ram; if (avail_ram > end_avail) { printf("oops... out of memory\n"); pause(); @@ -151,6 +183,17 @@ void *zalloc(void *x, unsigned items, unsigned size) void zfree(void *x, void *addr, unsigned nb) { + struct memchunk *mp = addr; + + nb = (nb + 7) & -8; + heap_use -= nb; + if (avail_ram == addr + nb) { + avail_ram = addr; + return; + } + mp->size = nb; + mp->next = freechunks; + freechunks = mp; } #define HEAD_CRC 2 diff --git a/arch/ppc/config.in b/arch/ppc/config.in index 6510dce98ef3..a1a3313cda31 100644 --- a/arch/ppc/config.in +++ b/arch/ppc/config.in @@ -26,12 +26,12 @@ if [ "$CONFIG_6xx" = "y" ]; then bool 'Altivec (G4) support' CONFIG_ALTIVEC fi -if [ "$CONFIG_ALL_PPC" != "y" ];then +if [ "$CONFIG_ALL_PPC" != "y" ]; then define_bool CONFIG_MACH_SPECIFIC y fi -if [ "$CONFIG_PPC64" != "y" ];then - define_bool CONFIG_6xx y +if [ "$CONFIG_ALL_PPC" = "y" -o "$CONFIG_PMAC" = "y" -o "$CONFIG_CHRP" = "y" ]; then + define_bool CONFIG_POWERMAC y fi endmenu @@ -82,16 +82,7 @@ fi bool 'Support for VGA Console' CONFIG_VGA_CONSOLE bool 'Support for frame buffer devices' CONFIG_FB - bool 'Power management support for Apple PowerBooks' CONFIG_PMAC_PBOOK -bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD -bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY -tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL -if [ "$CONFIG_MAC_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE -fi -tristate 'Support for /dev/rtc' CONFIG_PPC_RTC -bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT @@ -182,7 +173,27 @@ endmenu source drivers/char/Config.in source drivers/usb/Config.in -source fs/Config.in + +mainmenu_option next_comment +comment 'Mac device drivers' +if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then + bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID +fi +if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then + define_bool CONFIG_MAC_HID y + bool ' Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES + bool ' Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN +else + bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD + bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE +fi +tristate 'Support for /dev/rtc' CONFIG_PPC_RTC +bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY +tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL +if [ "$CONFIG_MAC_SERIAL" = "y" ]; then + bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE +fi +endmenu mainmenu_option next_comment comment 'Sound' @@ -194,6 +205,8 @@ fi endmenu +source fs/Config.in + mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 9ea51146dd1a..10dba8913479 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -36,20 +36,40 @@ endif ifeq ($(CONFIG_MBX),y) O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o -else +endif ifeq ($(CONFIG_APUS),y) O_OBJS += apus_setup.o prom.o openpic.o -else -ifneq ($(CONFIG_MBX),y) -O_OBJS += prep_time.o pmac_time.o chrp_time.o \ - pmac_setup.o pmac_support.o \ - prep_pci.o pmac_pci.o chrp_pci.o \ - residual.o prom.o openpic.o feature.o \ - prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o \ - gemini_pci.o gemini_prom.o gemini_setup.o -OX_OBJS += chrp_setup.o prep_setup.o endif + +PMAC_OBJS = pmac_time.o pmac_setup.o pmac_support.o pmac_pci.o pmac_pic.o \ + feature.o openpic.o open_pic.o prom.o +CHRP_OBJS = $(PMAC_OBJS) chrp_time.o chrp_pci.o i8259.o indirect_pci.o +CHRPX_OBJS = chrp_setup.o +PREP_OBJS = prep_time.o prep_pci.o residual.o prep_nvram.o i8259.o \ + indirect_pci.o openpic.o open_pic.o prom.o +PREPX_OBJS = prep_setup.o + +ifeq ($(CONFIG_ALL_PPC),y) +O_OBJS += $(sort $(PMAC_OBJS) $(PREP_OBJS) $(CHRP_OBJS)) +OX_OBJS += $(PMACX_OBJS) $(PREPX_OBJS) $(CHRPX_OBJS) +endif +ifeq ($(CONFIG_PMAC),y) +O_OBJS += $(PMAC_OBJS) +OX_OBJS += $(PMACX_OBJS) endif +ifeq ($(CONFIG_PREP),y) +O_OBJS += $(PREP_OBJS) +OX_OBJS += $(PREPX_OBJS) +endif +ifeq ($(CONFIG_CHRP),y) +O_OBJS += $(CHRP_OBJS) +OX_OBJS += $(CHRPX_OBJS) +endif + +GEMINI_OBJS = $(PREP_OBJS) gemini_pci.o gemini_prom.o gemini_setup.o +ifeq ($(CONFIG_GEMINI),y) +O_OBJS += $(GEMINI_OBJS) +OX_OBJS += $(PREPX_OBJS) endif ifdef CONFIG_SMP @@ -75,7 +95,7 @@ find_name : find_name.c $(HOSTCC) -o find_name find_name.c checks: checks.c - $(HOSTCC) ${CFLAGS} -D__KERNEL__ -o checks checks.c + $(HOSTCC) ${CFLAGS} -D__KERNEL__ -I../../../include -o checks checks.c ./checks include $(TOPDIR)/Rules.make diff --git a/arch/ppc/kernel/apus_setup.c b/arch/ppc/kernel/apus_setup.c index bcefcc7cea67..26db64271cb9 100644 --- a/arch/ppc/kernel/apus_setup.c +++ b/arch/ppc/kernel/apus_setup.c @@ -624,7 +624,7 @@ apus_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_unexpected_up = NULL; ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL; - ppc_md.kbd_sysrq_xlate = NULL; + ppc_md.sysrq_xlate = NULL; #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) ppc_ide_md.insw = apus_ide_insw; diff --git a/arch/ppc/kernel/chrp_pci.c b/arch/ppc/kernel/chrp_pci.c index 771c51364fd7..4f21f09989a3 100644 --- a/arch/ppc/kernel/chrp_pci.c +++ b/arch/ppc/kernel/chrp_pci.c @@ -19,6 +19,7 @@ #include #include "pci.h" +#include "open_pic.h" /* LongTrail */ #define pci_config_addr(bus, dev, offset) \ @@ -286,7 +287,7 @@ chrp_pcibios_fixup(void) for( dev=pci_devices ; dev; dev=dev->next ) { if ( dev->irq ) - dev->irq = openpic_to_irq( dev->irq ); + dev->irq = dev->irq + open_pic.irq_offset; /* these need to be absolute addrs for OF and Matrox FB -- Cort */ if ( dev->vendor == PCI_VENDOR_ID_MATROX ) { diff --git a/arch/ppc/kernel/chrp_setup.c b/arch/ppc/kernel/chrp_setup.c index 8d0630ffe62a..8e378a792cdb 100644 --- a/arch/ppc/kernel/chrp_setup.c +++ b/arch/ppc/kernel/chrp_setup.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "local_irq.h" @@ -68,7 +69,7 @@ unsigned long chrp_get_rtc_time(void); int chrp_set_rtc_time(unsigned long nowtime); unsigned long rtas_event_scan_rate = 0, rtas_event_scan_ct = 0; void chrp_calibrate_decr(void); -void chrp_time_init(void); +long chrp_time_init(void); void chrp_setup_pci_ptrs(void); @@ -95,6 +96,7 @@ kdev_t boot_dev; extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; +extern unsigned long loops_per_jiffy; unsigned long empty_zero_page[1024]; @@ -357,81 +359,6 @@ chrp_irq_cannonicalize(u_int irq) } } -void -chrp_do_IRQ(struct pt_regs *regs, - int cpu, - int isfake) -{ - int irq; - unsigned long bits = 0; - int openpic_eoi_done = 0; - -#ifdef __SMP__ - { - unsigned int loops = 1000000; - while (test_bit(0, &global_irq_lock)) { - if (smp_processor_id() == global_irq_holder) { - printk("uh oh, interrupt while we hold global irq lock!\n"); -#ifdef CONFIG_XMON - xmon(0); -#endif - break; - } - if (loops-- == 0) { - printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); -#ifdef CONFIG_XMON - xmon(0); -#endif - } - } - } -#endif /* __SMP__ */ - - irq = openpic_irq(smp_processor_id()); - if (irq == IRQ_8259_CASCADE) - { - /* - * This magic address generates a PCI IACK cycle. - * - * This should go in the above mask/ack code soon. -- Cort - */ - if ( chrp_int_ack_special ) - irq = *chrp_int_ack_special; - else - irq = i8259_irq(0); - /* - * Acknowledge as soon as possible to allow i8259 - * interrupt nesting */ - openpic_eoi(smp_processor_id()); - openpic_eoi_done = 1; - } - if (irq == OPENPIC_VEC_SPURIOUS) - { - /* - * Spurious interrupts should never be - * acknowledged - */ - ppc_spurious_interrupts++; - openpic_eoi_done = 1; - goto out; - } - bits = 1UL << irq; - - if (irq < 0) - { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } - else - { - ppc_irq_dispatch_handler( regs, irq ); - } -out: - if (!openpic_eoi_done) - openpic_eoi(smp_processor_id()); -} - __initfunc(void chrp_init_IRQ(void)) { @@ -446,7 +373,7 @@ __initfunc(void (*(unsigned long *)get_property(np, "8259-interrupt-acknowledge", NULL)); } - open_pic.irq_offset = 16; + open_pic.irq_offset = NUM_8259_INTERRUPTS; for ( i = 16 ; i < NR_IRQS ; i++ ) irq_desc[i].ctl = &open_pic; openpic_init(1); @@ -454,7 +381,7 @@ __initfunc(void irq_desc[i].ctl = &i8259_pic; i8259_init(); #ifdef CONFIG_XMON - request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI), + request_irq(HYDRA_INT_ADB_NMI+open_pic.irq_offset, xmon_irq, 0, "NMI", 0); #endif /* CONFIG_XMON */ #ifdef __SMP__ @@ -487,8 +414,8 @@ __initfunc(void ppc_md.kbd_leds = pckbd_leds; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif } else @@ -500,8 +427,8 @@ __initfunc(void ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x69; + ppc_md.sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; #endif } #else @@ -512,8 +439,8 @@ __initfunc(void ppc_md.kbd_leds = pckbd_leds; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #endif #endif @@ -643,7 +570,7 @@ __initfunc(void ppc_md.get_cpuinfo = chrp_get_cpuinfo; ppc_md.irq_cannonicalize = chrp_irq_cannonicalize; ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.do_IRQ = open_pic_do_IRQ; ppc_md.init = chrp_init2; diff --git a/arch/ppc/kernel/chrp_time.c b/arch/ppc/kernel/chrp_time.c index 2b7d9a23047d..03146756cb60 100644 --- a/arch/ppc/kernel/chrp_time.c +++ b/arch/ppc/kernel/chrp_time.c @@ -31,18 +31,19 @@ static int nvram_as1 = NVRAM_AS1; static int nvram_as0 = NVRAM_AS0; static int nvram_data = NVRAM_DATA; -__initfunc(void chrp_time_init(void)) +__initfunc(long chrp_time_init(void)) { struct device_node *rtcs; int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); if (rtcs == NULL || rtcs->addrs == NULL) - return; + return 0; base = rtcs->addrs[0].address; nvram_as1 = 0; nvram_as0 = base; nvram_data = base + 1; + return 0; } int chrp_cmos_clock_read(int addr) diff --git a/arch/ppc/kernel/feature.c b/arch/ppc/kernel/feature.c index 04bb15fe8bc9..8f2771b71725 100644 --- a/arch/ppc/kernel/feature.c +++ b/arch/ppc/kernel/feature.c @@ -2,16 +2,13 @@ * arch/ppc/kernel/feature.c * * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) + * Ben. Herrenschmidt (bh40@calva.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * - * BenH: Changed implementation to work on multiple registers - * polarity is also taken into account. Removed delay (now - * responsibility of the caller). Added spinlocks. - * */ #include #include @@ -22,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -29,18 +28,30 @@ #undef DEBUG_FEATURE #define MAX_FEATURE_CONTROLLERS 2 -#define MAX_FEATURE_OFFSET 0x50 +#define MAX_FEATURE_OFFSET 0x100 #define FREG(c,r) (&(((c)->reg)[(r)>>2])) +/* Keylargo reg. access. */ +#define KL_FCR(r) (keylargo_base + ((r) >> 2)) +#define KL_IN(r) (in_le32(KL_FCR(r))) +#define KL_OUT(r,v) (out_le32(KL_FCR(r), (v))) +#define KL_BIS(r,v) (KL_OUT((r), KL_IN(r) | (v))) +#define KL_BIC(r,v) (KL_OUT((r), KL_IN(r) & ~(v))) + +/* Uni-N reg. access. Note that Uni-N regs are big endian */ +#define UN_REG(r) (uninorth_base + ((r) >> 2)) +#define UN_IN(r) (in_be32(UN_REG(r))) +#define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) +#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) +#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) + typedef struct feature_bit { int reg; /* reg. offset from mac-io base */ unsigned int polarity; /* 0 = normal, 1 = inverse */ unsigned int mask; /* bit mask */ } fbit; -/* I don't have an OHare machine to test with, so I left those as they - * were. Someone with such a machine chould check out what OF says and - * try too see if they match the heathrow ones and should be changed too +/* Those features concern for OHare-based PowerBooks (2400, 3400, 3500) */ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_null */ @@ -69,12 +80,47 @@ static fbit feature_bits_ohare_pbook[] = { {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; -/* Those bits are from a PowerBook. It's possible that desktop machines - * based on heathrow need a different definition or some bits removed +/* Those bits concern heathrow-based desktop machines (Beige G3s). We have removed + * the SCC related bits and init them once. They have proven to occasionally cause + * problems with the desktop units. */ static fbit feature_bits_heathrow[] = { + {0x38,0,0}, /* FEATURE_null */ + {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,0}, /* FEATURE_Serial_enable */ + {0x38,0,0}, /* FEATURE_Serial_IO_A */ + {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */ + {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */ + {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */ + {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */ + {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */ + {0x38,1,0}, /* FEATURE_Mediabay_reset */ + {0x38,1,0}, /* FEATURE_Mediabay_power */ + {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ + {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_IDE1_enable */ + {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_IDE1_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ + {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */ + {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */ + {0x38,1,0}, /* FEATURE_Modem_power */ + {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */ + {0x38,1,0}, /* FEATURE_Sound_Power */ + {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ + {0x38,0,0}, /* FEATURE_IDE2_enable */ + {0x38,0,0}, /* FEATURE_IDE2_reset */ + {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ + {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ +}; + +/* Those bits concern heathrow-based PowerBooks (wallstreet/mainstreet). + * Heathrow-based desktop macs (Beige G3s) are _not_ handled here + */ +static fbit feature_bits_wallstreet[] = { {0x38,0,0}, /* FEATURE_null */ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ @@ -101,15 +147,17 @@ static fbit feature_bits_heathrow[] = { {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; /* * Those bits are from a 1999 G3 PowerBook, with a paddington chip. - * Mostly the same as the heathrow. + * Mostly the same as the heathrow. They are used on both PowerBooks + * and desktop machines using the paddington chip */ static fbit feature_bits_paddington[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ + {0x38,0,PADD_RESET_SCC}, /* FEATURE_Serial_reset */ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */ @@ -134,37 +182,40 @@ static fbit feature_bits_paddington[] = { {0x38,0,0}, /* FEATURE_IDE2_reset */ {0x38,0,0}, /* FEATURE_Mediabay_IDE_switch */ {0x38,0,0}, /* FEATURE_Mediabay_content */ + {0x38,0,0}, /* FEATURE_Airport_reset */ }; /* Those bits are for Core99 machines (iBook,G4,iMacSL/DV,Pismo,...). + * Note: Different sets may be needed for iBook, especially for sound */ static fbit feature_bits_keylargo[] = { {0x38,0,0}, /* FEATURE_null */ - {0x38,0,0}, /* FEATURE_Serial_reset */ - {0x38,0,0x00000054}, /* FEATURE_Serial_enable */ - {0x38,0,0}, /* FEATURE_Serial_IO_A */ - {0x38,0,0}, /* FEATURE_Serial_IO_B */ + {0x38,0,KL0_SCC_RESET}, /* FEATURE_Serial_reset */ + {0x38,0,KL0_SERIAL_ENABLE}, /* FEATURE_Serial_enable */ + {0x38,0,KL0_SCC_A_INTF_ENABLE}, /* FEATURE_Serial_IO_A */ + {0x38,0,KL0_SCC_B_INTF_ENABLE}, /* FEATURE_Serial_IO_B */ {0x38,0,0}, /* FEATURE_SWIM3_enable */ {0x38,0,0}, /* FEATURE_MESH_enable */ {0x3c,0,0}, /* FEATURE_IDE0_enable */ - {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */ + {0x3c,1,KL1_EIDE0_RESET_N}, /* FEATURE_IDE0_reset */ {0x38,0,0}, /* FEATURE_IOBUS_enable */ {0x34,1,0x00000200}, /* FEATURE_Mediabay_reset */ {0x34,1,0x00000400}, /* FEATURE_Mediabay_power */ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */ {0x3c,0,0x0}, /* FEATURE_IDE1_enable */ - {0x3c,1,0x08000000}, /* FEATURE_IDE1_reset */ + {0x3c,1,KL1_EIDE1_RESET_N}, /* FEATURE_IDE1_reset */ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */ {0x38,0,0}, /* FEATURE_BMac_reset */ {0x38,0,0}, /* FEATURE_BMac_IO_enable */ - {0x40,1,0x02000000}, /* FEATURE_Modem_power */ + {0x40,1,KL2_MODEM_POWER_N}, /* FEATURE_Modem_power */ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */ {0x38,0,0}, /* FEATURE_Sound_Power */ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */ {0x38,0,0}, /* FEATURE_IDE2_enable */ - {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */ - {0x34,0,0x00001000}, /* FEATURE_Mediabay_IDE_switch */ + {0x3c,1,KL1_UIDE_RESET_N}, /* FEATURE_IDE2_reset */ + {0x34,0,KL_MBCR_MBDEV_ENABLE}, /* FEATURE_Mediabay_IDE_switch */ {0x34,0,0x00000100}, /* FEATURE_Mediabay_content */ + {0x40,1,KL2_AIRPORT_RESET_N}, /* FEATURE_Airport_reset */ }; /* definition of a feature controller object */ @@ -176,33 +227,93 @@ struct feature_controller { }; /* static functions */ -static void +static struct feature_controller* feature_add_controller(struct device_node *controller_device, fbit* bits); static struct feature_controller* feature_lookup_controller(struct device_node *device); -/* static varialbles */ +static void uninorth_init(void); +static void keylargo_init(void); +#ifdef CONFIG_PMAC_PBOOK +static void heathrow_prepare_for_sleep(struct feature_controller* ctrler); +static void heathrow_wakeup(struct feature_controller* ctrler); +static void core99_prepare_for_sleep(struct feature_controller* ctrler); +static void core99_wake_up(struct feature_controller* ctrler); +#endif /* CONFIG_PMAC_PBOOK */ + +/* static variables */ static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS]; static int controller_count = 0; +/* Core99 stuffs */ +static volatile u32* uninorth_base; +static volatile u32* keylargo_base; +static struct feature_controller* keylargo; +static int uninorth_rev; +static int keylargo_rev; +static u32 board_features; + +#define FTR_NEED_OPENPIC_TWEAK 0x00000001 + +static struct board_features_t { + char* compatible; + u32 features; +} board_features_datas[] __init = +{ + { "PowerMac2,1", 0 }, /* iMac ? */ + { "PowerMac2,2", 0 }, /* iMac ? */ + { "PowerMac3,1", FTR_NEED_OPENPIC_TWEAK }, /* Sawtooth (G4) */ + { "PowerMac3,3", 0 }, /* Dual G4 or Cube ? */ + { "PowerMac5,1", 0 }, /* Dual G4 or Cube ? */ + { "PowerBook2,1", 0 }, /* iBook */ + { "PowerBook2,2", 0 }, /* iBook FireWire ? */ + { "PowerBook3,1", 0 }, /* PowerBook 2000 (Pismo) */ + { NULL, 0 } +}; void feature_init(void) { struct device_node *np; + u32* rev; + int i; + + /* Figure out motherboard type & options */ + for(i=0;board_features_datas[i].compatible;i++) + if (machine_is_compatible(board_features_datas[i].compatible)) { + board_features = board_features_datas[i].features; + break; + } + /* Track those poor mac-io's */ + np = find_devices("mac-io"); while (np != NULL) { /* KeyLargo contains several (5 ?) FCR registers in mac-io, * plus some gpio's which could eventually be handled here. */ if (device_is_compatible(np, "Keylargo")) { - feature_add_controller(np, feature_bits_keylargo); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_keylargo); + if (ctrler) { + keylargo = ctrler; + keylargo_base = ctrler->reg; + rev = (u32 *)get_property(ctrler->device, "revision-id", NULL); + if (rev) + keylargo_rev = *rev; + } } else if (device_is_compatible(np, "paddington")) { feature_add_controller(np, feature_bits_paddington); + } else if (machine_is_compatible("AAPL,PowerBook1998")) { + feature_add_controller(np, feature_bits_wallstreet); } else { - feature_add_controller(np, feature_bits_heathrow); + struct feature_controller* ctrler = + feature_add_controller(np, feature_bits_heathrow); + if (ctrler) + out_le32(FREG(ctrler,HEATHROW_FEATURE_REG), + in_le32(FREG(ctrler,HEATHROW_FEATURE_REG)) | HRW_DEFAULTS); + } np = np->next; } @@ -218,6 +329,20 @@ feature_init(void) } } + /* Locate core99 Uni-N */ + np = find_devices("uni-n"); + if (np && np->n_addrs > 0) { + uninorth_base = ioremap(np->addrs[0].address, 0x1000); + uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); + } + if (uninorth_base && keylargo_base) + printk("Uni-N revision: %d, KeyLargo revision: %d\n", + uninorth_rev, keylargo_rev); + if (uninorth_base) + uninorth_init(); + if (keylargo_base) + keylargo_init(); + if (controller_count) printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count); @@ -232,7 +357,7 @@ feature_init(void) #endif } -static void +static struct feature_controller* feature_add_controller(struct device_node *controller_device, fbit* bits) { struct feature_controller* controller; @@ -240,7 +365,7 @@ feature_add_controller(struct device_node *controller_device, fbit* bits) if (controller_count >= MAX_FEATURE_CONTROLLERS) { printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n", controller_device->full_name, MAX_FEATURE_CONTROLLERS); - return; + return NULL; } controller = &controllers[controller_count]; @@ -249,21 +374,27 @@ feature_add_controller(struct device_node *controller_device, fbit* bits) if (controller_device->n_addrs == 0) { printk(KERN_ERR "No addresses for %s\n", controller_device->full_name); - return; + return NULL; } + /* We remap the entire mac-io here. Normally, this will just + * give us back our already existing BAT mapping + */ controller->reg = (volatile u32 *)ioremap( - controller_device->addrs[0].address, MAX_FEATURE_OFFSET); + controller_device->addrs[0].address, + controller_device->addrs[0].size); if (bits == NULL) { printk(KERN_INFO "Twiddling the magic ohare bits\n"); out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES); - return; + return NULL; } spin_lock_init(&controller->lock); controller_count++; + + return controller; } static struct feature_controller* @@ -385,3 +516,369 @@ feature_test(struct device_node* device, enum system_feature f) return bit->polarity ? (value == 0) : (value == bit->mask); } +/* + * Core99 functions + * + * Note: We currently assume there is _one_ UniN chip and _one_ KeyLargo + * chip, which is the case on all Core99 machines so far + */ + +/* Only one GMAC is assumed */ +void +feature_set_gmac_power(struct device_node* device, int power) +{ + unsigned long flags; + + if (!uninorth_base || !keylargo) + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC); + spin_unlock_irqrestore(&keylargo->lock, flags); + udelay(20); +} + +void +feature_set_gmac_phy_reset(struct device_node* device, int reset) +{ + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + spin_lock_irqsave(&keylargo->lock, flags); + out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET), reset); + (void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET)); + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Pass the node of the correct controller, please */ +void +feature_set_usb_power(struct device_node* device, int power) +{ + char* prop; + int number; + u32 reg; + + unsigned long flags; + + if (!keylargo_base || !keylargo) + return; + + prop = (char *)get_property(device, "AAPL,clock-id", NULL); + if (!prop) + return; + if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + number = 0; + else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + number = 2; + else + return; + + spin_lock_irqsave(&keylargo->lock, flags); + if (power) { + /* Turn ON */ + + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + } else { + KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + mdelay(1); + KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + } + reg = KL_IN(KEYLARGO_FCR4); + reg &= ~(KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number)); + reg &= ~(KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1)); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(10); + } else { + /* Turn OFF */ + + reg = KL_IN(KEYLARGO_FCR4); + reg |= KL4_SET_PORT_ENABLE(number) | KL4_SET_PORT_RESUME(number) | + KL4_SET_PORT_CONNECT(number) | KL4_SET_PORT_DISCONNECT(number); + reg |= KL4_SET_PORT_ENABLE(number+1) | KL4_SET_PORT_RESUME(number+1) | + KL4_SET_PORT_CONNECT(number+1) | KL4_SET_PORT_DISCONNECT(number+1); + KL_OUT(KEYLARGO_FCR4, reg); + (void)KL_IN(KEYLARGO_FCR4); + udelay(1); + if (number == 0) { + KL_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } else { + KL_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE); + (void)KL_IN(KEYLARGO_FCR0); + udelay(1); + KL_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1)); + (void)KL_IN(KEYLARGO_FCR0); + } + udelay(1); + } + spin_unlock_irqrestore(&keylargo->lock, flags); +} + +/* Not yet implemented */ +void +feature_set_firewire_power(struct device_node* device, int power) +{ +} + +#ifdef CONFIG_SMP +void +feature_core99_kick_cpu1(void) +{ + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT); + udelay(1); + out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE); +} +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_PMAC_PBOOK +void +feature_prepare_for_sleep(void) +{ + /* We assume gatwick is second */ + struct feature_controller* ctrler = &controllers[0]; + + if (!ctrler) + return; + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_prepare_for_sleep(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_prepare_for_sleep(ctrler); + return; + } +} + + +void +feature_wake_up(void) +{ + struct feature_controller* ctrler = &controllers[0]; + + if (!ctrler) + return; + if (controller_count > 1 && + device_is_compatible(ctrler->device, "gatwick")) + ctrler = &controllers[1]; + + if (ctrler->bits == feature_bits_heathrow || + ctrler->bits == feature_bits_paddington) { + heathrow_wakeup(ctrler); + return; + } + if (ctrler->bits == feature_bits_keylargo) { + core99_wake_up(ctrler); + return; + } +} + +static u32 save_fcr[5]; +static u32 save_mbcr; +static u32 save_gpio_levels[2]; +static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT]; +static u8 save_gpio_normal[KEYLARGO_GPIO_CNT]; + +static void +heathrow_prepare_for_sleep(struct feature_controller* ctrler) +{ + save_mbcr = in_le32(FREG(ctrler, 0x34)); + save_fcr[0] = in_le32(FREG(ctrler, 0x38)); + save_fcr[1] = in_le32(FREG(ctrler, 0x3c)); + + out_le32(FREG(ctrler, 0x38), save_fcr[0] & ~HRW_IOBUS_ENABLE); +} + +static void +heathrow_wakeup(struct feature_controller* ctrler) +{ + out_le32(FREG(ctrler, 0x38), save_fcr[0]); + out_le32(FREG(ctrler, 0x3c), save_fcr[1]); + out_le32(FREG(ctrler, 0x34), save_mbcr); + mdelay(1); + out_le32(FREG(ctrler, 0x38), save_fcr[0] | HRW_IOBUS_ENABLE); + mdelay(1); +} + + +static void +core99_prepare_for_sleep(struct feature_controller* ctrler) +{ + u32 temp; + int i; + u8* base8; + + /* + * Save various bits of KeyLargo + */ + + save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0); + save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; i= 2) + temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); + + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | + KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE + | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + KL_OUT(KEYLARGO_FCR3, temp); + + /* + * Put the host bridge to sleep + */ + + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP); + + /* + * FIXME: A bit of black magic with OpenPIC (don't ask me why) + */ + if (board_features & FTR_NEED_OPENPIC_TWEAK) { + KL_BIS(0x506e0, 0x00400000); + KL_BIS(0x506e0, 0x80000000); + } +} + +static void +core99_wake_up(struct feature_controller* ctrler) +{ + int i; + u8* base8; + + /* + * Wakeup the host bridge + */ + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + + /* + * Restore KeyLargo + */ + + KL_OUT(KEYLARGO_MBCR, save_mbcr); + KL_OUT(KEYLARGO_FCR0, save_fcr[0]); + KL_OUT(KEYLARGO_FCR1, save_fcr[1]); + KL_OUT(KEYLARGO_FCR2, save_fcr[2]); + KL_OUT(KEYLARGO_FCR3, save_fcr[3]); + KL_OUT(KEYLARGO_FCR4, save_fcr[4]); + mdelay(1); + KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]); + KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]); + base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0); + for (i=0; inext; + } + if (gmac) + feature_set_gmac_power(gmac, 0); +} + +/* Initialize the Core99 KeyLargo ASIC. Currently, we just make sure + * OpenPIC is enabled + */ +static void +keylargo_init(void) +{ + KL_BIS(KEYLARGO_FCR2, KL2_MPIC_ENABLE); +} + diff --git a/arch/ppc/kernel/gemini_setup.c b/arch/ppc/kernel/gemini_setup.c index 79b6764db8f4..ded9e28d8bac 100644 --- a/arch/ppc/kernel/gemini_setup.c +++ b/arch/ppc/kernel/gemini_setup.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "local_irq.h" @@ -257,14 +258,6 @@ gemini_get_clock_speed(void) return clock; } - -#define L2CR_PIPE_LATEWR (0x01800000) /* late-write SRAM */ -#define L2CR_L2CTL (0x00100000) /* RAM control */ -#define L2CR_INST_DISABLE (0x00400000) /* disable for insn's */ -#define L2CR_L2I (0x00200000) /* global invalidate */ -#define L2CR_L2E (0x80000000) /* enable */ -#define L2CR_L2WT (0x00080000) /* write-through */ - void __init gemini_init_l2(void) { unsigned char reg; @@ -338,8 +331,7 @@ void __init gemini_init_l2(void) cache |= L2CR_L2WT; #endif cache |= L2CR_PIPE_LATEWR|L2CR_L2CTL|L2CR_INST_DISABLE; - _set_L2CR(0); - _set_L2CR(cache|L2CR_L2I|L2CR_L2E); + _set_L2CR(cache|L2CR_L2E); } } @@ -389,7 +381,7 @@ void __init gemini_init_IRQ(void) #define gemini_rtc_write(val,x) (writeb((val),(GEMINI_RTC+(x)))) /* ensure that the RTC is up and running */ -void __init gemini_time_init(void) +long __init gemini_time_init(void) { unsigned char reg; @@ -400,6 +392,7 @@ void __init gemini_time_init(void) gemini_rtc_write((reg & ~(M48T35_RTC_STOPPED)), M48T35_RTC_CONTROL); gemini_rtc_write((reg | M48T35_RTC_SET), M48T35_RTC_CONTROL); } + return 0; } #undef DEBUG_RTC @@ -570,6 +563,6 @@ void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = NULL; ppc_md.kbd_init_hw = NULL; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = NULL; + ppc_md.sysrq_xlate = NULL; #endif } diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S index e7941839099d..f379077776c6 100644 --- a/arch/ppc/kernel/head.S +++ b/arch/ppc/kernel/head.S @@ -23,6 +23,10 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * 2000-04-10. + * Add sys_rt_sigreturn in DoSyscall Handler. + * Giovanna Ambrosini (ambrosini@lightning.ch). * */ @@ -258,66 +262,15 @@ __start: __secondary_start: /* Switch MMU off, clear BATs and flush TLB */ bl mmu_off +mmu_off_return: bl clear_bats bl flush_tlbs - -/* Use the first pair of BAT registers to map the 1st 16MB - * of RAM to KERNELBASE. From this point on we can't safely - * call OF any more. - */ - lis r11,KERNELBASE@h - mfspr r9,PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpi 0,r9,1 - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f /* valid, block length = 8MB */ - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ - mtspr IBAT0L,r8 /* lower BAT register */ - mtspr IBAT1U,r9 - mtspr IBAT1L,r10 - b 5f -4: -#ifdef CONFIG_APUS - ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ - ori r11,r11,0xfe /* set up an 8MB mapping */ - lis r8,CYBERBASEp@h - lwz r8,0(r8) - addis r8,r8,KERNELBASE@h - addi r8,r8,2 -#else - ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ - li r8,2 /* R/W access */ - /* - * If the MMU is off clear the bats. See clear_bat() -- Cort - */ -#ifndef CONFIG_GEMINI - /* - * allow secondary cpus to get at all of ram in early bootup - * since their init_task may be up there -- Cort - */ - oris r18,r8,0x10000000@h - oris r21,r11,(KERNELBASE+0x10000000)@h - mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT1U,r21 /* bit in upper BAT register */ - mtspr IBAT1L,r18 - mtspr IBAT1U,r21 - - oris r18,r8,0x20000000@h - oris r21,r11,(KERNELBASE+0x20000000)@h - mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT2U,r21 /* bit in upper BAT register */ - mtspr IBAT2L,r18 - mtspr IBAT2U,r21 -#endif /* ndef CONFIG_GEMINI */ + bl setup_init_bats +#ifndef CONFIG_APUS +#ifdef CONFIG_BOOTX_TEXT + bl setup_disp_bat +#endif #endif - mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ - mtspr DBAT0U,r11 /* bit in upper BAT register */ - mtspr IBAT0L,r8 - mtspr IBAT0U,r11 -5: isync #ifdef CONFIG_APUS /* Unfortunately the APUS specific instructions bloat the * code so it cannot fit in the 0x100 bytes available. We have @@ -443,6 +396,15 @@ __secondary_start: #endif /* CONFIG_8xx */ b turn_on_mmu +/* Hack for sleep on Core99 machines + */ +#ifdef CONFIG_POWERMAC + . = 0x80 +SleepVector: + .long 0 + .long 0 +#endif /* CONFIG_POWERMAC */ + /* * GCC sometimes accesses words at negative offsets from the stack * pointer, although the SysV ABI says it shouldn't. To cope with @@ -515,7 +477,7 @@ label: \ #endif /* CONFIG_GEMINI */ #else STD_EXCEPTION(0x100, Reset, UnknownException) -#endif +#endif /* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) @@ -1383,11 +1345,7 @@ hash_page: /* Construct the high word of the PPC-style PTE */ mfsrin r5,r3 /* get segment reg for segment */ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */ - -#ifndef __SMP__ /* do this later for SMP */ oris r5,r5,0x8000 /* set V (valid) bit */ -#endif - rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */ /* Get the address of the primary PTE group in the hash table */ .globl hash_page_patch_A @@ -1499,6 +1457,7 @@ found_slot: */ found_empty: found_slot: + clrlwi r5,r5,1 /* clear valid bit (0x80000000) */ stw r5,0(r3) /* clear V (valid) bit in PTE */ sync tlbsync @@ -1819,14 +1778,8 @@ giveup_altivec: blr #endif /* CONFIG_ALTIVEC */ -#else /* CONFIG_8xx */ - .globl giveup_fpu -giveup_fpu: - blr -#endif /* CONFIG_8xx */ - mmu_off: - addi r4, r3, __secondary_start - _start + addi r4, r3, mmu_off_return - _start mfmsr r3 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ beqlr @@ -1892,6 +1845,12 @@ copy_and_flush: . = 0x4000 #endif +#else /* CONFIG_8xx */ + .globl giveup_fpu +giveup_fpu: + blr +#endif /* CONFIG_8xx */ + turn_on_mmu: mfmsr r0 ori r1,r0,MSR_DR|MSR_IR @@ -1984,6 +1943,7 @@ start_here: cror 14,14,18 bne 3,6f ori r11,r11,HID0_SGE|HID0_BHTE|HID0_BTIC|HID0_ABE /* for g3/g4, enable */ + rlwinm r11,r11,0,23,21 /* clear HID0_SPD */ li r3,0 mtspr ICTC,r3 5: mtspr HID0,r11 /* superscalar exec & br history tbl */ @@ -2166,7 +2126,9 @@ DoSyscall: 1: #endif /* SHOW_SYSCALLS */ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */ + cmpi 1,r0,0x6666 /* Special case for 'sys_rt_sigreturn' */ beq- 10f + beq- cr1,16f lwz r10,TASK_FLAGS(r2) andi. r10,r10,PF_TRACESYS bne- 50f @@ -2213,6 +2175,12 @@ syscall_ret_1: /* sys_sigreturn */ 10: addi r3,r1,STACK_FRAME_OVERHEAD bl sys_sigreturn + cmpi 0,r3,0 /* Check for restarted system call */ + bge int_return + b 20b +/* sys_rt_sigreturn */ +16: addi r3,r1,STACK_FRAME_OVERHEAD + bl sys_rt_sigreturn cmpi 0,r3,0 /* Check for restarted system call */ bge int_return b 20b @@ -2883,30 +2851,6 @@ m8xx_gorom: mtlr r4 blr #endif /* CONFIG_8xx */ - -/* - * We put a few things here that have to be page-aligned. - * This stuff goes at the beginning of the data segment, - * which is page-aligned. - */ - .data - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - - .globl swapper_pg_dir -swapper_pg_dir: - .space 4096 - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 /* * An undocumented "feature" of 604e requires that the v bit @@ -2951,4 +2895,117 @@ flush_tlbs: blt 1b sync blr + +/* Use the first pair of BAT registers to map the 1st 16MB + * of RAM to KERNELBASE. From this point on we can't safely + * call OF any more. + */ +setup_init_bats: + lis r11,KERNELBASE@h + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + bne 4f + ori r11,r11,4 /* set up BAT registers for 601 */ + li r8,0x7f /* valid, block length = 8MB */ + oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ + oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ + mtspr IBAT0U,r11 /* N.B. 601 has valid bit in */ + mtspr IBAT0L,r8 /* lower BAT register */ + mtspr IBAT1U,r9 + mtspr IBAT1L,r10 + b 5f +4: +#ifdef CONFIG_APUS + ori r11,r11,BL_8M<<2|0x2 /* set up an 8MB mapping */ + ori r11,r11,0xfe /* set up an 8MB mapping */ + lis r8,CYBERBASEp@h + lwz r8,0(r8) + addis r8,r8,KERNELBASE@h + addi r8,r8,2 +#else + ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ + li r8,2 /* R/W access */ + /* + * If the MMU is off clear the bats. See clear_bat() -- Cort + */ +#ifndef CONFIG_GEMINI + /* + * allow secondary cpus to get at all of ram in early bootup + * since their init_task may be up there -- Cort + */ + oris r18,r8,0x10000000@h + oris r21,r11,(KERNELBASE+0x10000000)@h + mtspr DBAT1L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT1U,r21 /* bit in upper BAT register */ + mtspr IBAT1L,r18 + mtspr IBAT1U,r21 + oris r18,r8,0x20000000@h + oris r21,r11,(KERNELBASE+0x20000000)@h + mtspr DBAT2L,r18 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT2U,r21 /* bit in upper BAT register */ + mtspr IBAT2L,r18 + mtspr IBAT2U,r21 +#endif /* ndef CONFIG_GEMINI */ +#endif + mtspr DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ + mtspr DBAT0U,r11 /* bit in upper BAT register */ + mtspr IBAT0L,r8 + mtspr IBAT0U,r11 +5: isync + blr + +#ifdef CONFIG_BOOTX_TEXT +setup_disp_bat: + /* + * setup the display bat prepared for us in prom.c + */ + mflr r8 + bl reloc_offset + mtlr r8 + lis r8, disp_BATL@h + ori r8, r8, disp_BATL@l + add r8, r3, r8 + lwz r8, 0(r8) + lis r11, disp_BATU@h + ori r11, r11, disp_BATU@l + add r11, r3, r11 + lwz r11, 0(r11) + mtspr IBAT3L,r8 + mtspr IBAT3U,r11 + mfspr r9,PVR + rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ + cmpi 0,r9,1 + beq 1f + mtspr DBAT3L,r8 + mtspr DBAT3U,r11 +1: + blr +#endif + +/* + * We put a few things here that have to be page-aligned. + * This stuff goes at the beginning of the data segment, + * which is page-aligned. + */ + .data + .globl sdata +sdata: + .globl empty_zero_page +empty_zero_page: + .space 4096 + + .globl swapper_pg_dir +swapper_pg_dir: + .space 4096 + +/* + * This space gets a copy of optional info passed to us by the bootstrap + * Used to pass parameters into the kernel like root=/dev/sda1, etc. + */ + .globl cmd_line +cmd_line: + .space 512 + + diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index f63000cb55f2..a85a0a0ca88d 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -61,7 +61,9 @@ #include "local_irq.h" -extern volatile unsigned long ipi_count; +extern atomic_t ipi_recv; +extern atomic_t ipi_sent; +void enable_irq(unsigned int irq_nr); void enable_irq(unsigned int irq_nr); void disable_irq(unsigned int irq_nr); @@ -137,20 +139,21 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) if (!handler) { /* Free */ - for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) - { - if (action->dev_id == dev_id) - { - /* Found it - now free it */ - save_flags(flags); - cli(); - *p = action->next; - restore_flags(flags); - irq_kfree(action); - return 0; - } - } - return -ENOENT; + p = &irq_desc[irq].action; + while ((action = *p) != NULL && action->dev_id != dev_id) + p = &action->next; + if (action == NULL) + return -ENOENT; + + /* Found it - now free it */ + save_flags(flags); + cli(); + *p = action->next; + if (irq_desc[irq].action == NULL) + disable_irq(irq); + restore_flags(flags); + irq_kfree(action); + return 0; } action = (struct irqaction *) @@ -241,8 +244,10 @@ int get_irq_list(char *buf) } #ifdef __SMP__ /* should this be per processor send/receive? */ - len += sprintf(buf+len, "IPI: %10lu\n", ipi_count); -#endif + /* should this be per processor send/receive? */ + len += sprintf(buf+len, "IPI: (recv/sent) %10lu/%lu\n", + atomic_read(&ipi_recv), atomic_read(&ipi_sent)); +#endif /* __SMP__ */ len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts); return len; } @@ -317,10 +322,14 @@ atomic_t global_irq_count; atomic_t global_bh_count; atomic_t global_bh_lock; +extern unsigned long *_get_SP(void); + static void show(char * str) { +#if 0 int i; unsigned long *stack; +#endif int cpu = smp_processor_id(); printk("\n%s, CPU %d:\n", str, cpu); @@ -332,6 +341,10 @@ static void show(char * str) atomic_read(&global_bh_count), ppc_local_bh_count[0], ppc_local_bh_count[1]); +#if 1 + printk(" CPU: %d last CPU: %d\n", current->processor,current->last_processor); + print_backtrace (_get_SP()); +#else stack = (unsigned long *) &str; for (i = 40; i ; i--) { unsigned long x = *++stack; @@ -339,6 +352,7 @@ static void show(char * str) printk("<[%08lx]> ", x); } } +#endif } static inline void wait_on_bh(void) diff --git a/arch/ppc/kernel/mbx_pci.c b/arch/ppc/kernel/mbx_pci.c index 5114c3cfb833..965ff65cce41 100644 --- a/arch/ppc/kernel/mbx_pci.c +++ b/arch/ppc/kernel/mbx_pci.c @@ -17,7 +17,9 @@ #include #include +#include +#include "pci.h" /* * This blows......The MBX uses the Tundra QSpan PCI bridge. When diff --git a/arch/ppc/kernel/mbx_setup.c b/arch/ppc/kernel/mbx_setup.c index d4f3c85fce96..b8daf85d54f2 100644 --- a/arch/ppc/kernel/mbx_setup.c +++ b/arch/ppc/kernel/mbx_setup.c @@ -41,14 +41,25 @@ #include #include #include - +#include +#include #include + #include "local_irq.h" static int mbx_set_rtc_time(unsigned long time); unsigned long mbx_get_rtc_time(void); void mbx_calibrate_decr(void); +extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); +extern int pckbd_getkeycode(unsigned int scancode); +extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode); +extern char pckbd_unexpected_up(unsigned char keycode); +extern void pckbd_leds(unsigned char leds); +extern void pckbd_init_hw(void); +extern unsigned char pckbd_sysrq_xlate[128]; + extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, @@ -452,8 +463,8 @@ mbx_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = pckbd_leds; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index 5ec8b36d985e..72fe9c71996f 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -125,12 +125,33 @@ do_lost_interrupts: * Flush MMU TLB */ _GLOBAL(_tlbia) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,10 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ sync tlbia sync #ifdef __SMP__ tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -138,11 +159,32 @@ _GLOBAL(_tlbia) * Flush MMU TLB for a particular address */ _GLOBAL(_tlbie) +#if defined(CONFIG_SMP) + mfmsr r10 + sync + rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ + mtmsr r0 + SYNC + lis r9,hash_table_lock@h + ori r9,r9,hash_table_lock@l + lwz r8,PROCESSOR(r2) + oris r8,r8,11 +10: lwarx r7,0,r9 + cmpi 0,r7,0 + bne- 10b + stwcx. r8,0,r9 + bne- 10b + eieio +#endif /* CONFIG_SMP */ tlbie r3 sync -#ifdef __SMP__ +#ifdef CONFIG_SMP tlbsync sync + li r0,0 + stw r0,0(r9) /* clear hash_table_lock */ + mtmsr r10 + SYNC #endif blr @@ -312,8 +354,10 @@ _GLOBAL(atomic_set_mask) * The *_ns versions don't do byte-swapping. */ _GLOBAL(_insb) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbz r5,0(r3) eieio stbu r5,1(r4) @@ -321,8 +365,10 @@ _GLOBAL(_insb) blr _GLOBAL(_outsb) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,1 + blelr- 00: lbzu r5,1(r4) stb r5,0(r3) eieio @@ -330,8 +376,10 @@ _GLOBAL(_outsb) blr _GLOBAL(_insw) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhbrx r5,0,r3 eieio sthu r5,2(r4) @@ -339,8 +387,10 @@ _GLOBAL(_insw) blr _GLOBAL(_outsw) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) eieio sthbrx r5,0,r3 @@ -348,8 +398,10 @@ _GLOBAL(_outsw) blr _GLOBAL(_insl) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwbrx r5,0,r3 eieio stwu r5,4(r4) @@ -357,8 +409,10 @@ _GLOBAL(_insl) blr _GLOBAL(_outsl) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stwbrx r5,0,r3 eieio @@ -367,8 +421,10 @@ _GLOBAL(_outsl) _GLOBAL(ide_insw) _GLOBAL(_insw_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhz r5,0(r3) eieio sthu r5,2(r4) @@ -377,8 +433,10 @@ _GLOBAL(_insw_ns) _GLOBAL(ide_outsw) _GLOBAL(_outsw_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,2 + blelr- 00: lhzu r5,2(r4) sth r5,0(r3) eieio @@ -386,8 +444,10 @@ _GLOBAL(_outsw_ns) blr _GLOBAL(_insl_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwz r5,0(r3) eieio stwu r5,4(r4) @@ -395,8 +455,10 @@ _GLOBAL(_insl_ns) blr _GLOBAL(_outsl_ns) + cmpwi 0,r5,0 mtctr r5 subi r4,r4,4 + blelr- 00: lwzu r5,4(r4) stw r5,0(r3) eieio @@ -494,15 +556,13 @@ _GLOBAL(_get_HID0) mfspr r3,HID0 blr -_GLOBAL(_get_ICTC) - mfspr r3,ICTC - blr - -_GLOBAL(_set_ICTC) - mtspr ICTC,r3 +_GLOBAL(_set_HID0) + sync + mtspr HID0, r3 + sync + isync /* Handle erratas in some cases */ blr - /* L2CR functions Copyright © 1997-1998 by PowerLogix R & D, Inc. @@ -524,6 +584,17 @@ _GLOBAL(_set_ICTC) /* Thur, Dec. 12, 1998. - First public release, contributed by PowerLogix. + *********** + Sat, Aug. 7, 1999. + - Terry: Made sure code disabled interrupts before running. (Previously + it was assumed interrupts were already disabled). + - Terry: Updated for tentative G4 support. 4MB of memory is now flushed + instead of 2MB. (Prob. only 3 is necessary). + - Terry: Updated for workaround to HID0[DPM] processor bug + during global invalidates. + *********** + Thu, July 13, 2000. + - Terry: Added isync to correct for an errata. Author: Terry Greeniaus (tgree@phys.ualberta.ca) Please e-mail updates to this file to me, thanks! @@ -562,82 +633,94 @@ _GLOBAL(_set_ICTC) causes cache pushes from the L1 cache to go to the L2 cache instead of to main memory. */ - +/* + * Summary: this procedure ignores the L2I bit in the value passed in, + * flushes the cache if it was already enabled, always invalidates the + * cache, then enables the cache if the L2E bit is set in the value + * passed in. + * -- paulus. + */ _GLOBAL(_set_L2CR) - /* Make sure this is a 750 chip */ + /* Make sure this is a 750 or 7400 chip */ mfspr r4,PVR rlwinm r4,r4,16,16,31 - cmplwi r4,0x0008 - beq thisIs750 - cmplwi r4,0x000c - beq thisIs750 - li r3,-1 - blr - -thisIs750: - /* Get the current enable bit of the L2CR into r4 */ - mfspr r4,L2CR - mfmsr r7 - - /* See if we want to perform a global inval this time. */ - rlwinm r6,r3,0,10,10 /* r6 contains the new invalidate bit */ - rlwinm. r5,r3,0,0,0 /* r5 contains the new enable bit */ - rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ - rlwimi r3,r4,0,0,0 /* Keep the enable bit the same as it was. */ - bne dontDisableCache /* Only disable the cache if L2CRApply - has the enable bit off */ - -disableCache: - /* Disable the cache. First, we turn off interrupts. - An interrupt while we are flushing the cache could bring - in data which may not get properly flushed. */ - rlwinm r4,r7,0,17,15 /* Turn off EE bit */ + cmpwi r4,0x0008 + cmpwi cr1,r4,0x000c + cror 2,2,4*cr1+2 + bne 99f + + /* Turn off interrupts and data relocation. */ + mfmsr r7 /* Save MSR in r7 */ + rlwinm r4,r7,0,17,15 + rlwinm r4,r4,0,28,26 /* Turn off DR bit */ sync mtmsr r4 sync + + /* Get the current enable bit of the L2CR into r4 */ + mfspr r4,L2CR -/* - Now, read the first 2MB of memory to put new data in the cache. - (Actually we only need the size of the L2 cache plus the size - of the L1 cache, but 2MB will cover everything just to be safe). -*/ - lis r4,0x0001 + /* Tweak some bits */ + rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ + rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ + rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ + + /* Check to see if we need to flush */ + rlwinm. r4,r4,0,0,0 + beq 2f + + /* Flush the cache. First, read the first 4MB of memory (physical) to + * put new data in the cache. (Actually we only need + * the size of the L2 cache plus the size of the L1 cache, but 4MB will + * cover everything just to be safe). + */ + + /**** Might be a good idea to set L2DO here - to prevent instructions + from getting into the cache. But since we invalidate + the next time we enable the cache it doesn't really matter. + ****/ + + lis r4,0x0002 mtctr r4 - lis r4,KERNELBASE@h -1: lwzx r0,r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ + li r4,0 +1: + lwzx r0,r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ bdnz 1b - /* Now, flush the first 2MB of memory */ - lis r4,0x0001 + /* Now, flush the first 4MB of memory */ + lis r4,0x0002 mtctr r4 - lis r4,KERNELBASE@h + li r4,0 sync -2: dcbf r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 2b - - /* Turn off the L2CR enable bit. */ - rlwinm r3,r3,0,1,31 - -dontDisableCache: - /* Set up the L2CR configuration bits */ +1: + dcbf r0,r4 + addi r4,r4,32 /* Go to start of next cache line */ + bdnz 1b + +2: + /* Set up the L2CR configuration bits (and switch L2 off) */ sync mtspr L2CR,r3 sync - /* Reenable interrupts if necessary. */ - mtmsr r7 + /* Before we perform the global invalidation, we must disable dynamic + * power management via HID0[DPM] to work around a processor bug where + * DPM can possibly interfere with the state machine in the processor + * that invalidates the L2 cache tags. + */ + mfspr r8,HID0 /* Save HID0 in r8 */ + rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ sync - - cmplwi r6,0 - beq noInval - + mtspr HID0,r4 /* Disable DPM */ + sync + /* Perform a global invalidation */ oris r3,r3,0x0020 sync mtspr L2CR,r3 sync + isync /* For errata */ /* Wait for the invalidation to complete */ 3: mfspr r3,L2CR @@ -649,27 +732,38 @@ dontDisableCache: mtspr L2CR,r3 sync -noInval: + /* Restore HID0[DPM] to whatever it was before */ + sync + mtspr 1008,r8 + sync + /* See if we need to enable the cache */ cmplwi r5,0 - beqlr + beq 4f /* Enable the cache */ oris r3,r3,0x8000 mtspr L2CR,r3 sync + + /* Restore MSR (restores EE and DR bits to original state) */ +4: sync + mtmsr r7 + sync + blr + +99: li r3,-1 blr _GLOBAL(_get_L2CR) /* Make sure this is a 750 chip */ mfspr r3,PVR - rlwinm r3,r3,16,16,31 - cmplwi r3,0x0008 - beq 1f - cmplwi r3,0x000c + srwi r3,r3,16 + cmpwi r3,0x0008 + cmpwi cr1,r3,0x000c li r3,0 + cror 2,2,4*cr1+2 bnelr -1: /* Return the L2CR contents */ mfspr r3,L2CR blr @@ -677,16 +771,6 @@ _GLOBAL(_get_L2CR) /* --- End of PowerLogix code --- */ -/* -_GLOBAL(_get_L2CR) - mfspr r3,L2CR - blr - -_GLOBAL(_set_L2CR) - mtspr L2CR,r3 - blr - -*/ /* * These are used in the alignment trap handler when emulating @@ -944,11 +1028,7 @@ sys_call_table: .long sys_getresuid /* 165 */ .long sys_query_module .long sys_poll -#ifdef CONFIG_NFSD .long sys_nfsservctl -#else - .long sys_ni_syscall -#endif .long sys_setresgid .long sys_getresgid /* 170 */ .long sys_prctl @@ -970,4 +1050,16 @@ sys_call_table: .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork - .space (NR_syscalls-183)*4 + .long sys_ni_syscall /* 190 */ /* MacOnLinux - old */ + .long sys_ni_syscall /* 191 */ /* Unused */ + .long sys_ni_syscall /* 192 - reserved - mmap2 */ + .long sys_ni_syscall /* 193 - reserved - truncate64 */ + .long sys_ni_syscall /* 194 - reserved - ftruncate64 */ + .long sys_ni_syscall /* 195 - reserved - stat64 */ + .long sys_ni_syscall /* 196 - reserved - lstat64 */ + .long sys_ni_syscall /* 197 - reserved - fstat64 */ + .long sys_pciconfig_read /* 198 */ + .long sys_pciconfig_write /* 199 */ + .long sys_pciconfig_iobase /* 200 */ + .long sys_ni_syscall /* 201 - reserved - MacOnLinux - new */ + .space (NR_syscalls-201)*4 diff --git a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c index 47b68e68fe2e..c1d99906aab0 100644 --- a/arch/ppc/kernel/open_pic.c +++ b/arch/ppc/kernel/open_pic.c @@ -1,48 +1,126 @@ +/* + * open_pic.c + * + * Common support routines for platforms with an OpenPIC interrupt controller + * + */ + #include #include #include #include #include #include +#include #include "open_pic.h" #include "i8259.h" -#ifdef __SMP__ -void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) -{ - smp_message_recv(cpl-OPENPIC_VEC_IPI); -} -#endif /* __SMP__ */ +extern volatile unsigned char *chrp_int_ack_special; -void chrp_mask_and_ack_irq(unsigned int irq_nr) +void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake) { - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.mask_and_ack(irq_nr); -} + int irq; + int openpic_eoi_done = 0; -static void chrp_mask_irq(unsigned int irq_nr) -{ - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.disable(irq_nr); +#ifdef __SMP__ + { + unsigned int loops = 1000000; + while (test_bit(0, &global_irq_lock)) { + if (smp_processor_id() == global_irq_holder) { + printk("uh oh, interrupt while we hold global irq lock!\n"); +#ifdef CONFIG_XMON + xmon(0); +#endif + break; + } + if (loops-- == 0) { + printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder); +#ifdef CONFIG_XMON + xmon(0); +#endif + } + } + } +#endif /* __SMP__ */ + + irq = openpic_irq(smp_processor_id()); + /* make sure open_pic.irq_offset is set to something! + * do we really need the _MACH_Pmac test?? + */ + if (!(_machine == _MACH_Pmac) && (irq == open_pic.irq_offset)) + { + /* + * This magic address generates a PCI IACK cycle. + * + * This should go in the above mask/ack code soon. -- Cort + */ + if ( chrp_int_ack_special ) + irq = *chrp_int_ack_special; +#ifndef CONFIG_PMAC + else + irq = i8259_irq(0); +#endif + /* + * Acknowledge as soon as possible to allow i8259 + * interrupt nesting */ + openpic_eoi(smp_processor_id()); + openpic_eoi_done = 1; + } + if (irq == OPENPIC_VEC_SPURIOUS) + { + /* + * Spurious interrupts should never be + * acknowledged + */ + ppc_spurious_interrupts++; + openpic_eoi_done = 1; + goto out; + } + + if (irq < 0) + { + printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", + irq, regs->nip); + ppc_spurious_interrupts++; + } else - openpic_disable_irq(irq_nr-open_pic.irq_offset); + { + ppc_irq_dispatch_handler( regs, irq ); + } +out: + if (!openpic_eoi_done) + openpic_eoi(smp_processor_id()); } -static void chrp_unmask_irq(unsigned int irq_nr) +#ifdef __SMP__ +void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs) { - if ((_machine != _MACH_gemini) && is_8259_irq(irq_nr)) - i8259_pic.enable(irq_nr); - else - openpic_enable_irq(irq_nr-open_pic.irq_offset); + smp_message_recv(cpl-OPENPIC_VEC_IPI); } +#endif /* __SMP__ */ + struct hw_interrupt_type open_pic = { " OpenPIC ", NULL, NULL, NULL, - chrp_unmask_irq, - chrp_mask_irq, - chrp_mask_and_ack_irq, + openpic_enable_irq, + openpic_disable_irq, + /* Theorically, the mask&ack should be NULL for OpenPIC. However, doing + * so shows tons of bogus interrupts coming in. + * This problem is apparently due to the common code always calling + * unmask(). I apparently (need more test) fixed it in the 2.4 new IRQ + * management by cleanly implementing the handler's end() function, so + * neither mask nor unmask are needed. In the meantime, the fix below will + * work for 2.2 -Benh + * + * Hopefully this will fix my bogus interrups on MTX + * I merged everthing together so we don't have the same code in three + * places. This might cause stability problems, but I'd rather + * get it right once than three different times because someone forgot + * to make the same change to PReP or something --Troy + */ + openpic_disable_irq, 0 }; diff --git a/arch/ppc/kernel/open_pic.h b/arch/ppc/kernel/open_pic.h index 83ffb7f91d0a..7b207ff96bdd 100644 --- a/arch/ppc/kernel/open_pic.h +++ b/arch/ppc/kernel/open_pic.h @@ -6,6 +6,7 @@ extern struct hw_interrupt_type open_pic; +void open_pic_do_IRQ(struct pt_regs *regs, int cpu, int isfake); void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs); void openpic_enable_IPI(u_int ipi); void do_openpic_setup_cpu(void); diff --git a/arch/ppc/kernel/openpic.c b/arch/ppc/kernel/openpic.c index f93945dd657f..be04097691cb 100644 --- a/arch/ppc/kernel/openpic.c +++ b/arch/ppc/kernel/openpic.c @@ -175,7 +175,10 @@ static void openpic_safe_writefield(volatile u_int *addr, u_int mask, * Note: We might want to adjust priorities too. */ -__initfunc(void openpic_init(int main_pic)) +/* Not an init func, called on pbook wakeup --BenH */ +void +__init +openpic_init(int main_pic) { u_int t, i; u_int timerfreq; @@ -227,7 +230,7 @@ __initfunc(void openpic_init(int main_pic)) /* Initialize IPI interrupts */ for (i = 0; i < OPENPIC_NUM_IPI; i++) { - openpic_initipi(i, 0/*10*/, OPENPIC_VEC_IPI+i); + openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i); } if (_machine != _MACH_Pmac) { @@ -264,7 +267,7 @@ __initfunc(void openpic_init(int main_pic)) openpic_initirq( np->intrs[j].line, pri, np->intrs[j].line, - np->intrs[j].sense, + 0, np->intrs[j].sense); irq_desc[np->intrs[j].line].level = np->intrs[j].sense; } @@ -309,6 +312,10 @@ void openpic_reset(void) { openpic_setfield(&OpenPIC->Global.Global_Configuration0, OPENPIC_CONFIG_RESET); + /* Wait for reset to complete */ + while(openpic_readfield(&OpenPIC->Global.Global_Configuration0, + OPENPIC_CONFIG_RESET)) + ; } @@ -459,12 +466,12 @@ void do_openpic_setup_cpu(void) for ( i = 0; i < OPENPIC_NUM_IPI ; i++ ) openpic_enable_IPI(i); -#if 0 + /* let the openpic know we want intrs */ for ( i = 0; i < NumSources ; i++ ) openpic_mapirq(i, openpic_read(&OpenPIC->Source[i].Destination) | (1<= NumSources) + return; openpic_clearfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { @@ -509,15 +520,30 @@ void openpic_enable_irq(u_int irq) OPENPIC_MASK)); } +u_int openpic_get_enable(u_int irq) +{ + if (irq < 0 || irq >= NumSources) + return 0; + return !openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK); +} + void openpic_disable_irq(u_int irq) { - check_arg_irq(irq); + u32 vp; + + /* on SMP, we get IPI vector numbers here, we should handle them + * or at least ignore them. + */ + if (irq < 0 || irq >= NumSources) + return; openpic_setfield(&OpenPIC->Source[irq].Vector_Priority, OPENPIC_MASK); /* make sure mask gets to controller before we return to user */ do { - mb(); - } while(!openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, - OPENPIC_MASK)); + mb(); /* sync is probably useless here */ + vp = openpic_readfield(&OpenPIC->Source[irq].Vector_Priority, + OPENPIC_MASK | OPENPIC_ACTIVITY); + } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK)); } /* @@ -564,3 +590,50 @@ void openpic_set_sense(u_int irq, int sense) OPENPIC_SENSE_LEVEL, (sense ? OPENPIC_SENSE_LEVEL : 0)); } + +#ifdef CONFIG_PMAC_PBOOK +static u32 save_ipi_vp[OPENPIC_NUM_IPI]; +static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES]; +static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES]; +static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS]; + +__pmac +void +openpic_sleep_save_intrs(void) +{ + int i; + + for (i=0; iGlobal.IPI_Vector_Priority(i)); + for (i=0; iSource[i].Vector_Priority); + save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination); + } + for (i=0; iProcessor[i].Current_Task_Priority); + openpic_set_priority(i, 0xf); + } +} + +__pmac +void +openpic_sleep_restore_intrs(void) +{ + int i; + + for (i = 0; i < OPENPIC_NUM_TIMERS; i++) { + openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i); + openpic_maptimer(i, 0); + } + for (i=0; iGlobal.IPI_Vector_Priority(i), save_ipi_vp[i]); + for (i=0; iSource[i].Vector_Priority, save_irq_src_vp[i]); + openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]); + } + openpic_set_spurious(OPENPIC_VEC_SPURIOUS); + openpic_disable_8259_pass_through(); + for (i=0; iProcessor[i].Current_Task_Priority, save_cpu_task_pri[i]); +} +#endif /* CONFIG_PMAC_PBOOK */ \ No newline at end of file diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c index 058dc1f511e7..4b0cb9afe701 100644 --- a/arch/ppc/kernel/pci.c +++ b/arch/ppc/kernel/pci.c @@ -10,15 +10,20 @@ #include #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include #include +#include #include "pci.h" @@ -105,3 +110,156 @@ void __init fix_intr(struct device_node *node, struct pci_dev *dev) } } #endif + + +void * +pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical) +{ + if (!ppc_md.pci_dev_io_base) { + /* Please, someone fix this for non-pmac machines, we + * need either the virtual or physical PCI IO base + */ + return 0; + } + return ppc_md.pci_dev_io_base(bus, devfn, physical); +} + +void * +pci_dev_mem_base(unsigned char bus, unsigned char devfn) +{ + /* Default memory base is 0 (1:1 mapping) */ + if (!ppc_md.pci_dev_mem_base) { + /* Please, someone fix this for non-pmac machines.*/ + return 0; + } + return ppc_md.pci_dev_mem_base(bus, devfn); +} + +/* Returns the root-bridge number (Uni-N number) of a device */ +int +pci_dev_root_bridge(unsigned char bus, unsigned char devfn) +{ + /* Defaults to 0 */ + if (!ppc_md.pci_dev_root_bridge) + return 0; + return ppc_md.pci_dev_root_bridge(bus, devfn); +} + +/* + * Those syscalls are derived from the Alpha versions, they + * allow userland apps to retreive the per-device iobase and + * mem-base. They also provide wrapper for userland to do + * config space accesses. + * The "host_number" returns the number of the Uni-N sub bridge + */ + +asmlinkage int +sys_pciconfig_read(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + switch (len) { + case 1: + err = pcibios_read_config_byte(bus, dfn, off, &ubyte); + put_user(ubyte, buf); + break; + case 2: + err = pcibios_read_config_word(bus, dfn, off, &ushort); + put_user(ushort, (unsigned short *)buf); + break; + case 4: + err = pcibios_read_config_dword(bus, dfn, off, &uint); + put_user(uint, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + } + return err; +} + +asmlinkage int +sys_pciconfig_write(unsigned long bus, unsigned long dfn, + unsigned long off, unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + long err = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (!pcibios_present()) + return -ENOSYS; + + switch (len) { + case 1: + err = get_user(ubyte, buf); + if (err) + break; + err = pcibios_write_config_byte(bus, dfn, off, ubyte); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 2: + err = get_user(ushort, (unsigned short *)buf); + if (err) + break; + err = pcibios_write_config_word(bus, dfn, off, ushort); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + case 4: + err = get_user(uint, (unsigned int *)buf); + if (err) + break; + err = pcibios_write_config_dword(bus, dfn, off, uint); + if (err != PCIBIOS_SUCCESSFUL) { + err = -EFAULT; + } + break; + default: + err = -EINVAL; + break; + } + return err; +} + +/* Provide information on locations of various I/O regions in physical + * memory. Do this on a per-card basis so that we choose the right + * root bridge. + * Note that the returned IO or memory base is a physical address + */ + +asmlinkage long +sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) +{ + long result = -EOPNOTSUPP; + + switch (which) { + case IOBASE_BRIDGE_NUMBER: + return (long)pci_dev_root_bridge(bus, devfn); + case IOBASE_MEMORY: + return (long)pci_dev_mem_base(bus, devfn); + case IOBASE_IO: + result = (long)pci_dev_io_base(bus, devfn, 1); + if (result == 0) + result = -EOPNOTSUPP; + break; + } + + return result; +} diff --git a/arch/ppc/kernel/pmac_pci.c b/arch/ppc/kernel/pmac_pci.c index 462b92bc70c7..1216aabe370a 100644 --- a/arch/ppc/kernel/pmac_pci.c +++ b/arch/ppc/kernel/pmac_pci.c @@ -32,6 +32,8 @@ struct uninorth_data { struct device_node* node; volatile unsigned int* cfg_addr; volatile unsigned int* cfg_data; + void* iobase; + void* iobase_phys; }; static struct uninorth_data uninorth_bridges[3]; @@ -83,6 +85,81 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, return 0; } +/* This routines figures out on which root bridge a given PCI device + * is attached. + * + * WARNING: When passed the address of the bridge itself (11), it must + * return the AGP bus. Currently, it returns 0, which is by + * chance the AGP one. We may have to improve that however... + */ +__pmac +int +pmac_pci_dev_root_bridge(unsigned char bus, unsigned char dev_fn) +{ + struct device_node *node, *bridge_node; + int bridge = uninorth_default; + + if (uninorth_count == 0) + return 0; + if (bus == 0 && PCI_SLOT(dev_fn) < 11) + return 0; + + /* We look for the OF device corresponding to this bus/devfn pair. If we + * don't find it, we default to the external PCI */ + bridge_node = NULL; + node = find_pci_device_OFnode(bus, dev_fn & 0xf8); + if (node) { + /* note: we don't stop on the first occurence since we need to go + * up to the root bridge */ + do { + if (node->type && !strcmp(node->type, "pci") + && device_is_compatible(node, "uni-north")) + bridge_node = node; + node=node->parent; + } while (node); + } + if (bridge_node) { + int i; + for (i=0;i max_bus || (bp = bridges[bus]) == 0) + return 0; + return physical ? bp->io_base_phys : bp->io_base; + } + return physical ? uninorth_bridges[bridge].iobase_phys + : uninorth_bridges[bridge].iobase; +} + +__pmac +void * +pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn) +{ + return 0; +} + /* This function only works for bus 0, uni-N uses a different mecanism for * other busses (see below) */ @@ -99,48 +176,20 @@ int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, |1UL) -/* We should really use RTAS here, unfortunately, it's not available with BootX. - * (one more reason for writing a beautiful OF booter). I'll do the RTAS stuff - * later, once I have something that works enough with BootX. - */ __pmac static unsigned int uni_north_access_data(unsigned char bus, unsigned char dev_fn, unsigned char offset) { - struct device_node *node, *bridge_node; - int bridge = uninorth_default; + int bridge; unsigned int caddr; - if (bus == 0) { - if (PCI_SLOT(dev_fn) < 11) { - return 0; - } - /* We look for the OF device corresponding to this bus/devfn pair. If we - * don't find it, we default to the external PCI */ - bridge_node = NULL; - node = find_pci_device_OFnode(bus, dev_fn & 0xf8); - if (node) { - /* note: we don't stop on the first occurence since we need to go - * up to the root bridge */ - do { - if (!strcmp(node->type, "pci")) - bridge_node = node; - node=node->parent; - } while (node); - } - if (bridge_node) { - int i; - for (i=0;icfg_data, val); } +static int __init +fixup_one_level_bus_range(struct device_node *node, int higher) +{ + for (; node != 0;node = node->sibling) { + int * bus_range; + unsigned int *class_code; + int len; + + /* For PCI<->PCI bridges or CardBus bridges, we go down */ + class_code = (unsigned int *) get_property(node, "class-code", 0); + if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && + (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) + continue; + bus_range = (int *) get_property(node, "bus-range", &len); + if (bus_range != NULL && len > 2 * sizeof(int)) { + if (bus_range[1] > higher) + higher = bus_range[1]; + } + higher = fixup_one_level_bus_range(node->child, higher); + } + return higher; +} + +/* This routine fixes the "bus-range" property of all bridges in the + * system since they tend to have their "last" member wrong on macs + * + * Note that the bus numbers manipulated here are OF bus numbers, they + * are not Linux bus numbers. + */ +static void __init +fixup_bus_range(struct device_node *bridge) +{ + int * bus_range; + int len; + + /* Lookup the "bus-range" property for the hose */ + bus_range = (int *) get_property(bridge, "bus-range", &len); + if (bus_range == NULL || len < 2 * sizeof(int)) { + printk(KERN_WARNING "Can't get bus-range for %s\n", + bridge->full_name); + return; + } + bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]); +} __initfunc(unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)) { @@ -596,6 +689,7 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p dev->full_name); continue; } + fixup_bus_range(dev); bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s\n", @@ -613,6 +707,9 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p uninorth_bridges[i].cfg_addr = ioremap(addr->address + 0x800000, 0x1000); uninorth_bridges[i].cfg_data = ioremap(addr->address + 0xc00000, 0x1000); uninorth_bridges[i].node = dev; + uninorth_bridges[i].iobase_phys = (void *)addr->address; + /* is 0x10000 enough for io space ? */ + uninorth_bridges[i].iobase = (void *)ioremap(addr->address, 0x10000); /* XXX This is the bridge with the PCI expansion bus. This is also the * address of the bus that will receive type 1 config accesses and io * accesses. Appears to be correct for iMac DV and G4 Sawtooth too. @@ -630,8 +727,8 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p if (device_is_compatible(dev, "uni-north")) { bp->cfg_addr = 0; bp->cfg_data = 0; - /* is 0x10000 enough for io space ? */ - bp->io_base = (void *)ioremap(addr->address, 0x10000); + bp->io_base = uninorth_bridges[uninorth_count-1].iobase; + bp->io_base_phys = uninorth_bridges[uninorth_count-1].iobase_phys; } else if (strcmp(dev->name, "pci") == 0) { /* XXX assume this is a mpc106 (grackle) */ bp->cfg_addr = (volatile unsigned int *) @@ -639,6 +736,7 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p bp->cfg_data = (volatile unsigned char *) ioremap(0xfee00000, 0x1000); bp->io_base = (void *) ioremap(0xfe000000, 0x20000); + bp->io_base_phys = (void *)0xfe000000; if (machine_is_compatible("AAPL,PowerBook1998")) grackle_set_loop_snoop(bp, 1); #if 0 /* Disabled for now, HW problems ??? */ @@ -651,6 +749,7 @@ __initfunc(static void add_bridges(struct device_node *dev, unsigned long *mem_p bp->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); bp->io_base = (void *) ioremap(addr->address, 0x10000); + bp->io_base_phys = (void *)addr->address; } if (isa_io_base == 0) isa_io_base = (unsigned long) bp->io_base; diff --git a/arch/ppc/kernel/pmac_pic.c b/arch/ppc/kernel/pmac_pic.c index 083e043e8b98..19e3796d9b74 100644 --- a/arch/ppc/kernel/pmac_pic.c +++ b/arch/ppc/kernel/pmac_pic.c @@ -10,6 +10,7 @@ #include #include #include "pmac_pic.h" +#include "open_pic.h" struct pmac_irq_hw { unsigned int flag; @@ -28,7 +29,8 @@ static volatile struct pmac_irq_hw *pmac_irq_hw[4] = { static int max_irqs; static int max_real_irqs; -static int has_openpic = 0; + +extern u_int openpic_read(volatile u_int *addr); #define MAXCOUNT 10000000 @@ -106,18 +108,6 @@ static void __pmac pmac_unmask_irq(unsigned int irq_nr) pmac_set_irq_mask(irq_nr); } -static void pmac_openpic_mask_irq(unsigned int irq_nr) -{ - openpic_disable_irq(irq_nr); -} - -static void pmac_openpic_unmask_irq(unsigned int irq_nr) -{ - openpic_enable_irq(irq_nr); -} - - - struct hw_interrupt_type pmac_pic = { " PMAC-PIC ", NULL, @@ -140,17 +130,6 @@ struct hw_interrupt_type gatwick_pic = { 0 }; -struct hw_interrupt_type pmac_open_pic = { - " OpenPIC ", - NULL, - NULL, - NULL, - pmac_openpic_unmask_irq, - pmac_openpic_mask_irq, - NULL,/*pmac_openpic_mask_irq,*/ - 0 -}; - static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) { int irq, bits; @@ -179,6 +158,8 @@ pmac_do_IRQ(struct pt_regs *regs, int cpu, int isfake) { + extern void psurge_smp_message_recv(void); + int irq; unsigned long bits = 0; @@ -193,7 +174,7 @@ pmac_do_IRQ(struct pt_regs *regs, if (xmon_2nd) xmon(regs); #endif - pmac_smp_message_recv(); + psurge_smp_message_recv(); goto out; } /* could be here due to a do_fake_interrupt call but we don't @@ -221,29 +202,6 @@ pmac_do_IRQ(struct pt_regs *regs, } #endif /* __SMP__ */ - /* Yeah, I know, this could be a separate do_IRQ function */ - if (has_openpic) { - irq = openpic_irq(0); - if (irq == OPENPIC_VEC_SPURIOUS) { - /* Spurious interrupts should never be ack'ed */ - ppc_spurious_interrupts++; - } else { - /* Can this happen ? (comes from CHRP code) */ - if (irq < 0) { - printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n", - irq, regs->nip); - ppc_spurious_interrupts++; - } else { - if (!irq_desc[irq].level) - openpic_eoi(0); - ppc_irq_dispatch_handler( regs, irq ); - if (irq_desc[irq].level) - openpic_eoi(0); - } - } - return; - } - for (irq = max_real_irqs - 1; irq > 0; irq -= 32) { int i = irq >> 5; bits = ld_le32(&pmac_irq_hw[i]->flag) @@ -398,6 +356,8 @@ pmac_pic_init(void)) struct device_node *irqctrler; volatile struct pmac_irq_hw *addr; int second_irq; + u_int t; + int nr_irq; /* We first try to detect Apple's new Core99 chipset, since mac-io * is quite different on those machines and contains an IBM MPIC2. @@ -412,18 +372,38 @@ pmac_pic_init(void)) OpenPIC = (volatile struct OpenPIC *) ioremap(irqctrler->addrs[0].address, irqctrler->addrs[0].size); - for ( i = 0 ; i < NR_IRQS ; i++ ) { - irq_desc[i].ctl = &pmac_open_pic; + /* from openpic.c code... --Troy + * dynamically figure out how many interrupts + * We should really do something like panic + * if nr_irq >= OPENPIC_VEC_IPI + */ + t = openpic_read(&OpenPIC->Global.Feature_Reporting0); + nr_irq = ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >> + OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1; + + for ( i = 0 ; i < nr_irq ; i++ ) { + irq_desc[i].ctl = &open_pic; irq_desc[i].level = 0; } + ppc_md.do_IRQ = open_pic_do_IRQ; + open_pic.irq_offset = 0; openpic_init(1); - has_openpic = 1; #ifdef CONFIG_XMON pswitch = find_devices("programmer-switch"); if (pswitch && pswitch->n_intrs) request_irq(pswitch->intrs[0].line, xmon_irq, 0, "NMI - XMON", 0); #endif /* CONFIG_XMON */ +#ifdef __SMP__ + request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, + 0, "IPI0", 0); + request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action, + 0, "IPI1 (invalidate TLB)", 0); + request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action, + 0, "IPI2 (stop CPU)", 0); + request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action, + 0, "IPI3 (reschedule)", 0); +#endif /* __SMP__ */ return; } irqctrler = NULL; @@ -507,17 +487,20 @@ pmac_pic_init(void)) * sleep_save_intrs() saves the states of all interrupt enables * and disables all interupts except for the nominated one. * sleep_restore_intrs() restores the states of all interrupt enables. + * + * TODO: Those should be sleep notifiers with high priority. */ unsigned int sleep_save_mask[2]; void -sleep_save_intrs(int viaint) +pmac_sleep_save_intrs(int viaint) { sleep_save_mask[0] = ppc_cached_irq_mask[0]; sleep_save_mask[1] = ppc_cached_irq_mask[1]; ppc_cached_irq_mask[0] = 0; ppc_cached_irq_mask[1] = 0; - set_bit(viaint, ppc_cached_irq_mask); + if (viaint > 0) + set_bit(viaint, ppc_cached_irq_mask); out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]); if (max_real_irqs > 32) out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]); @@ -526,10 +509,11 @@ sleep_save_intrs(int viaint) } void -sleep_restore_intrs(void) +pmac_sleep_restore_intrs(void) { int i; + out_le32(&pmac_irq_hw[0]->enable, 0); if (max_real_irqs > 32) out_le32(&pmac_irq_hw[1]->enable, 0); diff --git a/arch/ppc/kernel/pmac_setup.c b/arch/ppc/kernel/pmac_setup.c index 78def39c3639..42d1cfee68a2 100644 --- a/arch/ppc/kernel/pmac_setup.c +++ b/arch/ppc/kernel/pmac_setup.c @@ -57,19 +57,20 @@ #include #include #include - +#include #include + #include "local_irq.h" #include "pmac_pic.h" #undef SHOW_GATWICK_IRQS -void pmac_time_init(void); -unsigned long pmac_get_rtc_time(void); -int pmac_set_rtc_time(unsigned long nowtime); -void pmac_read_rtc_time(void); -void pmac_calibrate_decr(void); -void pmac_setup_pci_ptrs(void); +extern long pmac_time_init(void); +extern unsigned long pmac_get_rtc_time(void); +extern int pmac_set_rtc_time(unsigned long nowtime); +extern void pmac_read_rtc_time(void); +extern void pmac_calibrate_decr(void); +extern void pmac_setup_pci_ptrs(void); extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); @@ -79,22 +80,29 @@ extern char mackbd_unexpected_up(unsigned char keycode); extern void mackbd_leds(unsigned char leds); extern void mackbd_init_hw(void); #ifdef CONFIG_MAGIC_SYSRQ -unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mackbd_sysrq_xlate[128]; +extern unsigned char mac_hid_kbd_sysrq_xlate[128]; +extern unsigned char pckbd_sysrq_xlate[128]; #endif /* CONFIG_MAGIC_SYSRQ */ -extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); -extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode); -extern char pckbd_unexpected_up(unsigned char keycode); -extern void pckbd_leds(unsigned char leds); -extern void pckbd_init_hw(void); +extern int keyboard_sends_linux_keycodes; +extern int mac_hid_kbd_translate(unsigned char scancode, + unsigned char *keycode, char raw_mode); +extern char mac_hid_kbd_unexpected_up(unsigned char keycode); +extern void mac_hid_init_hw(void); + extern void pmac_nvram_update(void); +extern void *pmac_pci_dev_io_base(unsigned char bus, unsigned char devfn); +extern void *pmac_pci_dev_mem_base(unsigned char bus, unsigned char devfn); +extern int pmac_pci_dev_root_bridge(unsigned char bus, unsigned char devfn); + unsigned char drive_info; int ppc_override_l2cr = 0; int ppc_override_l2cr_value; +static int current_root_goodness = -1; + extern char saved_command_line[]; extern int pmac_newworld; @@ -104,7 +112,26 @@ extern int pmac_newworld; extern void zs_kgdb_hook(int tty_num); static void ohare_init(void); static void init_p2pbridge(void); -static void init_uninorth(void); + +#ifdef CONFIG_SMP +volatile static long int core99_l2_cache; +void core99_init_l2(void) +{ + int cpu = smp_processor_id(); + + if ( (_get_PVR() >> 16) != 8 && (_get_PVR() >> 16) != 12 ) + return; + + if (cpu == 0){ + core99_l2_cache = _get_L2CR(); + printk("CPU0: L2CR is %lx\n", core99_l2_cache); + } else { + printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR()); + _set_L2CR(core99_l2_cache); + printk("CPU%d: L2CR set to %lx\n", cpu, core99_l2_cache); + } +} +#endif /* CONFIG_SMP */ __pmac int @@ -247,7 +274,7 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) struct device_node *cpu; int *fp; - /* Set loops_per_sec to a half-way reasonable value, + /* Set loops_per_jiffy to a half-way reasonable value, for use until calibrate_delay gets called. */ cpu = find_type_devices("cpu"); if (cpu != 0) { @@ -260,13 +287,13 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) case 10: /* mach V (604ev5) */ case 12: /* G4 */ case 20: /* 620 */ - loops_per_jiffy = (*fp)/HZ; + loops_per_jiffy = *fp / HZ; break; default: /* 601, 603, etc. */ - loops_per_jiffy = (*fp / 2)/HZ; + loops_per_jiffy = *fp / (2*HZ); } } else - loops_per_jiffy = 50000000/HZ; + loops_per_jiffy = 50000000 / HZ; } /* this area has the CPU identification register @@ -277,9 +304,10 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) *memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p); init_p2pbridge(); - init_uninorth(); - /* Checks "l2cr-value" property in the registry */ + /* Checks "l2cr-value" property in the registry + * And enable G3/G4 Dynamic Power Management + */ if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) { struct device_node *np = find_devices("cpus"); if (np == 0) @@ -291,9 +319,11 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) ppc_override_l2cr = 1; ppc_override_l2cr_value = *l2cr; _set_L2CR(0); - _set_L2CR(ppc_override_l2cr_value); + if (ppc_override_l2cr_value) + _set_L2CR(ppc_override_l2cr_value); } } + _set_HID0(_get_HID0() | HID0_DPM); } if (ppc_override_l2cr) @@ -302,6 +332,10 @@ pmac_setup_arch(unsigned long *memory_start_p, unsigned long *memory_end_p)) ? "enabled" : "disabled"); feature_init(); +#ifdef CONFIG_SMP + core99_init_l2(); +#endif + #ifdef CONFIG_KGDB zs_kgdb_hook(0); #endif @@ -368,38 +402,6 @@ __initfunc(static void ohare_init(void)) } } -__initfunc(static void init_uninorth(void)) -{ - /* - * Turns OFF the gmac clock. The gmac driver will turn - * it back ON when the interface is enabled. This save - * power on portables. - * - * Note: We could also try to turn OFF the PHY. Since this - * has to be done by both the gmac driver and this code, - * I'll probably end-up moving some of this out of the - * modular gmac driver into a non-modular stub containing - * some basic PHY management and power management stuffs - */ - struct device_node* uni_n = find_devices("uni-n"); - struct device_node* gmac = find_devices("ethernet"); - unsigned long* addr; - - if (!uni_n || uni_n->n_addrs < 1) - return; - addr = ioremap(uni_n->addrs[0].address, 0x300); - - while(gmac) { - if (device_is_compatible(gmac, "gmac")) - break; - gmac = gmac->next; - } - if (gmac) { - *(addr + 8) &= ~0x00000002UL; - eieio(); - } -} - extern char *bootpath; extern char *bootdevice; void *boot_host; @@ -481,13 +483,14 @@ __initfunc(void find_boot_device(void)) /* can't be initfunc - can be called whenever a disk is first accessed */ __pmac -void note_bootable_part(kdev_t dev, int part) +void note_bootable_part(kdev_t dev, int part, int goodness) { static int found_boot = 0; char *p; /* Do nothing if the root has been set already. */ - if (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)) + if ((goodness < current_root_goodness) && + (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE))) return; p = strstr(saved_command_line, "root="); if (p != NULL && (p == saved_command_line || p[-1] == ' ')) @@ -500,7 +503,7 @@ void note_bootable_part(kdev_t dev, int part) if (boot_dev == 0 || dev == boot_dev) { ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part); boot_dev = NODEV; - printk(" (root on %d)", part); + current_root_goodness = goodness; } } @@ -655,7 +658,8 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.get_rtc_time = pmac_get_rtc_time; ppc_md.calibrate_decr = pmac_calibrate_decr; -#if defined(CONFIG_VT) && defined(CONFIG_MAC_KEYBOARD) +#ifdef CONFIG_VT +#ifdef CONFIG_MAC_KEYBOARD ppc_md.kbd_setkeycode = mackbd_setkeycode; ppc_md.kbd_getkeycode = mackbd_getkeycode; ppc_md.kbd_translate = mackbd_translate; @@ -663,10 +667,30 @@ pmac_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = mackbd_leds; ppc_md.kbd_init_hw = mackbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = mackbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x69; + ppc_md.sysrq_xlate = mackbd_sysrq_xlate; + SYSRQ_KEY = 0x69; #endif +#elif defined(CONFIG_INPUT_ADBHID) + ppc_md.kbd_setkeycode = 0; + ppc_md.kbd_getkeycode = 0; + ppc_md.kbd_translate = mac_hid_kbd_translate; + ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up; + ppc_md.kbd_leds = 0; + ppc_md.kbd_init_hw = mac_hid_init_hw; +#ifdef CONFIG_MAGIC_SYSRQ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; + } else +#endif /* CONFIG_MAC_ADBKEYCODES */ + { + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; + } #endif +#endif /* CONFIG_MAC_KEYBOARD */ +#endif /* CONFIG_VT */ #if defined(CONFIG_BLK_DEV_IDE_PMAC) ppc_ide_md.insw = pmac_ide_insw; diff --git a/arch/ppc/kernel/pmac_support.c b/arch/ppc/kernel/pmac_support.c index 5edaa8553104..8a976c621a4d 100644 --- a/arch/ppc/kernel/pmac_support.c +++ b/arch/ppc/kernel/pmac_support.c @@ -24,6 +24,7 @@ #include #include #include +#include #undef DEBUG @@ -66,6 +67,12 @@ static int nvram_mult, is_core_99; static int core99_bank = 0; static int nvram_partitions[3]; +static struct backlight_controller *backlighter = NULL; +static void* backlighter_data = NULL; +static int backlight_autosave = 0; +static int backlight_level = BACKLIGHT_MAX; +static int backlight_enabled = 1; + /* FIXME: kmalloc fails to allocate the image now that I had to move it * before time_init(). For now, I allocate a static buffer here * but it's a waste of space on all but core99 machines @@ -73,12 +80,12 @@ static int nvram_partitions[3]; #if 0 static char* nvram_image; #else -__pmac static char nvram_image[NVRAM_SIZE]; +static char nvram_image[NVRAM_SIZE]; #endif extern int pmac_newworld; -static u8 +static u8 __pmac chrp_checksum(struct chrp_header* hdr) { u8 *ptr; @@ -90,7 +97,7 @@ chrp_checksum(struct chrp_header* hdr) return sum; } -static u32 +static u32 __pmac core99_calc_adler(u8 *buffer) { int cnt; @@ -113,7 +120,7 @@ core99_calc_adler(u8 *buffer) return (high << 16) | low; } -static u32 +static u32 __pmac core99_check(u8* datas) { struct core99_header* hdr99 = (struct core99_header*)datas; @@ -139,7 +146,7 @@ core99_check(u8* datas) return hdr99->generation; } -static int +static int __pmac core99_erase_bank(int bank) { int stat, i; @@ -163,7 +170,7 @@ core99_erase_bank(int bank) return 0; } -static int +static int __pmac core99_write_bank(int bank, u8* datas) { int i, stat = 0; @@ -191,7 +198,7 @@ core99_write_bank(int bank, u8* datas) return 0; } -static void +static void __pmac lookup_partitions(void) { u8 buffer[17]; @@ -281,7 +288,8 @@ void pmac_nvram_init(void) } else if (nvram_naddrs == 2) { nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size); nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size); - } else if (nvram_naddrs == 0 && adb_controller->kind == ADB_VIAPMU) { + } else if (nvram_naddrs == 0 && adb_controller && + adb_controller->kind == ADB_VIAPMU) { nvram_naddrs = -1; } else { printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n", @@ -290,7 +298,7 @@ void pmac_nvram_init(void) lookup_partitions(); } -void +void __pmac pmac_nvram_update(void) { struct core99_header* hdr99; @@ -317,7 +325,7 @@ pmac_nvram_update(void) printk("nvram: Error writing bank %d\n", core99_bank); } -unsigned char +unsigned char __pmac nvram_read_byte(int addr) { struct adb_request req; @@ -342,7 +350,7 @@ nvram_read_byte(int addr) return 0; } -void +void __pmac nvram_write_byte(unsigned char val, int addr) { struct adb_request req; @@ -373,13 +381,13 @@ nvram_write_byte(unsigned char val, int addr) eieio(); } -int +int __pmac pmac_get_partition(int partition) { return nvram_partitions[partition]; } -u8 +u8 __pmac pmac_xpram_read(int xpaddr) { int offset = nvram_partitions[pmac_nvram_XPRAM]; @@ -390,7 +398,7 @@ pmac_xpram_read(int xpaddr) return nvram_read_byte(xpaddr + offset); } -void +void __pmac pmac_xpram_write(int xpaddr, u8 data) { int offset = nvram_partitions[pmac_nvram_XPRAM]; @@ -401,3 +409,118 @@ pmac_xpram_write(int xpaddr, u8 data) nvram_write_byte(xpaddr + offset, data); } +void __pmac +register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type) +{ + struct device_node* bk_node; + char *prop; + int valid = 0; + + bk_node = find_devices("backlight"); + + /* Special case for the old PowerBooks, they don't yet have + * the property we expect + */ + backlight_autosave = machine_is_compatible("AAPL,3400/2400") + || machine_is_compatible("AAPL,3500"); + if ((backlight_autosave + || machine_is_compatible("AAPL,PowerBook1998") + || machine_is_compatible("PowerBook1,1")) + && !strcmp(type, "pmu")) + valid = 1; + else if (bk_node) { + prop = get_property(bk_node, "backlight-control", NULL); + if (prop && !strncmp(prop, type, strlen(type))) + valid = 1; + } + if (!valid) + return; + backlighter = ctrler; + backlighter_data = data; + + if (bk_node && !backlight_autosave) + prop = get_property(bk_node, "bklt", NULL); + else + prop = NULL; + if (prop) { + backlight_level = ((*prop)+1) >> 1; + if (backlight_level > BACKLIGHT_MAX) + backlight_level = BACKLIGHT_MAX; + } + + if (backlight_autosave) { + struct adb_request req; + pmu_request(&req, NULL, 2, 0xd9, 0); + while (!req.complete) + pmu_poll(); + backlight_level = req.reply[1] >> 4; + } + + if (!backlighter->set_enable(1, backlight_level, data)) + backlight_enabled = 1; + + printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n", + type, backlight_level); +} + +void __pmac +unregister_backlight_controller(struct backlight_controller *ctrler, void *data) +{ + /* We keep the current backlight level (for now) */ + if (ctrler == backlighter && data == backlighter_data) + backlighter = NULL; +} + +int __pmac +set_backlight_enable(int enable) +{ + int rc; + + if (!backlighter) + return -ENODEV; + rc = backlighter->set_enable(enable, backlight_level, backlighter_data); + if (!rc) + backlight_enabled = enable; + return rc; +} + +int __pmac +get_backlight_enable(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_enabled; +} + +int __pmac +set_backlight_level(int level) +{ + int rc = 0; + + if (!backlighter) + return -ENODEV; + if (level < BACKLIGHT_MIN) + level = BACKLIGHT_OFF; + if (level > BACKLIGHT_MAX) + level = BACKLIGHT_MAX; + if (backlight_enabled) + rc = backlighter->set_level(level, backlighter_data); + if (!rc) + backlight_level = level; + if (!rc && !backlight_autosave) { + level <<=1; + if (level & 0x10) + level |= 0x01; + // -- todo: save to property "bklt" + } + return rc; +} + +int __pmac +get_backlight_level(void) +{ + if (!backlighter) + return -ENODEV; + return backlight_level; +} + diff --git a/arch/ppc/kernel/pmac_time.c b/arch/ppc/kernel/pmac_time.c index d65110d0df51..f4c5d7f5cf25 100644 --- a/arch/ppc/kernel/pmac_time.c +++ b/arch/ppc/kernel/pmac_time.c @@ -53,7 +53,7 @@ extern struct timezone sys_tz; __init -void pmac_time_init(void) +long pmac_time_init(void) { s32 delta = 0; int dst; @@ -66,16 +66,13 @@ void pmac_time_init(void) dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, dst ? "on" : "off"); - sys_tz.tz_minuteswest = -delta/60; - /* I _suppose_ this is 0:off, 1:on */ - sys_tz.tz_dsttime = dst; + return -delta; } __pmac unsigned long pmac_get_rtc_time(void) { struct adb_request req; - int offset = sys_tz.tz_minuteswest * 60; /* Get the time from the RTC */ if (adb_controller == 0) @@ -92,7 +89,7 @@ unsigned long pmac_get_rtc_time(void) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); return (req.reply[3] << 24) + (req.reply[4] << 16) - + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET + offset; + + (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET; case ADB_VIAPMU: if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) { printk("pmac_read_rtc_time: pmu_request failed\n"); @@ -104,7 +101,7 @@ unsigned long pmac_get_rtc_time(void) printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", req.reply_len); return (req.reply[1] << 24) + (req.reply[2] << 16) - + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET + offset; + + (req.reply[3] << 8) + req.reply[4] - RTC_OFFSET; default: return 0; } @@ -115,7 +112,7 @@ int pmac_set_rtc_time(unsigned long nowtime) struct adb_request req; int dst, delta; - nowtime += RTC_OFFSET - sys_tz.tz_minuteswest * 60; + nowtime += RTC_OFFSET; /* Set the time in the RTC */ if (adb_controller == 0) @@ -147,15 +144,6 @@ int pmac_set_rtc_time(unsigned long nowtime) return 0; } - /* write the timezone offset back into the xpram */ - delta = sys_tz.tz_minuteswest * -60; - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0x9, delta >> 16); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xa, delta >> 8); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 0xb, delta); - dst = pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 8); - dst = sys_tz.tz_dsttime? (dst | 0x80): (dst & ~0x80); - pmac_xpram_write(PMAC_XPRAM_MACHINE_LOC + 8, dst); - return 1; } diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c index 813179276e97..24d241bba070 100644 --- a/arch/ppc/kernel/ppc_htab.c +++ b/arch/ppc/kernel/ppc_htab.c @@ -587,9 +587,8 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp, buffer += len; left -= len; _set_L2CR(0); - _set_L2CR(val); - while ( _get_L2CR() & 0x1 ) - /* wait for invalidate to finish */; + if (val) + _set_L2CR(val); } else { p = buf; diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 54a8f763bfb9..5a051a79c4ea 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -81,8 +81,10 @@ EXPORT_SYMBOL(pci_dram_offset); EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); +#if defined(CONFIG_PREP) || defined(CONFIG_ALL_PPC) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); +#endif EXPORT_SYMBOL(atomic_add); EXPORT_SYMBOL(atomic_sub); @@ -188,23 +190,13 @@ EXPORT_SYMBOL(_read_lock); EXPORT_SYMBOL(_read_unlock); EXPORT_SYMBOL(_write_lock); EXPORT_SYMBOL(_write_unlock); -#endif +#endif /* __SMP__ */ EXPORT_SYMBOL(_machine); EXPORT_SYMBOL(ppc_md); - -EXPORT_SYMBOL(adb_request); -EXPORT_SYMBOL(adb_register); -EXPORT_SYMBOL(cuda_request); -EXPORT_SYMBOL(cuda_poll); -EXPORT_SYMBOL(pmu_request); -EXPORT_SYMBOL(pmu_poll); -#ifdef CONFIG_PMAC_PBOOK -EXPORT_SYMBOL(pmu_register_sleep_notifier); -EXPORT_SYMBOL(pmu_unregister_sleep_notifier); -EXPORT_SYMBOL(pmu_enable_irled); -#endif CONFIG_PMAC_PBOOK EXPORT_SYMBOL(abort); + +#ifndef CONFIG_MBX EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -215,25 +207,43 @@ EXPORT_SYMBOL(machine_is_compatible); EXPORT_SYMBOL(find_pci_device_OFnode); EXPORT_SYMBOL(find_all_nodes); EXPORT_SYMBOL(get_property); +#endif /* CONFIG_MBX */ +#ifdef CONFIG_POWERMAC +EXPORT_SYMBOL(adb_request); +EXPORT_SYMBOL(adb_register); +EXPORT_SYMBOL(cuda_request); +EXPORT_SYMBOL(cuda_poll); +EXPORT_SYMBOL(pmu_request); +EXPORT_SYMBOL(pmu_poll); +#endif /* CONFIG_POWERMAC */ +#ifdef CONFIG_PMAC_PBOOK +EXPORT_SYMBOL(pmu_register_sleep_notifier); +EXPORT_SYMBOL(pmu_unregister_sleep_notifier); +EXPORT_SYMBOL(pmu_enable_irled); +#endif /* CONFIG_PMAC_PBOOK */ +#ifdef CONFIG_POWERMAC EXPORT_SYMBOL(pci_io_base); +EXPORT_SYMBOL(pci_dev_io_base); +EXPORT_SYMBOL(pci_dev_mem_base); EXPORT_SYMBOL(pci_device_loc); EXPORT_SYMBOL(feature_set); EXPORT_SYMBOL(feature_clear); EXPORT_SYMBOL(feature_test); -#ifdef CONFIG_SCSI -EXPORT_SYMBOL(note_scsi_host); -#endif -EXPORT_SYMBOL(kd_mksound); -/*#ifdef CONFIG_PMAC */ +EXPORT_SYMBOL(feature_set_gmac_power); +EXPORT_SYMBOL(feature_set_gmac_phy_reset); +EXPORT_SYMBOL(feature_set_usb_power); +EXPORT_SYMBOL(feature_set_firewire_power); EXPORT_SYMBOL(nvram_read_byte); EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(pmac_xpram_read); EXPORT_SYMBOL(pmac_xpram_write); -/*#endif*/ /* CONFIG_PMAC */ -#ifdef CONFIG_PPC_RTC +#ifdef CONFIG_SCSI +EXPORT_SYMBOL(note_scsi_host); +#endif /* CONFIG_SCSI */ +#endif /* CONFIG_POWERMAC */ +EXPORT_SYMBOL(kd_mksound); EXPORT_SYMBOL(mktime); EXPORT_SYMBOL(to_tm); -#endif EXPORT_SYMBOL(abs); diff --git a/arch/ppc/kernel/prep_pci.c b/arch/ppc/kernel/prep_pci.c index 2932aedd5a80..71c8bcae5428 100644 --- a/arch/ppc/kernel/prep_pci.c +++ b/arch/ppc/kernel/prep_pci.c @@ -25,6 +25,7 @@ #include #include "pci.h" +#include "open_pic.h" #define MAX_DEVNR 22 @@ -42,8 +43,6 @@ void Powerplus_Map_Non0(struct pci_dev *); /* Used for Motorola to store system config register */ static unsigned long *ProcInfo; -extern void chrp_do_IRQ(struct pt_regs *,int , int); - /* Tables for known hardware */ /* Motorola PowerStackII - Utah */ @@ -784,7 +783,7 @@ __initfunc(int raven_init(void)) OpenPIC_InitSenses = mvme2600_openpic_initsenses; OpenPIC_NumInitSenses = sizeof(mvme2600_openpic_initsenses); - ppc_md.do_IRQ = chrp_do_IRQ; + ppc_md.do_IRQ = open_pic_do_IRQ; /* If raven is present on Motorola store the system config register * for later use. @@ -1131,7 +1130,7 @@ int motopenpic_to_irq(int n) if (n & 0xF0) { return (n & 0x0F); } else { - return(openpic_to_irq(n)); + return(n+open_pic.irq_offset); } } @@ -1170,6 +1169,17 @@ struct pci_dev *dev = NULL; dev->devfn, 0x44, short_reg); } } + if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, + PCI_DEVICE_ID_WINBOND_82C105, dev))){ + if (OpenPIC){ + /* Disable LEGIRQ mode so PCI INTs are routed to + the 8259 */ + pci_write_config_dword(dev, 0x40, 0x10ff00a1); + } else { + /* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */ + pci_write_config_dword(dev, 0x40, 0x10ff08a1); + } + } } __initfunc( void diff --git a/arch/ppc/kernel/prep_setup.c b/arch/ppc/kernel/prep_setup.c index 7b8137106f7b..f09627141f39 100644 --- a/arch/ppc/kernel/prep_setup.c +++ b/arch/ppc/kernel/prep_setup.c @@ -47,9 +47,10 @@ #include #include #include - - +#include #include +#include + #include "local_irq.h" #include "i8259.h" #include "open_pic.h" @@ -107,9 +108,6 @@ extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ extern int rd_image_start; /* starting block # of image */ #endif -#ifdef CONFIG_VGA_CONSOLE -unsigned long vgacon_remap_base; -#endif __prep int @@ -617,8 +615,14 @@ prep_init_IRQ(void)) irq_desc[i].ctl = &i8259_pic; i8259_init(); #ifdef __SMP__ - request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS), openpic_ipi_action, + request_irq(OPENPIC_VEC_IPI, openpic_ipi_action, 0, "IPI0", 0); + request_irq(OPENPIC_VEC_IPI+1, openpic_ipi_action, + 0, "IPI1 (invalidate TLB)", 0); + request_irq(OPENPIC_VEC_IPI+2, openpic_ipi_action, + 0, "IPI2 (stop CPU)", 0); + request_irq(OPENPIC_VEC_IPI+3, openpic_ipi_action, + 0, "IPI3 (reschedule)", 0); #endif /* __SMP__ */ } @@ -857,8 +861,8 @@ prep_init(unsigned long r3, unsigned long r4, unsigned long r5, ppc_md.kbd_leds = pckbd_leds; ppc_md.kbd_init_hw = pckbd_init_hw; #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.kbd_sysrq_xlate = pckbd_sysrq_xlate; - ppc_md.SYSRQ_KEY = 0x54; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; #endif #endif } diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index 0a6b08e66ec3..3f44de7d3116 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -233,7 +233,7 @@ void print_bits(unsigned int val, struct bits *bits) printk("["); for (; bits->bit != 0; ++bits) { if (val & bits->bit) { - printk("%s", bits->name); + printk("%s%s", sep, bits->name); sep = ", "; } } diff --git a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c index 8a240c46e0e3..4929adf8ce06 100644 --- a/arch/ppc/kernel/prom.c +++ b/arch/ppc/kernel/prom.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -27,6 +29,10 @@ #include #include #include +#include +#include +#include +#include /* * Properties whose value is longer than this get excluded from our @@ -109,6 +115,12 @@ static struct device_node *allnodes = 0; #ifdef CONFIG_BOOTX_TEXT +/* + * The VGA font is in the _pmac section. Can't this cause problems with CHRP + * using some of the prom_xxxx functions ? + * All this need to be moved in a separate source file anyway + */ + static void clearscreen(void); static void flushscreen(void); @@ -116,6 +128,9 @@ void drawchar(char c); void drawstring(const char *c); void drawhex(unsigned long v); static void scrollscreen(void); +static void prepare_disp_BAT(void); +static void boot_console_write(struct console *co, const char *s, + unsigned count); static void draw_byte(unsigned char c, long locX, long locY); static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb); @@ -128,10 +143,28 @@ static long g_loc_Y = 0; static long g_max_loc_X = 0; static long g_max_loc_Y = 0; +unsigned long disp_BATL = 0; +unsigned long disp_BATU = 0; + #define cmapsz (16*256) static unsigned char vga_font[cmapsz]; +static struct console boot_cons = { + "boot", + boot_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + 0, + 0, + NULL +}; +static int boot_cons_registered = 0; + #endif /* CONFIG_BOOTX_TEXT */ @@ -243,7 +276,7 @@ call_prom(const char *service, int nargs, int nret, ...) return prom_args.args[nargs]; } -__init +/*__init*/ void prom_print(const char *msg) { @@ -399,6 +432,7 @@ prom_init(int r3, int r4, prom_entry pp) } #ifdef CONFIG_BOOTX_TEXT + prepare_disp_BAT(); prom_print(RELOC("booting...\n")); flushscreen(); #endif @@ -573,7 +607,11 @@ prom_init(int r3, int r4, prom_entry pp) * is in its holding pattern code. * * -- Cort + * + * This code crashes on some pmacs since the memory at 8M is not + * claim'ed and so can be unmapped. -- BenH */ + if (chrp) { extern void __secondary_hold(void); unsigned long i; @@ -599,7 +637,7 @@ prom_init(int r3, int r4, prom_entry pp) } /* look for cpus */ - for (node = 0; prom_next_node(&node);) + for (node = 0; chrp && prom_next_node(&node);) { type[0] = 0; call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"), @@ -642,6 +680,7 @@ prom_init(int r3, int r4, prom_entry pp) if (!chrp && RELOC(disp_bi)) { RELOC(prom_stdout) = 0; clearscreen(); + prepare_disp_BAT(); prom_welcome(PTRRELOC(RELOC(disp_bi)), phys); } #endif @@ -692,9 +731,50 @@ void showvalue(char *str, unsigned long val) drawhex(val); drawstring("\n"); } + +/* Calc BAT values for mapping the display and store them + * in disp_BATH and disp_BATL. Those values are then used + * from head.S to map the display during identify_machine() + * and MMU_Init() + * + * For now, the display is mapped in place (1:1). This should + * be changed if the display physical address overlaps + * KERNELBASE, which is fortunately not the case on any machine + * I know of. This mapping is temporary and will disappear as + * soon as the setup done by MMU_Init() is applied + * + * For now, we align the BAT and then map 8Mb on 601 and 16Mb + * on other PPCs. This may cause trouble if the framebuffer + * is really badly aligned, but I didn't encounter this case + * yet. + */ +__init +static void +prepare_disp_BAT(void) +{ + unsigned long offset = reloc_offset(); + boot_infos_t* bi = PTRRELOC(RELOC(disp_bi)); + unsigned long addr = (unsigned long)bi->dispDeviceBase; + + if ((_get_PVR() >> 16) != 1) { + /* 603, 604, G3, G4, ... */ + addr &= 0xFF000000UL; + RELOC(disp_BATU) = addr | (BL_16M<<2) | 2; + RELOC(disp_BATL) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW); + } else { + /* 601 */ + addr &= 0xFF800000UL; + RELOC(disp_BATU) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4; + RELOC(disp_BATL) = addr | BL_8M | 0x40; + } + bi->logicalDisplayBase = bi->dispDeviceBase; +} + #endif -static int prom_set_color(ihandle ih, int i, int r, int g, int b) +__init +static int +prom_set_color(ihandle ih, int i, int r, int g, int b) { struct prom_args prom_args; unsigned long offset = reloc_offset(); @@ -729,7 +809,7 @@ check_display(unsigned long mem) ihandle ih; int i; unsigned long offset = reloc_offset(); - char type[16], *path; + char type[16], *path, name[32]; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, @@ -757,6 +837,12 @@ check_display(unsigned long mem) type, sizeof(type)); if (strcmp(type, RELOC("display")) != 0) continue; + name[0] = 0; + call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"), + name, sizeof(name)); + if (!strcmp(name, RELOC("offscreen-display"))) + continue; + /* It seems OF doesn't null-terminate the path :-( */ path = (char *) mem; memset(path, 0, 256); @@ -1189,7 +1275,7 @@ finish_node_interrupts(struct device_node *np, unsigned long mem_start) ((node->name && !strcmp(node->name, "open-pic")) || !node->name)) { for (i = 0; i < np->n_intrs; ++i) - np->intrs[i].line = openpic_to_irq(np->intrs[i].line); + np->intrs[i].line = np->intrs[i].line + NUM_8259_INTERRUPTS; } return mem_start; } @@ -1492,7 +1578,7 @@ interpret_macio_props(struct device_node *np, unsigned long mem_start) /* CHRP machines */ np->n_intrs = l / (2 * sizeof(int)); for (i = 0; i < np->n_intrs; ++i) { - np->intrs[i].line = openpic_to_irq(*ip++); + np->intrs[i].line = (*ip++) + NUM_8259_INTERRUPTS; np->intrs[i].sense = *ip++; } } @@ -1637,9 +1723,17 @@ find_pci_device_OFnode(unsigned char bus, unsigned char dev_fn) int l; for (np = allnodes; np != 0; np = np->allnext) { - char *pname = np->parent ? - (char *)get_property(np->parent, "name", &l) : 0; - if (pname && strcmp(pname, "mac-io") == 0) + int in_macio = 0; + struct device_node* parent = np->parent; + while(parent) { + char *pname = (char *)get_property(parent, "name", &l); + if (pname && strcmp(pname, "mac-io") == 0) { + in_macio = 1; + break; + } + parent = parent->parent; + } + if (in_macio) continue; reg = (unsigned int *) get_property(np, "reg", &l); if (reg == 0 || l < sizeof(struct reg_property)) @@ -1757,7 +1851,7 @@ get_property(struct device_node *np, const char *name, int *lenp) struct property *pp; for (pp = np->properties; pp != 0; pp = pp->next) - if (strcmp(pp->name, name) == 0) { + if (pp->name && strcmp(pp->name, name) == 0) { if (lenp != 0) *lenp = pp->length; return pp->value; @@ -1901,11 +1995,30 @@ __init void map_bootx_text(void) { + unsigned long base, offset, size; if (disp_bi == 0) return; - disp_bi->logicalDisplayBase = - ioremap((unsigned long) disp_bi->dispDeviceBase, - disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3]); + base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL; + offset = ((unsigned long) disp_bi->dispDeviceBase) - base; + size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset + + disp_bi->dispDeviceRect[0]; + disp_bi->logicalDisplayBase = ioremap(base, size) + offset; +} + +__init +void +install_boot_console(void) +{ + register_console(&boot_cons); + boot_cons_registered = 1; +} + +void +remove_boot_console(void) +{ + if (boot_cons_registered) + unregister_console(&boot_cons); + boot_cons_registered = 0; } /* Calc the base address of a given point (x,y) */ @@ -1981,7 +2094,11 @@ scrollscreen(void) unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3)) >> 2; int i,j; - + +#ifdef CONFIG_POWERMAC + pmu_suspend(); +#endif + for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) { unsigned long *src_ptr = src; @@ -1998,6 +2115,10 @@ scrollscreen(void) *(dst_ptr++) = 0; dst += (bi->dispDeviceRowBytes >> 2); } + +#ifdef CONFIG_POWERMAC + pmu_resume(); +#endif } __pmac @@ -2042,6 +2163,16 @@ drawstring(const char *c) drawchar(*c++); } +#ifdef CONFIG_BOOTX_TEXT +__pmac +static void boot_console_write(struct console *co, const char *s, + unsigned count) +{ + while(count--) + drawchar(*s++); +} +#endif + __pmac void drawhex(unsigned long v) diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c index 4d3a9a9e36da..0c11300c2c24 100644 --- a/arch/ppc/kernel/setup.c +++ b/arch/ppc/kernel/setup.c @@ -31,6 +31,7 @@ #endif #include #include +#include extern void pmac_init(unsigned long r3, unsigned long r4, @@ -68,9 +69,6 @@ extern void gemini_init(unsigned long r3, unsigned long r6, unsigned long r7); -#ifdef CONFIG_BOOTX_TEXT -extern void map_bootx_text(void); -#endif #ifdef CONFIG_XMON extern void xmon_map_scc(void); #endif @@ -98,6 +96,12 @@ int is_powerplus = 0; struct machdep_calls ppc_md; +#ifdef CONFIG_MAGIC_SYSRQ +unsigned long SYSRQ_KEY; +#endif /* CONFIG_MAGIC_SYSRQ */ +#ifdef CONFIG_VGA_CONSOLE +unsigned long vgacon_remap_base; +#endif /* copy of the residual data */ #ifndef CONFIG_MBX @@ -313,19 +317,11 @@ int get_cpuinfo(char *buffer) (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff); len += sprintf(buffer+len, "bogomips\t: %lu.%02lu\n", - (CD(loops_per_jiffy*HZ)+2500)/500000, - (CD(loops_per_jiffy*HZ)+2500)/5000 % 100); + (CD(loops_per_jiffy)+2500)/(500000/HZ), + (CD(loops_per_jiffy)+2500)/(5000/HZ) % 100); bogosum += CD(loops_per_jiffy); } -#ifdef __SMP__ - if ( i ) - len += sprintf(buffer+len, "\n"); - len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n", - (bogosum+2500)/500000, - (bogosum+2500)/5000 % 100); -#endif /* __SMP__ */ - /* * Ooh's and aah's info about zero'd pages in idle task */ @@ -490,15 +486,21 @@ identify_machine(unsigned long r3, unsigned long r4, unsigned long r5, switch (_machine) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: pmac_init(r3, r4, r5, r6, r7); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: prep_init(r3, r4, r5, r6, r7); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: chrp_init(r3, r4, r5, r6, r7); break; +#endif #ifdef CONFIG_APUS case _MACH_apus: apus_init(r3, r4, r5, r6, r7); @@ -557,7 +559,8 @@ void ppc_setup_l2cr(char *str, int *ints) unsigned long val = simple_strtoul(str, NULL, 0); printk(KERN_INFO "l2cr set to %lx\n", val); _set_L2CR(0); - _set_L2CR(val); + if (val) + _set_L2CR(val); } } @@ -578,9 +581,6 @@ __initfunc(void setup_arch(char **cmdline_p, extern unsigned long find_available_memory(void); extern unsigned long *end_of_DRAM; -#ifdef CONFIG_BOOTX_TEXT - map_bootx_text(); -#endif #ifdef CONFIG_XMON { @@ -610,8 +610,16 @@ __initfunc(void setup_arch(char **cmdline_p, *memory_end_p = (unsigned long) end_of_DRAM; ppc_md.setup_arch(memory_start_p, memory_end_p); + + sort_exception_table(); } +#ifndef CONFIG_POWERMAC +void note_bootable_part(kdev_t dev, int part, int goodness) +{ +} +#endif + void ppc_generic_ide_fix_driveid(struct hd_driveid *id) { int i; diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c index 1684fd31559e..20c3b1115a6d 100644 --- a/arch/ppc/kernel/signal.c +++ b/arch/ppc/kernel/signal.c @@ -14,6 +14,16 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. + * + * + * 2000-04-7. + * Define a real-time signal frame with siginfo and ucontext + * structures (setup_rt_frame()). + * Stuck up a real-time signal frame when setting the signal + * frame with SA_SIGINFO flags. + * Add sys_rt_sigreturn() to undo the signal stack. + * + * Giovanna Ambrosini (ambrosini@lightning.ch) */ #include @@ -121,13 +131,6 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, } -asmlinkage int sys_rt_sigreturn(unsigned long __unused) -{ - printk("sys_rt_sigreturn(): %s/%d not yet implemented.\n", - current->comm,current->pid); - do_exit(SIGSEGV); -} - asmlinkage int sys_sigaltstack(const stack_t *uss, stack_t *uoss) { @@ -171,13 +174,11 @@ sys_sigaction(int sig, const struct old_sigaction *act, * When we have signals to deliver, we set up on the * user stack, going down from the original stack pointer: * a sigregs struct - * one or more sigcontext structs + * one or more sigcontext structs with * a gap of __SIGNAL_FRAMESIZE bytes * * Each of these things must be a multiple of 16 bytes in size. * - * XXX ultimately we will have to stack up a siginfo and ucontext - * for each rt signal. */ struct sigregs { elf_gregset_t gp_regs; @@ -188,6 +189,15 @@ struct sigregs { int abigap[56]; }; +struct rt_sigframe +{ + unsigned long _unused[2]; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; +}; + /* * Do a signal return; undo the signal stack. */ @@ -259,6 +269,91 @@ badframe: do_exit(SIGSEGV); } + +/* + * When we have rt signals to deliver, we set up on the + * user stack, going down from the original stack pointer: + * a sigregs struct + * one rt_sigframe struct (siginfo + ucontext) + * a gap of __SIGNAL_FRAMESIZE bytes + * + * Each of these things must be a multiple of 16 bytes in size. + * + */ +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe *rt_sf; + struct sigcontext_struct sigctx; + struct sigregs *sr; + int ret; + elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ + sigset_t set; + stack_t st; + unsigned long prevsp; + + rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) + || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) + || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) + goto badframe; + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sigmask_lock); + current->blocked = set; + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + + rt_sf++; /* Look at next rt_sigframe */ + if (rt_sf == (struct rt_sigframe *)(sigctx.regs)) { + /* Last stacked signal - restore registers - + * sigctx is initialized to point to the + * preamble frame (where registers are stored) + * see handle_signal() + */ + sr = (struct sigregs *) sigctx.regs; + if (regs->msr & MSR_FP ) + giveup_fpu(current); + if (copy_from_user(saved_regs, &sr->gp_regs, + sizeof(sr->gp_regs))) + goto badframe; + saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) + | (saved_regs[PT_MSR] & MSR_USERCHANGE); + memcpy(regs, saved_regs, GP_REGS_SIZE); + if (copy_from_user(current->tss.fpr, &sr->fp_regs, + sizeof(sr->fp_regs))) + goto badframe; + /* This function sets back the stack flags into + the current task structure. */ + sys_sigaltstack(&st, NULL); + + ret = regs->result; + } else { + /* More signals to go */ + /* Set up registers for next signal handler */ + regs->gpr[1] = (unsigned long)rt_sf - __SIGNAL_FRAMESIZE; + if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))) + goto badframe; + sr = (struct sigregs *) sigctx.regs; + regs->gpr[3] = ret = sigctx.signal; + /* Get the siginfo */ + get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo); + /* Get the ucontext */ + get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc); + regs->gpr[6] = (unsigned long) rt_sf; + + regs->link = (unsigned long) &sr->tramp; + regs->nip = sigctx.handler; + if (get_user(prevsp, &sr->gp_regs[PT_R1]) + || put_user(prevsp, (unsigned long *) regs->gpr[1])) + goto badframe; + } + return ret; + +badframe: + lock_kernel(); + do_exit(SIGSEGV); +} + + /* * Set up a signal frame. */ @@ -305,6 +400,57 @@ badframe: do_exit(SIGSEGV); } + +static void +setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, + signed long newsp) +{ + struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp; + + /* Set up preamble frame */ + if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + goto badframe; + if (regs->msr & MSR_FP) + giveup_fpu(current); + if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE) + || __copy_to_user(&frame->fp_regs, current->tss.fpr, + ELF_NFPREG * sizeof(double)) + /* Set up to return from user space. + It calls the sc exception at offset 0x9999 + for sys_rt_sigreturn(). + */ + || __put_user(0x38006666UL, &frame->tramp[0]) /* li r0,0x6666 */ + || __put_user(0x44000002UL, &frame->tramp[1])) /* sc */ + goto badframe; + flush_icache_range((unsigned long) &frame->tramp[0], + (unsigned long) &frame->tramp[2]); + + /* Retrieve rt_sigframe from stack and + set up registers for signal handler + */ + newsp -= __SIGNAL_FRAMESIZE; + if (put_user(regs->gpr[1], (unsigned long *)newsp) + || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) + || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) + || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) + || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) + goto badframe; + + regs->gpr[1] = newsp; + regs->gpr[6] = (unsigned long) rt_sf; + regs->link = (unsigned long) frame->tramp; + + return; + +badframe: +#if DEBUG_SIG + printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n", + regs, frame, newsp); +#endif + lock_kernel(); + do_exit(SIGSEGV); +} + /* * OK, we're invoking a handler */ @@ -314,6 +460,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, unsigned long *newspp, unsigned long frame) { struct sigcontext_struct *sc; + struct rt_sigframe *rt_sf; if (regs->trap == 0x0C00 /* System Call! */ && ((int)regs->result == -ERESTARTNOHAND || @@ -321,20 +468,47 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, !(ka->sa.sa_flags & SA_RESTART)))) regs->result = -EINTR; - /* Put another sigcontext on the stack */ - *newspp -= sizeof(*sc); - sc = (struct sigcontext_struct *) *newspp; - if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) - goto badframe; - - if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) - || __put_user(oldset->sig[0], &sc->oldmask) + /* Set up Signal Frame */ + if (ka->sa.sa_flags & SA_SIGINFO) { + /* Put a Real Time Context onto stack */ + *newspp -= sizeof(*rt_sf); + rt_sf = (struct rt_sigframe *) *newspp; + if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) + goto badframe; + + if (__put_user((unsigned long) ka->sa.sa_handler, &rt_sf->uc.uc_mcontext.handler) + || __put_user(&rt_sf->info, &rt_sf->pinfo) + || __put_user(&rt_sf->uc, &rt_sf->puc) + /* Put the siginfo */ + || __copy_to_user(&rt_sf->info, info, sizeof(*info)) + /* Create the ucontext */ + || __put_user(0, &rt_sf->uc.uc_flags) + || __put_user(0, &rt_sf->uc.uc_link) + || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp) + || __put_user(sas_ss_flags(regs->gpr[1]), + &rt_sf->uc.uc_stack.ss_flags) + || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size) + || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)) + /* mcontext.regs points to preamble register frame */ + || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs) + || __put_user(sig, &rt_sf->uc.uc_mcontext.signal)) + goto badframe; + } else { + /* Put another sigcontext on the stack */ + *newspp -= sizeof(*sc); + sc = (struct sigcontext_struct *) *newspp; + if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) + goto badframe; + + if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler) + || __put_user(oldset->sig[0], &sc->oldmask) #if _NSIG_WORDS > 1 - || __put_user(oldset->sig[1], &sc->_unused[3]) + || __put_user(oldset->sig[1], &sc->_unused[3]) #endif - || __put_user((struct pt_regs *)frame, &sc->regs) - || __put_user(sig, &sc->signal)) - goto badframe; + || __put_user((struct pt_regs *)frame, &sc->regs) + || __put_user(sig, &sc->signal)) + goto badframe; + } if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; @@ -494,7 +668,10 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) if (newsp == frame) return 0; /* no signals delivered */ - setup_frame(regs, (struct sigregs *) frame, newsp); + if (ka->sa.sa_flags & SA_SIGINFO) + setup_rt_frame(regs, (struct sigregs *) frame, newsp); + else + setup_frame(regs, (struct sigregs *) frame, newsp); return 1; } diff --git a/arch/ppc/kernel/sleep.S b/arch/ppc/kernel/sleep.S index b73acd6ce156..e356912b56d8 100644 --- a/arch/ppc/kernel/sleep.S +++ b/arch/ppc/kernel/sleep.S @@ -113,8 +113,8 @@ _GLOBAL(low_sleep_handler) stw r4,SL_HID0(r1) /* Set up stuff at address 0 */ - lis r5,wake_up@ha - addi r5,r5,wake_up@l + lis r5,grackle_wake_up@ha + addi r5,r5,grackle_wake_up@l tophys(r5,r5) stw r5,SL_PC(r1) lis r4,KERNELBASE@h @@ -124,22 +124,28 @@ _GLOBAL(low_sleep_handler) addi r6,r6,MAGIC@l stw r5,0(r4) stw r6,4(r4) + /* Setup stuffs at 0x80-0x84 for Core99 */ + lis r3,core99_wake_up@ha + addi r3,r3,core99_wake_up@l + tophys(r3,r3) + stw r3,0x80(r4) + stw r5,0x84(r4) /* - * Flush the L1 data cache by reading the first 64kB of RAM + * Flush the L1 data cache by reading the first 128kB of RAM * and then flushing the same area with the dcbf instruction. * The L2 cache has already been disabled. */ - li r4,0x0800 /* 64kB / 32B */ + li r4,0x1000 /* 128kB / 32B */ mtctr r4 lis r4,KERNELBASE@h 1: lwz r0,0(r4) - addi r4,r4,0x0020 /* Go to start of next cache line */ + addi r4,r4,0x0020 /* Go to start of next cache line */ bdnz 1b sync - li r4,0x0800 /* 64k */ + li r4,0x1000 /* 128kB / 32B */ mtctr r4 lis r4,KERNELBASE@h 1: @@ -148,6 +154,14 @@ _GLOBAL(low_sleep_handler) bdnz 1b sync +/* Turn off L1 (necessary ?) */ + mfspr r3,HID0 + ori r3,r3, HID0_ICE|HID0_DCE + xori r3,r3, HID0_ICE|HID0_DCE + mtspr HID0,r3 + sync + isync + /* * Set the HID0 and MSR for sleep. */ @@ -163,20 +177,50 @@ _GLOBAL(low_sleep_handler) 1: sync mtmsr r2 isync - b 1b + b 1b + /* * Here is the resume code. + * Core99 machines resume here + * r4 has the physical address of SL_PC(sp). + */ + +core99_wake_up: + mr r1,r4 + mfspr r3,HID0 + /* use rlwinm ... */ + oris r3,r3,HID0_SLEEP@h + xoris r3,r3,HID0_SLEEP@h + mtspr HID0,r3 + sync + isync + + /* sanitize MSR */ + mfmsr r3 + ori r3,r3,MSR_EE|MSR_IP + xori r3,r3,MSR_EE|MSR_IP + mtmsr r3 + sync + isync + +/* + * Here is the resume code for older machines. * r1 has the physical address of SL_PC(sp). */ -wake_up: - /* Flash inval the instruction cache */ +grackle_wake_up: + /* Enable and then Flash inval the instruction cache */ mfspr r3,HID0 - ori r3,r3, HID0_ICFI - mtspr HID0,r3 + ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI + sync isync - /* Restore the HID0 register. This turns on the L1 caches. */ + mtspr HID0,r3 + xori r3,r3, HID0_ICFI|HID0_DCI + mtspr HID0,r3 + sync + + /* Restore the remaining bits of the HID0 register. */ subi r1,r1,SL_PC lwz r3,SL_HID0(r1) sync @@ -239,6 +283,13 @@ wake_up: lwz r4,SL_IBAT3+4(r1) mtibatl 3,r4 + /* Flush all TLBs */ + lis r4, 0x1000 +1: addic. r4, r4, -0x1000 + tlbie r4 + blt 1b + sync + /* restore the MSR and turn on the MMU */ lwz r3,SL_MSR(r1) bl turn_on_mmu @@ -247,6 +298,8 @@ wake_up: tovirt(r1,r1) /* Restore TB */ + lis r3,0 + mttbl r3 lwz r3,SL_TB(r1) lwz r4,SL_TB+4(r1) mttbu r3 @@ -267,3 +320,4 @@ turn_on_mmu: mtsrr1 r3 sync rfi + sync diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index dea942bc267e..ac38137c278d 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -8,6 +8,8 @@ * * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes * (troy@blacklablinux.com, hozer@drgw.net) + * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP + * by Troy Benjegerdes (hozer@drgw.net) */ #include @@ -37,6 +39,7 @@ #include #include #include +#include #include "open_pic.h" int first_cpu_booted = 0; @@ -46,7 +49,8 @@ int smp_num_cpus = 1; struct cpuinfo_PPC cpu_data[NR_CPUS]; struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 }; volatile unsigned char active_kernel_processor = NO_PROC_ID; /* Processor holding kernel spinlock */ -volatile unsigned long ipi_count; +atomic_t ipi_recv; +atomic_t ipi_sent; spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; @@ -64,6 +68,9 @@ extern int mot_multi; extern unsigned long *MotSave_SmpIar; extern unsigned char *MotSave_CpusState[2]; +/* l2 cache stuff for dual G4 macs */ +extern void core99_init_l2(void); + /* register for interrupting the secondary processor on the powersurge */ #define PSURGE_INTR ((volatile unsigned *)0xf80000c0) @@ -114,7 +121,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) void smp_message_recv(int msg) { - ipi_count++; + atomic_inc(&ipi_recv); switch( msg ) { @@ -136,6 +143,7 @@ void smp_message_recv(int msg) } } +#ifdef CONFIG_POWERMAC /* * As it is now, if we're sending two message at the same time * we have race conditions on Pmac. The PowerSurge doesn't easily @@ -147,10 +155,10 @@ void smp_message_recv(int msg) * rather than this. * -- Cort */ -int pmac_smp_message[NR_CPUS]; -void pmac_smp_message_recv(void) +int psurge_smp_message[NR_CPUS]; +void psurge_smp_message_recv(void) { - int msg = pmac_smp_message[smp_processor_id()]; + int msg = psurge_smp_message[smp_processor_id()]; /* clear interrupt */ out_be32(PSURGE_INTR, ~0); @@ -161,9 +169,9 @@ void pmac_smp_message_recv(void) smp_message_recv(msg); /* reset message */ - pmac_smp_message[smp_processor_id()] = -1; + psurge_smp_message[smp_processor_id()] = -1; } - +#endif /* powermac */ /* * 750's don't broadcast tlb invalidates so @@ -195,49 +203,65 @@ void smp_send_stop(void) smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0); } -void smp_message_pass(int target, int msg, unsigned long data, int wait) +#ifdef CONFIG_POWERMAC +static void psurge_message_pass(int target, int msg, unsigned long data, int wait) { int i; + /* + * IPI's on the Pmac are a hack but without reasonable + * IPI hardware SMP on Pmac is a hack. + * + * We assume here that the msg is not -1. If it is, + * the recipient won't know the message was destined + * for it. -- Cort + */ + for ( i = 0; i <= smp_num_cpus ; i++ ) + psurge_smp_message[i] = -1; + switch( target ) + { + case MSG_ALL: + psurge_smp_message[smp_processor_id()] = msg; + /* fall through */ + case MSG_ALL_BUT_SELF: + for ( i = 0 ; i < smp_num_cpus ; i++ ) + if ( i != smp_processor_id () ) + psurge_smp_message[i] = msg; + break; + default: + psurge_smp_message[target] = msg; + break; + } + /* interrupt secondary processor */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + /* + * Assume for now that the secondary doesn't send + * IPI's -- Cort + * Could be fixed with 2.4 code from Paulus -- BenH + */ + /* interrupt primary */ + /**(volatile unsigned long *)(0xf3019000);*/ +} +#endif /* powermac */ + +void smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + atomic_inc(&ipi_sent); + if ( !(_machine & (_MACH_Pmac|_MACH_chrp|_MACH_prep|_MACH_gemini)) ) return; switch (_machine) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: - /* - * IPI's on the Pmac are a hack but without reasonable - * IPI hardware SMP on Pmac is a hack. - * - * We assume here that the msg is not -1. If it is, - * the recipient won't know the message was destined - * for it. -- Cort - */ - for ( i = 0; i <= smp_num_cpus ; i++ ) - pmac_smp_message[i] = -1; - switch( target ) - { - case MSG_ALL: - pmac_smp_message[smp_processor_id()] = msg; - /* fall through */ - case MSG_ALL_BUT_SELF: - for ( i = 0 ; i < smp_num_cpus ; i++ ) - if ( i != smp_processor_id () ) - pmac_smp_message[i] = msg; - break; - default: - pmac_smp_message[target] = msg; + /* Hack, 2.4 does it cleanly */ + if (OpenPIC == NULL) { + psurge_message_pass(target, msg, data, wait); break; - } - /* interrupt secondary processor */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); - /* - * Assume for now that the secondary doesn't send - * IPI's -- Cort - */ - /* interrupt primary */ - /**(volatile unsigned long *)(0xf3019000);*/ - break; + } + /* else fall through and do something sane --Troy */ +#endif case _MACH_chrp: case _MACH_prep: case _MACH_gemini: @@ -261,6 +285,52 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait) } } +#ifdef CONFIG_POWERMAC +static void pmac_core99_kick_cpu(int nr) +{ + extern void __secondary_start_psurge(void); + + unsigned long save_int; + unsigned long flags; + volatile unsigned long *vector + = ((volatile unsigned long *)(KERNELBASE+0x500)); + + if (nr != 1) + return; + + __save_flags(flags); + __cli(); + + /* Save EE vector */ + save_int = *vector; + + /* Setup fake EE vector that does + * b __secondary_start_psurge - KERNELBASE + */ + *vector = 0x48000002 + + ((unsigned long)__secondary_start_psurge - KERNELBASE); + + /* flush data cache and inval instruction cache */ + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + /* Put some life in our friend */ + feature_core99_kick_cpu1(); + + /* FIXME: We wait a bit for the CPU to take the exception, I should + * instead wait for the entry code to set something for me. Well, + * ideally, all that crap will be done in prom.c and the CPU left + * in a RAM-based wait loop like CHRP. + */ + mdelay(1); + + /* Restore our exception vector */ + *vector = save_int; + flush_icache_range((unsigned long) vector, (unsigned long) vector + 4); + + __restore_flags(flags); +} +#endif /* powermac */ + void __init smp_boot_cpus(void) { extern struct task_struct *current_set[NR_CPUS]; @@ -297,15 +367,21 @@ void __init smp_boot_cpus(void) switch ( _machine ) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: - /* assume powersurge board - 2 processors -- Cort */ + /* assum e powersurge board - 2 processors -- Cort */ + /* or a dual G4 -- Troy */ cpu_nr = 2; break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: cpu_nr = ((openpic_read(&OpenPIC->Global.Feature_Reporting0) & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >> OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT)+1; break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: /* assume 2 for now == fix later -- Johnnie */ if ( mot_multi ) @@ -313,10 +389,13 @@ void __init smp_boot_cpus(void) cpu_nr = 2; break; } +#endif +#ifdef CONFIG_GEMINI case _MACH_gemini: cpu_nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK)>>2; cpu_nr = (cpu_nr == 0) ? 4 : cpu_nr; break; +#endif default: printk("SMP not supported on this machine.\n"); return; @@ -347,30 +426,41 @@ void __init smp_boot_cpus(void) /* wake up cpus */ switch ( _machine ) { +#ifdef CONFIG_POWERMAC case _MACH_Pmac: - /* setup entry point of secondary processor */ - *(volatile unsigned long *)(0xf2800000) = - (unsigned long)__secondary_start_psurge-KERNELBASE; - eieio(); - /* interrupt secondary to begin executing code */ - out_be32(PSURGE_INTR, ~0); - out_be32(PSURGE_INTR, 0); + if (OpenPIC == NULL) { + /* setup entry point of secondary processor */ + *(volatile unsigned long *)(0xf2800000) = + (unsigned long)__secondary_start_psurge-KERNELBASE; + eieio(); + /* interrupt secondary to begin executing code */ + out_be32(PSURGE_INTR, ~0); + out_be32(PSURGE_INTR, 0); + } else + pmac_core99_kick_cpu(i); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_CHRP) case _MACH_chrp: *(unsigned long *)KERNELBASE = i; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); break; +#endif +#if defined(CONFIG_ALL_PPC) || defined(CONFIG_PREP) case _MACH_prep: *MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE; *MotSave_CpusState[1] = CPU_GOOD; printk("CPU1 reset, waiting\n"); break; +#endif +#ifdef CONFIG_GEMINI case _MACH_gemini: openpic_init_processor( 1<> 16) == 1) { /* 601 processor: dec counts down by 128 every 128ns */ @@ -208,6 +208,12 @@ __initfunc(void time_init(void)) xtime.tv_sec = ppc_md.get_rtc_time(); xtime.tv_usec = 0; + if (time_offset) { + struct timezone tz; + tz.tz_minuteswest = time_offset/60; + tz.tz_dsttime = 0; /* Not handled correctly by the kernel anyway */ + do_sys_settimeofday(NULL, &tz); + } set_dec(decrementer_count); /* allow updates right away */ diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index 8b119e24000b..754dbfd06449 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -156,9 +156,52 @@ RunModeException(struct pt_regs *regs) _exception(SIGTRAP, regs); } +/* Illegal instruction emulation support. Originally written to + * provide the PVR to user applications using the mfspr rd, PVR. + * Return non-zero if we can't emulate, or EFAULT if the associated + * memory access caused an access fault. Return zero on success. + * + * There are a couple of ways to do this, either "decode" the instruction + * or directly match lots of bits. In this case, matching lots of + * bits is faster and easier. + * + */ +#define INST_MFSPR_PVR 0x7c1f42a6 +#define INST_MFSPR_PVR_MASK 0xfc1fffff + +static int +emulate_instruction(struct pt_regs *regs) +{ + uint instword; + uint rd; + int retval; + + retval = EINVAL; + if (!user_mode(regs)) + return retval; + + retval = EFAULT; + if (get_user(instword, (uint *)(regs->nip))) + return retval; + + /* Emulate the mfspr rD, PVR. + */ + retval = EINVAL; + if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { + rd = (instword >> 21) & 0x1f; + regs->gpr[rd] = _get_PVR(); + retval = 0; + } + if (retval == 0) + regs->nip += 4; + return(retval); +} + void ProgramCheckException(struct pt_regs *regs) { + int errcode; + if (regs->msr & 0x100000) { /* IEEE FP exception */ _exception(SIGFPE, regs); @@ -170,7 +213,13 @@ ProgramCheckException(struct pt_regs *regs) #endif _exception(SIGTRAP, regs); } else { - _exception(SIGILL, regs); + /* Try to emulate it if we should. */ + if ((errcode = emulate_instruction(regs))) { + if (errcode == EFAULT) + _exception(SIGBUS, regs); + else + _exception(SIGILL, regs); + } } } diff --git a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c index afcf705e14a6..f50f483b5a1f 100644 --- a/arch/ppc/mm/extable.c +++ b/arch/ppc/mm/extable.c @@ -7,8 +7,43 @@ #include #include -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; +extern struct exception_table_entry __start___ex_table[]; +extern struct exception_table_entry __stop___ex_table[]; + +/* + * The exception table needs to be sorted because we use the macros + * which put things into the exception table in a variety of segments + * such as the prep, pmac, chrp, etc. segments as well as the init + * segment and the main kernel text segment. + */ +static inline void +sort_ex_table(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + struct exception_table_entry el, *p, *q; + + /* insertion sort */ + for (p = start + 1; p < finish; ++p) { + /* start .. p-1 is sorted */ + if (p[0].insn < p[-1].insn) { + /* move element p down to its right place */ + el = *p; + q = p; + do { + /* el comes before q[-1], move q[-1] up one */ + q[0] = q[-1]; + --q; + } while (q > start && el.insn < q[-1].insn); + *q = el; + } + } +} + +void +sort_exception_table(void) +{ + sort_ex_table(__start___ex_table, __stop___ex_table); +} static inline unsigned long search_one_table(const struct exception_table_entry *first, @@ -36,7 +71,7 @@ search_exception_table(unsigned long addr) { unsigned long ret; -#if 1 /*ndef CONFIG_MODULES*/ +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr); if (ret) return ret; diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c index 45adbb20aa41..613d64a05068 100644 --- a/arch/ppc/mm/init.c +++ b/arch/ppc/mm/init.c @@ -1044,6 +1044,9 @@ __initfunc(void free_initmem(void)) * still be merged. * -- Cort */ +#ifdef CONFIG_BOOTX_TEXT +extern boot_infos_t *disp_bi; +#endif __initfunc(void MMU_init(void)) { #ifdef __SMP__ @@ -1092,7 +1095,13 @@ __initfunc(void MMU_init(void)) struct device_node *macio = find_devices("mac-io"); if (macio && macio->n_addrs) base = macio->addrs[0].address; - setbat(0, base, base, 0x100000, IO_PAGE); + /* Hrm... we have it at 0x80000000 on some machines + * and this is covered by the userland segment + * registers. Isn't that bad ? Well, the BAT takes + * precedence, but I don't like it. --BenH + */ + if (base >= 0xf0000000) + setbat(0, base, base, 0x100000, IO_PAGE); ioremap_base = 0xf0000000; } break; @@ -1131,6 +1140,10 @@ __initfunc(void MMU_init(void)) ioremap(0x80000000, 0x4000); ioremap(0x81000000, 0x4000); #endif /* CONFIG_8xx */ +#ifdef CONFIG_BOOTX_TEXT + if (_machine == _MACH_Pmac) + map_bootx_text(); +#endif } /* diff --git a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c index 18d17bd394a3..c853b9b7e4a6 100644 --- a/arch/ppc/xmon/start.c +++ b/arch/ppc/xmon/start.c @@ -467,3 +467,15 @@ xmon_fgets(char *str, int nb, void *f) *p = 0; return str; } + +void +xmon_enter(void) +{ + pmu_suspend(); +} + +void +xmon_leave(void) +{ + pmu_resume(); +} diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index f9a485371869..d41a9d9d23e4 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -86,6 +86,9 @@ extern int putchar(int ch); extern int setjmp(u_int *); extern void longjmp(u_int *, int); +extern void xmon_enter(void); +extern void xmon_leave(void); + #define GETWORD(v) (((v)[0] << 24) + ((v)[1] << 16) + ((v)[2] << 8) + (v)[3]) static char *help_string = "\ @@ -139,6 +142,7 @@ xmon(struct pt_regs *excp) msr = get_msr(); set_msr(msr & ~0x8000); /* disable interrupts */ remove_bpts(); + xmon_enter(); excprint(excp); cmd = cmds(excp); if (cmd == 's') { @@ -151,6 +155,7 @@ xmon(struct pt_regs *excp) xmon_trace = 0; insert_bpts(); } + xmon_leave(); set_msr(msr); /* restore interrupt enable */ } diff --git a/arch/s390/boot/ipleckd.S b/arch/s390/boot/ipleckd.S index c422ebbf7019..3831979fafa1 100644 --- a/arch/s390/boot/ipleckd.S +++ b/arch/s390/boot/ipleckd.S @@ -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: @@ -44,10 +46,10 @@ _start: .globl _start stsch .Lrdcdata oi .Lrdcdata+5,0x84 # enable ssch and multipath mode .Lecs: xi .Lrdcdata+27,0x01 # enable concurrent sense - msch .Lrdcdata + msch .Lrdcdata xi .Lprgn,6 # restore Wait and d/a bit in PCnew PSW l %r2,.Lparm - mvc 0x0(8,%r2),.Lnull # set parmarea to null + mvc 0x0(8,%r2),.Lnull # set parmarea to null lctl %c6,%c6,.Lc6 # enable all interrupts .Lrdc: # read device characteristics la %r6,.Lrdcccw @@ -94,7 +96,7 @@ _start: .globl _start .Lzeroes: lr %r2,%r3 .L001: slr %r3,%r3 - icm %r3,3,.Lcountarea+6 # get blocksize + icm %r3,3,.Lcountarea+6 # get blocksize slr %r5,%r5 # no bytes to move .L008: mvcle %r2,%r4,0 # fill zeroes to storage jo .L008 # until block is filled @@ -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,8 +142,8 @@ _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 + lhi %r6,9 + clc .Lrdcdata+3(2),.L9345 je .L011 lhi %r6,10 clc .Lrdcdata+3(2),.L3380 @@ -149,7 +151,7 @@ _start: .globl _start lhi %r6,12 clc .Lrdcdata+3(2),.L3390 je .L011 - bras %r14,.Ldisab + bras %r14,.Ldisab .L011: # loop for nbl times .Lrdloop: diff --git a/arch/s390/config.in b/arch/s390/config.in index b6c5787f0bd7..e1d357979d3c 100644 --- a/arch/s390/config.in +++ b/arch/s390/config.in @@ -8,6 +8,7 @@ define_bool CONFIG_ARCH_S390 y mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL +bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG endmenu mainmenu_option next_comment diff --git a/arch/s390/defconfig b/arch/s390/defconfig index cb4a8d726246..77b3c0443ad3 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -7,6 +7,7 @@ CONFIG_ARCH_S390=y # Code maturity level options # CONFIG_EXPERIMENTAL=y +CONFIG_PROCESS_DEBUG=n # # Processor type and features @@ -81,7 +82,7 @@ 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 diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index fbeee3d8ddd6..93b1a2d0a756 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include void cpcmd(char *cmd, char *response, int rlen) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index d03d566110c6..f08881a0c917 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -1,285 +1,1120 @@ +/* + * 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: + */ + #include #include #include #include +#include +#include +#include #include -#include +#include +#include #ifdef MODULE #include #endif -#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#if defined(CONFIG_ARCH_S390) +#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 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_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_ascii_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); +static int debug_ebcdic_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); + +/* globals */ + +struct debug_view debug_ascii_view = { + "ascii", + NULL, + &debug_dflt_header_fn, + &debug_ascii_format_fn, + NULL +}; + +struct debug_view debug_ebcdic_view = { + "ebcdic", + NULL, + &debug_dflt_header_fn, + &debug_ebcdic_format_fn, + NULL +}; + +struct debug_view debug_hex_view = { + "hex", + NULL, + &debug_dflt_header_fn, + &debug_hex_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_areas[DEBUG_MAX_AREAS]; +static debug_info_t *free_area = 0; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +static struct semaphore debug_lock = MUTEX; +#else +DECLARE_MUTEX(debug_lock); +#endif -debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },}; -debug_info_t *free_area = 0; static int initialized = 0; -static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED; - -debug_info_t * -debug_register (char *name, int page_order, int nr_areas) -{ - debug_info_t *rc = 0; - int i; - long flags; - - if ( ! initialized ){ - debug_init(); - initialized = 1; - } - if (!free_area) - { - printk (KERN_WARNING "No free debug area\n"); - return NULL; - } - spin_lock_irqsave (&debug_lock, flags); - rc = free_area; - free_area = *((debug_info_t **) rc); - - memset(rc, 0, nr_areas * sizeof(debug_info_t)); - rc->areas = (debug_entry_t **) kmalloc (nr_areas * - sizeof (debug_entry_t *), - GFP_ATOMIC); - if (!rc->areas) - { - goto noareas; - } - - for (i = 0; i < nr_areas; i++) - { - rc->areas[i] = (debug_entry_t *) __get_free_pages (GFP_ATOMIC, - page_order); - if (!rc->areas[i]) +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_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); + db_info->areas = NULL; + *((debug_info_t **) db_info) = free_area; + free_area = 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, + act_entry->data); + len += sprintf(buf + len, "\n"); + 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, j = 0, size = 0, rc = 0, f_entry_size = 0; + file_private_info_t *p_info; + +#ifdef DEBUG + printk("debug_open\n"); +#endif + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + down(&debug_lock); + + /* find debug log and view */ + + for (i = 0; i < DEBUG_MAX_AREAS; i++) { + if (debug_areas[i].areas == NULL) + continue; /* not in use */ + for (j = 0; j < DEBUG_MAX_VIEWS; j++) { + if (debug_areas[i].views[j] == NULL) + continue; + else if (debug_areas[i].proc_entries[j]->low_ino == + file->f_dentry->d_inode->i_ino) { + goto found; /* found view ! */ + } + } + } + /* 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_areas[i].views[j]->prolog_proc) + size += + debug_areas[i].views[j]->prolog_proc(&debug_areas[i], + debug_areas[i]. + views[j], NULL); + + if (debug_areas[i].views[j]->header_proc) + f_entry_size = + debug_areas[i].views[j]->header_proc(&debug_areas[i], + debug_areas[i]. + views[j], 0, NULL, + NULL); + if (debug_areas[i].views[j]->format_proc) + f_entry_size += + debug_areas[i].views[j]->format_proc(&debug_areas[i], + debug_areas[i]. + views[j], NULL, + NULL); + if (f_entry_size) + f_entry_size += 1; /* \n in each line */ + + + size += f_entry_size + * (PAGE_SIZE / debug_areas[i].entry_size + << debug_areas[i].page_order) + * debug_areas[i].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_areas[i]; + p_info->view = debug_areas[i].views[j]; + + spin_lock_irq(&debug_areas[i].lock); + + p_info->len = + debug_format_output(&debug_areas[i], p_info->data, size, + debug_areas[i].views[j]); +#ifdef DEBUG { - for (i--; i >= 0; i--) - { - free_pages ((unsigned long) rc->areas[i], page_order); - } - goto nopages; + int ilen = p_info->len; + printk("debug_open: len: %i\n", ilen); + } +#endif + + spin_unlock_irq(&debug_areas[i].lock); + debug_info_get(&debug_areas[i]); + + 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; + int i; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + if (!initialized) + debug_init(); + down(&debug_lock); + if (!free_area) { + printk(KERN_WARNING "debug: no free debug area for %s\n", + name); + goto out; + } + rc = free_area; + free_area = *((debug_info_t **) rc); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) { + free_area = rc; + rc = NULL; + goto out; + } + 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); + } + free_area = rc; + rc = NULL; + goto out; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } } - } - rc->page_order = page_order; - rc->nr_areas = nr_areas; - rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC); - strncpy (rc->name, name, strlen (name)); - ASCEBC(rc->name, strlen (name)); - rc->name[strlen (name)] = 0; - - rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC); - memset(rc->active_entry, 0, nr_areas * sizeof(int)); - rc->level=3; - printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n", - nr_areas, 1 << page_order, name); - goto exit; - -nopages: -noareas: - free_area = rc; -exit: - spin_unlock_irqrestore (&debug_lock, flags); - return rc; -} - -void -debug_unregister (debug_info_t * id, char *name) -{ - int i = id->nr_areas; - long flags; - spin_lock_irqsave (&debug_lock, flags); - printk (KERN_INFO "freeing debug area %p named '%s'\n", id, name); - if (strncmp (name, id->name, strlen (name))) - { - printk (KERN_ERR "name '%s' does not match against '%s'\n", - name, id->name); - } - for (i--; i >= 0; i--) - { - free_pages ((unsigned long) id->areas[i], id->page_order); - } - kfree (id->areas); - kfree (id->name); - *((debug_info_t **) id) = free_area; - free_area = id; - spin_unlock_irqrestore (&debug_lock, flags); - return; -} - -static inline void -proceed_active_entry (debug_info_t * id) -{ - id->active_entry[id->active_area] = - (id->active_entry[id->active_area]++) % - ((PAGE_SIZE / sizeof (debug_entry_t)) << (id->page_order)); -} - -static inline void -proceed_active_area (debug_info_t * id) -{ - id->active_area = (id->active_area++) % id->nr_areas; -} - -static inline debug_entry_t * -get_active_entry (debug_info_t * id) -{ - return &id->areas[id->active_area][id->active_entry[id->active_area]]; -} - -static inline debug_entry_t * -debug_common ( debug_info_t * id ) -{ - debug_entry_t * active; - proceed_active_entry (id); - active = get_active_entry (id); - STCK (active->id.stck); - active->id.stck = active->id.stck >> 4; - active->id.fields.cpuid = smp_processor_id (); - active->caller = __builtin_return_address (0); - return active; -} - -void -debug_event (debug_info_t * id, int level, unsigned int tag) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - active->tag.tag = tag; - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -void -debug_text_event (debug_info_t * id, int level, char tag[4]) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - strncpy ( active->tag.text, tag, 4); - ASCEBC (active->tag.text, 4 ); - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -void -debug_exception (debug_info_t * id, int level, unsigned int tag) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - active->tag.tag = tag; - proceed_active_area (id); - spin_unlock_irqrestore (&id->lock, flags); - - return; -} - -void -debug_text_exception (debug_info_t * id, int level, char tag[4]) -{ - long flags; - debug_entry_t *active; - if (!id) - { - return; - } - if (level < id->level) - { - return; - } - spin_lock_irqsave (&id->lock, flags); - active = debug_common(id); - strncpy ( active->tag.text, tag, 4); - ASCEBC (active->tag.text, 4 ); - proceed_active_area (id); - spin_unlock_irqrestore (&id->lock, flags); - return; -} - -int -debug_init (void) -{ - int rc = 0; - int i; - for (i = 0; i < MAX_DEBUG_AREAS - 1; i++) - { - *(debug_info_t **) (&debug_areas[i]) = - (debug_info_t *) (&debug_areas[i + 1]); - } - *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; - free_area = &(debug_areas[0]); - printk (KERN_INFO "%d areas reserved for debugging information\n", - MAX_DEBUG_AREAS); - return rc; + + 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 - 4; /* must subtract data[4] */ + 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->active_entry, 0, nr_areas * sizeof(int)); + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + 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); + debug_register_view(rc, &debug_level_view); + debug_info_get(rc); + 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 -int -init_module (void) -{ - int rc = 0; - rc = debug_init (); - if (rc) - { - printk (KERN_INFO "An error occurred with debug_init\n"); - } - - { /* test section */ - debug_info_t *a[4]; - printk (KERN_INFO "registering 1, %p\n", a[0] = - debug_register ("debug1", 1, 1)); - printk (KERN_INFO "registering 2, %p\n", a[1] = - debug_register ("debug2", 1, 2)); - printk (KERN_INFO "registering 3, %p\n", a[2] = - debug_register ("debug3", 2, 1)); - printk (KERN_INFO "registering 4, %p\n", a[3] = - debug_register ("debug4", 2, 2)); - debug_unregister (a[0], "debug1"); - debug_unregister (a[1], "debug3"); - printk (KERN_INFO "registering 1, %p\n", a[0] = - debug_register ("debug5", 1, 1)); - printk (KERN_INFO "registering 2, %p\n", a[1] = - debug_register ("debug6", 1, 2)); - debug_unregister (a[2], "debug2"); - debug_unregister (a[3], "debug4"); - debug_unregister (a[0], "debug5"); - debug_unregister (a[1], "debug6"); - } - return rc; -} - -void -cleanup_module (void) -{ - - return; -} - -#endif /* MODULE */ + MOD_DEC_USE_COUNT; +#endif + out: + return; +} + + +/* + * 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(active->data, 0, id->buf_size); + memcpy(active->data, 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(active->data, 0, id->buf_size); + memcpy(active->data, &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(active->data, 0, id->buf_size); + strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); + ASCEBC(active->data, 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(active->data, 0, id->buf_size); + memcpy(active->data, 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(active->data, 0, id->buf_size); + memcpy(active->data, &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(active->data, 0, id->buf_size); + strncpy(active->data, txt, MIN(strlen(txt), id->buf_size)); + ASCEBC(active->data, 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; + int i; + + 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); + for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) { + *(debug_info_t **) (&debug_areas[i]) = + (debug_info_t *) (&debug_areas[i + 1]); + } + *(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL; + free_area = &(debug_areas[0]); + printk(KERN_INFO + "debug: %d areas reserved for debugging information\n", + DEBUG_MAX_AREAS); + 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; + } + 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'); + if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: level %i is out of range (%i - %i)\n", + new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: set new level %i for %s\n", + id->level, id->name); + } + } 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 data in hex format + */ + +static int debug_hex_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 * 3; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + out: + return rc; +} + +/* + * prints debug data in ascii format + */ + +static int debug_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; + goto out; + } + 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); + } + out: + return rc; +} + +/* + * prints debug data in ebcdic format + */ + +static int debug_ebcdic_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; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + EBCASC(&c, 1); + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + 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_S390) + 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/entry.S b/arch/s390/kernel/entry.S index 6affe76f9828..a5b125e4e7e1 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -21,11 +21,11 @@ /* * stack layout for the system_call stack entry - * Martin please don't modify these back to hard coded values - * You know how bad I'm at mental arithmetic DJB & it gives + * Martin please don't modify these back to hard coded values + * You know how bad I'm at mental arithmetic DJB & it gives * me grief when I modify the pt_regs */ -SP_PTREGS = STACK_FRAME_OVERHEAD +SP_PTREGS = STACK_FRAME_OVERHEAD SP_PSW = SP_PTREGS SP_R0 = (SP_PSW+PSW_MASK_SIZE+PSW_ADDR_SIZE) SP_R1 = (SP_R0+GPR_SIZE) @@ -51,13 +51,13 @@ SP_CRREGS = (SP_TRAP+4) /* fpu registers are saved & restored by the gdb stub itself */ SP_FPC = (SP_CRREGS+(NUM_CRS*CR_SIZE)) SP_FPRS = (SP_FPC+FPC_SIZE+FPC_PAD_SIZE) -/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not +/* SP_PGM_OLD_ILC etc are not part of pt_regs & they are not defined in ptrace.h but space is needed for this too */ SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE)) #else SP_PGM_OLD_ILC= (SP_TRAP+4) #endif -SP_SVC_STEP = (SP_PGM_OLD_ILC+4) +SP_SVC_STEP = (SP_PGM_OLD_ILC+4) SP_SIZE = (SP_SVC_STEP+4) /* * these defines are offsets into the thread_struct @@ -140,7 +140,7 @@ sysc_dn: 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. */ \ + 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 */ \ la %r0,psworg ; /* store trap indication */ \ @@ -150,10 +150,10 @@ sysc_dn: #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 */ \ + 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 */ - + #define GET_CURRENT /* load pointer to task_struct to R9 */ \ lr %r9,%r15 ; \ n %r9,BASED(.Lc0xffffe000) @@ -170,12 +170,12 @@ resume: basr %r1,0 # setup base pointer resume_base: l %r4,_TSS_PTREGS(%r3) - tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? + tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? bz resume_noper-resume_base(%r1) # if not we're fine - stctl %r9,%r11,24(%r15) # We are using per stuff + stctl %r9,%r11,24(%r15) # We are using per stuff clc _TSS_PER(12,%r3),24(%r15) be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's - lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't + 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 @@ -248,7 +248,7 @@ sysc_leave: # # call do_signal before return # -sysc_signal_return: +sysc_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) @@ -276,7 +276,7 @@ sysc_tracesys: # call do_bottom_half and return from syscall, if interrupt-level # is zero # -sysc_handle_bottom_half: +sysc_handle_bottom_half: l %r1,BASED(.Ldo_bottom_half) la %r14,BASED(sysc_return_bh) br %r1 # call do_bottom_half @@ -284,7 +284,7 @@ sysc_handle_bottom_half: # # call schedule with sysc_return as return-address # -sysc_reschedule: +sysc_reschedule: l %r1,BASED(.Lschedule) la %r14,BASED(sysc_return) br %r1 # call scheduler, return to sysc_return @@ -293,7 +293,7 @@ sysc_reschedule: # a new process exits the kernel with ret_from_fork # .globl ret_from_fork -ret_from_fork: +ret_from_fork: basr %r13,0 l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base GET_CURRENT # load pointer to task_struct to R9 @@ -314,23 +314,23 @@ ret_from_fork: # but are called with different parameter. # return-address is set up above # -sys_clone_glue: +sys_clone_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lclone) br %r1 # branch to sys_clone -sys_fork_glue: +sys_fork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lfork) br %r1 # branch to sys_fork -sys_vfork_glue: +sys_vfork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lvfork) br %r1 # branch to sys_vfork -sys_execve_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs l %r1,BASED(.Lexecve) lr %r12,%r14 # save return address basr %r14,%r1 # call sys_execve @@ -339,12 +339,12 @@ sys_execve_glue: b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8 # in system_call/sysc_tracesys -sys_sigreturn_glue: +sys_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lsigreturn) br %r1 # branch to sys_sigreturn -sys_rt_sigreturn_glue: +sys_rt_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter l %r1,BASED(.Lrt_sigreturn) br %r1 # branch to sys_sigreturn @@ -352,11 +352,11 @@ sys_rt_sigreturn_glue: # # sigsuspend and rt_sigsuspend need pt_regs as an additional # parameter and they have to skip the store of %r2 into the -# user register %r2 because the return value was set in +# user register %r2 because the return value was set in # sigsuspend and rt_sigsuspend already and must not be overwritten! # -sys_sigsuspend_glue: +sys_sigsuspend_glue: lr %r5,%r4 # move mask back lr %r4,%r3 # move history1 parameter lr %r3,%r2 # move history0 parameter @@ -365,7 +365,7 @@ sys_sigsuspend_glue: la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_sigsuspend -sys_rt_sigsuspend_glue: +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 @@ -373,6 +373,12 @@ sys_rt_sigsuspend_glue: la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_rt_sigsuspend +sys_sigaltstack_glue: + la %r4,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 */ @@ -561,13 +567,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 */ .rept 255-190 - .long sys_ni_syscall + .long sys_ni_syscall .endr /* @@ -603,7 +609,7 @@ pgm_check_handler: be BASED(pgm_svcper) # no interesting special case, ignore PER event lm %r13,%r15,__LC_SAVE_AREA - lpsw 0x28 + lpsw 0x28 # it was a single stepped SVC that is causing all the trouble pgm_svcper: tm 0x21,0x01 # test problem state bit @@ -622,7 +628,7 @@ pgm_svcper: 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 + 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 b BASED(pgm_system_call) # now do the svc pgm_svcret: @@ -723,7 +729,7 @@ io_leave: # call do_bottom_half and return from syscall, if interrupt-level # is zero # -io_handle_bottom_half: +io_handle_bottom_half: l %r1,BASED(.Ldo_bottom_half) la %r14,BASED(io_return_bh) br %r1 # call do_bottom_half @@ -731,7 +737,7 @@ io_handle_bottom_half: # # call schedule with io_return as return-address # -io_reschedule: +io_reschedule: l %r1,BASED(.Lschedule) la %r14,BASED(io_return) br %r1 # call scheduler, return to io_return @@ -739,7 +745,7 @@ io_reschedule: # # call do_signal before return # -io_signal_return: +io_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset l %r1,BASED(.Ldo_signal) @@ -755,9 +761,7 @@ ext_int_handler: SAVE_ALL(0x18) la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code - lr %r1,%r3 # calculate index - srl %r1,8 # = (code + (code >> 8)) & 0xff - alr %r1,%r3 + lr %r1,%r3 # calculate index = code & 0xff n %r1,BASED(.Lc0xff) sll %r1,2 l %r9,BASED(.Lext_hash) @@ -773,7 +777,7 @@ ext_int_loop: ext_int_found: l %r9,4(%r9) # get handler address la %r14,BASED(io_return) - br %r9 # branch to ext call handler + br %r9 # branch to ext call handler /* * Machine check handler routines @@ -857,6 +861,7 @@ restart_go: .Lrt_sigreturn:.long sys_rt_sigreturn .Lrt_sigsuspend: .long sys_rt_sigsuspend +.Lsigaltstack: .long sys_sigaltstack .Lsigreturn: .long sys_sigreturn .Lsigsuspend: .long sys_sigsuspend .Ltrace: .long syscall_trace diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index ff047820cf2e..10693f696e8d 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -528,21 +528,21 @@ startup:basr %r13,0 # get base lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 -.Lentry:.long 0x04080000,0x80000000 + _stext +.Lentry:.long 0x00080000,0x80000000 + _stext .Lctl: .long 0x04b50002 # cr0: various things - .long .Lpgd+0x7f # cr1: primary space segment table + .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 .Lpgd+0x7f # cr7: secondary space segment table + .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 .Lpgd+0x7f # cr13: home space segment table + .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 @@ -630,43 +630,4 @@ _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 d110f9afdcf3..283257441e97 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -36,13 +36,13 @@ #include #include -unsigned long s390_init_IRQ(unsigned long); -void s390_free_irq(unsigned int irq, void *dev_id); -int s390_request_irq( unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, - void *dev_id); +unsigned long s390_init_IRQ ( unsigned long); +void s390_free_irq ( unsigned int irq, void *dev_id); +int s390_request_irq( unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); atomic_t nmi_counter; @@ -82,7 +82,7 @@ int get_irq_list(char *buf) action = ioinfo[i]->irq_desc.action; - if (!action) + if (!action) continue; p += sprintf(p, "%3d: ",i); @@ -90,8 +90,8 @@ int get_irq_list(char *buf) p += sprintf(p, "%10u ", kstat_irqs(i)); #else for (j=0; jirq_desc.handler->typename); p += sprintf(p, " %s", action->name); @@ -403,13 +403,16 @@ void enable_nop(int irq) __initfunc(unsigned long init_IRQ( unsigned long memory)) { - return s390_init_IRQ( memory); + int result; + + result=s390_init_IRQ(memory); + return result; } void free_irq(unsigned int irq, void *dev_id) { - s390_free_irq( irq, dev_id); + s390_free_irq( irq, dev_id); } @@ -419,7 +422,7 @@ int request_irq( unsigned int irq, const char *devname, void *dev_id) { - return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) ); + return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) ); } diff --git a/arch/s390/kernel/mathemu.c b/arch/s390/kernel/mathemu.c index f99d721376d1..2eb2f3da3bb0 100644 --- a/arch/s390/kernel/mathemu.c +++ b/arch/s390/kernel/mathemu.c @@ -16,20 +16,61 @@ #include #include +#include -static void display_emulation_not_implemented(char *instr) -{ - struct pt_regs *regs=current->tss.regs; - printk("%s not implemented\n",instr); - printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n", - instr, - current->comm, current->pid, 4096+(addr_t)current); - printk("%s's PSW: %08lx %08lx\n",instr, - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); +#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 set_CC_df(__u64 val1,__u64 val2) { + + +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->tss.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->tss.regs->psw.mask &= 0xFFFFCFFF; @@ -41,9 +82,10 @@ static void set_CC_df(__u64 val1,__u64 val2) { current->tss.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->tss.regs->psw.mask &= 0xFFFFCFFF; @@ -55,384 +97,473 @@ static void set_CC_sf(__u32 val1,__u32 val2) { current->tss.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void emu_adb (int rx, __u64 val) { +static int emu_adb (int rx, __u64 val) { current->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].d = __adddf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f,val); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].f = __addsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_axbr (int rx, int ry) { +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->tss.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->tss.fp_regs.fprs[rx].d,current->tss.fp_regs.fprs[ry].d); + return 0; } -static void emu_cdfbr (int rx, int ry) { +static int emu_cdfbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].d = __floatsidf(current->tss.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->tss.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->tss.fp_regs.fprs[rx].f,current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_cefbr (int rx, int ry) { +static int emu_cefbr (int rx, int ry) { current->tss.fp_regs.fprs[rx].f = __floatsisf(current->tss.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->tss.regs->gprs[rx] = __fixdfsi(current->tss.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->tss.regs->gprs[rx] = __fixsfsi(current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_cfxbr (int rx, int ry, int mask) { +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) { +static int emu_cxbr (int rx, int ry) { display_emulation_not_implemented("cxbr"); + return 0; } -static void emu_cxfbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].d = __divdf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f,val); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].f = __divsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_didbr (int rx, int ry, int mask) { +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) { +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) { +static int emu_dxbr (int rx, int ry) { display_emulation_not_implemented("dxbr"); + return 0; } -static void emu_efpc (int rx, int ry) { - display_emulation_not_implemented("efpc"); +static int emu_efpc (int rx, int ry) { + current->tss.regs->gprs[rx]=current->tss.fp_regs.fpc; + return 0; } -static void emu_fidbr (int rx, int ry, int mask) { +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) { +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) { +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) { +static int emu_kdb (int rx, __u64 val) { display_emulation_not_implemented("kdb"); + return 0; } -static void emu_kdbr (int rx, int ry) { +static int emu_kdbr (int rx, int ry) { display_emulation_not_implemented("kdbr"); + return 0; } -static void emu_keb (int rx, __u32 val) { +static int emu_keb (int rx, __u32 val) { display_emulation_not_implemented("keb"); + return 0; } -static void emu_kebr (int rx, int ry) { +static int emu_kebr (int rx, int ry) { display_emulation_not_implemented("kebr"); + return 0; } -static void emu_kxbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].d = __negdf2(current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].f = __negsf2(current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lcxbr (int rx, int ry) { +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->tss.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->tss.fp_regs.fprs[rx].d = __extendsfdf2(current->tss.fp_regs.fprs[ry].f); + return 0; } -static void emu_ldxbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].f = __truncdfsf2(current->tss.fp_regs.fprs[ry].d); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lexbr (int rx, int ry) { +static int emu_lexbr (int rx, int ry) { display_emulation_not_implemented("lexbr"); + return 0; } -static void emu_lndbr (int rx, int ry) { +static int emu_lndbr (int rx, int ry) { display_emulation_not_implemented("lndbr"); + return 0; } -static void emu_lnebr (int rx, int ry) { +static int emu_lnebr (int rx, int ry) { display_emulation_not_implemented("lnebr"); + return 0; } -static void emu_lnxbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].d = __absdf2(current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].f = __abssf2(current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lpxbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].d = current->tss.fp_regs.fprs[ry].d; set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].f = current->tss.fp_regs.fprs[ry].f; set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_ltxbr (int rx, int ry) { +static int emu_ltxbr (int rx, int ry) { display_emulation_not_implemented("ltxbr"); + return 0; } -static void emu_lxdb (int rx, __u64 val) { +static int emu_lxdb (int rx, __u64 val) { display_emulation_not_implemented("lxdb"); + return 0; } -static void emu_lxdbr (int rx, int ry) { +static int emu_lxdbr (int rx, int ry) { display_emulation_not_implemented("lxdbr"); + return 0; } -static void emu_lxeb (int rx, __u32 val) { +static int emu_lxeb (int rx, __u32 val) { display_emulation_not_implemented("lxeb"); + return 0; } -static void emu_lxebr (int rx, int ry) { +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) { +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) { +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) { +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) { +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->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d,val); set_CC_df(current->tss.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->tss.fp_regs.fprs[rx].d = __muldf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_df(current->tss.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdeb (int rx, __u32 val) { +static int emu_mdeb (int rx, __u32 val) { display_emulation_not_implemented("mdeb"); + return 0; } -static void emu_mdebr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f, val); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].f = __mulsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_msdb (int rx, __u64 val, int mask) { +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) { +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) { +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) { +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) { +static int emu_mxbr (int rx, int ry) { display_emulation_not_implemented("mxbr"); + return 0; } -static void emu_mxdb (int rx, __u64 val) { +static int emu_mxdb (int rx, __u64 val) { display_emulation_not_implemented("mxdb"); + return 0; } -static void emu_mxdbr (int rx, int ry) { +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->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d, val); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].d = __subdf3(current->tss.fp_regs.fprs[rx].d, current->tss.fp_regs.fprs[ry].d); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f, val); set_CC_sf(current->tss.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->tss.fp_regs.fprs[rx].f = __subsf3(current->tss.fp_regs.fprs[rx].f, current->tss.fp_regs.fprs[ry].f); set_CC_sf(current->tss.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sfpc (int rx, int ry) { - display_emulation_not_implemented("sfpc"); +static int emu_sfpc (int rx, int ry) { + __u32 val=current->tss.regs->gprs[rx]; + if(val==0) + current->tss.fp_regs.fpc=val; + else + display_emulation_not_implemented("sfpc"); + return 0; } -static void emu_sqdb (int rx, __u64 val) { +static int emu_sqdb (int rx, __u64 val) { display_emulation_not_implemented("sqdb"); + return 0; } -static void emu_sqdbr (int rx, int ry) { +static int emu_sqdbr (int rx, int ry) { display_emulation_not_implemented("sqdbr"); + return 0; } -static void emu_sqeb (int rx, __u32 val) { +static int emu_sqeb (int rx, __u32 val) { display_emulation_not_implemented("sqeb"); + return 0; } -static void emu_sqebr (int rx, int ry) { +static int emu_sqebr (int rx, int ry) { display_emulation_not_implemented("sqebr"); + return 0; } -static void emu_sqxbr (int rx, int ry) { +static int emu_sqxbr (int rx, int ry) { display_emulation_not_implemented("sqxbr"); + return 0; } -static void emu_sxbr (int rx, int ry) { +static int emu_sxbr (int rx, int ry) { display_emulation_not_implemented("sxbr"); + return 0; } -static void emu_tcdb (int rx, __u64 val) { +static int emu_tcdb (int rx, __u64 val) { display_emulation_not_implemented("tcdb"); + return 0; } -static void emu_tceb (int rx, __u32 val) { +static int emu_tceb (int rx, __u32 val) { display_emulation_not_implemented("tceb"); + return 0; } -static void emu_tcxb (int rx, __u64 val) { +static int emu_tcxb (int rx, __u64 val) { display_emulation_not_implemented("tcxb"); + return 0; } @@ -486,6 +617,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, @@ -551,84 +683,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; } @@ -645,6 +775,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, @@ -682,13 +814,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; @@ -697,13 +828,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; @@ -712,13 +842,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; @@ -727,29 +856,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; @@ -759,7 +886,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} */ @@ -785,12 +912,13 @@ void math_emu_ldr(__u8 *opcode) { current->tss.fp_regs.fprs[(opc&0x00f0)>>4] = current->tss.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} */ @@ -816,61 +944,68 @@ void math_emu_ler(__u8 *opcode) { current->tss.fp_regs.fprs[(opc&0x00f0)>>4] = current->tss.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(¤t->tss.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + mathemu_copy_from_user(¤t->tss.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 *) (¤t->tss.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, ¤t->tss.fp_regs.fprs[(opc>>20)&15].d, 8); + mathemu_copy_to_user(dxb, ¤t->tss.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 *) (¤t->tss.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; } @@ -878,7 +1013,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->tss.fp_regs.fpc, dxb); return 0; } @@ -887,6 +1025,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 f71b5fc31e1c..7f9a94546441 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -76,7 +76,9 @@ int cpu_idle(void *unused) if (bh_mask & bh_active) { #endif do_bottom_half(); - continue; + __sti(); + if (!current->need_resched) + continue; } if (current->need_resched) { schedule(); @@ -109,11 +111,13 @@ asmlinkage int sys_idle(void) 0 returned you know you've got all the lines */ -int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_struct *tss,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 { @@ -134,34 +138,36 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str sp_kern_backchain1 }; - if(task) - tss=&task->tss; - if(tss) - regs=tss->regs; + if (task) + ksp = task->tss.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"); + case sp_linefeed: + linelen=sprintf(buff,"\n"); break; case sp_psw: if(regs) - linelen=sprintf(buff,"User PSW: %08lx %08lx\n", + 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"); break; case sp_ksp: - if(task) - linelen+=sprintf(&buff[linelen],"task: %08x ",(addr_t)task); - if(tss) - linelen+=sprintf(&buff[linelen],"tss: %08x ksp: %08x ", - (addr_t)tss,(addr_t)tss->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"); + linelen=sprintf(buff, "%s GPRS:\n", mode); break; case sp_gprs1 ... sp_gprs4: if(regs) @@ -176,7 +182,7 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str break; case sp_acrs: if(regs) - linelen=sprintf(buff,"User ACRS:\n"); + linelen=sprintf(buff, "%s ACRS:\n", mode); break; case sp_acrs1 ... sp_acrs4: if(regs) @@ -190,14 +196,14 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str } break; case sp_kern_backchain: - if(tss&&tss->ksp&®s) - linelen=sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n"); + if (ksp) + linelen=sprintf(buff, "Kernel BackChain CallChain\n"); break; default: - if(tss&&tss->ksp&®s) + if (ksp) { - backchain=(tss->ksp&PSW_ADDR_MASK); + backchain=ksp&PSW_ADDR_MASK; endchain=((backchain&(-8192))+8192); prev_backchain=backchain-1; line-=sp_kern_backchain1; @@ -206,34 +212,48 @@ int sprintf_regs(int line,char *buff,struct task_struct * task,struct thread_str if((backchain==0)||(backchain>=endchain) ||(chaincnt>=8)||(prev_backchain>=backchain)) break; - if((chaincnt>>1)==line) + if(chaincnt==line) { - linelen+=sprintf(&buff[linelen],"%s%08x %08x ", - (chaincnt&1) ? "":" ", - backchain,*(u32 *)(backchain+56)); - } - if((chaincnt>>1)>line) + linelen+=sprintf(&buff[linelen]," %08x [<%08x>]\n", + backchain, + *(u32 *)(backchain+56)&PSW_ADDR_MASK); break; + } prev_backchain=backchain; backchain=(*((u32 *)backchain))&PSW_ADDR_MASK; } - if(linelen) - linelen+=sprintf(&buff[linelen],"\n"); } } return(linelen); } -void show_regs(struct task_struct * task,struct thread_struct *tss,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,tss,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->tss.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; @@ -283,15 +303,15 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp, struct task_struct * p, struct pt_regs * regs) { struct stack_frame - { - unsigned long back_chain; - unsigned long eos; - unsigned long glue1; - unsigned long glue2; - unsigned long scratch[2]; - unsigned long gprs[10]; /* gprs 6 -15 */ - unsigned long fprs[4]; /* fpr 4 and 6 */ - unsigned long empty[4]; + { + unsigned long back_chain; + unsigned long eos; + unsigned long glue1; + unsigned long glue2; + unsigned long scratch[2]; + unsigned long gprs[10]; /* gprs 6 -15 */ + unsigned long fprs[4]; /* fpr 4 and 6 */ + unsigned long empty[4]; #if CONFIG_REMOTE_DEBUG gdb_pt_regs childregs; #else @@ -344,7 +364,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, ®s); @@ -383,7 +403,19 @@ asmlinkage int sys_execve(struct pt_regs regs) goto out; error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s); if (error == 0) + { current->flags &= ~PF_DTRACE; + current->tss.fp_regs.fpc=0; + if(MACHINE_HAS_IEEE) + { + __asm__ __volatile__ + ("sr 0,0\n\t" + "sfpc 0,0\n\t" + : + : + :"0"); + } + } putname(filename); out: unlock_kernel(); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 896631756bd3..2b81c03f1650 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -229,7 +229,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr, struct vm_area_struct * vma; addr=ADDR_BITS_REMOVE(addr); vma= find_extend_vma(tsk, addr); - + if (!vma) return -EIO; if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { @@ -478,15 +478,15 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* ieee_instruction_pointer from the user structure DJB */ if(child!=current) { - if (!(child->flags & PF_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) - { - if (request != PTRACE_KILL) + if (!(child->flags & PF_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) { diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index e777170ccc38..8f2ae4d6f0b0 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -13,7 +13,7 @@ #include /* - * Simple hash strategy: index = ((code >> 8) + code) & 0xff; + * 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 @@ -27,7 +27,7 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) { ext_int_info_t *p; int index; - index = (code + (code >> 8)) & 0xff; + index = code & 0xff; p = ext_int_hash[index]; while (p != NULL) { if (p->code == code) @@ -54,7 +54,7 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { ext_int_info_t *p, *q; int index; - index = (code + (code >> 8)) & 0xff; + index = code & 0xff; q = NULL; p = ext_int_hash[index]; while (p != NULL) { diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 58a2568cab70..2477b5878a16 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -5,20 +5,18 @@ */ #include #include +#include #include #include #include #include #include -#include +#include #include #include #include #include #include -#if CONFIG_CHANDEV -#include -#endif #if CONFIG_IP_MULTICAST #include #endif @@ -27,6 +25,7 @@ * I/O subsystem */ EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); EXPORT_SYMBOL(do_IO); EXPORT_SYMBOL(resume_IO); EXPORT_SYMBOL(ioinfo); @@ -42,21 +41,31 @@ EXPORT_SYMBOL(s390_request_irq_special); EXPORT_SYMBOL(s390_device_register); EXPORT_SYMBOL(s390_device_unregister); +EXPORT_SYMBOL(s390_bh_lock); + 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_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_view); +EXPORT_SYMBOL(debug_ascii_view); +EXPORT_SYMBOL(debug_ebcdic_view); +EXPORT_SYMBOL(debug_dflt_header_fn); /* * memory management @@ -81,6 +90,7 @@ EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(_ascebc_500); EXPORT_SYMBOL_NOVERS(_ebcasc_500); @@ -92,6 +102,8 @@ EXPORT_SYMBOL_NOVERS(_ebc_toupper); /* * misc. */ +EXPORT_SYMBOL(__copy_from_user_fixup); +EXPORT_SYMBOL(__copy_to_user_fixup); EXPORT_SYMBOL(__udelay); #ifdef CONFIG_SMP #include @@ -104,12 +116,13 @@ EXPORT_SYMBOL(synchronize_bh); EXPORT_SYMBOL(kernel_flag); EXPORT_SYMBOL(smp_ctl_set_bit); EXPORT_SYMBOL(smp_ctl_clear_bit); +EXPORT_SYMBOL(smp_do_callback_all); #endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); EXPORT_SYMBOL(genhd_dasd_name); -#if CONFIG_IP_MULTICAST +#ifdef CONFIG_IP_MULTICAST /* Required for lcs gigibit ethernet multicast support */ EXPORT_SYMBOL(arp_mc_map); #endif diff --git a/arch/s390/kernel/s390dyn.c b/arch/s390/kernel/s390dyn.c index cf1a9f6a0d55..b40201d3f80d 100644 --- a/arch/s390/kernel/s390dyn.c +++ b/arch/s390/kernel/s390dyn.c @@ -3,7 +3,7 @@ * S/390 dynamic device attachment * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) */ diff --git a/arch/s390/kernel/s390fpu.c b/arch/s390/kernel/s390fpu.c index f1847e31bbf1..0061d46deed5 100644 --- a/arch/s390/kernel/s390fpu.c +++ b/arch/s390/kernel/s390fpu.c @@ -80,6 +80,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 index c63e62852d89..f256d03f6ea8 100644 --- a/arch/s390/kernel/s390io.c +++ b/arch/s390/kernel/s390io.c @@ -33,16 +33,16 @@ #include #include -#undef CONFIG_DEBUG_IO +#undef CONFIG_DEBUG_IO #define CONFIG_DEBUG_CRW #define REIPL_DEVID_MAGIC 0x87654321 struct s390_irqaction init_IRQ_action; -unsigned int highest_subchannel; -ioinfo_t *ioinfo_head = NULL; -ioinfo_t *ioinfo_tail = NULL; -ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { +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 }; @@ -83,9 +83,9 @@ static int disable_subchannel( unsigned int irq); int s390_DevicePathVerification( int irq, __u8 domask ); -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 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, @@ -124,9 +124,9 @@ void s390_displayhex(char *str,void *ptr,s32 cnt) 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) + unsigned long irqflags, + const char *devname, + void *dev_id) { int retval; struct s390_irqaction *action; @@ -137,35 +137,35 @@ int s390_request_irq_special( int irq, if ( !io_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 ) - { + /* + * 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 s390_irqaction *) kmalloc( sizeof(struct s390_irqaction), GFP_KERNEL); - } - else - { - action = &init_IRQ_action; + } + else + { + action = &init_IRQ_action; - } /* endif */ + } /* endif */ if (!action) - { + { return -ENOMEM; - } /* endif */ + } /* endif */ action->handler = io_handler; action->flags = irqflags; action->name = devname; action->dev_id = dev_id; - retval = s390_setup_irq(irq, action); + retval = s390_setup_irq( irq, action); if ( init_IRQ_complete ) { @@ -174,10 +174,10 @@ int s390_request_irq_special( int irq, s390_DevicePathVerification( irq, 0 ); } else - { - kfree(action); + { + kfree(action); - } /* endif */ + } /* endif */ } /* endif */ @@ -228,7 +228,7 @@ void s390_free_irq(unsigned int irq, void *dev_id) } /* endif */ - s390irq_spin_lock_irqsave(irq,flags); + s390irq_spin_lock_irqsave( irq, flags); #ifdef CONFIG_KERNEL_DEBUG if ( irq != cons_dev ) @@ -251,7 +251,7 @@ void s390_free_irq(unsigned int irq, void *dev_id) ioinfo[irq]->ui.flags.unready = 1; do - { + { ret = disable_subchannel( irq); count++; @@ -305,15 +305,15 @@ void s390_free_irq(unsigned int irq, void *dev_id) disable_subchannel( 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 */ - + { + 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 */ @@ -325,11 +325,11 @@ void s390_free_irq(unsigned int irq, void *dev_id) 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.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 */ + ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ ioinfo[irq]->nopfunc = NULL; @@ -405,15 +405,15 @@ int enable_irq(unsigned int irq) */ static int enable_subchannel( unsigned int irq) { - int ret; - int ccode; - int retry = 5; + int ret; + int ccode; + int retry = 5; - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); + if ( irq > highest_subchannel || irq < 0 ) + { + return( -ENODEV ); - } /* endif */ + } /* endif */ if ( ioinfo[irq] == INVALID_STORAGE_AREA ) return( -ENODEV); @@ -425,18 +425,18 @@ static int enable_subchannel( unsigned int irq) if ( ioinfo[irq]->ui.flags.d_disable ) { ioinfo[irq]->ui.flags.d_disable = 0; - ret = 0; + ret = 0; } else { ccode = stsch(irq, &(ioinfo[irq]->schib) ); - if ( ccode ) - { - ret = -ENODEV; - } - else - { + if ( ccode ) + { + ret = -ENODEV; + } + else + { ioinfo[irq]->schib.pmcw.ena = 1; if ( irq == cons_dev ) @@ -445,28 +445,28 @@ static int enable_subchannel( unsigned int irq) } else { - ioinfo[irq]->schib.pmcw.isc = 3; + ioinfo[irq]->schib.pmcw.isc = 3; } /* endif */ - do - { + do + { ccode = msch( irq, &(ioinfo[irq]->schib) ); - switch (ccode) { - case 0: - ret = 0; - break; + switch (ccode) { + case 0: + ret = 0; + break; - case 1: - /* + 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 ); @@ -475,8 +475,8 @@ static int enable_subchannel( unsigned int irq) ret = -EIO; /* might be overwritten */ /* ... on re-driving */ /* ... the msch() */ - retry--; - break; + retry--; + break; case 2: tod_wait(100); /* allow for recovery */ @@ -484,24 +484,24 @@ static int enable_subchannel( unsigned int irq) retry--; break; - case 3: + case 3: ioinfo[irq]->ui.flags.oper = 0; - ret = -ENODEV; - break; + ret = -ENODEV; + break; - default: + 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 - } + ret = -ENODEV; // never reached + } - } while ( (ccode == 1) && retry ); + } while ( (ccode == 1) && retry ); - } /* endif */ + } /* endif */ } /* endif */ @@ -514,9 +514,9 @@ static int enable_subchannel( unsigned int irq) */ static int disable_subchannel( unsigned int irq) { - int cc; /* condition code */ - int ret; /* function return value */ - int retry = 5; + int cc; /* condition code */ + int ret; /* function return value */ + int retry = 5; if ( irq > highest_subchannel ) { @@ -525,7 +525,7 @@ static int disable_subchannel( unsigned int irq) if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } + } else if ( ioinfo[irq]->ui.flags.busy ) { /* @@ -554,17 +554,17 @@ static int disable_subchannel( unsigned int irq) { ioinfo[irq]->schib.pmcw.ena = 0; - do - { + do + { cc = msch( irq, &(ioinfo[irq]->schib) ); - switch (cc) { - case 0 : - ret = 0; /* done */ - break; + switch (cc) { + case 0 : + ret = 0; /* done */ + break; - case 1 : - /* + case 1 : + /* * very bad, requires interrupt alike * processing, where "rbh" is a dummy * parm for interface compatibility @@ -577,46 +577,46 @@ static int disable_subchannel( unsigned int irq) ioinfo[irq]->ui.flags.s_pend = 0; ret = -EIO; /* might be overwritten */ - /* ... on re-driving the */ - /* ... msch() call */ - retry--; - break; - - case 2 : - /* - * *** must not occur ! *** - * *** *** + /* ... on re-driving the */ + /* ... msch() call */ + retry--; + break; + + case 2 : + /* + * *** must not occur ! *** + * *** *** * *** indicates our internal *** * *** interrupt accounting is out *** - * *** of sync ===> panic() *** - */ + * *** of sync ===> panic() *** + */ printk( KERN_CRIT"disable_subchannel(%04X) " "- unexpected busy condition for " "device %04X received !\n", irq, ioinfo[irq]->devstat.devno); ret = -EBUSY; - break; + break; - case 3 : - /* + 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; + break; - default : - ret = -ENODEV; // never reached ... - break; + default : + ret = -ENODEV; // never reached ... + break; - } /* endswitch */ + } /* endswitch */ - } while ( (cc == 1) && retry ); + } while ( (cc == 1) && retry ); } /* endif */ @@ -716,10 +716,10 @@ unsigned long s390_init_IRQ( unsigned long memstart) * 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. + * + * 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(); @@ -730,7 +730,7 @@ unsigned long s390_init_IRQ( unsigned long memstart) cr6 = 0; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - s390_process_subchannels(); + s390_process_subchannels(); /* * enable default I/O-interrupt sublass 3 @@ -740,7 +740,7 @@ unsigned long s390_init_IRQ( unsigned long memstart) s390_device_recognition_all(); - init_IRQ_complete = 1; + init_IRQ_complete = 1; __restore_flags(flags); @@ -788,7 +788,7 @@ int s390_start_IO( int irq, /* IRQ */ ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE); ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND ) - && (flag & DOIO_SUPPRESS_INTER) ); + && (flag & DOIO_SUPPRESS_INTER) ); if ( flag & DOIO_VALID_LPM ) { @@ -800,7 +800,7 @@ int s390_start_IO( int irq, /* IRQ */ } /* endif */ - ioinfo[irq]->orb.cpa = (ccw1_t *)virt_to_phys( cpa); + ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); /* * If sync processing was requested we lock the sync ISC, modify the @@ -849,7 +849,7 @@ int s390_start_IO( int irq, /* IRQ */ case 0: if ( !ioinfo[irq]->ui.flags.w4sense ) - { + { /* * init the device driver specific devstat irb area * @@ -895,7 +895,7 @@ int s390_start_IO( int irq, /* IRQ */ } /* 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 @@ -906,54 +906,54 @@ int s390_start_IO( int irq, /* IRQ */ */ if ( flag & DOIO_WAIT_FOR_INTERRUPT ) { - int io_sub = -1; - psw_t io_new_psw; - int ccode; + psw_t io_new_psw; + int ccode; uint64_t time_start; uint64_t time_curr; - int ready = 0; - struct _lowcore *lc = NULL; + int ready = 0; + int io_sub = -1; + struct _lowcore *lc = NULL; int do_retry = 1; - /* + /* * 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)); + */ + 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; + 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); @@ -974,8 +974,8 @@ int s390_start_IO( int irq, /* IRQ */ { tpi_info_t tpi_info; - do - { + do + { if ( tpi(&tpi_info) == 1 ) { io_sub = tpi_info.irq; @@ -990,20 +990,20 @@ int s390_start_IO( int irq, /* IRQ */ do_retry = 0; } /* endif */ - + } while ( do_retry ); } else { - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); + asm volatile ("lpsw %0" : : "m" (io_sync_wait)); io_wakeup: - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; + io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; } /* endif */ if ( do_retry ) - ready = s390_process_IRQ( io_sub ); + ready = s390_process_IRQ( io_sub ); /* * surrender when retry count's exceeded ... @@ -1032,9 +1032,9 @@ io_wakeup: 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 + /* + * 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 @@ -1076,8 +1076,8 @@ io_wakeup: if ( ioinfo[irq]->opm == 0 ) { - ret = -ENODEV; - ioinfo[irq]->ui.flags.oper = 0; + ret = -ENODEV; + ioinfo[irq]->ui.flags.oper = 0; } else { @@ -1088,12 +1088,12 @@ io_wakeup: ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; #ifdef CONFIG_DEBUG_IO - { - char buffer[80]; + { + char buffer[80]; stsch(irq, &(ioinfo[irq]->schib) ); - sprintf( buffer, "s390_start_IO(%04X) - irb for " + sprintf( buffer, "s390_start_IO(%04X) - irb for " "device %04X, after status pending\n", irq, ioinfo[irq]->devstat.devno ); @@ -1102,7 +1102,7 @@ io_wakeup: &(ioinfo[irq]->devstat.ii.irb) , sizeof(irb_t)); - sprintf( buffer, "s390_start_IO(%04X) - schib for " + sprintf( buffer, "s390_start_IO(%04X) - schib for " "device %04X, after status pending\n", irq, ioinfo[irq]->devstat.devno ); @@ -1113,7 +1113,7 @@ io_wakeup: if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) - { + { sprintf( buffer, "s390_start_IO(%04X) - sense " "data for " "device %04X, after status pending\n", @@ -1125,12 +1125,12 @@ io_wakeup: ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); } /* endif */ - } + } #endif } else { - ret = -EIO; + ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; @@ -1144,7 +1144,7 @@ io_wakeup: break; default: /* device/path not operational */ - + if ( flag & DOIO_VALID_LPM ) { ioinfo[irq]->opm &= ~lpm; @@ -1154,27 +1154,27 @@ io_wakeup: ioinfo[irq]->opm = 0; } /* endif */ - + if ( ioinfo[irq]->opm == 0 ) { ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; + ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; } /* endif */ ret = -ENODEV; memcpy( ioinfo[irq]->irq_desc.action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); + &(ioinfo[irq]->devstat), + sizeof( devstat_t) ); #ifdef CONFIG_DEBUG_IO - { - char buffer[80]; + { + char buffer[80]; stsch(irq, &(ioinfo[irq]->schib) ); - sprintf( buffer, "s390_start_IO(%04X) - schib for " + sprintf( buffer, "s390_start_IO(%04X) - schib for " "device %04X, after 'not oper' status\n", irq, ioinfo[irq]->devstat.devno ); @@ -1211,7 +1211,7 @@ io_wakeup: } while ( retry && (iret == -EBUSY ) ); - sync_isc_locked = 0; // local setting + sync_isc_locked = 0; // local setting ioinfo[irq]->ui.flags.syncio = 0; // global setting spin_unlock_irqrestore( &sync_isc, psw_flags); @@ -1222,7 +1222,7 @@ io_wakeup: { ioinfo[irq]->ui.flags.repnone = 0; - } /* endif */ + } /* endif */ return( ret); } @@ -1324,27 +1324,27 @@ int resume_IO( int irq) ccode = rsch( irq); switch (ccode) { - case 0 : - break; + case 0 : + break; - case 1 : + case 1 : s390_process_IRQ( irq ); - ret = -EBUSY; - break; + ret = -EBUSY; + break; - case 2 : - ret = -EINVAL; - break; + case 2 : + ret = -EINVAL; + break; - case 3 : - /* - * useless to wait for request completion - * as device is no longer operational ! - */ + 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; + ret = -ENODEV; + break; } /* endswitch */ @@ -1364,7 +1364,7 @@ int resume_IO( int irq) * it allows the device interrupt handler to associate the upcoming * interrupt with the halt_IO() request. */ -int halt_IO( int irq, +int halt_IO( int irq, unsigned long user_intparm, unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ { @@ -1482,13 +1482,13 @@ int halt_IO( int irq, { int io_sub; __u32 io_parm; - psw_t io_new_psw; - int ccode; + psw_t io_new_psw; + int ccode; int ready = 0; - struct _lowcore *lc = NULL; + 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 @@ -1504,31 +1504,31 @@ int halt_IO( int irq, 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; + 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); @@ -1568,7 +1568,7 @@ hio_wakeup: 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 @@ -1600,13 +1600,13 @@ hio_wakeup: */ if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) { - ret = -ENODEV; + ret = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 0; } else { - ret = -EIO; + ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; @@ -1630,8 +1630,8 @@ hio_wakeup: { disable_cpu_sync_isc( irq ); - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting + sync_isc_locked = 0; // local setting + ioinfo[irq]->ui.flags.syncio = 0; // global setting spin_unlock_irqrestore( &sync_isc, psw_flags); @@ -1653,7 +1653,7 @@ int clear_IO( int irq, unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ { int ret; - int ccode; + int ccode; unsigned long psw_flags; int sync_isc_locked = 0; @@ -1666,7 +1666,7 @@ int clear_IO( int irq, if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } + } /* * we only allow for halt_IO if the device has an I/O handler associated @@ -1675,62 +1675,62 @@ int clear_IO( int irq, { 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 */ - } /* endif */ - - /* + /* * Issue "Halt subchannel" and process condition code - */ + */ ccode = csch( irq ); switch ( ccode ) { @@ -1739,7 +1739,7 @@ int clear_IO( int irq, 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; @@ -1748,12 +1748,12 @@ int clear_IO( int irq, ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION; ioinfo[irq]->devstat.scnt = 0; - } - else - { + } + else + { ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION; - } /* endif */ + } /* endif */ /* * If synchronous I/O processing is requested, we have @@ -1764,16 +1764,16 @@ int clear_IO( int irq, * 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 @@ -1781,7 +1781,7 @@ int clear_IO( int irq, * 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)); @@ -1818,14 +1818,14 @@ int clear_IO( int irq, 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: @@ -1838,13 +1838,13 @@ cio_wakeup: *(__u32 *)__LC_SYNC_IO_WORD = 0; - } /* endif */ + } /* endif */ ret = 0; break; - - case 1 : /* status pending */ + case 1 : /* status pending */ + ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; /* @@ -1888,14 +1888,14 @@ cio_wakeup: ret = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 0; - } - else - { + } + else + { ret = -EIO; ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; ioinfo[irq]->ui.flags.oper = 1; - } /* endif */ + } /* endif */ break; @@ -1914,32 +1914,32 @@ cio_wakeup: if ( sync_isc_locked ) { disable_cpu_sync_isc( irq ); - + sync_isc_locked = 0; // local setting ioinfo[irq]->ui.flags.syncio = 0; // global setting 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; @@ -1958,15 +1958,15 @@ asmlinkage void do_IRQ( struct pt_regs regs, 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; @@ -1983,9 +1983,9 @@ asmlinkage void do_IRQ( struct pt_regs regs, #ifdef CONFIG_FAST_IRQ - /* + /* * more interrupts pending ? - */ + */ ccode = tpi( &tpi_info ); if ( ! ccode ) @@ -1993,29 +1993,29 @@ asmlinkage void do_IRQ( struct pt_regs regs, new_irq = tpi_info.irq; - /* + /* * 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 */ + } /* 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 @@ -2025,7 +2025,7 @@ asmlinkage void do_IRQ( struct pt_regs regs, * * 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; /* cond code from tsch() operation */ @@ -2056,18 +2056,18 @@ int s390_process_IRQ( unsigned int irq ) else { action = ioinfo[irq]->irq_desc.action; - - } /* endif */ + + } /* endif */ #ifdef CONFIG_DEBUG_IO - /* + /* * 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) " @@ -2077,14 +2077,15 @@ int s390_process_IRQ( unsigned int irq ) ioinfo[irq]->devstat.devno); } /* endif */ + } /* 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. @@ -2097,75 +2098,72 @@ int s390_process_IRQ( unsigned int irq ) * 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 the device is busy already // 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; + 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.intparm = ioinfo[irq]->u_intparm; + + } + 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 + ioinfo[irq]->devstat.intparm = 0; + } /* endif */ - /* + ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum; + + /* * 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 | SCSW_STCTL_INTER_STATUS ) ) - { + { ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count; ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa; #ifdef 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 ); + if ( irq != cons_dev ) + printk( "s390_process_IRQ( %04X ) : " + "residual count from irb after tsch() %d\n", + irq, ioinfo[irq]->devstat.rescnt ); #endif } /* 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 " @@ -2187,22 +2185,22 @@ int s390_process_IRQ( unsigned int irq ) ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt; ioinfo[irq]->devstat.flag |= DEVSTAT_FLAG_SENSE_AVAIL; - + sdevstat = sizeof( devstat_t); #ifdef CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "concurrent sense bytes avail %d\n", - irq, ioinfo[irq]->devstat.scnt ); + if ( irq != cons_dev ) + printk( "s390_process_IRQ( %04X ) : " + "concurrent sense bytes avail %d\n", + irq, ioinfo[irq]->devstat.scnt ); #endif - } - else - { + } + else + { /* don't copy the sense data area ! */ sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT; - } /* endif */ + } /* endif */ switch ( irb_cc ) { case 1: /* status pending */ @@ -2311,7 +2309,7 @@ int s390_process_IRQ( unsigned int irq ) sizeof( devstat_t) ); s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - s_ccw->cda = (char *)virt_to_phys( ioinfo[irq]->sense_data); + s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->sense_data ); s_ccw->count = SENSE_MAX_COUNT; s_ccw->flags = CCW_FLAG_SLI; @@ -2995,8 +2993,8 @@ int disable_cpu_sync_isc( int irq) // // Output : none // -void VM_virtual_device_info( unsigned int devno, - senseid_t *ps ) +void VM_virtual_device_info( unsigned int devno, + senseid_t *ps ) { diag210_t diag_data; int ccode; @@ -3222,7 +3220,7 @@ void VM_virtual_device_info( unsigned int devno, error = 1; - break; + break; } /* endswitch */ @@ -3322,19 +3320,19 @@ int read_dev_chars( int irq, void **buffer, int length ) } 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(); @@ -3357,11 +3355,11 @@ int read_dev_chars( int irq, void **buffer, int length ) if ( !ret ) { if ( ! *buffer ) - { + { rdc_buf = kmalloc( length, GFP_KERNEL); - } - else - { + } + else + { rdc_buf = *buffer; } /* endif */ @@ -3375,7 +3373,7 @@ int read_dev_chars( int irq, void **buffer, int length ) do { rdc_ccw->cmd_code = CCW_CMD_RDC; - rdc_ccw->cda = (char *)virt_to_phys( rdc_buf ); + rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf ); rdc_ccw->count = length; rdc_ccw->flags = CCW_FLAG_SLI; @@ -3398,21 +3396,21 @@ int read_dev_chars( int irq, void **buffer, int length ) } /* endif */ if ( !retry ) - { + { ret = -EBUSY; } /* endif */ __restore_flags(flags); - /* + /* * on success we update the user input parms - */ + */ if ( !ret ) { *buffer = rdc_buf; - } /* endif */ + } /* endif */ if ( emulated ) { @@ -3425,11 +3423,11 @@ int read_dev_chars( int irq, void **buffer, int length ) return( ret ); } - /* +/* * Read Configuration data - */ + */ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) - { +{ unsigned long flags; int ciw_cnt; @@ -3439,7 +3437,7 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) if ( (irq > highest_subchannel) || (irq < 0 ) ) { return( -ENODEV ); - } + } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); @@ -3456,12 +3454,12 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) { return( -EOPNOTSUPP ); - } /* endif */ + } /* endif */ - /* + /* * scan for RCD command in extended SenseID data - */ - + */ + for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ ) { if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD ) @@ -3473,15 +3471,16 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) { found = 1; - } /* endif */ + } /* endif */ break; + } /* endif */ } /* endfor */ if ( found ) -{ + { devstat_t devstat; /* inline device status area */ devstat_t *pdevstat; int ioflags; @@ -3506,9 +3505,9 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) emulated = 1; } /* endif */ - } + } else - { + { pdevstat = ioinfo[irq]->irq_desc.action->dev_id; } /* endif */ @@ -3519,9 +3518,9 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) { rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count, GFP_KERNEL); - } + } else - { + { rcd_buf = alloc_bootmem( ioinfo[irq]->senseid.ciw[ciw_cnt].count); } /* endif */ @@ -3530,18 +3529,18 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) { ret = -ENOMEM; - } /* endif */ + } /* endif */ if ( !ret ) { memset( rcd_buf, '\0', ioinfo[irq]->senseid.ciw[ciw_cnt].count); - + do - { + { rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd; - rcd_ccw->cda = (char *)virt_to_phys( rcd_buf ); + 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; @@ -3552,13 +3551,13 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) ioflags = DOIO_WAIT_FOR_INTERRUPT | DOIO_VALID_LPM | DOIO_DONT_CALL_INTHDLR; - } - else - { + } + else + { ioflags = DOIO_WAIT_FOR_INTERRUPT | DOIO_DONT_CALL_INTHDLR; - - } /* endif */ + + } /* endif */ ret = s390_start_IO( irq, rcd_ccw, @@ -3575,12 +3574,12 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) | DEVSTAT_FLAG_SENSE_AVAIL ) ) ) { retry = 0; // we got it ... - } - else - { + } + else + { retry--; // try again ... - } /* endif */ + } /* endif */ break; @@ -3612,9 +3611,9 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) if ( init_IRQ_complete ) { kfree( rcd_buf ); - } - else - { + } + else + { free_bootmem( (unsigned long)rcd_buf, ioinfo[irq]->senseid.ciw[ciw_cnt].count); @@ -3624,7 +3623,7 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ) *buffer = NULL; *length = 0; - + } /* endif */ if ( emulated ) @@ -3645,7 +3644,6 @@ 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; @@ -3667,7 +3665,7 @@ static int __inline__ get_next_available_irq( ioinfo_t *pi) if ( pi == NULL ) { ret_val = -ENODEV; - break; + break; } } /* endif */ @@ -3696,7 +3694,7 @@ int get_irq_first( void ) else { ret_irq = -ENODEV; - + } /* endif */ } else @@ -3820,8 +3818,8 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi) && ioinfo[i]->schib.pmcw.dev == devno ) { - pdi->irq = i; - pdi->devno = devno; + pdi->irq = i; + pdi->devno = devno; if ( ioinfo[i]->ui.flags.oper && !ioinfo[i]->ui.flags.unknown ) @@ -3845,7 +3843,7 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi) else { pdi->status = DEVSTAT_NOT_OPER; - + memset( &(pdi->sid_data), '\0', sizeof( senseid_t)); @@ -3858,7 +3856,7 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi) pdi->status |= DEVSTAT_DEVICE_OWNED; rc = 0; /* found */ - break; + break; } /* endif */ @@ -3889,7 +3887,7 @@ int get_irq_by_devno( unsigned int devno ) } /* endif */ } /* endfor */ - + } /* endif */ return( rc); @@ -3903,7 +3901,7 @@ unsigned int get_devno_by_irq( int irq ) || ( ioinfo[irq] == INVALID_STORAGE_AREA ) ) { return -1; - + } /* endif */ /* @@ -3955,7 +3953,7 @@ void s390_device_recognition_irq( int irq ) * single I/O during boot (IPL) processing. */ spin_lock_irqsave( &sync_isc, psw_flags); - + ret = enable_cpu_sync_isc( irq); if ( ret ) @@ -3964,7 +3962,7 @@ void s390_device_recognition_irq( int irq ) } else { - ioinfo[irq]->ui.flags.syncio = 1; // global + ioinfo[irq]->ui.flags.syncio = 1; // global ioinfo[irq]->ui.flags.unknown = 0; memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t)); @@ -4022,7 +4020,7 @@ void s390_device_recognition_irq( int irq ) free_irq( irq, &devstat ); } /* endif */ - + } /* endif */ } @@ -4063,13 +4061,14 @@ void s390_process_subchannels( void) { ret = s390_validate_subchannel( irq, 0); - irq++; - + if ( ret != -ENXIO) + irq++; + } while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) ); - highest_subchannel = --irq; + highest_subchannel = (--irq); - printk( "\nHighest subchannel number detected: %u\n", + printk( "Highest subchannel number detected (hex) : %04X\n", highest_subchannel); } @@ -4136,7 +4135,6 @@ int s390_validate_subchannel( int irq, int enable ) { if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { - if ( !init_IRQ_complete ) { ioinfo[irq] = @@ -4156,7 +4154,7 @@ int s390_validate_subchannel( int irq, int enable ) 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, @@ -4191,14 +4189,14 @@ int s390_validate_subchannel( int irq, int enable ) ioinfo[irq]->prev = pi; pi->next->prev = ioinfo[irq]; pi->next = ioinfo[irq]; - break; - + break; + } /* endif */ pi = pi->next; } while ( 1 ); - + } /* endif */ } /* endif */ @@ -4218,7 +4216,7 @@ int s390_validate_subchannel( int irq, int enable ) ioinfo[irq]->schib.pmcw.pam, ioinfo[irq]->schib.pmcw.pom); -/* + /* * initialize ioinfo structure */ ioinfo[irq]->irq = irq; @@ -4232,9 +4230,9 @@ int s390_validate_subchannel( int irq, int enable ) /* * We should have at least one CHPID ... - */ + */ if ( ioinfo[irq]->opm ) -{ + { /* * We now have to initially ... * ... set "interruption sublass" @@ -4260,15 +4258,15 @@ int s390_validate_subchannel( int irq, int enable ) && ( ioinfo[irq]->opm != 0x04 ) && ( ioinfo[irq]->opm != 0x02 ) && ( ioinfo[irq]->opm != 0x01 ) ) - { + { ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - } /* endif */ + } /* endif */ retry = 5; do - { + { ccode2 = msch_err( irq, &ioinfo[irq]->schib); switch (ccode2) { @@ -4280,7 +4278,7 @@ int s390_validate_subchannel( int irq, int enable ) ioinfo[irq]->ui.flags.consns = 1; ret = 0; break; - + case 1: // status pending // // How can we have a pending status as @@ -4293,12 +4291,12 @@ int s390_validate_subchannel( int irq, int enable ) retry--; ret = -EIO; break; - + case 2: // busy - /* + /* * we mark it not-oper as we can't * properly operate it ! - */ + */ ioinfo[irq]->ui.flags.oper = 0; tod_wait( 100); /* allow for recovery */ retry--; @@ -4315,39 +4313,39 @@ int s390_validate_subchannel( int irq, int enable ) #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( " ... msch() (2) failed with CC = %X\n", ccode2 ); ioinfo[irq]->ui.flags.oper = 0; ret = -EIO; - } - else - { + } + else + { ioinfo[irq]->ui.flags.oper = 1; ioinfo[irq]->ui.flags.consns = 0; ret = 0; - } /* endif */ - } - else - { + } /* endif */ + } + else + { printk( " ... msch() (1) failed with CC = %X\n", ccode2); ioinfo[irq]->ui.flags.oper = 0; ret = -EIO; - } /* endif */ - + } /* endif */ + retry = 0; break; @@ -4356,13 +4354,13 @@ int s390_validate_subchannel( int irq, int enable ) } while ( ccode2 && retry ); if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) ) - { + { printk( " ... msch() retry count for " "subchannel %04X exceeded, CC = %d\n", irq, ccode2); - } /* endif */ + } /* endif */ } else { @@ -4373,19 +4371,18 @@ int s390_validate_subchannel( int irq, int enable ) } /* endif */ } else - { + { ret = -ENODEV; - } /* endif */ + } /* endif */ } else { - ret = -ENXIO; - } /* endif */ + } /* endif */ - return( ret ); + return( ret ); } /* @@ -4417,70 +4414,70 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) senseid_t *psid = sid;/* start with the external buffer */ int sbuffer = 0; /* switch SID data buffer */ - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); + if ( (irq > highest_subchannel) || (irq < 0 ) ) + { + return( -ENODEV ); - } + } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); - } /* endif */ + } /* endif */ - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); + if ( ioinfo[irq]->ui.flags.oper == 0 ) + { + return( -ENODEV ); - } /* endif */ + } /* endif */ - if ( !ioinfo[irq]->ui.flags.ready ) - { + if ( !ioinfo[irq]->ui.flags.ready ) + { pdevstat = &devstat; - /* + /* * 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; - } - else - { + } + else + { inlreq = 0; irq_ret = 0; pdevstat = ioinfo[irq]->irq_desc.action->dev_id; - } /* endif */ + } /* endif */ if ( irq_ret == 0 ) -{ + { int i; s390irq_spin_lock( irq); // more than one path installed ? if ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) -{ + { sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN; sense_ccw[0].cda = 0; sense_ccw[0].count = 0; sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID; - sense_ccw[1].cda = (char *)virt_to_phys( psid ); + sense_ccw[1].cda = (__u32)virt_to_phys( sid ); sense_ccw[1].count = sizeof( senseid_t); sense_ccw[1].flags = CCW_FLAG_SLI; } else { sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID; - sense_ccw[0].cda = (char *)virt_to_phys( psid ); + sense_ccw[0].cda = (__u32)virt_to_phys( sid ); sense_ccw[0].count = sizeof( senseid_t); sense_ccw[0].flags = CCW_FLAG_SLI; @@ -4496,7 +4493,7 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) domask &= lpm; if ( domask ) - { + { psid->cu_type = 0xFFFF; /* initialize fields ... */ psid->cu_model = 0; psid->dev_type = 0; @@ -4504,14 +4501,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) retry = 5; /* retry count */ io_retry = 1; /* enable retries */ - + /* * We now issue a SenseID request. In case of BUSY, * STATUS PENDING or non-CMD_REJECT error conditions * we run simple retries. */ do - { + { memset( pdevstat, '\0', sizeof( devstat_t) ); irq_ret = s390_start_IO( irq, @@ -4533,9 +4530,9 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) // if ( psid->cu_type == 0xFFFF ) - { + { if ( pdevstat->flag & DEVSTAT_STATUS_PENDING ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : device %04X on " "Subchannel %04X " @@ -4548,14 +4545,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) } /* endif */ if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { + { /* * if the device doesn't support the SenseID * command further retries wouldn't help ... */ if ( pdevstat->ii.sense.data[0] & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : device %04X on " "Subchannel %04X " @@ -4565,10 +4562,10 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) irq); #endif io_retry = 1; - } + } #ifdef CONFIG_DEBUG_IO - else - { + else + { printk( "SenseID : UC on " "dev %04X, " "retry %d, " @@ -4590,12 +4587,12 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) pdevstat->ii.sense.data[6], pdevstat->ii.sense.data[7]); - } /* endif */ + } /* endif */ #endif - } + } else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER ) || ( irq_ret == -ENODEV ) ) - { + { #ifdef CONFIG_DEBUG_IO printk( "SenseID : path %02X for " "device %04X on " @@ -4608,8 +4605,8 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) io_retry = 0; ioinfo[irq]->opm &= ~domask; - -} + + } #ifdef CONFIG_DEBUG_IO else if ( (pdevstat->flag != ( DEVSTAT_START_FUNCTION @@ -4630,11 +4627,11 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) } /* endif */ #endif - } + } else // we got it ... - { + { if ( !sbuffer ) // switch buffers - { + { /* * we report back the * first hit only @@ -4642,14 +4639,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) psid = &isid; if ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) - { - sense_ccw[1].cda = (char *)virt_to_phys( psid ); - } - else - { - sense_ccw[0].cda = (char *)virt_to_phys( psid ); + { + sense_ccw[1].cda = (__u32)virt_to_phys( psid ); + } + else + { + sense_ccw[0].cda = (__u32)virt_to_phys( psid ); - } /* endif */ + } /* endif */ /* * if just the very first @@ -4662,35 +4659,35 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) sbuffer = 1; - } /* endif */ + } /* endif */ if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) ) -{ + { ioinfo[irq]->ui.flags.esid = 1; - + } /* endif */ io_retry = 0; - + } /* endif */ if ( io_retry ) - { + { retry--; - + if ( retry == 0 ) { io_retry = 0; - } /* endif */ - + } /* endif */ + } /* endif */ - + } while ( (io_retry) ); } /* endif - domask */ - } /* endfor */ + } /* endfor */ s390irq_spin_unlock( irq); @@ -4713,7 +4710,7 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) } /* endif */ if ( sid->cu_type == 0xFFFF ) -{ + { /* * SenseID CU-type of 0xffff indicates that no device * information could be retrieved (pre-init value). @@ -4733,10 +4730,10 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) /* * Issue device info message if unit was operational . */ - if ( ioinfo[irq]->ui.flags.unknown ) - { + if ( !ioinfo[irq]->ui.flags.unknown ) + { if ( sid->dev_type != 0 ) - { + { printk( "SenseID : device %04X reports: CU Type/Mod = %04X/%02X," " Dev Type/Mod = %04X/%02X\n", ioinfo[irq]->schib.pmcw.dev, @@ -4746,18 +4743,18 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm ) sid->dev_model); } else - { + { printk( "SenseID : device %04X reports:" " Dev Type/Mod = %04X/%02X\n", ioinfo[irq]->schib.pmcw.dev, sid->cu_type, sid->cu_model); - } /* endif */ + } /* endif */ - } /* endif */ + } /* endif */ - if ( ioinfo[irq]->ui.flags.unknown ) + if ( !ioinfo[irq]->ui.flags.unknown ) irq_ret = 0; else irq_ret = -ENODEV; @@ -4774,7 +4771,7 @@ static int __inline__ s390_SetMultiPath( int irq ) cc = stsch( irq, &ioinfo[irq]->schib ); if ( !cc ) - { + { ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ cc = msch( irq, &ioinfo[irq]->schib ); @@ -4812,17 +4809,17 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) if ( ccode ) { ret = -ENODEV; -} + } else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 ) { -/* + /* * no error, just not required for single path only devices - */ + */ ioinfo[irq]->ui.flags.pgid_supp = 0; ret = 0; } else -{ + { int i; pgid_t pgid; __u8 dev_path; @@ -4833,16 +4830,16 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) & ioinfo[irq]->schib.pmcw.pom; if ( usermask ) - { + { dev_path = usermask; - } - else - { + } + else + { dev_path = ioinfo[irq]->opm; - } /* endif */ + } /* endif */ - /* + /* * let's build a path group ID if we don't have one yet */ if ( ioinfo[irq]->ui.flags.pgid == 0) @@ -4854,7 +4851,7 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) ioinfo[irq]->ui.flags.pgid = 1; - } /* endif */ + } /* endif */ memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t)); @@ -4865,7 +4862,7 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) domask = dev_path & pathmask; if ( domask ) - { + { ret = s390_SetPGID( irq, domask, &pgid ); /* @@ -4879,30 +4876,30 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) if ( ret == -EOPNOTSUPP && first ) { *(int *)&pgid = 0; - + ret = s390_SensePGID( irq, domask, &pgid); first = 0; - + if ( ret == 0 ) { - /* + /* * Check whether we retrieved * a reasonable PGID ... - */ + */ if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED ) - { + { memcpy( &(ioinfo[irq]->pgid), &pgid, sizeof(pgid_t) ); - } + } else // ungrouped or garbage ... - { + { ret = -EOPNOTSUPP; } /* endif */ - } + } else - { + { ioinfo[irq]->ui.flags.pgid_supp = 0; #ifdef CONFIG_DEBUG_IO @@ -4924,18 +4921,18 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) " support path grouping\n", irq, ioinfo[irq]->schib.pmcw.dev); - + #endif ioinfo[irq]->ui.flags.pgid_supp = 0; } /* endif */ - - } /* endif */ + + } /* endif */ } /* endfor */ - } /* endif */ + } /* endif */ return ret; #else @@ -4943,14 +4940,14 @@ int s390_DevicePathVerification( int irq, __u8 usermask ) #endif } - /* +/* * s390_SetPGID * * Set Path Group ID - * - */ + * + */ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) - { +{ ccw1_t spid_ccw[2]; /* ccw area for SPID command */ devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; @@ -4966,7 +4963,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { + { return( -ENODEV); } /* endif */ @@ -5001,7 +4998,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) } /* endif */ if ( irq_ret == 0 ) - { + { s390irq_spin_lock( irq); spid_ccw[0].cmd_code = 0x5B; /* suspend multipath reconnect */ @@ -5010,16 +5007,16 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; spid_ccw[1].cmd_code = CCW_CMD_SET_PGID; - spid_ccw[1].cda = (char *)virt_to_phys( pgid ); + spid_ccw[1].cda = (__u32)virt_to_phys( pgid ); spid_ccw[1].count = sizeof( pgid_t); spid_ccw[1].flags = CCW_FLAG_SLI; pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH; - /* + /* * We now issue a SenseID request. In case of BUSY * or STATUS PENDING conditions we retry 5 times. - */ + */ do { memset( pdevstat, '\0', sizeof( devstat_t) ); @@ -5049,7 +5046,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION | DEVSTAT_FINAL_STATUS ) ) - { + { retry = 0; // successfully set ... } else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) @@ -5106,28 +5103,28 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) ioinfo[irq]->schib.pmcw.dev, irq); - retry = 0; + retry = 0; } /* endif */ } else if ( irq_ret != -ENODEV ) - { + { retry--; } else { retry = 0; - } /* endif */ + } /* 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, pdevstat); @@ -5146,12 +5143,12 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) 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() */ + devstat_t devstat; /* required by request_irq() */ devstat_t *pdevstat = &devstat; - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline 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 ) ) { @@ -5175,9 +5172,9 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) /* * 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. - */ + * 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, @@ -5195,11 +5192,11 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) } /* endif */ if ( irq_ret == 0 ) - { + { s390irq_spin_lock( irq); snid_ccw.cmd_code = CCW_CMD_SENSE_PGID; - snid_ccw.cda = (char *)virt_to_phys( pgid ); + snid_ccw.cda = (__u32)virt_to_phys( pgid ); snid_ccw.count = sizeof( pgid_t); snid_ccw.flags = CCW_FLAG_SLI; @@ -5220,7 +5217,7 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) | DOIO_DONT_CALL_INTHDLR ); if ( irq_ret == 0 ) - { + { if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) { /* @@ -5230,7 +5227,7 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) */ if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT ) { - retry = 0; + retry = 0; irq_ret = -EOPNOTSUPP; } else @@ -5270,12 +5267,12 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) retry = 0; - } + } else - { + { retry = 0; // success ... - } /* endif */ + } /* endif */ } else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY { @@ -5296,7 +5293,7 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) " start_io() reports rc : %d, retrying ...\n", ioinfo[irq]->schib.pmcw.dev, irq_ret); - retry--; + retry--; } else // -ENODEV ... { @@ -5320,16 +5317,16 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) return( irq_ret ); } - /* +/* * s390_do_crw_pending * * Called by the machine check handler to process CRW pending * conditions. It may be a single CRW, or CRWs may be chained. * * Note : we currently process CRWs for subchannel source only - */ + */ void s390_do_crw_pending( crwe_t *pcrwe ) - { +{ int irq; int dev_oper = 0; int dev_no = -1; @@ -5340,7 +5337,7 @@ void s390_do_crw_pending( crwe_t *pcrwe ) #endif while ( pcrwe != NULL ) - { + { switch ( pcrwe->crw.rsc ) { case CRW_RSC_SCH : @@ -5364,7 +5361,7 @@ void s390_do_crw_pending( crwe_t *pcrwe ) if ( ioinfo[irq]->ui.flags.dval ) dev_no = ioinfo[irq]->devno; - } /* endif */ + } /* endif */ #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : subchannel validation - start ...\n"); @@ -5377,19 +5374,19 @@ void s390_do_crw_pending( crwe_t *pcrwe ) #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : subchannel validation - done\n"); #endif - /* + /* * After the validate processing * the ioinfo control block * should be allocated ... - */ + */ if ( lock ) - { + { s390irq_spin_unlock( irq ); } /* endif */ #ifdef CONFIG_DEBUG_CRW - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) + if ( ioinfo[irq] != INVALID_STORAGE_AREA ) { printk( "do_crw_pending : ioinfo at %08X\n", (unsigned)ioinfo[irq]); @@ -5397,7 +5394,7 @@ void s390_do_crw_pending( crwe_t *pcrwe ) } /* endif */ #endif - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) + if ( ioinfo[irq] != INVALID_STORAGE_AREA ) { if ( ioinfo[irq]->ui.flags.oper == 0 ) { @@ -5408,15 +5405,15 @@ void s390_do_crw_pending( crwe_t *pcrwe ) if ( ( dev_oper == 1 ) && ( ioinfo[irq]->nopfunc != NULL ) ) { - free_irq( irq, - ioinfo[irq]->irq_desc.action->dev_id ); - ioinfo[irq]->nopfunc( irq, - DEVSTAT_DEVICE_GONE ); + free_irq( irq, + ioinfo[irq]->irq_desc.action->dev_id ); + ioinfo[irq]->nopfunc( irq, + DEVSTAT_DEVICE_GONE ); } /* endif */ - } - else - { + } + else + { #ifdef CONFIG_DEBUG_CRW printk( "do_crw_pending : device " "recognition - start ...\n"); @@ -5442,7 +5439,7 @@ void s390_do_crw_pending( crwe_t *pcrwe ) if ( pdevreg->oper_func != NULL ) pdevreg->oper_func( irq, pdevreg ); - } /* endif */ + } /* endif */ } /* * ... it is and was operational, but @@ -5453,11 +5450,11 @@ void s390_do_crw_pending( crwe_t *pcrwe ) ioinfo[irq]->nopfunc( irq, DEVSTAT_REVALIDATE ); - } /* endif */ + } /* endif */ } /* endif */ - } /* endif */ + } /* endif */ break; @@ -5516,13 +5513,13 @@ void s390_do_crw_pending( crwe_t *pcrwe ) /* added by Holger Smolinski for reipl support in reipl.S */ extern void do_reipl (int); -void +void reipl ( int sch ) { - int i; + int i; for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); + 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 index 898f0307e462..a055fc59f8fb 100644 --- a/arch/s390/kernel/s390mach.c +++ b/arch/s390/kernel/s390mach.c @@ -4,7 +4,7 @@ * currently only channel-reports are supported * * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) */ @@ -20,16 +20,16 @@ #include #include -#define S390_MACHCHK_DEBUG +#undef S390_MACHCHK_DEBUG -static int __init s390_machine_check_handler( void * parm ); +static int s390_machine_check_handler( void * parm ); static void s390_enqueue_mchchk( mache_t *mchchk ); static mache_t *s390_dequeue_mchchk( void ); static void s390_enqueue_free_mchchk( mache_t *mchchk ); static mache_t *s390_dequeue_free_mchchk( void ); static int s390_collect_crw_info( void ); -static struct semaphore s_sem[2]; +static struct semaphore s_sem; static mache_t *mchchk_queue_head = NULL; static mache_t *mchchk_queue_tail = NULL; @@ -58,8 +58,7 @@ void s390_init_machine_check( void ) crwe_t *pcrwe; /* CRW buffer element pointer */ mache_t *pmache; /* machine check element pointer */ - init_MUTEX_LOCKED( &s_sem[0] ); - init_MUTEX_LOCKED( &s_sem[1] ); + init_MUTEX_LOCKED( &s_sem ); pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL); @@ -69,7 +68,7 @@ void s390_init_machine_check( void ) crw_buffer_anchor = pcrwe; - for ( i=0; i < MAX_CRW_PENDING; i++) + for ( i=0; i < MAX_CRW_PENDING-1; i++) { pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t)); pcrwe = pcrwe->crwe_next; @@ -108,16 +107,7 @@ void s390_init_machine_check( void ) printk( "init_mach : starting machine check handler\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 machine check handler coming up ... \n"); -#endif - - down( &s_sem[0]); + kernel_thread( s390_machine_check_handler, &s_sem, 0); ctl_clear_bit( 14, 25 ); // disable damage MCH #if 1 @@ -145,10 +135,10 @@ void s390_init_machine_check( void ) * mchine check pre-processor, collecting the machine check info, * queueing it and posting the machine check handler for processing. */ -void __init s390_do_machine_check( void ) +void s390_do_machine_check( void ) { int crw_count; - mcic_t mcic; + mcic_t mcic; #ifdef S390_MACHCHK_DEBUG printk( "s390_do_machine_check : starting ...\n"); @@ -164,7 +154,7 @@ void __init s390_do_machine_check( void ) if ( crw_count ) { - up( &s_sem[1] ); + up( &s_sem ); } /* endif */ @@ -183,7 +173,7 @@ void __init s390_do_machine_check( void ) * machine check handler, dequeueing machine check entries * and processing them */ -static int __init s390_machine_check_handler( void *parm) +static int s390_machine_check_handler( void *parm) { struct semaphore *sem = parm; int flags; @@ -191,11 +181,12 @@ static int __init s390_machine_check_handler( void *parm) int found = 0; -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : up\n"); -#endif + /* set name to something sensible */ + strncpy(current->comm,"kmcheck",15); + current->comm[15]=0; - up( &sem[0] ); + /* block all signals */ + sigfillset(¤t->blocked); #ifdef S390_MACHCHK_DEBUG printk( "mach_handler : ready\n"); @@ -207,15 +198,18 @@ static int __init s390_machine_check_handler( void *parm) printk( "mach_handler : waiting for wakeup\n"); #endif - down_interruptible( &sem[1] ); + down_interruptible( sem ); #ifdef S390_MACHCHK_DEBUG printk( "\nmach_handler : wakeup ... \n"); #endif + found = 0; /* init ... */ __save_flags( flags ); __cli(); + do { + pmache = s390_dequeue_mchchk(); if ( pmache ) @@ -256,18 +250,19 @@ static int __init s390_machine_check_handler( void *parm) } else { - found = 0; // unconditional surrender ... #ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : terminated \n"); + printk( "mach_handler : nothing to do, sleeping\n"); #endif } /* endif */ + } while ( pmache ); + __restore_flags( flags ); - } while ( found ); + } while ( 1 ); return( 0); } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c7fdaa682554..5b362dc83223 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -137,7 +137,7 @@ __initfunc(void vmpoff_setup(char *str, char *ints)) #ifndef CONFIG_SMP void machine_restart(char * __unused) { - reipl(S390_lowcore.ipl_device); + reipl(S390_lowcore.ipl_device); } void machine_halt(void) @@ -145,14 +145,14 @@ void machine_halt(void) if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 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); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} #endif /* @@ -177,7 +177,7 @@ void tod_wait(unsigned long delay) __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)) { - static unsigned int smptrap=0; + static unsigned int smptrap = 0; unsigned long memory_start, memory_end; char c, cn, *to, *from; diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index cdd09d293d18..121c0155f6a7 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -39,7 +39,7 @@ #define SIGFRAME_COMMON \ __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \ struct sigcontext sc; \ -sigregs sregs; \ +_sigregs sregs; \ __u8 retcode[S390_SYSCALL_SIZE]; typedef struct @@ -79,7 +79,7 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma schedule(); if (do_signal(regs, &saveset)) return -EINTR; - } + } } asmlinkage int @@ -100,17 +100,17 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) current->blocked = newset; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - regs->gprs[2] = -EINTR; + regs->gprs[2] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); if (do_signal(regs, &saveset)) return -EINTR; - } + } } -asmlinkage int +asmlinkage int sys_sigaction(int sig, const struct old_sigaction *act, struct old_sigaction *oact) { @@ -126,7 +126,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, __get_user(new_ka.sa.sa_flags, &act->sa_flags); __get_user(mask, &act->sa_mask); siginitset(&new_ka.sa.sa_mask, mask); - } + } ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); @@ -137,22 +137,21 @@ sys_sigaction(int sig, const struct old_sigaction *act, return -EFAULT; __put_user(old_ka.sa.sa_flags, &oact->sa_flags); __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); - } + } return ret; } 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; @@ -167,7 +166,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; @@ -189,13 +188,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); } @@ -220,20 +219,20 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) { if (sigreturn_common(regs,sizeof(sigframe))) - goto badframe; + goto badframe; return regs->gprs[2]; - + badframe: force_sig(SIGSEGV, current); return 0; - } +} asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { rt_sigframe *frame = (rt_sigframe *)regs->gprs[15]; if (sigreturn_common(regs,sizeof(rt_sigframe))) - goto badframe; + goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]); @@ -279,7 +278,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) static void *setup_frame_common(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs, int frame_size,u16 retcode) - { +{ sigframe *frame; int err; @@ -291,7 +290,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 @@ -377,29 +376,29 @@ give_sigsegv: /* * OK, we're invoking a handler - */ + */ static void handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) - { +{ /* Are we from a system call? */ if (regs->orig_gpr2 >= 0) { /* If so, check system call restarting.. */ switch (regs->gprs[2]) { - case -ERESTARTNOHAND: + case -ERESTARTNOHAND: regs->gprs[2] = -EINTR; break; - case -ERESTARTSYS: + case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { - regs->gprs[2] = -EINTR; - break; - } + regs->gprs[2] = -EINTR; + break; + } /* fallthrough */ - case -ERESTARTNOINTR: - regs->gprs[2] = regs->orig_gpr2; - regs->psw.addr -= 2; + case -ERESTARTNOINTR: + regs->gprs[2] = regs->orig_gpr2; + regs->psw.addr -= 2; } } @@ -430,7 +429,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ -int do_signal(struct pt_regs *regs,sigset_t *oldset) +int do_signal(struct pt_regs *regs, sigset_t *oldset) { siginfo_t info; struct k_sigaction *ka; @@ -554,9 +553,9 @@ int do_signal(struct pt_regs *regs,sigset_t *oldset) if (regs->gprs[2] == -ERESTARTNOHAND || regs->gprs[2] == -ERESTARTSYS || regs->gprs[2] == -ERESTARTNOINTR) { - regs->gprs[2] = regs->orig_gpr2; + regs->gprs[2] = regs->orig_gpr2; regs->psw.addr -= 2; + } } -} return 0; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 80b4acc27646..2e36f6800e7c 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -108,7 +108,7 @@ void do_machine_halt(void) if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} void machine_halt(void) { @@ -125,7 +125,7 @@ void do_machine_power_off(void) if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); signal_processor(smp_processor_id(), sigp_stop_and_store_status); - } +} void machine_power_off(void) { @@ -248,6 +248,14 @@ void do_ext_call_interrupt(struct pt_regs *regs, __u16 source_cpu_addr) __flush_tlb(); atomic_set(&ec->status, ec_done); return; + case ec_callback: { + ec_callback_parms *cbp; + cbp = (ec_callback_parms *) ec->parms; + atomic_set(&ec->status,ec_executing); + (cbp->callback)(cbp->data); + atomic_set(&ec->status,ec_done); + return; + } default: } ec = ec->next; @@ -463,6 +471,19 @@ void smp_ctl_clear_bit(int cr, int bit) { __ctl_clear_bit(cr, bit); } +/* + * Execute a callback function on all cpus + */ +void smp_do_callback_all(void (*callback)(void *), void *data) { + ec_callback_parms parms; + + if (atomic_read(&smp_commenced) != 0) { + parms.callback = callback; + parms.data = data; + smp_ext_call_sync_others(ec_callback, &parms); + } + (callback)(data); +} /* * Lets check how many CPUs we have. @@ -573,7 +594,7 @@ void __init smp_boot_cpus(void) sigp_ccode ccode; int curr_cpu; int i; - + /* request the 0x1202 external interrupt */ if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) panic("Couldn't request external interrupt 0x1202"); diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 3afac79365f4..923318888599 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -43,134 +43,14 @@ 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); - static inline void console_verbose(void) { extern int console_loglevel; console_loglevel = 15; } -#define DO_ERROR(trapnr, signr, str, name, tsk) \ -asmlinkage void name(struct pt_regs * regs, long error_code) \ -{ \ - if (check_for_fixup(regs) == 0) { \ - tsk->tss.error_code = error_code; \ - tsk->tss.trap_no = trapnr; \ - force_sig(signr, tsk); \ - die(str,regs,error_code); \ - } \ -} - - -void page_exception(void); - -/* 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"); -*/ -} -#endif - - spinlock_t die_lock; void die(const char * str, struct pt_regs * regs, long err) @@ -178,22 +58,36 @@ 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); \ +} + +static void inline do_trap(long interruption_code, int signr, char *str, + struct pt_regs *regs) { - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { + if (regs->psw.mask & PSW_PROBLEM_STATE) { + struct task_struct *tsk = current; + tsk->tss.trap_no = interruption_code; + force_sig(signr, tsk); +#ifdef CONFIG_PROCESS_DEBUG + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); +#endif + } else { + unsigned long fixup = search_exception_table(regs->psw.addr); + if (fixup) regs->psw.addr = fixup; - return 1; - } + else + die(str, regs, interruption_code); } - return 0; } int do_debugger_trap(struct pt_regs *regs,int signal) @@ -219,39 +113,16 @@ int do_debugger_trap(struct pt_regs *regs,int signal) return(FALSE); } -asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code) -{ - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = error_code; - force_sig(SIGSEGV, current); - die("Unknown program exception",regs,error_code); - } -} - -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) - -/* 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 +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) -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; @@ -269,6 +140,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) { @@ -289,20 +161,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) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 1; - force_sig(SIGILL, current); - die("illegal operation", regs, error_code); - } } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "illegal operation", regs); 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; @@ -314,26 +185,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; @@ -341,25 +212,22 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code) } } else do_sig = 1; - if (do_sig) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 1; - force_sig(SIGILL, current); - die("illegal operation", regs, error_code); - } - } + if (do_sig) + do_trap(interruption_code, SIGILL, "specification exception", regs); 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(); - 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" @@ -374,31 +242,32 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code) (addr_t)ADDR_BITS_REMOVE((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); @@ -427,24 +296,14 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code) break; } } +#endif else do_sig = 1; - if (do_sig) { - if (check_for_fixup(regs) == 0) { - current->tss.error_code = error_code; - current->tss.trap_no = 7; - force_sig(SIGILL, current); - die("data exception", regs, error_code); - } - } + if (do_sig) + do_trap(interruption_code, SIGILL, "data exception", regs); 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 */ @@ -487,7 +346,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 c098792b435a..a9a9e362416a 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -11,7 +11,7 @@ else endif L_TARGET = lib.a -L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o +L_OBJS = 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 136218a6783f..d13b1efe49f9 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -27,7 +27,7 @@ void __delay(unsigned long loops) * yield the megahertz number of the cpu. The important function * is udelay and that is done using the tod clock. -- martin. */ - __asm__ __volatile__( + __asm__ __volatile__( "0: brct %0,0b" : /* no outputs */ : "r" (loops/2) ); } diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S new file mode 100644 index 000000000000..8044d156dea2 --- /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 + + .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/fault.c b/arch/s390/mm/fault.c index 7f777fbebb58..5ee70d1fa1a4 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -48,6 +48,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) int write; unsigned long psw_mask; unsigned long psw_addr; + int kernel_address = 0; /* * get psw mask of Program old psw to find out, @@ -71,6 +72,49 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) if (atomic_read(&S390_lowcore.local_irq_count)) die("page fault from irq handler",regs,error_code); + /* + * 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); @@ -129,12 +173,12 @@ bad_area: /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { tsk->tss.prot_addr = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; - + tsk->tss.trap_no = error_code; +#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(); + show_regs(regs); +#endif force_sig(SIGSEGV, tsk); return; } @@ -149,14 +193,13 @@ 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 */ @@ -171,17 +214,17 @@ bad_area: */ out_of_memory: if (tsk->pid == 1) - { + { tsk->policy |= SCHED_YIELD; schedule(); goto survive; - } + } up(&mm->mmap_sem); if (psw_mask & PSW_PROBLEM_STATE) { printk("VM: killing process %s\n", tsk->comm); do_exit(SIGKILL); - } + } goto no_context; do_sigbus: @@ -192,8 +235,7 @@ do_sigbus: * or user mode. */ tsk->tss.prot_addr = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; + tsk->tss.trap_no = error_code; force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index bc90b9514141..7a3cc5cb6d4e 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -251,6 +251,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ unsigned long tmp; unsigned long address=0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; + static const int ssm_mask = 0x04000000L; /* unmap whole virtual address space */ @@ -295,7 +296,9 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_ /* 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(); diff --git a/arch/s390/tools/dasdfmt/dasdfmt.8 b/arch/s390/tools/dasdfmt/dasdfmt.8 index 9cbf87ab79e8..906151fbc7fe 100644 --- a/arch/s390/tools/dasdfmt/dasdfmt.8 +++ b/arch/s390/tools/dasdfmt/dasdfmt.8 @@ -1,68 +1,68 @@ -.TH DASDFMT 8 "Tue Jan 25 2000" -.UC 4 -.SH NAME -dasdfmt \- formatting of DSAD (ECKD) disk drives. -.SH SYNOPSIS +.TH DASDFMT 8 "Tue Jan 25 2000" +.UC 4 +.SH NAME +dasdfmt \- formatting of DSAD (ECKD) disk drives. +.SH SYNOPSIS \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 -\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR. - -.SH OPTIONS -.TP -\fB-t\fR -Disables any modification of the disk drive. \fBdasdfmt\fR just prints -out, what it \fBwould\fR do. - -.TP -\fB-v\fR -Increases verbosity. - -.TP -\fB-y\fR -Start formatting without further user-confirmation. - -.TP +.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 +\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR. + +.SH OPTIONS +.TP +\fB-t\fR +Disables any modification of the disk drive. \fBdasdfmt\fR just prints +out, what it \fBwould\fR do. + +.TP +\fB-v\fR +Increases verbosity. + +.TP +\fB-y\fR +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. - -.TP -\fB-b\fR \fIblockSize\fR -Specify blocksize to be used. \fIblocksize\fR must be a positive integer -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 +\fB-V\fR +Print version number and exit. + +.TP +\fB-b\fR \fIblockSize\fR +Specify blocksize to be used. \fIblocksize\fR must be a positive integer +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 \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 + +.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/dasd\fR\fIX\fR -.br -or -.br - \fB-n\fR \fIdevnum\fR -.sp -The first form uses the commonly used -.SM UNIX -device notation where \fIX\fR is a single lowercase letter. +.br +or +.br + \fB-n\fR \fIdevnum\fR +.sp +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 device number. - -.SH BUGS -None so far ;-) - -.SH AUTHOR -.nf -This man-page was written by Fritz Elfert -.fi + +.SH BUGS +None so far ;-) + +.SH AUTHOR +.nf +This man-page was written by Fritz Elfert +.fi diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c index 9f86a8f0477d..3ad43ba2b2f1 100644 --- a/arch/s390/tools/dasdfmt/dasdfmt.c +++ b/arch/s390/tools/dasdfmt/dasdfmt.c @@ -458,12 +458,11 @@ check_mounted(int major, int minor) void do_format_dasd(char *dev_name,format_data_t format_params,int testmode, int verbosity,int writenolabel,int labelspec, - char *label,int withoutprompt) + 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; @@ -489,7 +488,7 @@ 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); } @@ -645,9 +644,10 @@ int main(int argc,char *argv[]) { 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; @@ -811,7 +811,7 @@ int main(int argc,char *argv[]) { /******* issue the real command and reread part table *******/ do_format_dasd(dev_name,format_params,testmode,verbosity, - writenolabel,labelspec,label,withoutprompt); + writenolabel,labelspec,label,withoutprompt,devno); /*************** cleanup ********************************/ if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) { diff --git a/arch/s390/tools/hwc/Makefile b/arch/s390/tools/hwc/Makefile new file mode 100644 index 000000000000..1d5e4ec91e98 --- /dev/null +++ b/arch/s390/tools/hwc/Makefile @@ -0,0 +1,12 @@ +CROSS_COMPILE = s390- + +hwc_measure: hwc_measure.c + $(CROSS_COMPILE)gcc -o $@ $^ + +hwc_cntl_key: hwc_cntl_key.c + $(CROSS_COMPILE)gcc -o $@ $^ + +clean: + rm -f hwc_measure + rm -f hwc_cntl_key + diff --git a/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c b/arch/s390/tools/hwc/hwc_cntl_key.c similarity index 100% rename from arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c rename to arch/s390/tools/hwc/hwc_cntl_key.c diff --git a/arch/s390/tools/hwc/hwc_measure.c b/arch/s390/tools/hwc/hwc_measure.c new file mode 100644 index 000000000000..2570ab4be366 --- /dev/null +++ b/arch/s390/tools/hwc/hwc_measure.c @@ -0,0 +1,79 @@ +/* + * small application for HWC measurement + * + * Copyright (C) 2000 IBM Corporation + * Author(s): Martin Peschke + */ + +#include +#include +#include +#include + +/* everything about the HWC low level driver ioctl-commands */ +#include "../../../../drivers/s390/char/hwc_rw.h" + +/* standard input, should be our HWC tty */ +#define DESCRIPTOR 0 + +int main(int argc, char *argv[], char *env[]) +{ + ioctl_meas_t measured = 0; + signed int retval = 0; + + if (argc = 2) { + + if (strcmp(argv[1], "lines") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASL, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "chars") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASC, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "wcalls") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCGMEASS, + &measured); + if (retval < 0) + return errno; + else { + printf("%ld\n", measured); + return retval; + } + } + + if (strcmp(argv[1], "reset") == 0) { + retval = ioctl(DESCRIPTOR, TIOCHWCSMEAS); + if (retval < 0) + return errno; + else return retval; + } + } + + printf("usage:\n"); + printf(" hwc_measure lines " + "(prints # of measured lines) or\n"); + printf(" hwc_measure_chars " + "(prints # of measured characters) or\n"); + printf(" hwc_measure wcalls " + "(prints # of measured write calls to HWC interface) or\n"); + printf(" hwc_measure reset " + "(resets measurement counters)\n"); + + return -1; +} + diff --git a/arch/s390/tools/hwc_cntl_key/Makefile b/arch/s390/tools/hwc_cntl_key/Makefile deleted file mode 100644 index 111f298605cd..000000000000 --- a/arch/s390/tools/hwc_cntl_key/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -CROSS_COMPILE = s390- - -all: hwc_cntl_key - -hwc_cntl_key: hwc_cntl_key.c - $(CROSS_COMPILE)gcc -o $@ $^ - $(STRIP) $@ - -clean: - rm -f hwc_cntl_key.c - diff --git a/arch/s390/tools/silo/silo.c b/arch/s390/tools/silo/silo.c index 6cc01a4cafae..99a098b926e2 100644 --- a/arch/s390/tools/silo/silo.c +++ b/arch/s390/tools/silo/silo.c @@ -144,7 +144,7 @@ read_cfg(struct silo_options *o) if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) o->parmfile = tmp; if ( ! o -> ramdisk ) - o->ramdisk = cfg_get_strg(cf_options, "ramdisk"); + o->ramdisk = cfg_get_strg(cf_options, "ramdisk"); tmp = cfg_get_strg(cf_options, "bootsect"); if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp) o->bootsect = tmp; @@ -181,7 +181,7 @@ gen_tmpparm( char *pfile ) return pfile; of = fopen(pfile, "r"); if ( of ) { - NTRY( fn = tempnam(NULL,"parm.")); + NTRY( fn = tempnam(NULL,"parm.")); } else { fn = pfile; } @@ -193,11 +193,11 @@ gen_tmpparm( char *pfile ) } } if (root) - fprintf(f, "root=%s ", root); + fprintf(f, " root=%s", root); if (ro) - fprintf(f, "ro "); + fprintf(f, " ro"); if (append) - fprintf(f, "%s", append); + fprintf(f, " %s", append); fprintf(f, "\n"); fclose(f); fclose(of); @@ -312,7 +312,7 @@ verify_file (char *name, int dev) int bs = 1024; int l; - ITRY (stat (name, &dst)); + ITRY(stat ( name, &dst )); if (S_ISREG (dst.st_mode)) { if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK)) @@ -394,9 +394,9 @@ verify_options (struct silo_options *o) PRINT_LEVEL (1, "...ok..."); o->parmfile = gen_tmpparm(o->parmfile); PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile); - ITRY (verify_file (o->parmfile, dev)); - PRINT_LEVEL (1, "...ok..."); - PRINT_LEVEL (0, "\n"); + ITRY (verify_file (o->parmfile, dev)); + PRINT_LEVEL (1, "...ok..."); + PRINT_LEVEL (0, "\n"); if (o->ramdisk) { @@ -492,9 +492,9 @@ write_bootsect (struct silo_options *o, struct blocklist *blklst) int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff); PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr); if ( o->testlevel <= 1 ) { - NTRY (write (s_fd, &offset, sizeof (int))); - NTRY (write (s_fd, &addrct, sizeof (int))); - } + NTRY (write (s_fd, &offset, sizeof (int))); + NTRY (write (s_fd, &addrct, sizeof (int))); + } } ITRY (ioctl (s_fd,FIGETBSZ, &bs)); ITRY (stat (o->bootmap, &s_st)); @@ -508,7 +508,7 @@ write_bootsect (struct silo_options *o, struct blocklist *blklst) NTRY ( tmpdev = tmpnam(NULL) ); ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev)); ITRY (bd_fd = open (tmpdev, O_RDONLY)); - ITRY ( ioctl(s_fd,FIBMAP,&boots)); + ITRY (ioctl(s_fd,FIBMAP,&boots)); ITRY (ioctl (bd_fd, BIODASDRWTB, &boots)); PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots); close (bd_fd); diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 136b0a9812d1..f33939b29410 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.62.2.16 2000/09/05 00:10:54 davem Exp $ +/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -2793,6 +2793,7 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) case ENVCTRL_RD_ETHERNET_TEMPERATURE: case ENVCTRL_RD_MTHRBD_TEMPERATURE: case ENVCTRL_RD_CPU_VOLTAGE: + case ENVCTRL_RD_GLOBALADDRESS: case D7SIOCWR: /* case D7SIOCRD: Same value as ENVCTRL_RD_VOLTAGE_STATUS */ case D7SIOCTM: diff --git a/drivers/Makefile b/drivers/Makefile index 61aa7a7140ba..57b2b05101fe 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -43,7 +43,7 @@ SUB_DIRS += video MOD_SUB_DIRS += video endif -ifdef CONFIG_PPC +ifdef CONFIG_POWERMAC SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 4faeb42e4abd..86f388d6c27a 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -53,7 +53,7 @@ else bool ' Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105 fi fi - if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + if [ "$CONFIG_POWERMAC" = "y" ]; then bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 7f4fd9212f72..25e9d786d5e5 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -29,6 +29,10 @@ #include #include +#ifdef CONFIG_ARCH_S390 +#include +#endif /* CONFIG_ARCH_S390 */ + #include #include @@ -67,7 +71,7 @@ extern int scsi_dev_init(void); extern int net_dev_init(void); #ifdef CONFIG_PPC -extern void note_bootable_part(kdev_t dev, int part); +extern void note_bootable_part(kdev_t dev, int part, int goodness); #endif static char *raid_name (struct gendisk *hd, int minor, int major_base, @@ -84,6 +88,10 @@ static char *raid_name (struct gendisk *hd, int minor, int major_base, return buf; } +#ifdef CONFIG_ARCH_S390 +int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL; +#endif + /* * disk_name() is used by genhd.c and md.c. * It formats the devicename of the indicated disk @@ -96,6 +104,14 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) const char *maj = hd->major_name; int unit = (minor >> hd->minor_shift) + 'a'; +#ifdef CONFIG_ARCH_S390 + if ( strncmp ( hd->major_name,"dasd",4) == 0 ){ + part = minor & ((1 << hd->minor_shift) - 1); + if ( genhd_dasd_name ) + genhd_dasd_name(buf,minor>>hd->minor_shift,part,hd); + return buf; + } +#endif /* * IDE devices use multiple major numbers, but the drives * are named as: {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}.. @@ -1179,7 +1195,8 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec) goodness++; if (strcasecmp(part->type, "Apple_UNIX_SVR2") == 0 - || strcasecmp(part->type, "Linux_PPC") == 0) { + || (strnicmp(part->type, "Linux", 5) == 0 + && strcasecmp(part->type, "Linux_swap") != 0)) { int i, l; goodness++; @@ -1208,7 +1225,7 @@ static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec) } #ifdef CONFIG_PPC if (found_root_goodness) - note_bootable_part(dev, found_root); + note_bootable_part(dev, found_root, found_root_goodness); #endif brelse(bh); printk("\n"); @@ -1402,10 +1419,11 @@ static int ultrix_partition(struct gendisk *hd, kdev_t dev, unsigned long first_ #endif /* CONFIG_ULTRIX_PARTITION */ #ifdef CONFIG_ARCH_S390 +#include +#include +#include #include -#include "../s390/block/dasd_types.h" - -dasd_information_t **dasd_information = NULL; +#include typedef enum { ibm_partition_none = 0, @@ -1442,14 +1460,45 @@ ibm_partition (struct gendisk *hd, kdev_t dev, int first_sector) ibm_partition_t partition_type; char type[5] = {0,}; char name[7] = {0,}; - int di = MINOR(dev) >> hd->minor_shift; - if ( ! get_ptable_blocksize(dev) ) + struct hd_geometry geo; + mm_segment_t old_fs; + int blocksize; + struct file *filp = NULL; + struct inode *inode = NULL; + int offset, size; + int rc; + + blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)]; + if ( blocksize <= 0 ) { return 0; - if ( ! dasd_information ) + } + set_blocksize(dev, blocksize); /* OUCH !! */ + + /* find out offset of volume label (partn table) */ + filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL); + if ( filp == NULL ) { + printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed for filp\n"); + return 0; + } + memset(filp,0,sizeof(struct file)); + filp ->f_mode = 1; /* read only */ + inode = get_empty_inode(); + inode -> i_rdev = dev; + rc = blkdev_open(inode,filp); + if ( rc ) { + return 0; + } + old_fs=get_fs(); + set_fs(KERNEL_DS); + rc = filp->f_op->ioctl (inode, filp, HDIO_GETGEO, (unsigned long)(&geo)); + set_fs(old_fs); + if ( rc ) { return 0; - if ( ( bh = bread( dev, - dasd_information[di]->sizes.label_block, - dasd_information[di]->sizes.bp_sector ) ) != NULL ) { + } + blkdev_release(inode); + + size = hd -> sizes[MINOR(dev)]<<1; + if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) { strncpy ( type,bh -> b_data, 4); strncpy ( name,bh -> b_data + 4, 6); } else { @@ -1459,50 +1508,45 @@ ibm_partition (struct gendisk *hd, kdev_t dev, int first_sector) EBCASC(name,6); } switch ( partition_type = get_partition_type(type) ) { - case ibm_partition_lnx1: + case ibm_partition_lnx1: + offset = (geo.start + 1); printk ( "(LNX1)/%6s:",name); - add_partition( hd, MINOR(dev) + 1, - (dasd_information[di]->sizes.label_block + 1) << - dasd_information[di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information[di]->sizes.label_block - 1) << - dasd_information[di]->sizes.s2b_shift,0 ); break; case ibm_partition_vol1: + offset = 0; + size = 0; printk ( "(VOL1)/%6s:",name); break; case ibm_partition_cms1: printk ( "(CMS1)/%6s:",name); if (* (((long *)bh->b_data) + 13) == 0) { /* disk holds a CMS filesystem */ - add_partition( hd, MINOR(dev) + 1, - (dasd_information [di]->sizes.label_block + 1) << - dasd_information [di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information [di]->sizes.label_block) << - dasd_information [di]->sizes.s2b_shift,0 ); + offset = (geo.start + 1); printk ("(CMS)"); } else { - /* disk is reserved minidisk */ - long *label=(long*)bh->b_data; - int offset = label[13]; - int size = (label[7]-1-label[13])*(label[3]>>9); - add_partition( hd, MINOR(dev) + 1, - offset << dasd_information [di]->sizes.s2b_shift, - size<sizes.s2b_shift,0 ); + /* disk is reserved minidisk */ + // mdisk_setup_data.size[i] = + // (label[7] - 1 - label[13]) * + // (label[3] >> 9) >> 1; + long *label=(long*)bh->b_data; + blocksize = label[3]; + offset = label[13]; + size = (label[7]-1)*(blocksize>>9); printk ("(MDSK)"); } break; case ibm_partition_none: printk ( "(nonl)/ :"); - add_partition( hd, MINOR(dev) + 1, - (dasd_information [di]->sizes.label_block + 1) << - dasd_information [di]->sizes.s2b_shift, - (dasd_information [di]->sizes.blocks - - dasd_information [di]->sizes.label_block - 1) << - dasd_information [di]->sizes.s2b_shift,0 ); + offset = (geo.start+1); break; + default: + offset = 0; + size = 0; + } + add_partition( hd, MINOR(dev), 0,size,0); + add_partition( hd, MINOR(dev) + 1, offset * (blocksize >> 9), + size-offset*(blocksize>>9) ,0 ); printk ( "\n" ); bforget(bh); return 1; @@ -1609,14 +1653,18 @@ static inline void setup_dev(struct gendisk *dev) dev->part[i].start_sect = 0; dev->part[i].nr_sects = 0; } - dev->init(dev); + if ( dev->init != NULL ) + dev->init(dev); for (drive = 0 ; drive < dev->nr_real ; drive++) { int first_minor = drive << dev->minor_shift; current_minor = 1 + first_minor; - check_partition(dev, MKDEV(dev->major, first_minor)); + /* If we really have a device check partition table */ + if ( blksize_size[dev->major] == NULL || + blksize_size[dev->major][current_minor]) + check_partition(dev, MKDEV(dev->major, first_minor)); } if (dev->sizes != NULL) { /* optional safeguard in ll_rw_blk.c */ - for (i = 0; i < end_minor; i++) + for (i = 0; i < end_minor; i++) dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); blk_size[dev->major] = dev->sizes; } diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index e66320309d54..ac2230abe9f7 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -93,14 +94,14 @@ static pmac_ide_timing udma_timings[] = /* allow up to 256 DBDMA commands per xfer */ #define MAX_DCMDS 256 -/* Wait 1.5s for disk to answer on IDE bus after +/* Wait 2s for disk to answer on IDE bus after * enable operation. * NOTE: There is at least one case I know of a disk that needs about 10sec * before anwering on the bus. I beleive we could add a kernel command * line arg to override this delay for such cases. */ -#define IDE_WAKEUP_DELAY_MS 1500 -#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ +#define IDE_WAKEUP_DELAY_MS 2000 +#define MAX_DCMDS 256 /* allow up to 256 DBDMA commands per xfer */ static void pmac_ide_setup_dma(struct device_node *np, int ix); static int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive); @@ -393,6 +394,7 @@ pmac_ide_probe(void)) */ feature_set(np, FEATURE_IDE0_enable); feature_set(np, FEATURE_IOBUS_enable); + big_delay = 1; /* Poor old machines with crappy disks */ } else { /* This is necessary to enable IDE when net-booting */ printk("pmac_ide: enabling IDE bus ID %d\n", pmac_ide[i].aapl_bus_id); @@ -596,13 +598,13 @@ udma_bits_to_command(unsigned char bits) static __inline__ int wait_for_ready(ide_drive_t *drive) { - /* Timeout bumped for some powerbooks */ - int timeout = 2000; + /* Timeout bumped (again) for some powerbooks with old disks */ + int timeout = 10000; byte stat; while(--timeout) { stat = GET_STAT(); - if(!(stat & BUSY_STAT)) { + if (!(stat & BUSY_STAT)) { if (drive->ready_stat == 0) break; else if((stat & drive->ready_stat) || (stat & ERR_STAT)) @@ -631,20 +633,31 @@ pmac_ide_do_setfeature(ide_drive_t *drive, byte command) old_select = IN_BYTE(IDE_SELECT_REG); OUT_BYTE(drive->select.all, IDE_SELECT_REG); udelay(10); - OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); - OUT_BYTE(command, IDE_NSECTOR_REG); if(wait_for_ready(drive)) { printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } + OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); +#if 0 + /* That one cause the wallstreet to freeze, I don't know why yet. We'll have to leave with + * the bogus interrupt until I figure out what's up + */ + /* Better not leave a dangling interrupt */ + OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); +#endif + OUT_BYTE(command, IDE_NSECTOR_REG); OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); + udelay(10); result = wait_for_ready(drive); if (result) printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); + /* May help kill the bogus interrupt */ + mdelay(1); + (void)GET_STAT(); out: OUT_BYTE(old_select, IDE_SELECT_REG); restore_flags(flags); - + return result; } @@ -848,13 +861,15 @@ int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ #ifdef CONFIG_PMAC_PBOOK -static void idepmac_sleep_disk(int i, unsigned long base) +static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) { - struct device_node* np = pmac_ide[i].node; int j; - - /* FIXME: We only handle the master IDE */ - if (ide_hwifs[i].drives[0].media == ide_disk) { + + /* FIXME: We only handle the master IDE disk, we shoud + * try to fix CD-ROMs here + */ + switch (drive->media) { + case ide_disk: /* Spin down the drive */ outb(0xa0, base+0x60); outb(0x0, base+0x30); @@ -870,99 +885,127 @@ static void idepmac_sleep_disk(int i, unsigned long base) if (!(status & BUSY_STAT) && (status & DRQ_STAT)) break; } - } - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_clear(np, FEATURE_IDE1_enable); + case ide_cdrom: + // todo break; - case 2: - feature_set(np, FEATURE_IDE2_reset); + case ide_floppy: + // todo break; } - pmac_ide[i].timings[0] = 0; - pmac_ide[i].timings[1] = 0; } -static void idepmac_wake_disk(int i, unsigned long base) +static void idepmac_wake_device(ide_drive_t *drive, int used_dma) + { + unsigned long flags; + + /* We force the IDE subdriver to check for a media change + * This must be done first or we may lost the condition + * + * Problem: This can schedule. I moved the block device + * wakeup almost late by priority because of that. + */ + DRIVER(drive)->media_change(drive); + + /* We kick the VFS too (see fix in ide.c revalidate) */ + check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); + +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + /* We re-enable DMA on the drive if it was active. */ + /* This doesn't work with the CD-ROM in the media-bay, probably + * because of a pending unit attention. The problem if that if I + * clear the error, the filesystem dies. + */ + if (used_dma && !ide_spin_wait_hwgroup(drive, &flags)) { + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + pmac_ide_dma_onoff(drive, 1); + HWGROUP(drive)->busy = 0; + spin_unlock_irqrestore(&io_request_lock, flags); + } +#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ +} + +static void idepmac_sleep_interface(int i, unsigned base, int mediabay) { struct device_node* np = pmac_ide[i].node; - int j; - /* Revive IDE disk and controller */ + /* We clear the timings */ + pmac_ide[i].timings[0] = 0; + pmac_ide[i].timings[1] = 0; + + /* The media bay will handle itself just fine */ + if (mediabay) + return; + + /* Disable and reset the bus */ + feature_set(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); switch(pmac_ide[i].aapl_bus_id) { case 0: feature_set(np, FEATURE_IDE0_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); + feature_clear(np, FEATURE_IDE0_enable); break; case 1: feature_set(np, FEATURE_IDE1_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); + feature_clear(np, FEATURE_IDE1_enable); break; case 2: - /* This one exists only for KL, I don't know - about any enable bit */ feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); break; } - mdelay(IDE_WAKEUP_DELAY_MS); - - /* Reset timings */ - pmac_ide_selectproc(&ide_hwifs[i].drives[0]); - mdelay(10); - - /* Wait up to 10 seconds (enough for recent drives) */ - for (j = 0; j < 100; j++) { - int status; - mdelay(100); - status = inb(base + 0x70); - if (!(status & BUSY_STAT)) - break; - } } -/* Here we handle media bay devices */ -static void -idepmac_wake_bay(int i, unsigned long base) +static void idepmac_wake_interface(int i, unsigned long base, int mediabay) { - int timeout; + struct device_node* np = pmac_ide[i].node; + if (!mediabay) { + /* Revive IDE disk and controller */ + switch(pmac_ide[i].aapl_bus_id) { + case 0: + feature_set(np, FEATURE_IDE0_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE0_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE0_reset); + break; + case 1: + feature_set(np, FEATURE_IDE1_reset); + feature_set(np, FEATURE_IOBUS_enable); + mdelay(10); + feature_set(np, FEATURE_IDE1_enable); + mdelay(10); + feature_clear(np, FEATURE_IDE1_reset); + break; + case 2: + /* This one exists only for KL, I don't know + about any enable bit */ + feature_set(np, FEATURE_IDE2_reset); + mdelay(10); + feature_clear(np, FEATURE_IDE2_reset); + break; + } + } + /* Reset timings */ pmac_ide_selectproc(&ide_hwifs[i].drives[0]); mdelay(10); - - timeout = 10000; - while ((inb(base + 0x70) & BUSY_STAT) && timeout) { - mdelay(1); - --timeout; - } } /* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */ + static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; - + unsigned long flags; + int big_delay; + switch (when) { case PBOOK_SLEEP_REQUEST: break; @@ -970,37 +1013,108 @@ static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { + ide_hwif_t *hwif; + ide_drive_t *drive; + int unlock = 0; + if ((base = pmac_ide[i].regbase) == 0) - continue; + continue; + + hwif = &ide_hwifs[i]; + drive = &hwif->drives[0]; + + if (drive->present) { + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive, &flags)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + + /* Stop the device */ + idepmac_sleep_device(drive, i, base); + + } + } /* Disable irq during sleep */ - disable_irq(pmac_ide[i].irq); + disable_irq(pmac_ide[i].irq); + if (unlock) + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Check if this is a media bay with an IDE device or not + * a media bay. + */ ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - /* not media bay - put the disk to sleep */ - idepmac_sleep_disk(i, base); + if ((ret == 0) || (ret == -ENODEV)) + idepmac_sleep_interface(i, base, (ret == 0)); } break; case PBOOK_WAKE: + big_delay = 0; + for (i = 0; i < pmac_ide_count; ++i) { + + if ((base = pmac_ide[i].regbase) == 0) + continue; + + /* Check if this is a media bay with an IDE device or not + * a media bay + */ + ret = check_media_bay_by_base(base, MB_CD); + if ((ret == 0) || (ret == -ENODEV)) { + idepmac_wake_interface(i, base, (ret == 0)); + big_delay = 1; + } + + } + /* Let hardware get up to speed */ + if (big_delay) + mdelay(IDE_WAKEUP_DELAY_MS); + for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; + ide_drive_t *drive; + int j, used_dma; + if ((base = pmac_ide[i].regbase) == 0) continue; + hwif = &ide_hwifs[i]; - /* We don't handle media bay devices this way */ - ret = check_media_bay_by_base(base, MB_CD); - if ((ret == -ENODEV) && ide_hwifs[i].drives[0].present) - idepmac_wake_disk(i, base); - else if (ret == 0) - idepmac_wake_bay(i, base); - enable_irq(pmac_ide[i].irq); + drive = &hwif->drives[0]; + + /* Wait for the drive to come up and set it's DMA */ + if (drive->present) { + /* Wait up to 20 seconds */ + for (j = 0; j < 200; j++) { + int status; + mdelay(100); + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } + } + + /* We don't have re-configured DMA yet */ + used_dma = drive->using_dma; + drive->using_dma = 0; -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (hwif->drives[0].present && hwif->drives[0].using_dma) - pmac_ide_dma_onoff(&hwif->drives[0], 1); -#endif + /* We resume processing on the HW group */ + spin_lock_irqsave(&io_request_lock, flags); + enable_irq(pmac_ide[i].irq); + if (drive->present) + HWGROUP(drive)->busy = 0; + spin_unlock_irqrestore(&io_request_lock, flags); + + /* Wake the device + * We could handle the slave here + */ + if (drive->present) + idepmac_wake_device(drive, used_dma); } break; } return PBOOK_SLEEP_OK; } + #endif /* CONFIG_PMAC_PBOOK */ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index d39af4f01666..f1d54b24810a 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -614,8 +614,10 @@ __initfunc(static void rd_load_disk(int n)) #ifdef CONFIG_MAC_FLOPPY if(MAJOR(ROOT_DEV) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(ROOT_DEV)); +#ifdef CONFIG_BLK_DEV_INITRD else if(MAJOR(real_root_dev) == FLOPPY_MAJOR) swim3_fd_eject(MINOR(real_root_dev)); +#endif #endif printk(KERN_NOTICE "VFS: Insert root floppy disk to be loaded into RAM disk and press ENTER\n"); diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 355ca2bf514d..26793bfd2841 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -189,7 +189,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then fi fi dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV - if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then + if [ "$CONFIG_POWERMAC" = "y" ]; then dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV fi dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV diff --git a/drivers/char/buz.c b/drivers/char/buz.c index be201e9d99d0..c186b063a6b0 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -2390,7 +2390,7 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case VIDIOCSCHAN: { struct video_channel v; - int input; + int input, norm; int on, res; if (copy_from_user(&v, arg, sizeof(v))) { @@ -2422,9 +2422,10 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) if (on) zr36057_overlay(zr, 0); + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm); if (on) zr36057_overlay(zr, 1); @@ -2782,7 +2783,7 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) case BUZIOC_S_PARAMS: { struct zoran_params bp; - int input, on; + int input, on, norm; if (zr->codec_mode != BUZ_MODE_IDLE) { return -EINVAL; @@ -2809,9 +2810,10 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) zr36057_overlay(zr, 0); input = zr->params.input == 0 ? 3 : 7; + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &norm); if (on) zr36057_overlay(zr, 1); @@ -2940,8 +2942,9 @@ static int zoran_ioctl(struct video_device *dev, unsigned int cmd, void *arg) /* restore previous input and norm */ input = zr->params.input == 0 ? 3 : 7; + norm = zr->params.norm; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &input); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &norm); if (copy_to_user(arg, &bs, sizeof(bs))) { return -EFAULT; @@ -3253,8 +3256,9 @@ static int zr36057_init(int i) j = zr->params.input == 0 ? 3 : 7; i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_INPUT, &j); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &zr->params.norm); - i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &zr->params.norm); + j = zr->params.norm; + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_NORM, &j); + i2c_control_device(&zr->i2c, I2C_DRIVERID_VIDEOENCODER, ENCODER_SET_NORM, &j); /* set individual interrupt enables (without GIRQ0) but don't global enable until zoran_open() */ diff --git a/drivers/char/console.c b/drivers/char/console.c index 01bb86f3eb3a..c249016a4024 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -575,10 +575,12 @@ void redraw_screen(int new_console, int is_switch) } if (redraw) { + int update; + set_origin(currcons); + update = sw->con_switch(vc_cons[currcons].d); set_palette(currcons); - if (sw->con_switch(vc_cons[currcons].d) && vcmode != KD_GRAPHICS) - /* Update the screen contents */ + if (update && vcmode != KD_GRAPHICS) do_update_region(currcons, origin, screenbuf_size/2); } set_cursor(currcons); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 1c17a987fea7..e4624e9cbdcc 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -315,7 +315,7 @@ void handle_scancode(unsigned char scancode, int down) #if 1 /* how? two almost equivalent choices follow */ compute_shiftstate(); #else - keysym = U(plain_map[keycode]); + keysym = U(key_maps[0][keycode]); type = KTYP(keysym); if (type == KT_SHIFT) (*key_handler[type])(keysym & 0xff, up_flag); @@ -759,7 +759,7 @@ void compute_shiftstate(void) k = i*BITS_PER_LONG; for(j=0; j #include #include +#include #include #include #include #include #include #include -#include EXPORT_SYMBOL(adb_controller); EXPORT_SYMBOL(adb_client_list); @@ -390,7 +390,7 @@ adb_get_infos(int address, int *original_address, int *handler_id) #define ADB_MAJOR 56 /* major number for /dev/adb */ -extern void adbdev_init(void); +extern int adbdev_init(void); struct adbdev_state { spinlock_t lock; @@ -601,10 +601,19 @@ static struct file_operations adb_fops = { adb_release }; -void adbdev_init() +static int __init adbdev_init(void) { - if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + if (adb_controller == NULL) + return 0; if (register_chrdev(ADB_MAJOR, "adb", &adb_fops)) printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR); + return 0; } + +static void adbdev_cleanup(void) +{ + unregister_chrdev(ADB_MAJOR, "adb"); +} + +module_init(adbdev_init); +module_exit(adbdev_cleanup); diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c new file mode 100644 index 000000000000..ffa26efa2378 --- /dev/null +++ b/drivers/macintosh/adbhid.c @@ -0,0 +1,875 @@ +/* + * drivers/input/adbhid.c + * + * ADB HID driver for Power Macintosh computers. + * + * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl + * (see that file for its authors and contributors). + * + * Copyright (C) 2000 Franz Sirl. + * + * Adapted to ADB changes and support for more devices by + * Benjamin Herrenschmidt. Adapted from code in MkLinux + * and reworked. + * + * Supported devices: + * + * - Standard 1 button mouse + * - All standard Apple Extended protocol (handler ID 4) + * - mouseman and trackman mice & trackballs + * - PowerBook Trackpad (default setup: enable tapping) + * - MicroSpeed mouse & trackball (needs testing) + * - CH Products Trackball Pro (needs testing) + * - Contour Design (Contour Mouse) + * - Hunter digital (NoHandsMouse) + * - Kensignton TurboMouse 5 (needs testing) + * - Mouse Systems A3 mice and trackballs + * - MacAlly 2-buttons mouse (needs testing) + * + * To do: + * + * Improve Kensington support. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + +MODULE_AUTHOR("Franz Sirl "); + +#define KEYB_KEYREG 0 /* register # for key up/down data */ +#define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ +#define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ + +static int adb_message_handler(struct notifier_block *, unsigned long, void *); +static struct notifier_block adbhid_adb_notifier = { + notifier_call: adb_message_handler, +}; + +unsigned char adb_to_linux_keycodes[128] = { + 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19, + 21, 20, 2, 3, 4, 5, 7, 6, 13, 10, 8, 12, 9, 11, 27, 24, + 22, 26, 23, 25, 28, 38, 36, 40, 37, 39, 43, 51, 53, 49, 50, 52, + 15, 57, 41, 14, 96, 1, 29,125, 42, 58, 56,105,106,108,103, 0, + 0, 83, 0, 55, 0, 78, 0, 69, 0, 0, 0, 98, 96, 0, 74, 0, + 0,117, 82, 79, 80, 81, 75, 76, 77, 71, 0, 72, 73,183,181,124, + 63, 64, 65, 61, 66, 67,191, 87,190, 99, 0, 70, 0, 68,101, 88, + 0,119,110,102,104,111, 62,107, 60,109, 59, 54,100, 97,116,116 +}; + +struct adbhid { + struct input_dev input; + int id; + int default_id; + int original_handler_id; + int current_handler_id; + int mouse_kind; + unsigned char *keycode; + char name[64]; +}; + +static struct adbhid *adbhid[16] = { 0 }; + +static void adbhid_probe(void); + +static void adbhid_input_keycode(int, int, int); +static void leds_done(struct adb_request *); + +static void init_trackpad(int id); +static void init_trackball(int id); +static void init_turbomouse(int id); +static void init_microspeed(int id); +static void init_ms_a3(int id); + +static struct adb_ids keyboard_ids; +static struct adb_ids mouse_ids; +static struct adb_ids buttons_ids; + +/* Kind of keyboard, see Apple technote 1152 */ +#define ADB_KEYBOARD_UNKNOWN 0 +#define ADB_KEYBOARD_ANSI 0x0100 +#define ADB_KEYBOARD_ISO 0x0200 +#define ADB_KEYBOARD_JIS 0x0300 + +/* Kind of mouse */ +#define ADBMOUSE_STANDARD_100 0 /* Standard 100cpi mouse (handler 1) */ +#define ADBMOUSE_STANDARD_200 1 /* Standard 200cpi mouse (handler 2) */ +#define ADBMOUSE_EXTENDED 2 /* Apple Extended mouse (handler 4) */ +#define ADBMOUSE_TRACKBALL 3 /* TrackBall (handler 4) */ +#define ADBMOUSE_TRACKPAD 4 /* Apple's PowerBook trackpad (handler 4) */ +#define ADBMOUSE_TURBOMOUSE5 5 /* Turbomouse 5 (previously req. mousehack) */ +#define ADBMOUSE_MICROSPEED 6 /* Microspeed mouse (&trackball ?), MacPoint */ +#define ADBMOUSE_TRACKBALLPRO 7 /* Trackball Pro (special buttons) */ +#define ADBMOUSE_MS_A3 8 /* Mouse systems A3 trackball (handler 3) */ +#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */ + +static void +adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n", + id, data[0], data[1], data[2], data[3]); + return; + } + + /* first check this is from register 0 */ + if (nb != 3 || (data[0] & 3) != KEYB_KEYREG) + return; /* ignore it */ + kbd_pt_regs = regs; + adbhid_input_keycode(id, data[1], 0); + if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f))) + adbhid_input_keycode(id, data[2], 0); +} + +static void +adbhid_input_keycode(int id, int keycode, int repeat) +{ + int up_flag; + + up_flag = (keycode & 0x80); + keycode &= 0x7f; + + switch (keycode) { + case 0x39: /* Generate down/up events for CapsLock everytime. */ + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1); + input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0); + return; + case 0x3f: /* ignore Powerbook Fn key */ + return; + } + + if (adbhid[id]->keycode[keycode]) + input_report_key(&adbhid[id]->input, + adbhid[id]->keycode[keycode], !up_flag); + else + printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode, + up_flag ? "released" : "pressed"); +} + +static void +adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + /* + Handler 1 -- 100cpi original Apple mouse protocol. + Handler 2 -- 200cpi original Apple mouse protocol. + + For Apple's standard one-button mouse protocol the data array will + contain the following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx First button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + + Handler 4 -- Apple Extended mouse protocol. + + For Apple's 3-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Second button and y-axis motion. + data[3] = byyy bxxx Third button and fourth button. Y is additional + high bits of y-axis motion. XY is additional + high bits of x-axis motion. + + MacAlly 2-button mouse protocol. + + For MacAlly 2-button mouse protocol the data array will contain the + following values: + + BITS COMMENTS + data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. + data[1] = bxxx xxxx Left button and x-axis motion. + data[2] = byyy yyyy Right button and y-axis motion. + data[3] = ???? ???? unknown + data[4] = ???? ???? unknown + + */ + + /* If it's a trackpad, we alias the second button to the first. + NOTE: Apple sends an ADB flush command to the trackpad when + the first (the real) button is released. We could do + this here using async flush requests. + */ + switch (adbhid[id]->mouse_kind) + { + case ADBMOUSE_TRACKPAD: + data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80); + data[2] = data[2] | 0x80; + break; + case ADBMOUSE_MICROSPEED: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5) + | (data[3] & 0x08); + break; + case ADBMOUSE_TRACKBALLPRO: + data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5) + & ((data[3] & 0x08) << 4)); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7); + data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); + break; + case ADBMOUSE_MS_A3: + data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7); + data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6); + data[3] = ((data[3] & 0x04) << 5); + break; + case ADBMOUSE_MACALLY2: + data[3] = (data[2] & 0x80) ? 0x80 : 0x00; + data[2] |= 0x80; /* Right button is mapped as button 3 */ + nb=4; + break; + } + + input_report_key(&adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1)); + input_report_key(&adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1)); + + if (nb >= 4) + input_report_key(&adbhid[id]->input, BTN_RIGHT, !((data[3] >> 7) & 1)); + + input_report_rel(&adbhid[id]->input, REL_X, + ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 )); + input_report_rel(&adbhid[id]->input, REL_Y, + ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 )); +} + +static void +adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) +{ + int id = (data[0] >> 4) & 0x0f; + + if (!adbhid[id]) { + printk(KERN_ERR "ADB HID on ID %d not yet registered\n", id); + return; + } + + switch (adbhid[id]->original_handler_id) { + default: + case 0x02: /* Adjustable keyboard button device */ + printk(KERN_INFO "Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n", + data[0], data[1], data[2], data[3]); + break; + case 0x1f: /* Powerbook button device */ + { +#ifdef CONFIG_PMAC_BACKLIGHT + int backlight = get_backlight_level(); + + /* + * XXX: Where is the contrast control for the passive? + * -- Cort + */ + + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) + break; + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) + break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; + } +#endif /* CONFIG_PMAC_BACKLIGHT */ + } + break; + } +} + +static struct adb_request led_request; +static int leds_pending[16]; +static int pending_devs[16]; +static int pending_led_start=0; +static int pending_led_end=0; + +static void real_leds(unsigned char leds, int device) +{ + if (led_request.complete) { + adb_request(&led_request, leds_done, 0, 3, + ADB_WRITEREG(device, KEYB_LEDREG), 0xff, + ~leds); + } else { + if (!(leds_pending[device] & 0x100)) { + pending_devs[pending_led_end] = device; + pending_led_end++; + pending_led_end = (pending_led_end < 16) ? pending_led_end : 0; + } + leds_pending[device] = leds | 0x100; + } +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ +static int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct adbhid *adbhid = dev->private; + unsigned char leds; + + switch (type) { + case EV_LED: + leds = (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) + | (test_bit(LED_NUML, dev->led) ? 1 : 0) + | (test_bit(LED_CAPSL, dev->led) ? 2 : 0); + real_leds(leds, adbhid->id); + return 0; + } + + return -1; +} + +static void leds_done(struct adb_request *req) +{ + int leds,device; + + if (pending_led_start != pending_led_end) { + device = pending_devs[pending_led_start]; + leds = leds_pending[device] & 0xff; + leds_pending[device] = 0; + pending_led_start++; + pending_led_start = (pending_led_start < 16) ? pending_led_start : 0; + real_leds(leds,device); + } + +} + +static int +adb_message_handler(struct notifier_block *this, unsigned long code, void *x) +{ + unsigned long flags; + + switch (code) { + case ADB_MSG_PRE_RESET: + case ADB_MSG_POWERDOWN: + /* Stop the repeat timer. Autopoll is already off at this point */ + save_flags(flags); + cli(); + { + int i; + for (i = 1; i < 16; i++) { + if (adbhid[i]) + del_timer(&adbhid[i]->input.timer); + } + } + restore_flags(flags); + + /* Stop pending led requests */ + while(!led_request.complete) + adb_poll(); + break; + + case ADB_MSG_POST_RESET: + adbhid_probe(); + break; + } + return NOTIFY_DONE; +} + +static void +adbhid_input_register(int id, int default_id, int original_handler_id, + int current_handler_id, int mouse_kind) +{ + int i; + + if (adbhid[id]) { + printk(KERN_ERR "Trying to reregister ADB HID on ID %d\n", id); + return; + } + + if (!(adbhid[id] = kmalloc(sizeof(struct adbhid), GFP_KERNEL))) + return; + + memset(adbhid[id], 0, sizeof(struct adbhid)); + + adbhid[id]->id = default_id; + adbhid[id]->original_handler_id = original_handler_id; + adbhid[id]->current_handler_id = current_handler_id; + adbhid[id]->mouse_kind = mouse_kind; + adbhid[id]->input.private = adbhid[id]; + adbhid[id]->input.name = adbhid[id]->name; + adbhid[id]->input.idbus = BUS_ADB; + adbhid[id]->input.idvendor = 0x0001; + adbhid[id]->input.idproduct = (id << 12) | (default_id << 8) | original_handler_id; + adbhid[id]->input.idversion = 0x0100; + + switch (default_id) { + case ADB_KEYBOARD: + if (!(adbhid[id]->keycode = kmalloc(sizeof(adb_to_linux_keycodes), GFP_KERNEL))) { + kfree(adbhid[id]); + return; + } + + sprintf(adbhid[id]->name, "ADB keyboard on ID %d:%d.%02x", + id, default_id, original_handler_id); + + memcpy(adbhid[id]->keycode, adb_to_linux_keycodes, sizeof(adb_to_linux_keycodes)); + + printk(KERN_INFO "Detected ADB keyboard, type "); + switch (original_handler_id) { + default: + printk(".\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_UNKNOWN; + break; + + case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: + case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: + case 0xC0: case 0xC3: case 0xC6: + printk("ANSI.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ANSI; + break; + + case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: + case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: + case 0xC4: case 0xC7: + printk("ISO, swapping keys.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_ISO; + i = adbhid[id]->keycode[10]; + adbhid[id]->keycode[10] = adbhid[id]->keycode[50]; + adbhid[id]->keycode[50] = i; + break; + + case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: + case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9: + printk("JIS.\n"); + adbhid[id]->input.idversion = ADB_KEYBOARD_JIS; + break; + } + + for (i = 0; i < 128; i++) + if (adbhid[id]->keycode[i]) + set_bit(adbhid[id]->keycode[i], adbhid[id]->input.keybit); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + adbhid[id]->input.ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML); + adbhid[id]->input.event = adbhid_kbd_event; + adbhid[id]->input.keycodemax = 127; + adbhid[id]->input.keycodesize = 1; + break; + + case ADB_MOUSE: + sprintf(adbhid[id]->name, "ADB mouse on ID %d:%d.%02x", + id, default_id, original_handler_id); + + adbhid[id]->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + adbhid[id]->input.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + adbhid[id]->input.relbit[0] = BIT(REL_X) | BIT(REL_Y); + break; + + case ADB_MISC: + switch (original_handler_id) { + case 0x02: /* Adjustable keyboard button device */ + sprintf(adbhid[id]->name, "ADB adjustable keyboard buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + case 0x1f: /* Powerbook button device */ + sprintf(adbhid[id]->name, "ADB Powerbook buttons on ID %d:%d.%02x", + id, default_id, original_handler_id); + break; + } + if (adbhid[id]->name[0]) + break; + /* else fall through */ + + default: + printk(KERN_INFO "Trying to register unknown ADB device to input layer.\n"); + kfree(adbhid[id]); + return; + } + + adbhid[id]->input.keycode = adbhid[id]->keycode; + + input_register_device(&adbhid[id]->input); + + printk(KERN_INFO "input%d: ADB HID on ID %d:%d.%02x\n", + adbhid[id]->input.number, id, default_id, original_handler_id); + + if (default_id == ADB_KEYBOARD) { + /* HACK WARNING!! This should go away as soon there is an utility + * to control that for event devices. + */ + adbhid[id]->input.rep[REP_DELAY] = HZ/2; /* input layer default: HZ/4 */ + adbhid[id]->input.rep[REP_PERIOD] = HZ/15; /* input layer default: HZ/33 */ + } +} + +static void adbhid_input_unregister(int id) +{ + input_unregister_device(&adbhid[id]->input); + if (adbhid[id]->keycode) + kfree(adbhid[id]->keycode); + kfree(adbhid[id]); + adbhid[id] = 0; +} + + +static void +adbhid_probe(void) +{ + struct adb_request req; + int i, default_id, org_handler_id, cur_handler_id; + + for (i = 1; i < 16; i++) { + if (adbhid[i]) + adbhid_input_unregister(i); + } + + adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input); + adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input); + adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input); + + for (i = 0; i < keyboard_ids.nids; i++) { + int id = keyboard_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + + /* turn off all leds */ + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff); + + /* Enable full feature set of the keyboard + ->get it to send separate codes for left and right shift, + control, option keys */ +#if 0 /* handler 5 doesn't send separate codes for R modifiers */ + if (adb_try_handler_change(id, 5)) + printk("ADB keyboard at %d, handler set to 5\n", id); + else +#endif + if (adb_try_handler_change(id, 3)) + printk("ADB keyboard at %d, handler set to 3\n", id); + else + printk("ADB keyboard at %d, handler 1\n", id); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, cur_handler_id, 0); + } + + for (i = 0; i < buttons_ids.nids; i++) { + int id = buttons_ids.id[i]; + + adb_get_infos(id, &default_id, &org_handler_id); + adbhid_input_register(id, default_id, org_handler_id, org_handler_id, 0); + } + + /* Try to switch all mice to handler 4, or 2 for three-button + mode and full resolution. */ + for (i = 0; i < mouse_ids.nids; i++) { + int id = mouse_ids.id[i]; + int mouse_kind; + + adb_get_infos(id, &default_id, &org_handler_id); + + if (adb_try_handler_change(id, 4)) { + printk("ADB mouse at %d, handler set to 4", id); + mouse_kind = ADBMOUSE_EXTENDED; + } + else if (adb_try_handler_change(id, 0x2F)) { + printk("ADB mouse at %d, handler set to 0x2F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x42)) { + printk("ADB mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_TRACKBALLPRO; + } + else if (adb_try_handler_change(id, 0x66)) { + printk("ADB mouse at %d, handler set to 0x66", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 0x5F)) { + printk("ADB mouse at %d, handler set to 0x5F", id); + mouse_kind = ADBMOUSE_MICROSPEED; + } + else if (adb_try_handler_change(id, 3)) { + printk("ADB mouse at %d, handler set to 3", id); + mouse_kind = ADBMOUSE_MS_A3; + } + else if (adb_try_handler_change(id, 2)) { + printk("ADB mouse at %d, handler set to 2", id); + mouse_kind = ADBMOUSE_STANDARD_200; + } + else { + printk("ADB mouse at %d, handler 1", id); + mouse_kind = ADBMOUSE_STANDARD_100; + } + + if ((mouse_kind == ADBMOUSE_TRACKBALLPRO) + || (mouse_kind == ADBMOUSE_MICROSPEED)) { + init_microspeed(id); + } else if (mouse_kind == ADBMOUSE_MS_A3) { + init_ms_a3(id); + } else if (mouse_kind == ADBMOUSE_EXTENDED) { + /* + * Register 1 is usually used for device + * identification. Here, we try to identify + * a known device and call the appropriate + * init function. + */ + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id, 1)); + + if ((req.reply_len) && + (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) + || (req.reply[2] == 0x20))) { + mouse_kind = ADBMOUSE_TRACKBALL; + init_trackball(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && + (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) { + mouse_kind = ADBMOUSE_TRACKPAD; + init_trackpad(id); + } + else if ((req.reply_len >= 4) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) && + (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) { + mouse_kind = ADBMOUSE_TURBOMOUSE5; + init_turbomouse(id); + } + else if ((req.reply_len == 9) && + (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) && + (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) { + if (adb_try_handler_change(id, 0x42)) { + printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id); + mouse_kind = ADBMOUSE_MACALLY2; + } + } + } + printk("\n"); + + adb_get_infos(id, &default_id, &cur_handler_id); + adbhid_input_register(id, default_id, org_handler_id, + cur_handler_id, mouse_kind); + } +} + +static void +init_trackpad(int id) +{ + struct adb_request req; + unsigned char r1_buffer[8]; + + printk(" (trackpad)"); + + adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1, + ADB_READREG(id,1)); + if (req.reply_len < 8) + printk("bad length for reg. 1\n"); + else + { + memcpy(r1_buffer, &req.reply[1], 8); + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x0d, /*r1_buffer[6],*/ + r1_buffer[7]); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,2), + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(id,1), + r1_buffer[0], + r1_buffer[1], + r1_buffer[2], + r1_buffer[3], + r1_buffer[4], + r1_buffer[5], + 0x03, /*r1_buffer[6],*/ + r1_buffer[7]); + } +} + +static void +init_trackball(int id) +{ + struct adb_request req; + + printk(" (trackman/mouseman)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 00,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 01,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 02,0x81); + + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id,1), 03,0x38); +} + +static void +init_turbomouse(int id) +{ + struct adb_request req; + + printk(" (TurboMouse 5)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xe7, + 0x8c, + 0, + 0, + 0, + 0xff, + 0xff, + 0x94); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3)); + + adb_request(&req, NULL, ADBREQ_SYNC, 9, + ADB_WRITEREG(3,2), + 0xa5, + 0x14, + 0, + 0, + 0x69, + 0xff, + 0xff, + 0x27); +} + +static void +init_microspeed(int id) +{ + struct adb_request req; + + printk(" (Microspeed/MacPoint or compatible)"); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); + + /* This will initialize mice using the Microspeed, MacPoint and + other compatible firmware. Bit 12 enables extended protocol. + + Register 1 Listen (4 Bytes) + 0 - 3 Button is mouse (set also for double clicking!!!) + 4 - 7 Button is locking (affects change speed also) + 8 - 11 Button changes speed + 12 1 = Extended mouse mode, 0 = normal mouse mode + 13 - 15 unused 0 + 16 - 23 normal speed + 24 - 31 changed speed + + Register 1 talk holds version and product identification information. + Register 1 Talk (4 Bytes): + 0 - 7 Product code + 8 - 23 undefined, reserved + 24 - 31 Version number + + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. + */ + adb_request(&req, NULL, ADBREQ_SYNC, 5, + ADB_WRITEREG(id,1), + 0x20, /* alt speed = 0x20 (rather slow) */ + 0x00, /* norm speed = 0x00 (fastest) */ + 0x10, /* extended protocol, no speed change */ + 0x07); /* all buttons enabled as mouse buttons, no locking */ + + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static void +init_ms_a3(int id) +{ + struct adb_request req; + + printk(" (Mouse Systems A3 Mouse, or compatible)"); + adb_request(&req, NULL, ADBREQ_SYNC, 3, + ADB_WRITEREG(id, 0x2), + 0x00, + 0x07); + + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); +} + +static int __init adbhid_init(void) +{ + if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) + return 0; + + led_request.complete = 1; + + adbhid_probe(); + + notifier_chain_register(&adb_client_list, &adbhid_adb_notifier); + + return 0; +} + +static void adbhid_exit(void) +{ +} + +module_init(adbhid_init); +module_exit(adbhid_exit); diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c new file mode 100644 index 000000000000..73529fc1e8a0 --- /dev/null +++ b/drivers/macintosh/mac_hid.c @@ -0,0 +1,492 @@ +/* + * drivers/macintosh/mac_hid.c + * + * HID support stuff for Macintosh computers. + * + * Copyright (C) 2000 Franz Sirl. + * + * Stuff inside CONFIG_MAC_ADBKEYCODES should go away during 2.5 when all + * major distributions are using the Linux keycodes. + * Stuff inside CONFIG_MAC_EMUMOUSEBTN should really be moved to userspace. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_MAC_ADBKEYCODES +#include +#include +#include +#endif + +#ifdef CONFIG_MAC_ADBKEYCODES +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +unsigned char mac_hid_kbd_sysrq_xlate[128] = + "asdfhgzxcv\000bqwer" /* 0x00 - 0x0f */ + "yt123465=97-80o]" /* 0x10 - 0x1f */ + "u[ip\rlj'k;\\,/nm." /* 0x20 - 0x2f */ + "\t `\177\000\033\000\000\000\000\000\000\000\000\000\000" + /* 0x30 - 0x3f */ + "\000\000\000*\000+\000\000\000\000\000/\r\000-\000" + /* 0x40 - 0x4f */ + "\000\0000123456789\000\000\000" /* 0x50 - 0x5f */ + "\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214"; + /* 0x60 - 0x6f */ +extern unsigned char pckbd_sysrq_xlate[128]; +#endif + +static u_short macplain_map[NR_KEYS] = { + 0xfb61, 0xfb73, 0xfb64, 0xfb66, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xfb63, 0xfb76, 0xf200, 0xfb62, 0xfb71, 0xfb77, 0xfb65, 0xfb72, + 0xfb79, 0xfb74, 0xf031, 0xf032, 0xf033, 0xf034, 0xf036, 0xf035, + 0xf03d, 0xf039, 0xf037, 0xf02d, 0xf038, 0xf030, 0xf05d, 0xfb6f, + 0xfb75, 0xf05b, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf027, + 0xfb6b, 0xf03b, 0xf05c, 0xf02c, 0xf02f, 0xfb6e, 0xfb6d, 0xf02e, + 0xf009, 0xf020, 0xf060, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_map[NR_KEYS] = { + 0xfb41, 0xfb53, 0xfb44, 0xfb46, 0xfb48, 0xfb47, 0xfb5a, 0xfb58, + 0xfb43, 0xfb56, 0xf200, 0xfb42, 0xfb51, 0xfb57, 0xfb45, 0xfb52, + 0xfb59, 0xfb54, 0xf021, 0xf040, 0xf023, 0xf024, 0xf05e, 0xf025, + 0xf02b, 0xf028, 0xf026, 0xf05f, 0xf02a, 0xf029, 0xf07d, 0xfb4f, + 0xfb55, 0xf07b, 0xfb49, 0xfb50, 0xf201, 0xfb4c, 0xfb4a, 0xf022, + 0xfb4b, 0xf03a, 0xf07c, 0xf03c, 0xf03f, 0xfb4e, 0xfb4d, 0xf03e, + 0xf009, 0xf020, 0xf07e, 0xf07f, 0xf200, 0xf01b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf10e, 0xf10f, 0xf110, 0xf10c, 0xf111, 0xf112, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf203, 0xf200, 0xf113, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf20b, 0xf116, 0xf10d, 0xf117, + 0xf10b, 0xf20a, 0xf10a, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macaltgr_map[NR_KEYS] = { + 0xf914, 0xfb73, 0xf917, 0xf919, 0xfb68, 0xfb67, 0xfb7a, 0xfb78, + 0xf916, 0xfb76, 0xf200, 0xf915, 0xfb71, 0xfb77, 0xf918, 0xfb72, + 0xfb79, 0xfb74, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf200, 0xf05d, 0xf07b, 0xf05c, 0xf05b, 0xf07d, 0xf07e, 0xfb6f, + 0xfb75, 0xf200, 0xfb69, 0xfb70, 0xf201, 0xfb6c, 0xfb6a, 0xf200, + 0xfb6b, 0xf200, 0xf200, 0xf200, 0xf200, 0xfb6e, 0xfb6d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf90a, 0xf90b, 0xf90c, 0xf90d, 0xf90e, 0xf90f, + 0xf910, 0xf911, 0xf200, 0xf912, 0xf913, 0xf200, 0xf200, 0xf200, + 0xf510, 0xf511, 0xf512, 0xf50e, 0xf513, 0xf514, 0xf200, 0xf516, + 0xf200, 0xf10c, 0xf200, 0xf202, 0xf200, 0xf515, 0xf200, 0xf517, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf50f, 0xf117, + 0xf50d, 0xf119, 0xf50c, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01e, 0xf01d, + 0xf200, 0xf200, 0xf01f, 0xf01f, 0xf07f, 0xf200, 0xf01d, 0xf00f, + 0xf015, 0xf01b, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf007, + 0xf00b, 0xf200, 0xf01c, 0xf200, 0xf07f, 0xf00e, 0xf00d, 0xf20e, + 0xf200, 0xf000, 0xf000, 0xf008, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf104, 0xf105, 0xf106, 0xf102, 0xf107, 0xf108, 0xf200, 0xf10a, + 0xf200, 0xf10c, 0xf200, 0xf204, 0xf200, 0xf109, 0xf200, 0xf10b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf103, 0xf117, + 0xf101, 0xf119, 0xf100, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macshift_ctrl_map[NR_KEYS] = { + 0xf001, 0xf013, 0xf004, 0xf006, 0xf008, 0xf007, 0xf01a, 0xf018, + 0xf003, 0xf016, 0xf200, 0xf002, 0xf011, 0xf017, 0xf005, 0xf012, + 0xf019, 0xf014, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf00f, + 0xf015, 0xf200, 0xf009, 0xf010, 0xf201, 0xf00c, 0xf00a, 0xf200, + 0xf00b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf00e, 0xf00d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf200, 0xf117, + 0xf200, 0xf119, 0xf200, 0xf700, 0xf701, 0xf702, 0xf200, 0xf20c, +}; + +static u_short macalt_map[NR_KEYS] = { + 0xf861, 0xf873, 0xf864, 0xf866, 0xf868, 0xf867, 0xf87a, 0xf878, + 0xf863, 0xf876, 0xf200, 0xf862, 0xf871, 0xf877, 0xf865, 0xf872, + 0xf879, 0xf874, 0xf831, 0xf832, 0xf833, 0xf834, 0xf836, 0xf835, + 0xf83d, 0xf839, 0xf837, 0xf82d, 0xf838, 0xf830, 0xf85d, 0xf86f, + 0xf875, 0xf85b, 0xf869, 0xf870, 0xf80d, 0xf86c, 0xf86a, 0xf827, + 0xf86b, 0xf83b, 0xf85c, 0xf82c, 0xf82f, 0xf86e, 0xf86d, 0xf82e, + 0xf809, 0xf820, 0xf860, 0xf87f, 0xf200, 0xf81b, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf210, 0xf211, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf900, 0xf901, 0xf902, 0xf903, 0xf904, 0xf905, + 0xf906, 0xf907, 0xf200, 0xf908, 0xf909, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf209, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static u_short macctrl_alt_map[NR_KEYS] = { + 0xf801, 0xf813, 0xf804, 0xf806, 0xf808, 0xf807, 0xf81a, 0xf818, + 0xf803, 0xf816, 0xf200, 0xf802, 0xf811, 0xf817, 0xf805, 0xf812, + 0xf819, 0xf814, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80f, + 0xf815, 0xf200, 0xf809, 0xf810, 0xf201, 0xf80c, 0xf80a, 0xf200, + 0xf80b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf80e, 0xf80d, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf702, 0xf703, + 0xf700, 0xf207, 0xf701, 0xf601, 0xf602, 0xf600, 0xf603, 0xf200, + 0xf200, 0xf310, 0xf200, 0xf30c, 0xf200, 0xf30a, 0xf200, 0xf208, + 0xf200, 0xf200, 0xf200, 0xf30d, 0xf30e, 0xf200, 0xf30b, 0xf200, + 0xf200, 0xf200, 0xf300, 0xf301, 0xf302, 0xf303, 0xf304, 0xf305, + 0xf306, 0xf307, 0xf200, 0xf308, 0xf309, 0xf200, 0xf200, 0xf200, + 0xf504, 0xf505, 0xf506, 0xf502, 0xf507, 0xf508, 0xf200, 0xf50a, + 0xf200, 0xf10c, 0xf200, 0xf200, 0xf200, 0xf509, 0xf200, 0xf50b, + 0xf200, 0xf11d, 0xf115, 0xf114, 0xf118, 0xf116, 0xf503, 0xf117, + 0xf501, 0xf119, 0xf500, 0xf700, 0xf701, 0xf702, 0xf200, 0xf200, +}; + +static unsigned short *mac_key_maps_save[MAX_NR_KEYMAPS] = { + macplain_map, macshift_map, macaltgr_map, 0, + macctrl_map, macshift_ctrl_map, 0, 0, + macalt_map, 0, 0, 0, + macctrl_alt_map, 0 +}; + +static unsigned short *pc_key_maps_save[MAX_NR_KEYMAPS]; + +int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep, + char raw_mode); +static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp); +char mac_hid_kbd_unexpected_up(unsigned char keycode); + +static int keyboard_lock_keycodes = 0; +int keyboard_sends_linux_keycodes = 0; +#else +int keyboard_sends_linux_keycodes = 1; +#endif /* CONFIG_MAC_ADBKEYCODES */ + + +static unsigned char e0_keys[128] = { + 0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, KEY_LANG1, KEY_LANG2, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, KEY_KPENTER, KEY_RIGHTCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, KEY_KPSLASH, 0, KEY_SYSRQ, /* 0x30-0x37 */ + KEY_RIGHTALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, 0, KEY_HOME, /* 0x40-0x47 */ + KEY_UP, KEY_PAGEUP, 0, KEY_LEFT, 0, KEY_RIGHT, 0, KEY_END, /* 0x48-0x4f */ + KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, KEY_LEFTMETA, KEY_RIGHTMETA, KEY_COMPOSE, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, KEY_MACRO, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +#ifdef CONFIG_MAC_EMUMOUSEBTN +static struct input_dev emumousebtn; +static void emumousebtn_input_register(void); +static int mouse_emulate_buttons = 0; +static int mouse_button2_keycode = KEY_RIGHTCTRL; /* right control key */ +static int mouse_button3_keycode = KEY_RIGHTALT; /* right option key */ +static int mouse_last_keycode = 0; +#endif + +extern void pckbd_init_hw(void); + +#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) +/* file(s) in /proc/sys/dev/mac_hid */ +ctl_table mac_hid_files[] = +{ +#ifdef CONFIG_MAC_ADBKEYCODES + { + DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES, + "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int), + 0644, NULL, &mac_hid_sysctl_keycodes + }, + { + DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES, + "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif +#ifdef CONFIG_MAC_EMUMOUSEBTN + { + DEV_MAC_HID_MOUSE_BUTTON_EMULATION, + "mouse_button_emulation", &mouse_emulate_buttons, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE, + "mouse_button2_keycode", &mouse_button2_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, + { + DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE, + "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int), + 0644, NULL, &proc_dointvec + }, +#endif + { 0 } +}; + +/* dir in /proc/sys/dev */ +ctl_table mac_hid_dir[] = +{ + { DEV_MAC_HID, "mac_hid", NULL, 0, 0555, mac_hid_files }, + { 0 } +}; + +/* /proc/sys/dev itself, in case that is not there yet */ +ctl_table mac_hid_root_dir[] = +{ + { CTL_DEV, "dev", NULL, 0, 0555, mac_hid_dir }, + { 0 } +}; + +static struct ctl_table_header *mac_hid_sysctl_header; + +#ifdef CONFIG_MAC_ADBKEYCODES +static +int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp, + void *buffer, size_t *lenp) +{ + int val = keyboard_sends_linux_keycodes; + int ret = 0; + + if (!write + || (write && !keyboard_lock_keycodes)) + ret = proc_dointvec(ctl, write, filp, buffer, lenp); + + if (write + && keyboard_sends_linux_keycodes != val) { + if (!keyboard_sends_linux_keycodes) { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + SYSRQ_KEY = 0x69; +#endif + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); + } else { +#ifdef CONFIG_MAGIC_SYSRQ + ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + SYSRQ_KEY = 0x54; +#endif + memcpy(mac_key_maps_save, key_maps, sizeof(key_maps)); + memcpy(key_maps, pc_key_maps_save, sizeof(key_maps)); + } + } + + return ret; +} +#endif +#endif /* endif CONFIG_SYSCTL */ + +int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ +#ifdef CONFIG_MAC_ADBKEYCODES + if (!keyboard_sends_linux_keycodes) { + if (!raw_mode) { + /* + * Convert R-shift/control/option to L version. + */ + switch (scancode) { + case 0x7b: scancode = 0x38; break; /* R-shift */ + case 0x7c: scancode = 0x3a; break; /* R-option */ + case 0x7d: scancode = 0x36; break; /* R-control */ + } + } + *keycode = scancode; + return 1; + } else +#endif + { + /* This code was copied from char/pc_keyb.c and will be + * superflous when the input layer is fully integrated. + * We don't need the high_keys handling, so this part + * has been removed. + */ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = KEY_PAUSE; + prev_scancode = 0; + } else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + if (scancode == 0x2a || scancode == 0x36) + return 0; + } + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); + return 0; + } + } else { + switch (scancode) { + case 91: scancode = KEY_LINEFEED; break; + case 92: scancode = KEY_KPEQUAL; break; + case 125: scancode = KEY_INTL1; break; + } + *keycode = scancode; + } + return 1; + } +} + +char mac_hid_kbd_unexpected_up(unsigned char keycode) +{ + if (keyboard_sends_linux_keycodes && keycode == KEY_F13) + return 0; + else + return 0x80; +} + +#ifdef CONFIG_MAC_ADBKEYCODES +int mac_hid_keyboard_sends_linux_keycodes(void) +{ + return keyboard_sends_linux_keycodes; +} + +static int __init mac_hid_setup(char *str) +{ + int ints[11]; + + str = get_options(str, ints); + if (ints[0] == 1) { + keyboard_sends_linux_keycodes = ints[1] != 0; + keyboard_lock_keycodes = 1; + } + return 1; +} + +__setup("keyboard_sends_linux_keycodes=", mac_hid_setup); + +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN +int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down) +{ + switch (caller) { + case 1: + /* Called from keybdev.c */ + if (mouse_emulate_buttons + && (keycode == mouse_button2_keycode + || keycode == mouse_button3_keycode)) { + if (mouse_emulate_buttons == 1) { + input_report_key(&emumousebtn, + keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT, + down); + return 1; + } + mouse_last_keycode = down ? keycode : 0; + } + break; + case 2: + /* Called from mousedev.c */ + if (mouse_emulate_buttons == 2 && keycode == 0) { + if (mouse_last_keycode == mouse_button2_keycode) + return 1; /* map to middle button */ + if (mouse_last_keycode == mouse_button3_keycode) + return 2; /* map to right button */ + } + return keycode; /* keep button */ + } + return 0; +} + +static void emumousebtn_input_register(void) +{ + emumousebtn.name = "Macintosh mouse button emulation"; + + emumousebtn.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + emumousebtn.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + emumousebtn.relbit[0] = BIT(REL_X) | BIT(REL_Y); + + emumousebtn.idbus = BUS_ADB; + emumousebtn.idvendor = 0x0001; + emumousebtn.idproduct = 0x0001; + emumousebtn.idversion = 0x0100; + + input_register_device(&emumousebtn); + + printk(KERN_INFO "input%d: Macintosh mouse button emulation\n", emumousebtn.number); +} +#endif + +void __init mac_hid_init_hw(void) +{ + +#ifdef CONFIG_MAC_ADBKEYCODES + memcpy(pc_key_maps_save, key_maps, sizeof(key_maps)); + + if (!keyboard_sends_linux_keycodes) + memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); +#endif + +#ifdef CONFIG_MAC_EMUMOUSEBTN + emumousebtn_input_register(); +#endif + +#if CONFIG_PPC + if (_machine != _MACH_Pmac) + pckbd_init_hw(); +#endif + +#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN)) + mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1); +#endif /* CONFIG_SYSCTL */ +} diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index ab90dcef6492..db365794f87c 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -16,7 +16,7 @@ * * - Standard 1 button mouse * - All standard Apple Extended protocol (handler ID 4) - * - mouseman and trackman mice & trackballs + * - mouseman and trackman mice & trackballs * - PowerBook Trackpad (default setup: enable tapping) * - MicroSpeed mouse & trackball (needs testing) * - CH Products Trackball Pro (needs testing) @@ -48,10 +48,16 @@ #include #include #include +#include +#include #include #include +#ifdef CONFIG_PMAC_BACKLIGHT +#include +#endif + #define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ @@ -226,7 +232,7 @@ static u_short macctrl_alt_map[NR_KEYS] __initdata = { static void kbd_repeat(unsigned long); -static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat }; +static struct timer_list repeat_timer = { function: kbd_repeat }; static int last_keycode; static void mackeyb_probe(void); @@ -347,7 +353,7 @@ input_keycode(int keycode, int repeat) #ifdef CONFIG_ADBMOUSE /* * XXX: Add mouse button 2+3 fake codes here if mouse open. - * Keep track of 'button' states here as we only send + * Keep track of 'button' states here as we only send * single up/down events! * Really messy; might need to check if keyboard is in * VC_RAW mode. @@ -587,61 +593,47 @@ mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) } #endif /* CONFIG_ADBMOUSE */ -/* XXX Needs to get rid of this, see comments in pmu.c */ -extern int backlight_level; - static void buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll) { + int backlight = get_backlight_level(); + /* * XXX: Where is the contrast control for the passive? * -- Cort */ - + /* Ignore data from register other than 0 */ - if ((adb_hardware != ADB_VIAPMU) || (data[0] & 0x3) || (nb < 2)) + if ((data[0] & 0x3) || (nb < 2)) return; - switch (data[1]&0xf ) - { - /* mute */ - case 0x8: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast decrease */ - case 0x7: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* contrast increase */ - case 0x6: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - } - break; - /* brightness decrease */ - case 0xa: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level > 2) - pmu_set_brightness(backlight_level-2); - else - pmu_set_brightness(0); - } + switch (data[1]) { + case 0x8: /* mute */ + break; + + case 0x7: /* contrast decrease */ + break; + + case 0x6: /* contrast increase */ + break; + + case 0xa: /* brightness decrease */ + if (backlight < 0) break; - /* brightness increase */ - case 0x9: - /* down event */ - if ( data[1] == (data[1]&0xf) ) { - if (backlight_level < 0x1e) - pmu_set_brightness(backlight_level+2); - else - pmu_set_brightness(0x1f); - } + if (backlight > BACKLIGHT_OFF) + set_backlight_level(backlight-1); + else + set_backlight_level(BACKLIGHT_OFF); + break; + + case 0x9: /* brightness increase */ + if (backlight < 0) break; + if (backlight < BACKLIGHT_MAX) + set_backlight_level(backlight+1); + else + set_backlight_level(BACKLIGHT_MAX); + break; } } @@ -702,10 +694,10 @@ static void leds_done(struct adb_request *req) } -__initfunc(void mackbd_init_hw(void)) +void __init mackbd_init_hw(void) { if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) ) - return; + return; /* setup key map */ memcpy(key_maps[0], macplain_map, sizeof(plain_map)); @@ -736,7 +728,7 @@ adb_message_handler(struct notifier_block *this, unsigned long code, void *x) switch (code) { case ADB_MSG_PRE_RESET: case ADB_MSG_POWERDOWN: - /* Stop the repeat timer. Autopoll is already off at this point */ + /* Stop the repeat timer. Autopoll is already off at this point */ save_flags(flags); cli(); del_timer(&repeat_timer); @@ -842,7 +834,7 @@ mackeyb_probe(void) if ((req.reply_len) && (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21) - || (req.reply[2] == 0x20))) + || (req.reply[2] == 0x20))) init_trackball(id); else if ((req.reply_len >= 4) && (req.reply[1] == 0x74) && (req.reply[2] == 0x70) && @@ -865,7 +857,7 @@ mackeyb_probe(void) } } -static void +static void init_trackpad(int id) { struct adb_request req; @@ -895,15 +887,15 @@ init_trackpad(int id) adb_request(&req, NULL, ADBREQ_SYNC, 9, ADB_WRITEREG(id,2), - 0x99, - 0x94, - 0x19, - 0xff, - 0xb2, - 0x8a, - 0x1b, - 0x50); - + 0x99, + 0x94, + 0x19, + 0xff, + 0xb2, + 0x8a, + 0x1b, + 0x50); + adb_request(&req, NULL, ADBREQ_SYNC, 9, ADB_WRITEREG(id,1), r1_buffer[0], @@ -917,7 +909,7 @@ init_trackpad(int id) } } -static void +static void init_trackball(int id) { struct adb_request req; @@ -1000,7 +992,7 @@ init_microspeed(int id) /* This will initialize mice using the Microspeed, MacPoint and other compatible firmware. Bit 12 enables extended protocol. - + Register 1 Listen (4 Bytes) 0 - 3 Button is mouse (set also for double clicking!!!) 4 - 7 Button is locking (affects change speed also) @@ -1015,7 +1007,7 @@ init_microspeed(int id) 0 - 7 Product code 8 - 23 undefined, reserved 24 - 31 Version number - + Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max. */ adb_request(&req, NULL, ADBREQ_SYNC, 5, @@ -1039,7 +1031,7 @@ init_ms_a3(int id) ADB_WRITEREG(id, 0x2), 0x00, 0x07); - + adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id)); } diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c index d3d5686c9758..9b3bafeba5e6 100644 --- a/drivers/macintosh/macserial.c +++ b/drivers/macintosh/macserial.c @@ -953,6 +953,67 @@ static void dma_init(struct mac_serial * info) info->dma_initted = 1; } +/* + * FixZeroBug....Works around a bug in the SCC receving channel. + * Taken from Darwin code, 15 Sept. 2000 -DanM + * + * The following sequence prevents a problem that is seen with O'Hare ASICs + * (most versions -- also with some Heathrow and Hydra ASICs) where a zero + * at the input to the receiver becomes 'stuck' and locks up the receiver. + * This problem can occur as a result of a zero bit at the receiver input + * coincident with any of the following events: + * + * The SCC is initialized (hardware or software). + * A framing error is detected. + * The clocking option changes from synchronous or X1 asynchronous + * clocking to X16, X32, or X64 asynchronous clocking. + * The decoding mode is changed among NRZ, NRZI, FM0, or FM1. + * + * This workaround attempts to recover from the lockup condition by placing + * the SCC in synchronous loopback mode with a fast clock before programming + * any of the asynchronous modes. + */ +static void fix_zero_bug_scc(struct mac_serial * info) +{ + write_zsreg(info->zs_channel, 9, + (info->zs_channel == info->zs_chan_a? CHRA: CHRB)); + udelay(10); + write_zsreg(info->zs_channel, 9, + ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV)); + + write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC)); + + /* I think this is wrong....but, I just copying code.... + */ + write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE)); + + write_zsreg(info->zs_channel, 5, (8 & ~TxENAB)); + write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */ + write_zsreg(info->zs_channel, 11, (RCBR | TCBR)); + write_zsreg(info->zs_channel, 12, 0); + write_zsreg(info->zs_channel, 13, 0); + write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR)); + write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL)); + write_zsreg(info->zs_channel, 3, (8 | RxENABLE)); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */ + + /* The channel should be OK now, but it is probably receiving + * loopback garbage. + * Switch to asynchronous mode, disable the receiver, + * and discard everything in the receive buffer. + */ + write_zsreg(info->zs_channel, 9, NV); + write_zsreg(info->zs_channel, 4, PAR_ENA); + write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE)); + + while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) { + (void)read_zsreg(info->zs_channel, 8); + write_zsreg(info->zs_channel, 0, RES_EXT_INT); + write_zsreg(info->zs_channel, 0, ERR_RES); + } +} + static int setup_scc(struct mac_serial * info) { unsigned long flags; @@ -961,6 +1022,9 @@ static int setup_scc(struct mac_serial * info) save_flags(flags); cli(); /* Disable interrupts */ + /* Nice buggy HW ... */ + fix_zero_bug_scc(info); + /* * Reset the chip. */ @@ -1081,7 +1145,7 @@ static void shutdown(struct mac_serial * info) info->curregs[5] &= ~TxENAB; if (!info->tty || C_HUPCL(info->tty)) - info->curregs[5] &= ~(DTR | RTS); + info->curregs[5] &= ~DTR; info->pendregs[5] = info->curregs[5]; write_zsreg(info->zs_channel, 5, info->curregs[5]); @@ -1253,7 +1317,7 @@ static void irda_setup(struct mac_serial *info) /* assert DTR, wait 30ms, talk to the chip */ write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR); - udelay(30000); + mdelay(30); while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) read_zsdata(info->zs_channel); @@ -1592,17 +1656,35 @@ static void rs_throttle(struct tty_struct * tty) if (C_CRTSCTS(tty)) { /* * Here we want to turn off the RTS line. On Macintoshes, - * we only get the DTR line, which goes to both DTR and - * RTS on the modem. RTS doesn't go out to the serial - * port socket. So you should make sure your modem is - * set to ignore DTR if you're using CRTSCTS. + * the external serial ports using a DIN-8 or DIN-9 + * connector only have the DTR line (which is usually + * wired to both RTS and DTR on an external modem in + * the cable). RTS doesn't go out to the serial port + * socket, it acts as an output enable for the transmit + * data line. So in this case we don't drop RTS. + * + * Macs with internal modems generally do have both RTS + * and DTR wired to the modem, so in that case we do + * drop RTS. */ + if (info->is_internal_modem) { + save_flags(flags); cli(); + info->curregs[5] &= ~RTS; + info->pendregs[5] &= ~RTS; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } + } + +#ifdef CDTRCTS + if (tty->termios->c_cflag & CDTRCTS) { save_flags(flags); cli(); - info->curregs[5] &= ~(DTR | RTS); - info->pendregs[5] &= ~(DTR | RTS); + info->curregs[5] &= ~DTR; + info->pendregs[5] &= ~DTR; write_zsreg(info->zs_channel, 5, info->curregs[5]); restore_flags(flags); } +#endif /* CDTRCTS */ } static void rs_unthrottle(struct tty_struct * tty) @@ -1629,14 +1711,25 @@ static void rs_unthrottle(struct tty_struct * tty) restore_flags(flags); } - if (C_CRTSCTS(tty)) { - /* Assert RTS and DTR lines */ + if (C_CRTSCTS(tty) && info->is_internal_modem) { + /* Assert RTS line */ save_flags(flags); cli(); - info->curregs[5] |= DTR | RTS; - info->pendregs[5] |= DTR | RTS; + info->curregs[5] |= RTS; + info->pendregs[5] |= RTS; write_zsreg(info->zs_channel, 5, info->curregs[5]); restore_flags(flags); } + +#ifdef CDTRCTS + if (tty->termios->c_cflag & CDTRCTS) { + /* Assert DTR line */ + save_flags(flags); cli(); + info->curregs[5] |= DTR; + info->pendregs[5] |= DTR; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + restore_flags(flags); + } +#endif } /* @@ -2311,6 +2404,7 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, /* setup misc varariables */ zss->kgdb_channel = 0; zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); + zss->is_internal_modem = zss->is_cobalt_modem; /* XXX tested only with wallstreet PowerBook, should do no harm anyway */ @@ -2318,8 +2412,12 @@ chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, zss->is_irda = conn && (strcmp(conn, "infrared") == 0); /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); - if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0) - zss->is_irda = 1; + if (slots && slots->count > 0) { + if (strcmp(slots->name, "IrDA") == 0) + zss->is_irda = 1; + else if (strcmp(slots->name, "Modem") == 0) + zss->is_internal_modem = 1; + } if (zss->has_dma) { zss->dma_priv = NULL; @@ -2560,6 +2658,8 @@ int macserial_init(void) printk(", port = %s", connector); if (info->is_cobalt_modem) printk(" (cobalt modem)"); + else if (info->is_internal_modem) + printk(" (internal modem)"); if (info->is_irda) printk(" (IrDA)"); printk("\n"); @@ -2898,7 +2998,7 @@ static struct console sercons = { /* * Register console. */ -__initfunc (long serial_console_init(long kmem_start, long kmem_end)) +__initfunc (long mac_scc_console_init(long kmem_start, long kmem_end)) { register_console(&sercons); return kmem_start; diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h index 26e28ead0aa5..80c4351bd5e5 100644 --- a/drivers/macintosh/macserial.h +++ b/drivers/macintosh/macserial.h @@ -110,6 +110,7 @@ struct mac_serial { char break_abort; /* Is serial console in, so process brk/abrt */ char kgdb_channel; /* Kgdb is running on this channel */ char is_cons; /* Is this our console. */ + char is_internal_modem; /* is connected to an internal modem */ char is_cobalt_modem; /* is a gatwick-based cobalt modem */ char is_irda; /* is connected to an IrDA codec */ unsigned char tx_active; /* character is being xmitted */ diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 2f0a420c7d33..7087a3c4272f 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -474,8 +474,11 @@ media_bay_step(int i) } else if (MB_IDE_READY(i)) { bay->timer = 0; bay->state = mb_up; - if (bay->cd_index < 0) + if (bay->cd_index < 0) { + pmu_suspend(); bay->cd_index = ide_register(bay->cd_base, 0, bay->cd_irq); + pmu_resume(); + } if (bay->cd_index == -1) { /* We eventually do a retry */ bay->cd_retry++; @@ -582,7 +585,7 @@ poll_media_bay(int which) #ifdef CONFIG_PMAC_PBOOK /* - * notify clients before sleep and reset bus afterwards + * notify ents before sleep and reset bus afterwards */ int mb_notify_sleep(struct pmu_sleep_notifier *self, int when) @@ -611,7 +614,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when) they seem to help the 3400 get it right. */ feature_set(bay->dev_node, FEATURE_IOBUS_enable); - mdelay(MB_STABLE_DELAY); + /* Force MB power to 0 */ + set_mb_power(i, 0); + mdelay(MB_POWER_DELAY); if (!bay->pismo) out_8(&bay->addr->contents, 0x70); mdelay(MB_STABLE_DELAY); @@ -621,7 +626,9 @@ mb_notify_sleep(struct pmu_sleep_notifier *self, int when) bay->last_value = bay->content_id; bay->value_count = MS_TO_HZ(MB_STABLE_DELAY); bay->timer = MS_TO_HZ(MB_POWER_DELAY); +#ifdef CONFIG_BLK_DEV_IDE bay->cd_retry = 0; +#endif do { mdelay(1000/HZ); media_bay_step(i); diff --git a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c index 695946c3a5a9..9c1580b3c631 100644 --- a/drivers/macintosh/nvram.c +++ b/drivers/macintosh/nvram.c @@ -14,6 +14,7 @@ #include #include #include +#include #define NVRAM_SIZE 8192 @@ -76,6 +77,30 @@ static ssize_t write_nvram(struct file *file, const char *buf, return p - buf; } +static int nvram_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + switch(cmd) { + case PMAC_NVRAM_GET_OFFSET: + { + int part, offset; + if (copy_from_user(&part,(void*)arg,sizeof(part))!=0) + return -EFAULT; + if (part < pmac_nvram_OF || part > pmac_nvram_NR) + return -EINVAL; + offset = pmac_get_partition(part); + if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0) + return -EFAULT; + break; + } + + default: + return -EINVAL; + } + + return 0; +} + static int nvram_open(struct inode *inode, struct file *file) { MOD_INC_USE_COUNT; @@ -94,7 +119,7 @@ struct file_operations nvram_fops = { write_nvram, NULL, /* nvram_readdir */ NULL, /* nvram_select */ - NULL, /* nvram_ioctl */ + nvram_ioctl, NULL, /* nvram_mmap */ nvram_open, NULL, /* flush */ diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 577820ea1070..3164b9e8dc23 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -3,19 +3,17 @@ * * The VIA (versatile interface adapter) interfaces to the PMU, * a 6805 microprocessor core whose primary function is to control - * battery charging and system power on the PowerBook 3400 and 2400. - * The PMU also controls the ADB (Apple Desktop Bus) which connects + * battery charging and system power on the PowerBooks and new + * "Core99" Apple machines. + * The PMU may also controls the ADB (Apple Desktop Bus) which connects * to the keyboard and mouse, as well as the non-volatile RAM * and the RTC (real time clock) chip. * - * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi. - * - * todo: - Check this driver for smp safety (new Core99 motherboards). - * - Cleanup synchro between VIA interrupt and GPIO-based PMU - * interrupt. - * - * + * Copyright (C) 1998 Paul Mackerras, Fabio Riccardi + * and Benjamin Herrenschmidt + * */ + #include #include #include @@ -40,6 +38,10 @@ #include #include #include +#include + +#define DEBUG_SLEEP +#define PMU_CORE99_SLEEP /* Doesn't work yet (almost there...) */ /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 @@ -103,9 +105,11 @@ static struct adb_request bright_req_1, bright_req_2, bright_req_3; static struct device_node *vias; static int pmu_kind = PMU_UNKNOWN; static int pmu_fully_inited = 0; -static int pmu_has_adb, pmu_has_backlight; +static int pmu_has_adb; static unsigned char *gpio_reg = NULL; static int gpio_irq = -1; +static int pmu_suspended = 0; +static spinlock_t pmu_lock; int asleep; @@ -124,6 +128,8 @@ static void pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs); static void set_volume(int level); static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); +static int pmu_set_backlight_level(int level, void* data); +static int pmu_set_backlight_enable(int on, int level, void* data); #ifdef CONFIG_PMAC_PBOOK static void pmu_pass_intr(unsigned char *data, int len); #endif @@ -137,8 +143,10 @@ static struct adb_controller pmu_controller = { }; extern void low_sleep_handler(void); -extern void sleep_save_intrs(int); -extern void sleep_restore_intrs(void); +extern void pmac_sleep_save_intrs(int); +extern void pmac_sleep_restore_intrs(void); +extern void openpic_sleep_save_intrs(void); +extern void openpic_sleep_restore_intrs(void); extern int grackle_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short *val); @@ -146,12 +154,18 @@ extern int grackle_pcibios_read_config_word(unsigned char bus, extern int grackle_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn, unsigned char offset, unsigned short val); +#ifdef DEBUG_SLEEP +int pmu_polled_request(struct adb_request *req); +int pmu_wink(struct adb_request *req); +#endif + + /* * This table indicates for each PMU opcode: * - the number of data bytes to be sent with the command, or -1 * if a length byte should be sent, * - the number of response bytes which the PMU will return, or - * -1 if it will send a length byte. + * -1 if it will send a length byte */ static s8 pmu_data_len[256][2] __openfirmwaredata = { /* 0 1 2 3 4 5 6 7 */ @@ -197,6 +211,11 @@ static char *pbook_type[] = { "Core99" }; +static struct backlight_controller pmu_backlight_controller = { + pmu_set_backlight_enable, + pmu_set_backlight_level +}; + int __openfirmware find_via_pmu() { @@ -226,8 +245,9 @@ find_via_pmu() return 0; } + spin_lock_init(&pmu_lock); + pmu_has_adb = 1; - pmu_has_backlight = 1; if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0) || device_is_compatible(vias->parent, "ohare"))) @@ -241,7 +261,6 @@ find_via_pmu() pmu_kind = PMU_KEYLARGO_BASED; pmu_has_adb = (find_type_devices("adb") != NULL); - pmu_has_backlight = 0; /* Not driven by PMU */ gpiop = find_devices("gpio"); if (gpiop && gpiop->n_addrs) { @@ -301,7 +320,7 @@ via_pmu_init(void) pmu_fully_inited = 1; /* Enable backlight */ - pmu_enable_backlight(1); + register_backlight_controller(&pmu_backlight_controller, NULL, "pmu"); /* Make sure PMU settle down before continuing */ do { @@ -318,7 +337,7 @@ init_pmu() out_8(&via[B], via[B] | TREQ); /* negate TREQ */ out_8(&via[DIRB], (via[DIRB] | TREQ) & ~TACK); /* TACK in, TREQ out */ - pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xff); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); timeout = 100000; while (!req.complete) { if (--timeout < 0) { @@ -349,7 +368,7 @@ init_pmu() while (!req.complete) pmu_poll(); } - + return 1; } @@ -553,8 +572,8 @@ pmu_queue_request(struct adb_request *req) req->next = 0; req->sent = 0; req->complete = 0; - save_flags(flags); cli(); + spin_lock_irqsave(&pmu_lock, flags); if (current_req != 0) { last_req->next = req; last_req = req; @@ -565,7 +584,7 @@ pmu_queue_request(struct adb_request *req) pmu_start(); } - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); return 0; } @@ -639,35 +658,90 @@ out: void __openfirmware pmu_poll() { - int ie; - + if (!via) + return; if (disable_poll) return; - ie = _disable_interrupts(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) + /* Kicks ADB read when PMU is suspended */ + if (pmu_suspended) + adb_int_pending = 1; + do { via_pmu_interrupt(0, 0, 0); - _enable_interrupts(ie); + } while (pmu_suspended && (adb_int_pending || pmu_state != idle + || req_awaiting_reply)); } -/* This function loops until the PMU is idle, to avoid spurrious shutdowns - * when prom.c scrollscreen or xmon spends too much time without interupts - * while some PMU communication is going on +/* This function loops until the PMU is idle and prevents it from + * anwsering to ADB interrupts. pmu_request can still be called. + * This is done to avoid spurrious shutdowns when we know we'll have + * interrupts switched off for a long time */ void __openfirmware -pmu_safe_poll(void) +pmu_suspend(void) { - int ie; +#ifdef SUSPEND_USES_PMU + struct adb_request *req; +#endif + unsigned long flags; - if (!via || disable_poll) + if (!via) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended++; + if (pmu_suspended != 1) { + spin_unlock_irqrestore(&pmu_lock, flags); return; + } + do { - ie = _disable_interrupts(); - if ((via[IFR] & (SR_INT | CB1_INT)) || - (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0)) - via_pmu_interrupt(0, 0, 0); - _enable_interrupts(ie); - } while (adb_int_pending || pmu_state != idle); + spin_unlock(&pmu_lock); + via_pmu_interrupt(0, 0, 0); + spin_lock(&pmu_lock); + if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + disable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_CLR); + spin_unlock_irqrestore(&pmu_lock, flags); +#endif /* SUSPEND_USES_PMU */ + break; + } + } while (1); +} + +void __openfirmware +pmu_resume(void) +{ + unsigned long flags; + + if (!via || pmu_suspended < 1) + return; + + spin_lock_irqsave(&pmu_lock, flags); + pmu_suspended--; + if (pmu_suspended > 0) { + spin_unlock_irqrestore(&pmu_lock, flags); + return; + } + adb_int_pending = 1; +#ifdef SUSPEND_USES_PMU + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + spin_unlock_irqrestore(&pmu_lock, flags); + while(!req.complete) + pmu_poll(); +#else /* SUSPEND_USES_PMU */ + if (gpio_irq >= 0) + enable_irq(gpio_irq); + out_8(&via[IER], CB1_INT | IER_SET); + spin_unlock_irqrestore(&pmu_lock, flags); + pmu_poll(); +#endif /* SUSPEND_USES_PMU */ } static void __openfirmware @@ -680,8 +754,9 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) /* Currently, we use brute-force cli() for syncing with GPIO * interrupt. I'll make this smarter later, along with some * spinlocks for SMP */ - save_flags(flags);cli(); + spin_lock_irqsave(&pmu_lock, flags); ++disable_poll; + while ((intr = in_8(&via[IFR])) != 0) { if (++nloop > 1000) { printk(KERN_DEBUG "PMU: stuck in intr loop, " @@ -699,9 +774,15 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) out_8(&via[IFR], intr); } } + /* This is not necessary except if synchronous ADB requests are done + * with interrupts off, which should not happen. Since I'm not sure + * this "wiring" will remain, I'm commenting it out for now. Please do + * not remove. -- BenH. + */ +#if 0 if (gpio_reg && (in_8(gpio_reg + 0x9) & 0x02) == 0) adb_int_pending = 1; - +#endif if (pmu_state == idle) { if (adb_int_pending) { pmu_state = intack; @@ -713,16 +794,17 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) } } --disable_poll; - restore_flags(flags); + spin_unlock_irqrestore(&pmu_lock, flags); } static void __openfirmware gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) { + adb_int_pending = 1; via_pmu_interrupt(0, 0, 0); } - + static void __openfirmware pmu_sr_intr(struct pt_regs *regs) { @@ -749,7 +831,7 @@ pmu_sr_intr(struct pt_regs *regs) /* if reading grab the byte, and reset the interrupt */ if (pmu_state == reading || pmu_state == reading_intr) bite = in_8(&via[SR]); - + out_8(&via[IFR], SR_INT); switch (pmu_state) { @@ -771,8 +853,11 @@ pmu_sr_intr(struct pt_regs *regs) current_req = req->next; if (req->reply_expected) req_awaiting_reply = req; - else + else { + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); + } } else { pmu_state = reading; data_index = 0; @@ -797,7 +882,8 @@ pmu_sr_intr(struct pt_regs *regs) printk(KERN_ERR "PMU: bad reply len %d\n", bite); } else { - reply_ptr[data_index++] = bite; + if (data_index < 32) + reply_ptr[data_index++] = bite; } if (data_index < data_len) { recv_byte(); @@ -810,7 +896,9 @@ pmu_sr_intr(struct pt_regs *regs) req = current_req; current_req = req->next; req->reply_len += data_index; + spin_unlock(&pmu_lock); pmu_done(req); + spin_lock(&pmu_lock); } pmu_state = idle; @@ -877,7 +965,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } } else if (data[0] == 0x08 && len == 3) { /* sound/brightness buttons pressed */ - pmu_set_brightness(data[1] >> 3); + set_backlight_level(data[1] >> 4); set_volume(data[2]); } else { #ifdef CONFIG_PMAC_PBOOK @@ -886,53 +974,22 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) } } -int backlight_level = -1; -int backlight_enabled = 0; - -#define LEVEL_TO_BRIGHT(lev) ((lev) < 1? 0x7f: 0x4a - ((lev) << 1)) - -void __openfirmware -pmu_enable_backlight(int on) +static int backlight_to_bright[] = { + 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e, + 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e +}; + +static int __openfirmware +pmu_set_backlight_enable(int on, int level, void* data) { struct adb_request req; + + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return; - - /* first call: get current backlight value */ - if (on && backlight_level < 0) { - switch (pmu_kind) { - case PMU_OHARE_BASED: - pmu_request(&req, NULL, 2, 0xd9, 0); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1] >> 3; - break; - case PMU_HEATHROW_BASED: - /* We cannot use nvram_read_byte here (not yet initialized) */ - pmu_request(&req, NULL, 3, PMU_READ_NVRAM, 0x14, 0xe); - while (!req.complete) - pmu_poll(); - backlight_level = req.reply[1]; - printk(KERN_DEBUG "pmu: nvram returned bright: %d\n", backlight_level); - break; - case PMU_PADDINGTON_BASED: - case PMU_KEYLARGO_BASED: - /* the G3 PB 1999 has a backlight node - and chrp-structured nvram */ - /* XXX should read macos's "blkt" property in nvram - for this node. For now this ensures that the - backlight doesn't go off as soon as linux boots. */ - backlight_level = 20; - break; - default: - backlight_enabled = 0; - return; - } - } if (on) { pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, - LEVEL_TO_BRIGHT(backlight_level)); + backlight_to_bright[level]); while (!req.complete) pmu_poll(); } @@ -940,34 +997,26 @@ pmu_enable_backlight(int on) PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF)); while (!req.complete) pmu_poll(); - backlight_enabled = on; + + return 0; } -void __openfirmware -pmu_set_brightness(int level) +static int __openfirmware +pmu_set_backlight_level(int level, void* data) { - int bright; + if (vias == NULL) + return -ENODEV; - if ((vias == NULL) || !pmu_has_backlight) - return ; + if (!bright_req_1.complete) + return -EAGAIN; + pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, + backlight_to_bright[level]); + if (!bright_req_2.complete) + return -EAGAIN; + pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, PMU_POW_BACKLIGHT + | (level > BACKLIGHT_OFF ? PMU_POW_ON : PMU_POW_OFF)); - backlight_level = level; - bright = LEVEL_TO_BRIGHT(level); - if (!backlight_enabled) - return; - if (bright_req_1.complete) - pmu_request(&bright_req_1, NULL, 2, PMU_BACKLIGHT_BRIGHT, - bright); - if (bright_req_2.complete) - pmu_request(&bright_req_2, NULL, 2, PMU_POWER_CTRL, - PMU_POW_BACKLIGHT | (bright < 0x7f ? PMU_POW_ON : PMU_POW_OFF)); - - /* XXX nvram address is hard-coded and looks ok on wallstreet, please - test on your machine. Note that newer MacOS system software may break - the nvram layout. */ - if ((pmu_kind == PMU_HEATHROW_BASED) && bright_req_3.complete) - pmu_request(&bright_req_3, NULL, 4, PMU_WRITE_NVRAM, - 0x14, 0xe, level); + return 0; } void __openfirmware @@ -1083,7 +1132,7 @@ broadcast_sleep(int when, int fallback) when, current, current->notifier_call); for (; list != &sleep_notifiers; list = list->next) { current = list_entry(list, struct pmu_sleep_notifier, list); - current->notifier_call(current, fallback); + current->notifier_call(current, fallback); } return ret; } @@ -1178,21 +1227,40 @@ pbook_pci_restore(void) } } -#if 0 +#ifdef DEBUG_SLEEP /* N.B. This doesn't work on the 3400 */ -void pmu_blink(int n) +void +pmu_blink(int n) { struct adb_request req; + memset(&req, 0, sizeof(req)); + for (; n > 0; --n) { - pmu_request(&req, NULL, 4, 0xee, 4, 0, 1); - while (!req.complete) pmu_poll(); - udelay(50000); - pmu_request(&req, NULL, 4, 0xee, 4, 0, 0); - while (!req.complete) pmu_poll(); - udelay(50000); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 1; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); + req.nbytes = 4; + req.done = NULL; + req.data[0] = 0xee; + req.data[1] = 4; + req.data[2] = 0; + req.data[3] = 0; + req.reply[0] = ADB_RET_OK; + req.reply_len = 1; + req.reply_expected = 0; + pmu_polled_request(&req); + mdelay(50); } - udelay(50000); + mdelay(50); } #endif @@ -1200,7 +1268,33 @@ void pmu_blink(int n) * Put the powerbook to sleep. */ -#define FEATURE_CTRL(base) ((unsigned int *)(base + 0x38)) +static u32 save_via[8]; +static void save_via_state(void) +{ + save_via[0] = in_8(&via[ANH]); + save_via[1] = in_8(&via[DIRA]); + save_via[2] = in_8(&via[B]); + save_via[3] = in_8(&via[DIRB]); + save_via[4] = in_8(&via[PCR]); + save_via[5] = in_8(&via[ACR]); + save_via[6] = in_8(&via[T1CL]); + save_via[7] = in_8(&via[T1CH]); +} +static void restore_via_state(void) +{ + out_8(&via[ANH], save_via[0]); + out_8(&via[DIRA], save_via[1]); + out_8(&via[B], save_via[2]); + out_8(&via[DIRB], save_via[3]); + out_8(&via[PCR], save_via[4]); + out_8(&via[ACR], save_via[5]); + out_8(&via[T1CL], save_via[6]); + out_8(&via[T1CH], save_via[7]); + out_8(&via[IER], IER_CLR | 0x7f); /* disable all intrs */ + out_8(&via[IFR], 0x7f); /* clear IFR */ + out_8(&via[IER], IER_SET | SR_INT | CB1_INT); +} + #define GRACKLE_PM (1<<7) #define GRACKLE_DOZE (1<<5) #define GRACKLE_NAP (1<<4) @@ -1208,20 +1302,12 @@ void pmu_blink(int n) int __openfirmware powerbook_sleep_G3(void) { - int ret; unsigned long save_l2cr; - unsigned long save_fcr; unsigned long wait; unsigned short pmcr1; - struct adb_request sleep_req; - struct device_node *macio; - unsigned long macio_base = 0; - - macio = find_devices("mac-io"); - if (macio != 0 && macio->n_addrs > 0) - macio_base = (unsigned long) - ioremap(macio->addrs[0].address, 0x40); - + struct adb_request req; + int ret, timeout; + /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); if (ret != PBOOK_SLEEP_OK) { @@ -1245,31 +1331,57 @@ int __openfirmware powerbook_sleep_G3(void) } /* Give the disks a little time to actually finish writing */ - for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) + for (wait = jiffies + HZ; time_before(jiffies, wait); ) mb(); - /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + + /* Turn off various things. Darwin does some retry tests here... */ + pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY); + while (!req.complete) + pmu_poll(); + + /* Disable all interrupts */ + pmac_sleep_save_intrs(-1); + + /* Make sure the PMU is idle */ + while (pmu_state != idle) + pmu_poll(); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); -#if 0 - /* Save the state of PCI config space for some slots */ - pbook_pci_save(); -#endif + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Giveup the FPU */ + if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* We can now disable MSR_EE */ + cli(); + /* For 750, save backside cache setting and disable it */ save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ if (save_l2cr) _set_L2CR(0); - if (macio_base != 0) { - save_fcr = in_le32(FEATURE_CTRL(macio_base)); - /* Check if this is still valid on older powerbooks */ - out_le32(FEATURE_CTRL(macio_base), save_fcr & ~(0x00000140UL)); - } + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + pmu_poll(); - if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) - giveup_fpu(current); + /* The VIA is supposed not to be restored correctly*/ + save_via_state(); + /* We shut down some HW */ + feature_prepare_for_sleep(); grackle_pcibios_read_config_word(0,0,0x70,&pmcr1); /* Apparently, MacOS uses NAP mode for Grackle ??? */ @@ -1277,15 +1389,6 @@ int __openfirmware powerbook_sleep_G3(void) pmcr1 |= GRACKLE_PM|GRACKLE_NAP; grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); - /* Ask the PMU to put us to sleep */ - pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) - mb(); - - cli(); - while (pmu_state != idle) - pmu_poll(); - /* Call low-level ASM sleep handler */ low_sleep_handler(); @@ -1293,26 +1396,201 @@ int __openfirmware powerbook_sleep_G3(void) grackle_pcibios_read_config_word(0, 0, 0x70, &pmcr1); pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP); grackle_pcibios_write_config_word(0, 0, 0x70, pmcr1); + + /* Restore things */ + feature_wake_up(); + restore_via_state(); + + /* Restore L2 cache */ + if (save_l2cr) + _set_L2CR(save_l2cr); + + /* Restore userland MMU context */ + set_context(current->mm->context); + + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); + + /* Power things up */ + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, + PMU_POW0_ON|PMU_POW0_HARD_DRIVE); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_POWER_CTRL, + PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY); + while (!req.complete) + pmu_poll(); + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) + break; + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + /* reenable interrupt controller */ + pmac_sleep_restore_intrs(); + + /* Leave some time for HW to settle down */ + mdelay(100); + + /* Notify drivers */ + broadcast_wake(); + + return 0; +} + +#ifdef PMU_CORE99_SLEEP + +/* Not finished yet */ +int __openfirmware powerbook_sleep_Core99(void) +{ + unsigned long save_l2cr; + unsigned long wait; + struct adb_request req; + int ret, timeout; + + /* Notify device drivers */ + ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep rejected\n"); + return -EBUSY; + } + + /* Sync the disks. */ + /* XXX It would be nice to have some way to ensure that + * nobody is dirtying any new buffers while we wait. + * BenH: Moved to _after_ sleep request and changed video + * drivers to vmalloc() during sleep request. This way, all + * vmalloc's are done before actual sleep of block drivers */ + fsync_dev(0); + + /* Sleep can fail now. May not be very robust but useful for debugging */ + ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE); + if (ret != PBOOK_SLEEP_OK) { + printk("pmu: sleep failed\n"); + return -EBUSY; + } + + /* Give the disks a little time to actually finish writing */ + for (wait = jiffies + HZ; time_before(jiffies, wait); ) + mb(); + + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + + /* Tell PMU what events will wake us up */ + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, + 0xff, 0xff); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS, + 0, PMU_PWR_WAKEUP_KEY | PMU_PWR_WAKEUP_LID_OPEN); + while (!req.complete) + pmu_poll(); + + /* Save & disable all interrupts */ + openpic_sleep_save_intrs(); /* Make sure the PMU is idle */ while (pmu_state != idle) pmu_poll(); - sti(); -#if 0 - /* According to someone from Apple, this should not be needed, - at least not for all devices. Let's keep it for now until we - have something that works. */ - pbook_pci_restore(); -#endif - set_context(current->mm->context); + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* Giveup the FPU */ + if (current->tss.regs && (current->tss.regs->msr & MSR_FP) != 0) + giveup_fpu(current); + + /* We can now disable MSR_EE */ + cli(); + + /* For 750, save backside cache setting and disable it */ + save_l2cr = _get_L2CR(); /* (returns 0 if not 750) */ + if (save_l2cr) + _set_L2CR(0); + + /* Save the state of PCI config space for some slots */ + // pbook_pci_save(); + + /* Ask the PMU to put us to sleep */ + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) + pmu_poll(); + + /* The VIA is supposed not to be restored correctly*/ + save_via_state(); + + /* Shut down various ASICs. There's a chance that we can no longer + * talk to the PMU after this, so I moved it to _after_ sending the + * sleep command to it. Still need to be checked. + */ + feature_prepare_for_sleep(); + + /* Call low-level ASM sleep handler */ + low_sleep_handler(); + + /* Restore things */ + feature_wake_up(); + // Don't restore PCI for now, it crashes. Maybe unnecessary on pbook + // pbook_pci_restore(); + + restore_via_state(); + /* Restore L2 cache */ if (save_l2cr) - _set_L2CR(save_l2cr | 0x200000); /* set invalidate bit */ + _set_L2CR(save_l2cr); + + /* Restore userland MMU context */ + set_context(current->mm->context); - /* reenable interrupts */ - sleep_restore_intrs(); + /* Re-enable DEC interrupts and kick DEC */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + sti(); + asm volatile("mtdec %0" : : "r" (0x10000000)); + + /* Tell PMU we are ready */ + pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2); + while (!req.complete) + pmu_poll(); + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0xfc); + while (!req.complete) + pmu_poll(); + + /* ack all pending interrupts */ + timeout = 100000; + interrupt_data[0] = 1; + while (interrupt_data[0] || pmu_state != idle) { + if (--timeout < 0) + break; + if (pmu_state == idle) + adb_int_pending = 1; + via_pmu_interrupt(0, 0, 0); + udelay(10); + } + + /* reenable interrupt controller */ + openpic_sleep_restore_intrs(); + + /* Leave some time for HW to settle down */ + mdelay(100); /* Notify drivers */ broadcast_wake(); @@ -1320,6 +1598,8 @@ int __openfirmware powerbook_sleep_G3(void) return 0; } +#endif + #define PB3400_MEM_CTRL ((unsigned int *)0xf8000070) int __openfirmware powerbook_sleep_3400(void) @@ -1328,7 +1608,7 @@ int __openfirmware powerbook_sleep_3400(void) unsigned long msr; unsigned int hid0; unsigned long p, wait; - struct adb_request sleep_req; + struct adb_request req; /* Notify device drivers */ ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT); @@ -1356,8 +1636,12 @@ int __openfirmware powerbook_sleep_3400(void) for (wait = jiffies + (HZ/4); time_before(jiffies, wait); ) mb(); + /* Wait for completion of async backlight requests */ + while (!bright_req_1.complete || !bright_req_2.complete || !bright_req_3.complete) + pmu_poll(); + /* Disable all interrupts except pmu */ - sleep_save_intrs(vias->intrs[0].line); + pmac_sleep_save_intrs(vias->intrs[0].line); /* Make sure the decrementer won't interrupt us */ asm volatile("mtdec %0" : : "r" (0x7fffffff)); @@ -1377,8 +1661,8 @@ int __openfirmware powerbook_sleep_3400(void) } /* Ask the PMU to put us to sleep */ - pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); - while (!sleep_req.complete) + pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); + while (!req.complete) mb(); /* displacement-flush the L2 cache - necessary? */ @@ -1387,9 +1671,9 @@ int __openfirmware powerbook_sleep_3400(void) asleep = 1; /* Put the CPU into sleep mode */ - asm volatile("mfspr %0,1008" : "=r" (hid0) :); + hid0 = _get_HID0(); hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; - asm volatile("mtspr 1008,%0" : : "r" (hid0)); + _set_HID0(hid0); save_flags(msr); msr |= MSR_POW | MSR_EE; restore_flags(msr); @@ -1404,7 +1688,7 @@ int __openfirmware powerbook_sleep_3400(void) mb(); /* reenable interrupts */ - sleep_restore_intrs(); + pmac_sleep_restore_intrs(); /* Notify drivers */ broadcast_wake(); @@ -1576,20 +1860,24 @@ static int pmu_ioctl(struct inode * inode, struct file *filp, case PMU_PADDINGTON_BASED: error = powerbook_sleep_G3(); break; +#ifdef PMU_CORE99_SLEEP + case PMU_KEYLARGO_BASED: + error = powerbook_sleep_Core99(); + break; +#endif default: error = -ENOSYS; } return error; case PMU_IOC_GET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; - return put_user(backlight_level, (__u32 *)arg); + error = get_backlight_level(); + if (error < 0) + return error; + return put_user(error, (__u32 *)arg); case PMU_IOC_SET_BACKLIGHT: - if (!pmu_has_backlight) - return -ENOSYS; error = get_user(value, (__u32 *)arg); if (!error) - pmu_set_brightness(value); + error = set_backlight_level(value); return error; case PMU_IOC_GET_MODEL: return put_user(pmu_kind, (__u32 *)arg); @@ -1623,7 +1911,7 @@ void pmu_device_init(void) } #endif /* CONFIG_PMAC_PBOOK */ -#if 0 +#ifdef DEBUG_SLEEP static inline void polled_handshake(volatile unsigned char *via) { via[B] &= ~TREQ; eieio(); @@ -1689,4 +1977,4 @@ pmu_polled_request(struct adb_request *req) restore_flags(flags); return 0; } -#endif /* 0 */ +#endif /* DEBUG_SLEEP */ diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index 9eb96e8ac344..c8cb6dbf2761 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -248,12 +248,16 @@ bmac_reset_chip(struct device *dev) dbdma_reset(rd); dbdma_reset(td); + dbdma_st32((volatile unsigned long *)&rd->intr_sel, 0x40); + dbdma_st32((volatile unsigned long *)&rd->br_sel, 0x40); + dbdma_st32((volatile unsigned long *)&td->wait_sel, 0x20); + feature_set(bp->node, FEATURE_BMac_IO_enable); - udelay(10000); + mdelay(100); feature_set(bp->node, FEATURE_BMac_reset); - udelay(10000); + mdelay(10); feature_clear(bp->node, FEATURE_BMac_reset); - udelay(10000); + mdelay(10); } #define MIFDELAY udelay(10) diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 7ec8407eaecd..47a3c1c78ddb 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -4165,7 +4165,7 @@ get_hw_addr(struct device *dev) /* If possible, try to fix a broken card - SMC only so far */ srom_repair(dev, broken); -#ifdef CONFIG_PMAC +#ifdef CONFIG_POWERMAC /* ** If the address starts with 00 a0, we have to bit-reverse ** each byte of the address. @@ -4178,7 +4178,7 @@ get_hw_addr(struct device *dev) dev->dev_addr[i] = ((x & 0x55) << 1) + ((x & 0xaa) >> 1); } } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_POWERMAC */ /* Test for a bad enet address */ status = test_bad_enet(dev, status); diff --git a/drivers/net/gmac.c b/drivers/net/gmac.c index 76f92dc9b797..3e625911a4da 100644 --- a/drivers/net/gmac.c +++ b/drivers/net/gmac.c @@ -6,6 +6,13 @@ * * portions based on sunhme.c by David S. Miller * + * Changes: + * Arnaldo Carvalho de Melo - 08/06/2000 + * - check init_etherdev return in gmac_probe1 + * BenH - 03/09/2000 + * - Add support for new PHYs + * - Add some PowerBook sleep code + * */ #include @@ -21,18 +28,25 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include +#ifdef CONFIG_PMAC_PBOOK +#include +#include +#include +#endif #include "gmac.h" #define DEBUG_PHY -/* Driver version 1.1, kernel 2.2.x */ -#define GMAC_VERSION "v1.1k2" +/* Driver version 1.3, kernel 2.2.x */ +#define GMAC_VERSION "v1.3k2" static unsigned char dummy_buf[RX_BUF_ALLOC_SIZE + RX_OFFSET + GMAC_BUFFER_ALIGN]; static struct device *gmacs = NULL; @@ -45,9 +59,12 @@ static void mii_poll_stop(struct gmac *gm); static void mii_interrupt(struct gmac *gm); static int mii_lookup_and_reset(struct gmac *gm); static void mii_setup_phy(struct gmac *gm); +static int mii_do_reset_phy(struct gmac *gm, int phy_addr); +static void mii_init_BCM5400(struct gmac *gm); static void gmac_set_power(struct gmac *gm, int power_up); static int gmac_powerup_and_reset(struct device *dev); +static void gmac_set_gigabit_mode(struct gmac *gm, int gigabit); static void gmac_set_duplex_mode(struct gmac *gm, int full_duplex); static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr); static void gmac_init_rings(struct gmac *gm, int from_irq); @@ -67,6 +84,13 @@ int gmac_probe(struct device *dev); extern int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr, unsigned char *devfn_ptr); +#ifdef CONFIG_PMAC_PBOOK +int gmac_sleep_notify(struct pmu_sleep_notifier *self, int when); +static struct pmu_sleep_notifier gmac_sleep_notifier = { + gmac_sleep_notify, SLEEP_LEVEL_NET, +}; +#endif + /* Stuff for talking to the physical-layer chip */ static int mii_read(struct gmac *gm, int phy, int r) @@ -136,6 +160,18 @@ mii_poll_stop(struct gmac *gm) udelay(GM_MIF_POLL_DELAY); } +/* Link modes of the BCM5400 PHY */ +static int phy_BCM5400_link_table[8][3] = { + { 0, 0, 0 }, /* No link */ + { 0, 0, 0 }, /* 10BT Half Duplex */ + { 1, 0, 0 }, /* 10BT Full Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 0, 1, 0 }, /* 100BT Half Duplex */ + { 1, 1, 0 }, /* 100BT Full Duplex*/ + { 1, 0, 1 }, /* 1000BT */ + { 1, 0, 1 }, /* 1000BT */ +}; + static void mii_interrupt(struct gmac *gm) { @@ -150,8 +186,9 @@ mii_interrupt(struct gmac *gm) /* We read the Auxilliary Status Summary register */ phy_status = mii_read(gm, gm->phy_addr, MII_SR); if ((phy_status ^ gm->phy_status) & (MII_SR_ASSC | MII_SR_LKS)) { - int full_duplex; - int link_100; + int full_duplex = 0; + int link_100 = 0; + int gigabit = 0; #ifdef DEBUG_PHY printk("Link state change, phy_status: 0x%04x\n", phy_status); #endif @@ -163,8 +200,9 @@ mii_interrupt(struct gmac *gm) else GM_BIC(GM_MAC_CTRL_CONFIG, GM_MAC_CTRL_CONF_SND_PAUSE_EN); - /* Link ? For now we handle only the 5201 PHY */ + /* Link ? Check for speed and duplex */ if ((phy_status & MII_SR_LKS) && (phy_status & MII_SR_ASSC)) { + int restart = 0; if (gm->phy_type == PHY_B5201) { int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5201_AUXCTLSTATUS); #ifdef DEBUG_PHY @@ -172,19 +210,41 @@ mii_interrupt(struct gmac *gm) #endif full_duplex = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_DUPLEX) != 0); link_100 = ((aux_stat & MII_BCM5201_AUXCTLSTATUS_SPEED) != 0); - } else { - full_duplex = 1; - link_100 = 1; + } else if (gm->phy_type == PHY_B5400) { + int aux_stat = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXSTATUS); + int link = (aux_stat & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >> + MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT; +#ifdef DEBUG_PHY + printk(" Link up ! BCM5400 aux_stat: 0x%04x (link mode: %d)\n", + aux_stat, link); +#endif + full_duplex = phy_BCM5400_link_table[link][0]; + link_100 = phy_BCM5400_link_table[link][1]; + gigabit = phy_BCM5400_link_table[link][2]; + } else if (gm->phy_type == PHY_LXT971) { + int stat2 = mii_read(gm, gm->phy_addr, MII_LXT971_STATUS2); +#ifdef DEBUG_PHY + printk(" Link up ! LXT971 stat2: 0x%04x\n", stat2); +#endif + full_duplex = ((stat2 & MII_LXT971_STATUS2_FULLDUPLEX) != 0); + link_100 = ((stat2 & MII_LXT971_STATUS2_SPEED) != 0); } #ifdef DEBUG_PHY printk(" full_duplex: %d, speed: %s\n", full_duplex, - link_100 ? "100" : "10"); + gigabit ? "1000" : (link_100 ? "100" : "10")); #endif + if (gigabit != gm->gigabit) { + gm->gigabit = gigabit; + gmac_set_gigabit_mode(gm, gm->gigabit); + restart = 1; + } if (full_duplex != gm->full_duplex) { gm->full_duplex = full_duplex; gmac_set_duplex_mode(gm, gm->full_duplex); - gmac_start_dma(gm); + restart = 1; } + if (restart) + gmac_start_dma(gm); } else if (!(phy_status & MII_SR_LKS)) { #ifdef DEBUG_PHY printk(" Link down !\n"); @@ -193,17 +253,74 @@ mii_interrupt(struct gmac *gm) } } +static int +mii_do_reset_phy(struct gmac *gm, int phy_addr) +{ + int mii_control, timeout; + + mii_control = mii_read(gm, phy_addr, MII_CR); + mii_write(gm, phy_addr, MII_CR, mii_control | MII_CR_RST); + mdelay(10); + for (timeout = 100; timeout > 0; --timeout) { + mii_control = mii_read(gm, phy_addr, MII_CR); + if (mii_control == -1) { + printk(KERN_ERR "%s PHY died after reset !\n", + gm->dev->name); + return 1; + } + if ((mii_control & MII_CR_RST) == 0) + break; + mdelay(10); + } + if (mii_control & MII_CR_RST) { + printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + return 1; + } + mii_write(gm, phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); + return 0; +} + +static void +mii_init_BCM5400(struct gmac *gm) +{ + int data; + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data |= MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL); + data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP; + mii_write(gm, gm->phy_addr, MII_BCM5400_GB_CONTROL, data); + + mdelay(10); + mii_do_reset_phy(gm, 0x1f); + + data = mii_read(gm, 0x1f, MII_BCM5201_MULTIPHY); + data |= MII_BCM5201_MULTIPHY_SERIALMODE; + mii_write(gm, 0x1f, MII_BCM5201_MULTIPHY, data); + + data = mii_read(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL); + data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET; + mii_write(gm, gm->phy_addr, MII_BCM5400_AUXCONTROL, data); +} + static int mii_lookup_and_reset(struct gmac *gm) { - int i, timeout; - int mii_status, mii_control; + int i, mii_status, mii_control; - /* Find the PHY */ gm->phy_addr = -1; gm->phy_type = PHY_UNKNOWN; + + /* Hard reset the PHY */ + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_ASSERT); + mdelay(10); + feature_set_gmac_phy_reset(gm->of_node, KL_GPIO_ETH_PHY_RESET_RELEASE); + mdelay(10); - for(i=31; i>0; --i) { + /* Find the PHY */ + for(i=0; i<32; i++) { mii_control = mii_read(gm, i, MII_CR); mii_status = mii_read(gm, i, MII_SR); if (mii_control != -1 && mii_status != -1 && @@ -211,29 +328,13 @@ mii_lookup_and_reset(struct gmac *gm) break; } gm->phy_addr = i; - if (gm->phy_addr < 0) + if (gm->phy_addr > 31) return 0; /* Reset it */ - mii_write(gm, gm->phy_addr, MII_CR, mii_control | MII_CR_RST); - mdelay(10); - for (timeout = 100; timeout > 0; --timeout) { - mii_control = mii_read(gm, gm->phy_addr, MII_CR); - if (mii_control == -1) { - printk(KERN_ERR "%s PHY died after reset !\n", - gm->dev->name); - goto fail; - } - if ((mii_control & MII_CR_RST) == 0) - break; - mdelay(10); - } - if (mii_control & MII_CR_RST) { - printk(KERN_ERR "%s PHY reset timeout !\n", gm->dev->name); + if (mii_do_reset_phy(gm, gm->phy_addr)) goto fail; - } - mii_write(gm, gm->phy_addr, MII_CR, mii_control & ~MII_CR_ISOL); - + /* Read the PHY ID */ gm->phy_id = (mii_read(gm, gm->phy_addr, MII_ID0) << 16) | mii_read(gm, gm->phy_addr, MII_ID1); @@ -242,10 +343,15 @@ mii_lookup_and_reset(struct gmac *gm) #endif if ((gm->phy_id & MII_BCM5400_MASK) == MII_BCM5400_ID) { gm->phy_type = PHY_B5400; - printk(KERN_ERR "%s Warning ! Unsupported BCM5400 PHY !\n", + printk(KERN_ERR "%s Found Broadcom BCM5400 PHY (Gigabit)\n", gm->dev->name); + mii_init_BCM5400(gm); } else if ((gm->phy_id & MII_BCM5201_MASK) == MII_BCM5201_ID) { gm->phy_type = PHY_B5201; + printk(KERN_INFO "%s Found Broadcom BCM5201 PHY\n", gm->dev->name); + } else if ((gm->phy_id & MII_LXT971_MASK) == MII_LXT971_ID) { + gm->phy_type = PHY_LXT971; + printk(KERN_INFO "%s Found LevelOne LX971 PHY\n", gm->dev->name); } else { printk(KERN_ERR "%s: Warning ! Unknown PHY ID 0x%08x !\n", gm->dev->name, gm->phy_id); @@ -288,9 +394,7 @@ static void gmac_set_power(struct gmac *gm, int power_up) { if (power_up) { - out_le32(gm->sysregs + 0x20/4, - in_le32(gm->sysregs + 0x20/4) | 0x02000000); - udelay(20); + feature_set_gmac_power(gm->of_node, 1); if (gm->pci_devfn != 0xff) { u16 cmd; @@ -308,9 +412,7 @@ gmac_set_power(struct gmac *gm, int power_up) } else { /* FIXME: Add PHY power down */ gm->phy_type = 0; - out_le32(gm->sysregs + 0x20/4, - in_le32(gm->sysregs + 0x20/4) & ~0x02000000); - udelay(20); + feature_set_gmac_power(gm->of_node, 0); } } @@ -357,6 +459,22 @@ gmac_set_duplex_mode(struct gmac *gm, int full_duplex) } } +/* Set the MAC gigabit mode. Side effect: stops Tx MAC */ +static void +gmac_set_gigabit_mode(struct gmac *gm, int gigabit) +{ + /* Stop Tx MAC */ + GM_BIC(GM_MAC_TX_CONFIG, GM_MAC_TX_CONF_ENABLE); + while(GM_IN(GM_MAC_TX_CONFIG) & GM_MAC_TX_CONF_ENABLE) + ; + + if (gigabit) { + GM_BIS(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } else { + GM_BIC(GM_MAC_XIF_CONFIG, GM_MAC_XIF_CONF_GMII_MODE); + } +} + static void gmac_mac_init(struct gmac *gm, unsigned char *mac_addr) { @@ -388,12 +506,12 @@ gmac_mac_init(struct gmac *gm, unsigned char *mac_addr) (31 << GM_GCONF_TXDMA_LIMIT_SHIFT) | (31 << GM_GCONF_RXDMA_LIMIT_SHIFT)); GM_OUT(GM_TX_CONF, - GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT | + (GM_TX_CONF_FIFO_THR_DEFAULT << GM_TX_CONF_FIFO_THR_SHIFT) | NTX_CONF); -/* 34 byte offset for checksum computation. This works because ip_input() will clear out - * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are - * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr) - */ + /* 34 byte offset for checksum computation. This works because ip_input() will clear out + * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are + * present in the header. 34 == (ethernet header len) + sizeof(struct iphdr) + */ GM_OUT(GM_RX_CONF, (RX_OFFSET << GM_RX_CONF_FBYTE_OFF_SHIFT) | (0x22 << GM_RX_CONF_CHK_START_SHIFT) | @@ -703,6 +821,65 @@ gmac_close(struct device *dev) return 0; } +#ifdef CONFIG_PMAC_PBOOK +int +gmac_sleep_notify(struct pmu_sleep_notifier *self, int when) +{ + struct gmac *gm; + int i; + + /* XXX should handle more than one */ + if (gmacs == NULL) + return PBOOK_SLEEP_OK; + + gm = (struct gmac *) gmacs->priv; + if (!gm->opened) + return PBOOK_SLEEP_OK; + + switch (when) { + case PBOOK_SLEEP_REQUEST: + break; + case PBOOK_SLEEP_REJECT: + break; + case PBOOK_SLEEP_NOW: + disable_irq(gm->dev->irq); + gm->dev->tbusy = 1; + gmac_stop_dma(gm); + mii_poll_stop(gm); + gmac_set_power(gm, 0); + for (i = 0; i < NRX; ++i) { + if (gm->rx_buff[i] != 0) { + dev_kfree_skb(gm->rx_buff[i]); + gm->rx_buff[i] = 0; + } + } + for (i = 0; i < NTX; ++i) { + if (gm->tx_buff[i] != 0) { + dev_kfree_skb(gm->tx_buff[i]); + gm->tx_buff[i] = 0; + } + } + break; + case PBOOK_WAKE: + /* see if this is enough */ + gmac_powerup_and_reset(gm->dev); + gm->full_duplex = 0; + gm->phy_status = 0; + mii_lookup_and_reset(gm); + mii_setup_phy(gm); + gmac_init_rings(gm, 0); + gmac_mac_init(gm, gm->dev->dev_addr); + gmac_set_multicast(gm->dev); + mii_interrupt(gm); + gmac_start_dma(gm); + gm->dev->tbusy = 0; + enable_irq(gm->dev->irq); + break; + } + return PBOOK_SLEEP_OK; +} +#endif /* CONFIG_PMAC_PBOOK */ + /* * Handle a transmit timeout */ @@ -712,12 +889,11 @@ gmac_tx_timeout(struct device *dev) struct gmac *gm = (struct gmac *) dev->priv; int i, timeout; unsigned long flags; - - save_flags(flags); - cli(); printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); + spin_lock_irqsave(&gm->lock, flags); + /* * Do something useful here * @@ -758,7 +934,7 @@ gmac_tx_timeout(struct device *dev) /* Restart chip */ gmac_start_dma(gm); - restore_flags(flags); + spin_unlock_irqrestore(&gm->lock, flags); dev->tbusy = 0; } @@ -770,6 +946,7 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev) struct gmac *gm = (struct gmac *) dev->priv; volatile struct gmac_dma_desc *dp; int i; + unsigned long flags; /* Check tbusy bit and handle eventual transmitter timeout */ if(test_and_set_bit(0, (void *) &dev->tbusy) != 0) { @@ -780,9 +957,12 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev) return 1; } + spin_lock_irqsave(&gm->lock, flags); + i = gm->next_tx; if (gm->tx_buff[i] != 0) { /* buffer is full, can't send this packet at the moment */ + spin_unlock_irqrestore(&gm->lock, flags); return 1; } gm->next_tx = (i + 1) & (NTX - 1); @@ -804,6 +984,8 @@ gmac_xmit_start(struct sk_buff *skb, struct device *dev) dev->tbusy = (gm->tx_buff[gm->next_tx] != 0); + spin_unlock_irqrestore(&gm->lock, flags); + return 0; } @@ -820,9 +1002,8 @@ gmac_tx_cleanup(struct device *dev, int force_cleanup) int gone, i; i = gm->tx_gone; - gone = GM_IN(GM_TX_COMP); - - while (force_cleanup || i != gone) { + do { + gone = GM_IN(GM_TX_COMP); skb = gm->tx_buff[i]; if (skb == NULL) break; @@ -837,7 +1018,7 @@ gmac_tx_cleanup(struct device *dev, int force_cleanup) dev_kfree_skb(skb); if (++i >= NTX) i = 0; - } + } while (force_cleanup || i != gone); gm->tx_gone = i; if (!force_cleanup && dev->tbusy && @@ -987,15 +1168,23 @@ gmac_interrupt(int irq, void *dev_id, struct pt_regs *regs) } if (status & GM_IRQ_MIF) { + spin_lock(&gm->lock); mii_interrupt(gm); + spin_unlock(&gm->lock); } - if (status & GM_IRQ_RX_DONE) + if (status & GM_IRQ_RX_DONE) { + spin_lock(&gm->lock); gmac_receive(dev); - - if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) + spin_unlock(&gm->lock); + } + + if (status & (GM_IRQ_TX_INT_ME | GM_IRQ_TX_ALL)) { + spin_lock(&gm->lock); gmac_tx_cleanup(dev, 0); - + spin_unlock(&gm->lock); + } + dev->interrupt = 0; } @@ -1076,10 +1265,12 @@ gmac_probe(struct device *dev) dev->base_addr = gmac->addrs[0].address; gm->regs = (volatile unsigned int *) ioremap(gmac->addrs[0].address, 0x10000); - gm->sysregs = (volatile unsigned int *) ioremap(0xf8000000, 0x1000); dev->irq = gmac->intrs[0].line; gm->dev = dev; - + gm->of_node = gmac; + + spin_lock_init(&gm->lock); + if (pci_device_loc(gmac, &gm->pci_bus, &gm->pci_devfn)) { gm->pci_bus = gm->pci_devfn = 0xff; printk(KERN_ERR "Can't locate GMAC PCI entry\n"); @@ -1117,6 +1308,9 @@ gmac_probe(struct device *dev) gmacs = dev; +#ifdef CONFIG_PMAC_PBOOK + pmu_register_sleep_notifier(&gmac_sleep_notifier); +#endif return 0; } diff --git a/drivers/net/gmac.h b/drivers/net/gmac.h index 6473ec54eb15..128e3f2076c7 100644 --- a/drivers/net/gmac.h +++ b/drivers/net/gmac.h @@ -730,8 +730,9 @@ */ /* Supported PHYs (phy_type field ) */ -#define PHY_B5400 5400 -#define PHY_B5201 5201 +#define PHY_B5400 0x5400 +#define PHY_B5201 0x5201 +#define PHY_LXT971 0x0971 #define PHY_UNKNOWN 0 /* Identification (for multi-PHY) */ @@ -745,6 +746,11 @@ #define MII_BCM5400_REV 0x01 #define MII_BCM5400_ID ((MII_BCM5400_OUI << 10) | (MII_BCM5400_MODEL << 4)) #define MII_BCM5400_MASK 0xfffffff0 +#define MII_LXT971_OUI 0x0004de +#define MII_LXT971_MODEL 0x0e +#define MII_LXT971_REV 0x00 +#define MII_LXT971_ID ((MII_LXT971_OUI << 10) | (MII_LXT971_MODEL << 4)) +#define MII_LXT971_MASK 0xfffffff0 /* BCM5201 AUX STATUS register */ #define MII_BCM5201_AUXCTLSTATUS 0x18 @@ -764,6 +770,26 @@ #define MII_BCM5201_MULTIPHY_SERIALMODE 0x0002 #define MII_BCM5201_MULTIPHY_SUPERISOLATE 0x0008 +/* MII BCM5400 1000-BASET Control register */ +#define MII_BCM5400_GB_CONTROL 0x09 +#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200 + +/* MII BCM5400 AUXCONTROL register */ +#define MII_BCM5400_AUXCONTROL 0x18 +#define MII_BCM5400_AUXCONTROL_PWR10BASET 0x0004 + +/* MII BCM5400 AUXSTATUS register */ +#define MII_BCM5400_AUXSTATUS 0x19 +#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8 + +/* MII LXT971 STATUS2 register */ +#define MII_LXT971_STATUS2 0x11 +#define MII_LXT971_STATUS2_SPEED 0x4000 +#define MII_LXT971_STATUS2_LINK 0x0400 +#define MII_LXT971_STATUS2_FULLDUPLEX 0x0200 +#define MII_LXT971_STATUS2_AUTONEG_COMPLETE 0x0080 + /* @@ -829,8 +855,8 @@ struct gmac_dma_desc { struct gmac { volatile unsigned int *regs; /* hardware registers, virtual addr */ - volatile unsigned int *sysregs; struct device *dev; + struct device_node *of_node; unsigned long tx_desc_page; /* page for DMA descriptors */ unsigned long rx_desc_page; /* page for DMA descriptors */ volatile struct gmac_dma_desc *rxring; @@ -845,9 +871,11 @@ struct gmac { int phy_type; int phy_status; /* Cached PHY status */ int full_duplex; /* Current set to full duplex */ + int gigabit; /* Current set to 1000BT */ struct net_device_stats stats; u8 pci_bus; u8 pci_devfn; + spinlock_t lock; int opened; }; diff --git a/drivers/net/hdlc.c b/drivers/net/hdlc.c index a248b27227ed..2ac145a1198e 100644 --- a/drivers/net/hdlc.c +++ b/drivers/net/hdlc.c @@ -50,6 +50,7 @@ static const char* version = "HDLC support routines revision: 1.0"; #define CISCO_ADDR_REQ 0 /* Cisco address request */ #define CISCO_ADDR_REPLY 1 /* Cisco address reply */ #define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ +#define CISCO_SYS_INFO 0x2000 /* Cisco interface/system info */ static int hdlc_ioctl(struct device *dev, struct ifreq *ifr, int cmd); @@ -141,6 +142,11 @@ static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb) return; #endif + case CISCO_SYS_INFO: + /* Packet is not needed, drop it. */ + dev_kfree_skb(skb); + return; + case CISCO_KEEPALIVE: if (skb->len != CISCO_PACKET_LEN && skb->len != CISCO_BIG_PACKET_LEN) { @@ -206,7 +212,7 @@ static void cisco_netif(hdlc_device *hdlc, struct sk_buff *skb) } /* switch(keepalive type) */ } /* switch(protocol) */ - printk(KERN_INFO "%s: Unusupported protocol %x\n", hdlc->name, + printk(KERN_INFO "%s: Unsupported protocol %x\n", hdlc->name, data->protocol); hdlc->stats.rx_bytes+=skb->len; hdlc->stats.rx_packets++; diff --git a/drivers/s390/Config.in b/drivers/s390/Config.in index b8a092c54175..53f5b894d237 100644 --- a/drivers/s390/Config.in +++ b/drivers/s390/Config.in @@ -52,7 +52,7 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then comment 'S390 Network devices' - bool 'CTC device support' CONFIG_CTC + tristate 'CTC device support' CONFIG_CTC bool 'IUCV device support (VM only)' CONFIG_IUCV tristate 'Dummy net driver support' CONFIG_DUMMY bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index ad92e36a1ccc..89174105a268 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -11,18 +11,17 @@ all: io.o CFLAGS += O_TARGET := io.o -O_OBJS := ccwcache.o +O_OBJS := ccwcache.o idals.o M_OBJS := SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \ arch/s390/drivers/misc arch/s390/drivers/net MOD_SUB_DIRS += ./net ./block -O_OBJS := block/s390-block.o \ +O_OBJS += block/s390-block.o \ char/s390-char.o \ misc/s390-misc.o \ - net/s390-net.o \ - ccwcache.o + net/s390-net.o io.o: $(O_OBJS) @@ -38,5 +37,4 @@ misc/s390-misc.o: dummy net/s390-net.o: dummy $(MAKE) -C net - include $(TOPDIR)/Rules.make diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile index 94d89876b69c..53ab87600e4d 100644 --- a/drivers/s390/block/Makefile +++ b/drivers/s390/block/Makefile @@ -2,7 +2,7 @@ all: s390-block.o CFLAGS += O_TARGET := s390-block.o -O_OBJS := +O_OBJS := M_OBJS := D_OBJS := diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 42107addd607..19557d044340 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -11,7 +11,7 @@ Adapted request function to make it work on 2.4 * 07/10/00 Added some code to the request function to dequeue requests that cannot be handled due to errors - * 07/10/00 Moved linux/ccwcache.h to asm/ + * 07/10/00 Moved linux/dasd.h and linux/ccwcache.h to asm/ * 07/10/00 Fixed a bug when formatting a 'new' device * 07/10/00 Removed an annoying message from dasd_format * 07/11/00 Reanimated probeonly mode @@ -20,9 +20,25 @@ * 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices * 07/13/00 fixed error message when having no device * 07/13/00 added code for dynamic device recognition + * 07/14/00 reorganized the format process for better ERP + * 07/17/00 fixed a race condition when sleeping on a request + * 07/17/00 modified default ERP action to use TIC instead of NOP + * 07/20/00 fixed proc filesystem for 2.4 + * 07/24/00 fixed missing interrupt handler + * 08/01/00 fixed a race condition when sleeping on a request + * 09/15/00 fixed a race condition on dasd_do_chanq + * 09/15/00 got rid of some paranoia + * 09/18/00 fixed the state machine for duplicate devnos in dasd ranges + * 10/26/00 fixed ITPM PL020141RSC load module to a kernel with static driver + are the fixes in dasd_init + * 10/26/00 fixed ITPM PL020062RSC formatting r/o volume + are the fixes in dasd_format + * 10/26/00 fixed ITPM PL010261EPA race condition when formatting + are the fixes in dasd_do_chanq */ #include +#include #include #include #include @@ -34,6 +50,12 @@ #include #include #include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include +#else +#include +#endif + #include #include #include @@ -49,15 +71,15 @@ #include #include #include -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -#include -#endif /* LINUX_IS_24 */ #include #include #include #include #include #include +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include +#endif /* LINUX_IS_24 */ #include "dasd.h" #ifdef CONFIG_DASD_ECKD @@ -73,7 +95,7 @@ #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static struct block_device_operations dasd_device_operations; #endif /* VERSION_CODE */ - + #ifdef MODULE #define EXPORT_SYMTAB #include @@ -113,7 +135,6 @@ static void do_dasd_request (void); static void dasd_do_chanq (void); static void schedule_request_fn (void (*func) (void)); static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int); -static int dasd_oper_handler ( int irq, devreg_t *devreg ); /* SECTION: managing setup of dasd_driver */ typedef struct dasd_range_t { @@ -145,7 +166,7 @@ dasd_create_devreg ( int devno ) { } return r; } - + static void dasd_add_range (int from, int to) { @@ -162,7 +183,7 @@ dasd_add_range (int from, int to) } else { range -> to = to; } - + /* chain current range to end of list */ if ( dasd_range_head == NULL ) { dasd_range_head = range; @@ -226,7 +247,7 @@ dasd_split_parm_string ( char * str ) count ++; tmp = end; } while ( tmp != NULL && *tmp != '\0' ); - } +} static char dasd_parm_string[1024] = {0,}; @@ -239,12 +260,12 @@ dasd_setup (char *str) *(dasd_parm_string+strlen(dasd_parm_string))=','; } else { first_time = 0; - } + } memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1); return 1; } #else -void +void dasd_setup (char *str, int *ints) { static int first_time = 1; @@ -269,7 +290,7 @@ dasd_parse (char **str) { char *temp; int from, to; - + if ( *str ) { dasd_probeonly = 0; } @@ -284,19 +305,19 @@ dasd_parse (char **str) } else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) { dasd_probeonly = 1; printk (KERN_INFO "turning to probeonly mode\n"); - break; + break; } else { dasd_autodetect = 0; from = dasd_strtoul (temp, &temp); if (*temp == '-') { temp++; to = dasd_strtoul (temp, &temp); - } + } dasd_add_range (from, to); - } + } str ++; - } - } + } +} int devindex_from_devno (int devno) @@ -310,11 +331,11 @@ devindex_from_devno (int devno) devindex += devno - temp -> from; break; } - } + } if ( temp == NULL ) return -ENODEV; return devindex; - } +} /* SECTION: ALl needed for multiple major numbers */ @@ -335,7 +356,7 @@ static major_info_t dasd_major_info[] = #endif /* LINUX_IS_24 */ nr_real:DASD_PER_MAJOR, } - } + } #if 0 , { @@ -352,8 +373,8 @@ static major_info_t dasd_major_info[] = max_nr:DASD_PER_MAJOR, #endif /* LINUX_IS_24 */ nr_real:DASD_PER_MAJOR, - } } + } #endif }; @@ -361,7 +382,7 @@ static dasd_device_t * find_dasd_device (int devindex) { major_info_t *major_info = dasd_major_info; - while (major_info && devindex > DASD_PER_MAJOR) { + while (major_info && devindex >= DASD_PER_MAJOR) { devindex -= DASD_PER_MAJOR; major_info = major_info->next; } @@ -374,12 +395,12 @@ static major_info_t * major_info_from_devindex (int devindex) { major_info_t *major_info = dasd_major_info; - while (major_info && devindex > DASD_PER_MAJOR) { + while (major_info && devindex >= DASD_PER_MAJOR) { devindex -= DASD_PER_MAJOR; major_info = major_info->next; } return major_info; - } +} int major_from_devindex (int devindex) @@ -413,7 +434,7 @@ static spinlock_t discipline_lock; * void dasd_discipline_enq (dasd_discipline_t * d) */ -void +void dasd_discipline_enq (dasd_discipline_t * d) { spin_lock (&discipline_lock); @@ -473,14 +494,14 @@ dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr) static void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr) - { +{ cqr->next = q->head; q->head = cqr; if (q->tail == NULL) q->tail = cqr; q->queued_requests++; atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED); - } +} /* * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) @@ -507,7 +528,7 @@ dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr) if (prev->next == NULL) q->tail = prev; } - cqr->next = NULL; +/* cqr->next = NULL; */ q->queued_requests--; return 0; } @@ -520,6 +541,8 @@ static spinlock_t cq_lock; /* spinlock for cq_head */ #else static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED; /* spinlock for cq_head */ #endif /* LINUX_IS_24 */ +#else +int cq_lock; #endif /* __SMP__ */ static dasd_chanq_t *qlist_head = NULL; /* head of queue of queues */ @@ -532,18 +555,19 @@ static dasd_chanq_t *qlist_head = NULL; /* head of queue of queues */ static void qlist_enq (dasd_chanq_t * q) { + long flags; if (q == NULL) { printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n"); return; } - spin_lock (&cq_lock); + spin_lock_irqsave (&cq_lock,flags); if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) { printk (KERN_WARNING PRINTK_HEADER " Queue already active"); } atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags); q->next_q = qlist_head; qlist_head = q; - spin_unlock (&cq_lock); + spin_unlock_irqrestore (&cq_lock,flags); } /* @@ -555,8 +579,8 @@ qlist_enq (dasd_chanq_t * q) static void qlist_deq (dasd_chanq_t * q) { - - if (qlist_head == NULL) { + long flags; + if (qlist_head == NULL) { printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", ""); return; } @@ -564,7 +588,7 @@ qlist_deq (dasd_chanq_t * q) printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n"); return; } - spin_lock (&cq_lock); + spin_lock_irqsave (&cq_lock,flags); if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) { printk (KERN_WARNING PRINTK_HEADER " Queue not active\n"); } else if (qlist_head == q) { @@ -580,7 +604,7 @@ qlist_deq (dasd_chanq_t * q) } atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags); q->next_q = NULL; - spin_unlock (&cq_lock); + spin_unlock_irqrestore (&cq_lock,flags); } /* SECTION: All the gendisk stuff */ @@ -608,7 +632,7 @@ dasd_partn_detect (int devindex) resetup_one_dev(dd,minor>>DASD_PARTN_BITS); #endif /* LINUX_IS_24 */ return rc; - } +} /* SECTION: Managing wrappers for ccwcache */ @@ -623,8 +647,8 @@ dasd_init_emergency_req ( void ) int i; for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) { dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL); - } } +} static void dasd_cleanup_emergency_req ( void ) @@ -654,6 +678,7 @@ dasd_alloc_request (char *magic, int cplength, int datasize) if ( dasd_emergency_req[i] != NULL ) { rv = dasd_emergency_req[i]; dasd_emergency_req[i] = NULL; + break; } } spin_unlock(&dasd_emergency_req_lock); @@ -670,15 +695,15 @@ dasd_alloc_request (char *magic, int cplength, int datasize) return rv; } -void +void dasd_free_request (ccw_req_t * request) { if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req && request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) { *((ccw_req_t **)(request -> cache)) = request; - } else { + } else { ccw_free_request(request); - } + } } /* SECTION: Managing the device queues etc. */ @@ -718,7 +743,7 @@ try_request_fn (void) major_info_t *mi; for (mi=dasd_major_info; mi != NULL; mi = mi->next ) { do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major)); - } + } } #else do_dasd_request (); @@ -754,10 +779,10 @@ dasd_start_IO (ccw_req_t * cqr) major_info_t *major_info; struct request *req; - if (!cqr) { + if (!cqr) { printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function"); return -EINVAL; - } + } irq = device->devinfo.irq; devno = device->devinfo.devno; req = (struct request *) cqr->req; @@ -776,39 +801,39 @@ dasd_start_IO (ccw_req_t * cqr) return -EINVAL; } atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO); - do { + do { asm volatile ("STCK %0":"=m" (cqr->startclk)); rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options); switch (rc) { case 0: if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) { atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags); - } + } if ( cqr->expires ) { cqr->expires += cqr->startclk; - } - break; + } + break; case -ENODEV: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " appears not to be present %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; case -EIO: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " I/O error %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; case -EBUSY: /* set up timer, try later */ printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " is busy %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, retries); - break; + break; default: printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -816,26 +841,63 @@ dasd_start_IO (ccw_req_t * cqr) " Pls report this message to linux390@de.ibm.com\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc, retries); - break; - } + break; + } } while (rc && retries--); if (rc) { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR); - } + } return rc; - } +} + + +static int +sleep_on_req ( ccw_req_t * req ) +{ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + DECLARE_WAITQUEUE (wait,current); +#else + struct wait_queue wait = {current, NULL}; +#endif /* LINUX_VERSION_CODE */ + unsigned long flags; + int cs; + int rc = 0; + dasd_device_t *device = (dasd_device_t *)req->device; + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + dasd_chanq_enq (&device->queue, req); + if (!(atomic_read (&device->queue.flags) & DASD_CHANQ_ACTIVE)) { + qlist_enq (&device->queue); + } + dasd_schedule_bh(); + add_wait_queue (&device->wait_q, &wait); + do { + current->state = TASK_INTERRUPTIBLE; + s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); + schedule (); + s390irq_spin_lock_irqsave (device->devinfo.irq, flags); + cs = atomic_read (&req->status); + } while ( ! (cs & CQR_STATUS_FINISHED) ); + /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ + remove_wait_queue (&device->wait_q, &wait); + s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); + if ( cs & CQR_STATUS_FAILED ) { + rc = -EIO; + } + return rc; +} + static void dasd_end_request (struct request *req, int uptodate) { struct buffer_head *bh; while ((bh = req->bh) != NULL) { - req->bh = bh->b_reqnext; + req->bh = bh->b_reqnext; bh->b_reqnext = NULL; bh->b_end_io (bh, uptodate); - } + } if (!end_that_request_first (req, uptodate, DASD_NAME)) { #ifndef DEVICE_NO_RANDOM add_blkdev_randomness (MAJOR (req->rq_dev)); @@ -871,7 +933,7 @@ do_dasd_request (void) major_info_t *major_info; int devno; int major; - + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) { @@ -894,34 +956,34 @@ do_dasd_request (void) #else for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) { major = major_info->gendisk.major; - prev = NULL; - for (req = CURRENT; req != NULL; req = next) { - next = req->next; + prev = NULL; + for (req = CURRENT; req != NULL; req = next) { + next = req->next; if (req == &blk_dev[major].plug) { /* remove plug if applicable */ req->next = NULL; - if (prev) { - prev->next = next; - } else { - CURRENT = next; - } + if (prev) { + prev->next = next; + } else { + CURRENT = next; + } continue; - } + } #endif /* LINUX_IS_24 */ devindex = devindex_from_kdev_t(req->rq_dev); if ( devindex < 0 ) { printk ( KERN_WARNING PRINTK_HEADER "requesting I/O on nonexistent device %d -> %d\n", devindex,req->rq_dev); - dasd_end_request (req, 0); + dasd_end_request(req,0); #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) blkdev_dequeue_request (req); #else req->next = NULL; if (prev) { prev->next = next; - } else { + } else { CURRENT = next; - } + } #endif /* LINUX_IS_24 */ continue; } @@ -1068,43 +1130,45 @@ dasd_do_chanq (void) volatile int cqrstatus; for (qp = qlist_head; qp != NULL; qp = nqp) { + + device = (dasd_device_t *)((long)qp - (long)offsetof(dasd_device_t,queue)); + irq = device->devinfo.irq; + + s390irq_spin_lock_irqsave (irq, flags); + /* Get first request */ cqr = (ccw_req_t *) (qp->head); nqp = qp->next_q; /* empty queue -> dequeue and proceed */ if (!cqr) { qlist_deq (qp); + s390irq_spin_unlock_irqrestore(irq,flags); continue; } + s390irq_spin_unlock_irqrestore(irq,flags); + /* process all requests on that queue */ do { - dasd_discipline_t *discipline; + dasd_discipline_t *discipline=device->discipline; next = NULL; - /* Sanity check... walk through disciplines */ - for (discipline = dasd_disciplines; - discipline != NULL; - discipline = discipline->next) - if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) - break; - if (!discipline) { /* 1st sanity check */ + + if (strncmp ((char *) &cqr->magic, discipline->ebcname, 4)) { panic (PRINTK_HEADER "in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n", cqr, cqr->magic); } - device = (dasd_device_t *) (cqr->device); - if (discipline != device->discipline) { /* 1st sanity check */ - printk (KERN_WARNING PRINTK_HEADER - "in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n", - cqr, cqr->magic); - discipline = device->discipline; + if ( device != cqr->device ) { + panic (PRINTK_HEADER + "in dasd_do_chanq: device mismatch %p -> %p(qcr) vs. %p\n", + cqr, cqr->device,device); } - irq = device->devinfo.irq; devno = device->devinfo.devno; devindex = devindex_from_devno (devno); - s390irq_spin_lock_irqsave (irq, flags); - + s390irq_spin_lock_irqsave (irq, + flags); cqrstatus = atomic_read (&cqr->status); + switch (cqrstatus) { case CQR_STATUS_QUEUED: if (discipline->start_IO && @@ -1118,8 +1182,8 @@ dasd_do_chanq (void) case EBUSY: if (cqr->retries--) { printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " retrying %d retries left\n", + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:" + " retrying ... %d retries left\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries); break; } @@ -1128,24 +1192,29 @@ dasd_do_chanq (void) " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Giving up this request!\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED); + + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_QUEUED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); break; } } } break; case CQR_STATUS_IN_IO:{ - unsigned long long now; - unsigned long long delta; - + unsigned long long now; + unsigned long long delta; + asm volatile ("STCK %0":"=m" (now)); if (cqr->expires && cqr->startclk && cqr->expires < now) { delta = cqr->expires - cqr->startclk; printk (KERN_ERR PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " I/O operation outstanding longer than %Ld usecs on req %p\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr); + " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", + devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); + cqr->expires += delta; +#if 0 if ( cqr->retries-- ) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -1159,46 +1228,45 @@ dasd_do_chanq (void) " You should disable that device by issueing '@#?!'\n", /* FIXME */ devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT); break; } +#endif } break; - } + } case CQR_STATUS_ERROR:{ - dasd_erp_action_fn_t erp_action; - ccw_req_t *erp_cqr = NULL; - if (discipline->erp_action && - ((erp_action = discipline->erp_action (cqr)) != NULL)) { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Taking error recovery action %p on req %p \n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr); - erp_cqr = erp_action (cqr); - } else { - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " No error recovery action\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); - atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); - } - if ( erp_cqr != NULL ) { - dasd_chanq_enq_head (qp, erp_cqr); - next = erp_cqr; /* prefer execution of erp ccw */ - } + dasd_erp_action_fn_t erp_action; + ccw_req_t *erp_cqr = NULL; + + if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) { + atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED); + next = cqr; + } else if ( cqr -> retries-- && + cqr -> refers == NULL && + discipline -> erp_action != NULL && + (erp_action = discipline->erp_action (cqr)) != NULL && + (erp_cqr = erp_action (cqr)) != NULL ) { + dasd_chanq_enq_head (qp, erp_cqr); + next = erp_cqr; /* prefer execution of erp ccw */ + } else { + atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); + next = cqr; + } break; } case CQR_STATUS_DONE:{ dasd_erp_postaction_fn_t erp_postaction; next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if (discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing successful error recovery action %p\n", + " postprocessing successful error recovery action using %p\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); erp_postaction (cqr, 1); - atomic_dec (&device->queue.dirty_requests); } else { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" @@ -1207,68 +1275,93 @@ dasd_do_chanq (void) devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); } + atomic_dec (&device->queue.dirty_requests); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else if ( cqr->req ) { - asm volatile ("STCK %0":"=m" (cqr->endclk)); dasd_end_request (cqr->req, 1); #ifdef DASD_PROFILE dasd_profile_add (cqr); #endif /* DASD_PROFILE */ - } - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ + } else { + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_DONE, + CQR_STATUS_DONE | CQR_STATUS_FINISHED); + dasd_chanq_deq (&device->queue, cqr); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + wake_up (&device->wait_q); +#else + if (device->wait_q) { + wake_up (&device->wait_q); + } +#endif /* LINUX_IS_24 */ + } break; } case CQR_STATUS_FAILED:{ dasd_erp_postaction_fn_t erp_postaction; next = cqr->next; + asm volatile ("STCK %0":"=m" (cqr->endclk)); if (cqr->refers && cqr->function) { /* we deal with an ERP */ - if (discipline->erp_postaction && - ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { + if ( discipline->erp_postaction && + ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " postprocessing unsuccessful error recovery action %p\n", + " postprocessing unsuccessful error recovery action using %p\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction); erp_postaction (cqr, 0); - atomic_dec (&device->queue.dirty_requests); - } else { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " No procedure to postprocess unsuccessful error recovery action" - " giving up request", + " giving up request", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED); } + atomic_dec (&device->queue.dirty_requests); + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else if (cqr->req) { - asm volatile ("STCK %0":"=m" (cqr->endclk)); dasd_end_request (cqr->req, 0); #ifdef DASD_PROFILE dasd_profile_add (cqr); #endif /* DASD_PROFILE */ + dasd_chanq_deq (&device->queue, cqr); + dasd_free_request(cqr); /* Only free request if nobody is waiting on it */ } else { - printk (KERN_WARNING PRINTK_HEADER - "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" - " refers = %p,function = %p, request = %p" - " Pls send this message and your System.map to" - " linux390@de.ibm.com\n", - __LINE__, cqr->refers, cqr->function, cqr->req); - } - dasd_chanq_deq (&device->queue, cqr); - dasd_free_request(cqr); + /* during format we don't have the request structure */ + /* notify sleeping task about finished postprocessing */ + atomic_compare_and_swap_debug (&cqr->status, + CQR_STATUS_FAILED, + CQR_STATUS_FAILED | CQR_STATUS_FINISHED); + + dasd_chanq_deq (&device->queue, cqr); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + wake_up (&device->wait_q); +#else + if (device->wait_q) { + wake_up (&device->wait_q); + } +#endif /* LINUX_IS_24 */ + } break; } + default:{ printk (KERN_WARNING PRINTK_HEADER "Internal error in " __FILE__ " on line %d." - " inconsistent content of ccw_req_t" + " inconsistent content of ccw_req_t" " cqrstatus = %d" " Pls send this message and your System.map to" " linux390@de.ibm.com\n", __LINE__, cqrstatus); + } } - } - s390irq_spin_unlock_irqrestore (irq, flags); + s390irq_spin_unlock_irqrestore (irq, flags); } while ((cqr = next) != NULL); } schedule_request_fn (try_request_fn); @@ -1286,9 +1379,9 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) dasd_device_t *device; int devno = -1, devindex = -1; -#undef ERP_DEBUG +#undef ERP_DEBUG #ifdef ERP_DEBUG - static int counter = 0; + static int counter = 0; #endif if (!stat) { @@ -1301,11 +1394,11 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) stat->devno); return; } - if (ip & 0x80000001) { + if (ip & 0x80000001) { PRINT_INFO ("%04X caught spurious interrupt with parm %08x\n", stat->devno, ip); - return; - } + return; + } cqr = (ccw_req_t *) ip; device = (dasd_device_t *) cqr->device; devno = device->devinfo.devno; @@ -1341,10 +1434,11 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) cqr->magic, *(int *) (&device->discipline->name)); return; } - asm volatile ("STCK %0":"=m" (cqr->stopclk)); - if ((stat->cstat == 0x00 && - stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || - (device->discipline->examine_error && + asm volatile ("STCK %0":"=m" (cqr->stopclk)); + if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) && + stat->cstat == 0x00 && + stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) || + (device->discipline->examine_error && (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) { #ifdef ERP_DEBUG if ( ++counter % 137 == 0 ) { @@ -1353,20 +1447,20 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL; stat->dstat |= 0x02; goto error_fake_done; - } + } #endif atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE); atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, &device->level); - if (cqr->next && - (atomic_read (&cqr->next->status) == - CQR_STATUS_QUEUED)) { - if (dasd_start_IO (cqr->next) == 0) { - done_fast_io = 1; + if (cqr->next && + (atomic_read (&cqr->next->status) == + CQR_STATUS_QUEUED)) { + if (dasd_start_IO (cqr->next) == 0) { + done_fast_io = 1; } } - } else { /* only visited in case of error ! */ + } else { /* only visited in case of error ! */ #ifdef ERP_DEBUG error_fake_done: #endif @@ -1375,7 +1469,7 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) if (cqr->dstat) { memcpy (cqr->dstat, stat, sizeof (devstat_t)); } else { - PRINT_ERR ("no memory for dstat\n"); + PRINT_ERR ("no memory for dstat\n"); } if (device->discipline && device->discipline->dump_sense) { @@ -1390,14 +1484,14 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) } atomic_inc (&device->queue.dirty_requests); /* errorprocessing */ - if (era == dasd_era_fatal) { - PRINT_WARN ("ERP returned fatal error\n"); + if (era == dasd_era_fatal) { + PRINT_WARN ("ERP returned fatal error\n"); atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_IN_IO, CQR_STATUS_FAILED); - } else { + CQR_STATUS_IN_IO, CQR_STATUS_FAILED); + } else { atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR); - } + } } if (done_fast_io == 0) atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags); @@ -1412,56 +1506,30 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs) dasd_schedule_bh (); } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) -static wait_queue_head_t watcher_queue; -#else -static struct wait_queue watcher_queue_Qend = {NULL,}; -static struct wait_queue *watcher_queue = &watcher_queue_Qend; -#endif /* LINUX_IS_24 */ - -static void -dasd_watcher (void) -{ - do { - dasd_schedule_bh (); - schedule_request_fn (try_request_fn); - interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ); - } while (1); - } - /* SECTION: Some stuff related to error recovery */ ccw_req_t * default_erp_action (ccw_req_t * cqr) { ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0); - - erp->cpaddr->cmd_code = CCW_CMD_NOOP; + + erp->cpaddr->cmd_code = CCW_CMD_TIC; + erp->cpaddr->cda = (__u32)cqr -> cpaddr; erp->function = default_erp_action; erp->refers = cqr; erp->device = cqr->device; erp->magic = cqr->magic; + erp->retries = 16; atomic_set (&erp->status, CQR_STATUS_FILLED); - if ( cqr->startclk && cqr->expires ) - cqr->expires -= cqr->startclk; - - if (cqr->retries++ <= 16) { - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_ERROR, - CQR_STATUS_QUEUED); - } else { - printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n"); - atomic_compare_and_swap_debug (&cqr->status, - CQR_STATUS_ERROR, - CQR_STATUS_FAILED); + if ( cqr->startclk && cqr->expires ) { + /* cqr->expires -= cqr->startclk; */ } - return erp; + return erp; } int default_erp_postaction (ccw_req_t * cqr, int success) { - int rc = 0; if (cqr->refers == NULL || cqr->function == NULL) { printk (KERN_WARNING PRINTK_HEADER "ERP postaction called for non ERP cqr\n"); @@ -1471,55 +1539,183 @@ default_erp_postaction (ccw_req_t * cqr, int success) printk (KERN_WARNING PRINTK_HEADER "default ERP postaction called for non default ERP cqr\n"); return -EINVAL; - } - return rc; + } + if ( success ) { + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_DONE); + } else { + atomic_compare_and_swap_debug (&cqr->refers->status, + CQR_STATUS_ERROR, + CQR_STATUS_FAILED); + } + return 0; } /* SECTION: The helpers of the struct file_operations */ +/* + * int dasd_format ( device* device, format_data_t *fdata ) + * performs formatting of _device_ according to _fdata_ + * Note: The discipline's format_function is assumed to deliver formatting + * commands to format a single unit of the device. In terms of the ECKD + * devices this means CCWs are generated to format a single track. + */ + static int dasd_format (dasd_device_t * device, format_data_t * fdata) { - int rc = 0; - int devno = device->devinfo.devno; - int irq = device->devinfo.irq; - int devindex = devindex_from_devno (devno); - + int rc = 0; + int devno = device->devinfo.devno; + int irq = device->devinfo.irq; + int devindex = devindex_from_devno (devno); + ccw_req_t *req = NULL; + if (device->open_count != 1) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " you shouldn't format a device that is already open\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS); + " you shouldn't format a device that is already open\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); return -EINVAL; } + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Starting format process\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + dasd_set_device_level( device->devinfo.irq, DASD_DEVICE_LEVEL_RECOGNIZED, device->discipline, 0); - if (device->discipline->format_device) - rc = device->discipline->format_device (device, fdata); - if (rc) { + + if (device->discipline->format_device) { + format_data_t temp = { + fdata->start_unit, + fdata->stop_unit, + fdata->blksize, + fdata->intensity}; printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Formatting failed with rc = %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); - return rc; - } - printk (KERN_WARNING PRINTK_HEADER - " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Formatting finished successfully rc = %d\n", - devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc); + " invalidating disk...\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT && + fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + !(fdata -> intensity & 0x04)) { + format_data_t temp2 = { 0,0,DASD_FORMAT_DEFAULT_BLOCKSIZE,0x04}; + req = device->discipline->format_device (device,&temp2); + + if ( req ) { + rc = sleep_on_req(req); + dasd_free_request(req); /* request is no longer used */ + } else { + rc = -EINVAL; + } + if ( rc ) { + printk (KERN_WARNING PRINTK_HEADER "Can't invalidate Track 0\n"); + } + temp.start_unit++; + } + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " ...invalidation done.\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + while ((!rc ) && + ((req = device->discipline->format_device (device, &temp)) != NULL ) ) { + + if ( rc=sleep_on_req(req) ) { + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Formatting failed with rc = %d\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS, + rc); + break; + } + dasd_free_request(req); /* request is no longer used */ + temp.start_unit++; + } /* end if no more requests */ + + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " revalidating disk...\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + + if (!rc && + req == NULL ) { + if ( fdata -> start_unit == DASD_FORMAT_DEFAULT_START_UNIT && + fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT && + !(fdata -> intensity & 0x04)) { + format_data_t temp2 = { 0,0,fdata->blksize,fdata->intensity}; + + req = device->discipline->format_device (device, + &temp2); + if ( req ) { + rc = sleep_on_req(req); + dasd_free_request(req); /* request is no longer used */ + } else { + rc = -EINVAL; + } + if ( rc ) { + printk (KERN_WARNING PRINTK_HEADER "Can't revalidate Track 0\n"); + } + } + } + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " ...revalidation done\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + } /* end if discipline->format_device */ + printk (KERN_WARNING PRINTK_HEADER + " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" + " Formatting finished successfully\n", + devno, + irq, + device->name, + major_from_devindex (devindex), + devindex << DASD_PARTN_BITS); + dasd_set_device_level( device->devinfo.irq, - DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, device->discipline, 0); udelay(1500000); + dasd_set_device_level( device->devinfo.irq, DASD_DEVICE_LEVEL_ANALYSED, device->discipline, 0); + return rc; -} +} /* end dasd_format */ static int do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) @@ -1617,15 +1813,14 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) case BIODASDFORMAT:{ /* fdata == NULL is a valid arg to dasd_format ! */ int partn; - format_data_t *fdata = NULL; + format_data_t fdata = { + DASD_FORMAT_DEFAULT_START_UNIT, + DASD_FORMAT_DEFAULT_STOP_UNIT, + DASD_FORMAT_DEFAULT_BLOCKSIZE, + DASD_FORMAT_DEFAULT_INTENSITY }; + if (data) { - fdata = kmalloc (sizeof (format_data_t), - GFP_ATOMIC); - if (!fdata) { - rc = -ENOMEM; - break; - } - rc = copy_from_user (fdata, (void *) data, + rc = copy_from_user (&fdata, (void *) data, sizeof (format_data_t)); if (rc) break; @@ -1634,15 +1829,12 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) if (partn != 0) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " Cannot low-level format a partition\n", + " Cannot low-level format a partition\n", device->devinfo.devno, device->devinfo.irq, device->name, - MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); + MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } - rc = dasd_format (device, fdata); - if (fdata) { - kfree (fdata); - } + rc = dasd_format (device, &fdata); break; } case BIODASDEXCP:{ @@ -1675,11 +1867,11 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data) static int dasd_ioctl (struct inode *inp, struct file *filp, unsigned int no, unsigned long data) - { +{ int rc = 0; if ((!inp) || !(inp->i_rdev)) { return -EINVAL; - } + } rc = do_dasd_ioctl (inp, no, data); return rc; } @@ -1719,7 +1911,7 @@ dasd_open (struct inode *inp, struct file *filp) printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Cannot open unrecognized device\n", - device->devinfo.devno, device->devinfo.irq, device->name, + device->devinfo.devno, device->devinfo.irq, device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev)); return -EINVAL; } @@ -1833,7 +2025,7 @@ dasd_register_major (major_info_t * major_info) if (rc < 0) { printk (KERN_WARNING PRINTK_HEADER "Cannot register to major no %d, rc = %d\n", major, rc); - return rc; + return rc; } else if (rc > 0) { if (major == 0) { major = rc; @@ -1950,11 +2142,11 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) if ( hd ) { index = devindex_from_kdev_t (MKDEV(hd->major,index<minor_shift)); -} + } third = index % 26; second = (index / 26) % 27; first = ((index / 26) / 27) % 27; - + len = sprintf (str, "dasd"); if (first) { len += sprintf (str + len, "%c", first + 'a' - 1 ); @@ -1968,7 +2160,7 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) return -EINVAL; } else { len += sprintf (str + len, "%d", partition); - } + } } str[len] = '\0'; return 0; @@ -1976,25 +2168,40 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd) static void dasd_not_oper_handler ( int irq, int status ) { - int devno,devindex; - dasd_device_t *device; - devno = get_devno_by_irq(irq); + dasd_device_t *device=NULL; + major_info_t * major_info; + int i,devno = -ENODEV; + + for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) { + for ( i = 0; i <= DASD_PER_MAJOR; i ++ ) { + device = major_info->dasd_device[i]; + if ( device && + device -> devinfo.irq == irq ) { + devno = device->devinfo.devno; + break; + } + } + if ( devno != -ENODEV ) + break; + } if ( devno < 0 ) { - printk (KERN_WARNING PRINTK_HEADER - "not_oper_handler called on irq %d no devno!\n", irq); - return; - } + printk ( KERN_WARNING PRINTK_HEADER + "not_oper_handler called on irq %d no devno!\n", irq); + return; + } printk ( KERN_INFO PRINTK_HEADER "not_oper_handler called on irq %d devno %04X\n", irq,devno); - devindex = devindex_from_devno(devno); - device = find_dasd_device(devindex); - dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 ); + if ( device -> open_count != 0 ) { + printk (KERN_ALERT PRINTK_HEADER + "Device %04X detached has still been open. expect errors\n", devno); } + dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 ); +} static int dasd_enable_single_volume ( int irq ) { int rc = 0; - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); printk (KERN_INFO PRINTK_HEADER "waiting for response...\n"); { @@ -2008,14 +2215,14 @@ dasd_enable_single_volume ( int irq ) { } dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, NULL, 0); - return rc; + return rc; } -static int +int dasd_oper_handler ( int irq, devreg_t *devreg ) { int devno; int devindex; - int rc; + int rc; devno = get_devno_by_irq(irq); if ( devno == -ENODEV ) return -ENODEV; @@ -2024,12 +2231,12 @@ dasd_oper_handler ( int irq, devreg_t *devreg ) { if ( dasd_autodetect ) { dasd_add_range(devno,0); } else { - return -ENODEV; - } + return -ENODEV; + } } while ( devindex == -ENODEV ); rc = dasd_enable_single_volume(irq); - return rc; - } + return rc; +} /* * int @@ -2061,8 +2268,8 @@ dasd_set_device_level (unsigned int irq, int desired_level, devindex = devindex_from_devno (devno); if (devindex < 0) { printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq); - return -ENODEV; - } + return -ENODEV; + } device = find_dasd_device (devindex); while ( (major_info = major_info_from_devindex (devindex)) == NULL ) { if ((rc = dasd_register_major (major_info)) > 0) { @@ -2072,8 +2279,8 @@ dasd_set_device_level (unsigned int irq, int desired_level, printk (KERN_WARNING PRINTK_HEADER "Couldn't register successfully to another major no\n"); return -ERANGE; - } - } + } + } ind = devindex & (DASD_PER_MAJOR-1); device = major_info->dasd_device[ind]; if (!device) { /* allocate device descriptor */ @@ -2108,7 +2315,7 @@ dasd_set_device_level (unsigned int irq, int desired_level, if (temp->check_characteristics) { if (temp->check_characteristics (device)) continue; - } + } discipline = temp; break; } @@ -2119,17 +2326,25 @@ dasd_set_device_level (unsigned int irq, int desired_level, devno, irq, discipline->name, device->name, major_from_devindex (devindex), (devindex % 64) << DASD_PARTN_BITS); - } else { + } else { break; - } + } device->discipline = discipline; if (device->discipline->int_handler) { +#ifdef CONFIG_DASD_DYNAMIC s390_request_irq_special(irq, device->discipline->int_handler, dasd_not_oper_handler, 0, DASD_NAME, &device->dev_status); +#else /* !defined(CONFIG_DASD_DYNAMIC) */ + request_irq(irq, + device->discipline->int_handler, + 0, + DASD_NAME, + &device->dev_status); +#endif /* CONFIG_DASD_DYNAMIC */ } atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_UNKNOWN, @@ -2149,13 +2364,13 @@ dasd_set_device_level (unsigned int irq, int desired_level, DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_ANALYSIS_PENDING); s390irq_spin_unlock_irqrestore (irq, flags); -} + } } } else { atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED); } - if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING) + if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING) break; case DASD_DEVICE_LEVEL_ANALYSIS_PENDING: /* Fallthrough ?? */ return -EAGAIN; @@ -2170,7 +2385,7 @@ dasd_set_device_level (unsigned int irq, int desired_level, case 4096: break; default: -{ + { printk (KERN_INFO PRINTK_HEADER "/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes" " Did you format the drive?\n", @@ -2220,19 +2435,6 @@ dasd_set_device_level (unsigned int irq, int desired_level, } } else if (desired_level < current_level) { /* donwgrade device status */ switch (current_level) { - case DASD_DEVICE_LEVEL_PARTITIONED: /* Fallthrough ?? */ - /* delete the partition information */ - for (i = 0; i < (1 << DASD_PARTN_BITS); i++) { - struct hd_struct *p = &major_info->gendisk.part[minor+i]; - p->start_sect = 0; - p->nr_sects = 0; - p->type = 0; - } - atomic_compare_and_swap_debug (&device->level, - DASD_DEVICE_LEVEL_PARTITIONED, - DASD_DEVICE_LEVEL_ANALYSED); - if (desired_level == DASD_DEVICE_LEVEL_ANALYSED) - break; case DASD_DEVICE_LEVEL_ANALYSED: /* Fallthrough ?? */ atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_ANALYSED, @@ -2315,7 +2517,7 @@ static struct proc_dir_entry dasd_proc_root_entry = #endif /* KERNEL_VERSION */ static struct proc_dir_entry* dasd_devices_entry; - + static int dasd_devices_open (struct inode* inode, struct file* file ) { @@ -2331,7 +2533,7 @@ dasd_devices_open (struct inode* inode, struct file* file ) return -ENOMEM; } else { file->private_data = (void *)info; - } + } while ( temp ) { int i; for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) { @@ -2393,7 +2595,7 @@ dasd_devices_open (struct inode* inode, struct file* file ) temp = temp->next; } info->len=len; - return rc; + return rc; } #define MIN(a,b) ((a)<(b)?(a):(b)) @@ -2407,41 +2609,59 @@ dasd_devices_read ( struct file *file, char* user_buf, size_t user_len, lo if(*offset >= p_info->len) { return 0; /* EOF */ - } + } else { len = MIN(user_len, (p_info->len - *offset)); copy_to_user(user_buf, &(p_info->data[*offset]), len); (*offset) += len; return len; /* number of bytes "read" */ + } +} + +static ssize_t +dasd_devices_write ( struct file *file, const char* user_buf, size_t user_len, loff_t* offset ) +{ + char * buffer = vmalloc(user_len); + + if ( buffer == NULL) + return -ENOMEM; + copy_from_user ( buffer, user_buf, user_len); + buffer[user_len] = 0; + printk ( KERN_INFO PRINTK_HEADER "Now executing %s\n",buffer); + if ( ! strncmp(buffer,"add range",strlen("add_range"))) { + + } else if ( ! strncmp(buffer,"enable device",strlen("enable device"))) { + + } else if ( ! strncmp(buffer,"disable device",strlen("disable device"))) { + + } else { + printk (KERN_WARNING PRINTK_HEADER "unknown command %s", + buffer ); } + vfree(buffer); + return user_len; } -static int +static int dasd_devices_close (struct inode* inode, struct file* file) { - int rc = 0; + int rc = 0; tempinfo_t* p_info = (tempinfo_t*)file->private_data; if ( p_info ) { if ( p_info->data ) vfree(p_info->data); vfree(p_info); - } - return rc; + } + return rc; } static struct file_operations dasd_devices_file_ops = { - NULL, /* lseek */ - dasd_devices_read, /* read */ - NULL, /* dasd_devices_write, */ /* write */ - NULL, /* readdir */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - dasd_devices_open, /* open */ - NULL, /* flush */ - dasd_devices_close, /* close */ + read: dasd_devices_read, /* read */ + write: dasd_devices_write, /* write */ + open: dasd_devices_open, /* open */ + release: dasd_devices_close, /* close */ }; static struct inode_operations dasd_devices_inode_ops = @@ -2451,16 +2671,17 @@ static struct inode_operations dasd_devices_inode_ops = #endif /* LINUX_IS_24 */ }; -void +int dasd_proc_init (void) { + int rc = 0; #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - dasd_proc_root_entry = create_proc_entry("dasd", - S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, - &proc_root); + dasd_proc_root_entry = proc_mkdir("dasd",&proc_root); dasd_devices_entry = create_proc_entry("devices", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); + dasd_devices_entry -> proc_fops = &dasd_devices_file_ops; + dasd_devices_entry -> proc_iops = &dasd_devices_inode_ops; #else proc_register (&proc_root, &dasd_proc_root_entry); dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); @@ -2479,6 +2700,7 @@ dasd_proc_init (void) proc_register(&dasd_proc_root_entry, dasd_devices_entry); } #endif /* LINUX_IS_24 */ + return rc; } void @@ -2506,15 +2728,13 @@ dasd_init (void) dasd_range_t *range; printk (KERN_INFO PRINTK_HEADER "initializing...\n"); - genhd_dasd_name = dasd_device_name; #ifndef MODULE dasd_split_parm_string(dasd_parm_string); #endif /* ! MODULE */ dasd_parse(dasd); - dasd_proc_init(); dasd_init_emergency_req(); - + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) init_waitqueue_head(&watcher_queue); spin_lock_init(&cq_lock); @@ -2527,72 +2747,115 @@ dasd_init (void) } else { printk (KERN_WARNING PRINTK_HEADER "Couldn't register successfully to major no %d\n", major_info->gendisk.major); - } + /* revert registration of major infos */ + goto major_failed; } + } + rc = dasd_proc_init(); + if ( rc ) { + goto proc_failed; + } + + genhd_dasd_name = dasd_device_name; #ifdef CONFIG_DASD_ECKD rc = dasd_eckd_init (); if (rc==0) { printk (KERN_INFO PRINTK_HEADER "Registered ECKD discipline successfully\n"); - } + } else { + goto eckd_failed; + } #endif /* CONFIG_DASD_ECKD */ #ifdef CONFIG_DASD_FBA rc = dasd_fba_init (); if (rc == 0) { printk (KERN_INFO PRINTK_HEADER "Registered FBA discipline successfully\n"); + } else { + goto fba_failed; } #endif /* CONFIG_DASD_FBA */ #ifdef CONFIG_DASD_MDSK - rc = dasd_diag_init (); - if (rc == 0) { + if ( MACHINE_IS_VM ) { + rc = dasd_diag_init (); + if (rc == 0) { printk (KERN_INFO PRINTK_HEADER "Registered MDSK discipline successfully\n"); - } + } else { + goto mdsk_failed; + } + } #endif /* CONFIG_DASD_MDSK */ rc = 0; for (range = dasd_range_head; range; range= range->next) { for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); + } } - } if ( dasd_autodetect ) { for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) { int devno = get_devno_by_irq(irq); int index = devindex_from_devno(devno); if ( index == -ENODEV ) { /* not included in ranges */ dasd_add_range (devno,0); - dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING, + dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, NULL, 0); - } - } -} + } + } + } printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n"); -{ + { #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) static wait_queue_head_t wait_queue; init_waitqueue_head(&wait_queue); #else static struct wait_queue *wait_queue = NULL; #endif /* LINUX_IS_24 */ - interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 ); - } + interruptible_sleep_on_timeout (&wait_queue, + (20 * HZ) >> 1 ); + } for (range = dasd_range_head; range; range= range->next) { for (j = range->from; j <= range->to; j++) { irq = get_irq_by_devno (j); if (irq >= 0) { dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, NULL, 0); - } + } } } - - printk (KERN_INFO PRINTK_HEADER "initialization completed\n"); - return rc; + goto out; +#ifdef CONFIG_DASD_MDSK + mdsk_failed: + dasd_diag_cleanup (); +#endif /* CONFIG_DASD_MDSK */ +#ifdef CONFIG_DASD_FBA + fba_failed: + dasd_fba_cleanup (); +#endif /* CONFIG_DASD_FBA */ +#ifdef CONFIG_DASD_ECKD + eckd_failed: + dasd_eckd_cleanup (); +#endif /* CONFIG_DASD_ECKD */ + proc_failed: + dasd_proc_cleanup(); + major_failed: { + for (major_info = dasd_major_info; + major_info; + major_info = major_info->next) { + dasd_unregister_major(major_info); + } + } + emergency_failed: + dasd_cleanup_emergency_req(); + failed: + printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); + out: + printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); + return rc; } void @@ -2615,7 +2878,7 @@ cleanup_dasd (void) dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0); kfree(find_dasd_device(devindex_from_devno(j))); - } + } } } for (major_info = dasd_major_info; major_info; major_info = major_info->next) { @@ -2634,19 +2897,19 @@ cleanup_dasd (void) next = range -> next; kfree (range); if ( next == NULL ) - break; + break; else range = next; - } + } dasd_range_head = NULL; while ( dasd_devreg_head ) { reg = dasd_devreg_head->next; kfree ( dasd_devreg_head ); dasd_devreg_head = reg; - } + } printk (KERN_INFO PRINTK_HEADER "shutdown completed\n"); - } +} #ifdef MODULE int @@ -2655,7 +2918,7 @@ init_module ( void ) int rc=0; return dasd_init(); return rc; - } +} void cleanup_module ( void ) diff --git a/drivers/s390/block/dasd.h b/drivers/s390/block/dasd.h index b77e731f9094..bb063f304aff 100644 --- a/drivers/s390/block/dasd.h +++ b/drivers/s390/block/dasd.h @@ -5,6 +5,5 @@ void dasd_int_handler (int , void *, struct pt_regs *); ccw_req_t * dasd_alloc_request (char *, int , int ) ; void dasd_free_request(ccw_req_t *); int (*genhd_dasd_name)(char*,int,int,struct gendisk*); - - +int dasd_oper_handler ( int irq, devreg_t *devreg ); diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 63d01f6601a5..963260f3f9c9 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -64,13 +64,22 @@ dasd_era_t dasd_3990_erp_examine_24 (char *sense) { - /* check for 'Command Recejct' which is always a fatal error */ + /* check for 'Command Recejct' whithout environmental data present */ if (sense[0] & 0x80) { - return dasd_era_fatal; - } - /* check for 'Invalid Track Format' */ + if (sense[2] &0x10){ + return dasd_era_recover; + } else { + return dasd_era_fatal; + } + } + + /* check for 'Invalid Track Format' whithout environmental data present */ if (sense[1] & 0x40) { - return dasd_era_fatal; + if (sense[2] &0x10){ + return dasd_era_recover; + } else { + return dasd_era_fatal; + } } /* check for 'No Record Found' */ if (sense[1] & 0x08) { diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 91a0448c7d78..afb82c4b6f3b 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -5,6 +5,10 @@ * ...............: by Hartmunt Penner * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + + * History of changes + * 07/13/00 Added fixup sections for diagnoses ans saved some registers + * 07/14/00 fixed constraints in newly generated inline asm */ #include @@ -20,6 +24,7 @@ #include #include #include +#include #include "dasd.h" #include "dasd_diag.h" @@ -47,13 +52,24 @@ dia210 (void *devchar) { int rc; - __asm__ __volatile__ (" lr 2,%1\n" - " .long 0x83200210\n" + __asm__ __volatile__ (" diag %1,0,0x210\n" "0: ipm %0\n" - " srl %0,28" + " srl %0,28\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: lhi %0,3\n" + " bras 1,3f\n" + " .long 1b\n" + "3: l 1,0(1)\n" + " br 1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" + ".previous\n" :"=d" (rc) :"d" ((void *) __pa (devchar)) - :"2"); + :"1"); return rc; } @@ -62,13 +78,23 @@ dia250 (void *iob, int cmd) { int rc; - __asm__ __volatile__ (" lr 2,%1\n" - " lr 3,%2\n" - " .long 0x83230250\n" - " lr %0,3" - :"=d" (rc) - :"d" ((void *) __pa (iob)), "d" (cmd) - :"2", "3"); + __asm__ __volatile__ (" lr 1,%1\n" + " diag 1,%2,0x250\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: lhi %0,3\n" + " bras 1,3f\n" + " .long 1b\n" + "3: l 1,0(1)\n" + " br 1\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,2b\n" + ".previous\n" + : "=d" (rc) + : "d" ((void *) __pa (iob)), "0" (cmd) + : "1" ); return rc; } @@ -535,6 +561,23 @@ dasd_diag_init( void ) { } return rc; } + +void +dasd_diag_cleanup( void ) { + int rc = 0; + if ( MACHINE_IS_VM ) { + printk ( KERN_INFO PRINTK_HEADER + "%s discipline cleaning up\n", dasd_diag_discipline.name); + dasd_discipline_deq(&dasd_diag_discipline); + unregister_external_interrupt (0x2603, dasd_ext_handler); + ctl_clear_bit (0, 9); + } else { + printk ( KERN_INFO PRINTK_HEADER + "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name); + rc = -EINVAL; + } + return rc; +} /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 3e18eba06cb2..521a940710a4 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -6,6 +6,12 @@ * History of changes (starts July 2000) * 07/11/00 Enabled rotational position sensing + * 07/14/00 Reorganized the format process for better ERP + * 07/20/00 added experimental support for 2105 control unit (ESS) + * 07/24/00 increased expiration time and added the missing zero + * 08/07/00 added some bits to define_extent for ESS support + * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF) + * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages) */ #include @@ -21,6 +27,7 @@ #include #include #include +#include #include "dasd.h" #include "dasd_eckd.h" @@ -32,15 +39,15 @@ #define PRINTK_HEADER DASD_NAME"(eckd):" #define ECKD_C0(i) (i->home_bytes) -#define ECKD_F(i) (i -> formula) + #define ECKD_F(i) (i->formula) #define ECKD_F1(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f1):(i->factors.f_0x02.f1)) #define ECKD_F2(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f2):(i->factors.f_0x02.f2)) #define ECKD_F3(i) (ECKD_F(i)==0x01?(i->factors.f_0x01.f3):(i->factors.f_0x02.f3)) #define ECKD_F4(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f4):0) #define ECKD_F5(i) (ECKD_F(i)==0x02?(i->factors.f_0x02.f5):0) -#define ECKD_F6(i) (i -> factor6) -#define ECKD_F7(i) (i -> factor7) -#define ECKD_F8(i) (i -> factor8) +#define ECKD_F6(i) (i->factor6) +#define ECKD_F7(i) (i->factor7) +#define ECKD_F8(i) (i->factor8) #define DASD_ECKD_CCW_WRITE 0x05 #define DASD_ECKD_CCW_READ 0x06 @@ -67,6 +74,25 @@ dasd_eckd_private_t { eckd_count_t count_area; } dasd_eckd_private_t; +static +devreg_t dasd_eckd_known_devices[] = { + { + ci : { hc: { ctype: 0x3990, dtype: 0x3390 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x3990, dtype: 0x3380 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x9343, dtype: 0x9345 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + } +}; + static inline unsigned int round_up_multiple (unsigned int no, unsigned int mult) { @@ -133,15 +159,15 @@ recs_per_track (dasd_eckd_characteristics_t * rdc, { int rpt = 0; int dn; - switch ( rdc -> dev_type ) { - case 0x3380: + switch (rdc->dev_type) { + case 0x3380: if (kl) return 1499 / (15 + 7 + ceil_quot (kl + 12, 32) + ceil_quot (dl + 12, 32)); else return 1499 / (15 + ceil_quot (dl + 12, 32)); - case 0x3390: + case 0x3390: dn = ceil_quot (dl + 6, 232) + 1; if (kl) { int kn = ceil_quot (kl + 6, 232) + 1; @@ -151,16 +177,16 @@ recs_per_track (dasd_eckd_characteristics_t * rdc, } else return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34)); - case 0x9345: - dn = ceil_quot (dl + 6, 232) + 1; - if (kl) { - int kn = ceil_quot (kl + 6, 232) + 1; - return 1420 / (18 + - 7 + ceil_quot (kl + 6 * kn, 34) + - ceil_quot (dl + 6 * dn, 34)); - } else - return 1420 / (18 + - 7 + ceil_quot (dl + 6 * dn, 34)); + case 0x9345: + dn = ceil_quot (dl + 6, 232) + 1; + if (kl) { + int kn = ceil_quot (kl + 6, 232) + 1; + return 1420 / (18 + + 7 + ceil_quot (kl + 6 * kn, 34) + + ceil_quot (dl + 6 * dn, 34)); + } else + return 1420 / (18 + + 7 + ceil_quot (dl + 6 * dn, 34)); } return rpt; } @@ -186,7 +212,7 @@ define_extent (ccw1_t * de_ccw, memset (de_ccw, 0, sizeof (ccw1_t)); de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; de_ccw->count = 16; - de_ccw->cda = (void *) __pa (data); + de_ccw->cda = (__u32) __pa (data); memset (data, 0, sizeof (DE_eckd_data_t)); switch (cmd) { @@ -198,12 +224,12 @@ define_extent (ccw1_t * de_ccw, case DASD_ECKD_CCW_READ_CKD_MT: case DASD_ECKD_CCW_READ_COUNT: data->mask.perm = 0x1; - data->attributes.operation = 0x3; /* enable seq. caching */ + data->attributes.operation = 0x3; /* enable seq. caching */ break; case DASD_ECKD_CCW_WRITE: case DASD_ECKD_CCW_WRITE_MT: data->mask.perm = 0x02; - data->attributes.operation = 0x3; /* enable seq. caching */ + data->attributes.operation = 0x3; /* enable seq. caching */ break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: @@ -220,6 +246,9 @@ define_extent (ccw1_t * de_ccw, break; } data->attributes.mode = 0x3; + if ( private -> rdc_data.cu_type == 0x2105 ) { + data -> reserved |= 0x40; + } data->beg_ext.cyl = beg.cyl; data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; @@ -233,19 +262,19 @@ locate_record (ccw1_t * lo_ccw, int rec_on_trk, int no_rec, int cmd, - dasd_device_t * device) + dasd_device_t * device, + int reclen) { dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; ch_t geo = {private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl}; ch_t seek ={trk / (geo.head), trk % (geo.head)}; - int reclen = device->sizes.bp_block; int sector; memset (lo_ccw, 0, sizeof (ccw1_t)); lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; lo_ccw->count = 16; - lo_ccw->cda = (void *) __pa (data); + lo_ccw->cda = (__u32) __pa (data); memset (data, 0, sizeof (LO_eckd_data_t)); switch (cmd) { @@ -293,7 +322,7 @@ locate_record (ccw1_t * lo_ccw, break; case DASD_ECKD_CCW_READ_COUNT: data->operation.operation = 0x06; - break; + break; default: INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd); } @@ -325,17 +354,19 @@ locate_record (ccw1_t * lo_ccw, static int dasd_eckd_id_check ( dev_info_t *info ) { - if ( info->sid_data.cu_type == 0x3990 ) + if ( info->sid_data.cu_type == 0x3990 || + info->sid_data.cu_type == 0x2105 ) if ( info->sid_data.dev_type == 0x3390 ) return 0; - if ( info->sid_data.cu_type == 0x3990 ) + if ( info->sid_data.cu_type == 0x3990 || + info->sid_data.cu_type == 0x2105 ) if ( info->sid_data.dev_type == 0x3380 ) return 0; if ( info->sid_data.cu_type == 0x9343 ) if ( info->sid_data.dev_type == 0x9345 ) return 0; return -ENODEV; - } +} static int dasd_eckd_check_characteristics (struct dasd_device_t *device) @@ -366,7 +397,7 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device) printk ( KERN_WARNING PRINTK_HEADER "Read device characteristics returned error %d\n",rc); return rc; - } + } printk ( KERN_INFO PRINTK_HEADER "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n", device->devinfo.devno, device->devinfo.irq, @@ -381,7 +412,7 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device) printk ( KERN_WARNING PRINTK_HEADER "Read configuration data returned error %d\n",rc); return rc; - } + } if ( conf_len != sizeof(dasd_eckd_confdata_t)) { printk ( KERN_WARNING PRINTK_HEADER "sizes of configuration data mismatch %d (read) vs %ld (expected)\n", @@ -429,13 +460,14 @@ dasd_eckd_init_analysis (struct dasd_device_t *device) define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device); ccw->flags = CCW_FLAG_CC; ccw++; - locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device); + locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device,0); ccw->flags = CCW_FLAG_CC; ccw++; ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT; ccw->count = 8; - ccw->cda = (void *) __pa (count_data); + ccw->cda = (__u32) __pa (count_data); cqr->device = device; + cqr->retries = 0; atomic_set (&cqr->status, CQR_STATUS_FILLED); return cqr; @@ -511,10 +543,9 @@ dasd_eckd_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo) return rc; } -static inline int -dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags) +static ccw_req_t * +dasd_eckd_format_device (dasd_device_t *device, format_data_t *fdata) { - int rc = 0; int i; ccw_req_t *fcp = NULL; DE_eckd_data_t *DE_data = NULL; @@ -525,252 +556,177 @@ dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags) ccw1_t *last_ccw = NULL; void * last_data = NULL; dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; - int retries; - + int trk = fdata -> start_unit; + int bs = fdata -> blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize; + int flags = fdata -> intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata -> intensity; + int rpt = recs_per_track (&(private->rdc_data), 0, bs); int cyl = trk / private->rdc_data.trk_per_cyl; int head = trk % private->rdc_data.trk_per_cyl; int wrccws = rpt; int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t); + + if ( ( (fdata -> stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) && + trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl ) ) || + ( (fdata -> stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) && + trk > fdata->stop_unit ) ) { + printk (KERN_WARNING PRINTK_HEADER "Track %d reached...ending!\n",trk); + return NULL; + } + switch(bs) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n",bs); + return NULL; + } switch ( flags ) { case 0x00: case 0x01: case 0x03: - break; + case 0x04: /* make track invalid */ + break; default: - return -EINVAL; + printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n",flags); + return NULL; } - - if ( flags & 0x1 ) { - wrccws++; - datasize += sizeof(eckd_count_t); + + /* print status line */ + if ( (private->rdc_data.no_cyl < 20 ) ? + ( trk % private->rdc_data.no_cyl == 0 ) : + ( trk % private->rdc_data.no_cyl == 0 && + (trk / private->rdc_data.no_cyl) % + (private->rdc_data.no_cyl / 20 ) ) ) { + + printk (KERN_INFO PRINTK_HEADER + "Format %04X Cylinder: %d Flags: %d\n", + device->devinfo.devno, + trk / private->rdc_data.trk_per_cyl, + flags); } - if ( flags & 0x2 ) { - wrccws++; - datasize += sizeof(eckd_home_t); + + if ( flags & 0x04) { + rpt = 1; + wrccws = 1; + } else { + if ( flags & 0x1 ) { + wrccws++; + datasize += sizeof(eckd_count_t); + } + if ( flags & 0x2 ) { + wrccws++; + datasize += sizeof(eckd_home_t); + } } fcp = ccw_alloc_request (dasd_eckd_discipline.name, wrccws + 2, datasize+rpt*sizeof(eckd_count_t)); - fcp->device = device; - - last_data = fcp->data; - DE_data = (DE_eckd_data_t *) last_data; - last_data = (void*)(DE_data +1); - LO_data = (LO_eckd_data_t *) last_data; - last_data = (void*)(LO_data +1); - if ( flags & 0x2 ) { - ha_data = (eckd_home_t *) last_data; - last_data = (void*)(ha_data +1); - } - if ( flags & 0x1 ) { - r0_data = (eckd_count_t *) last_data; - last_data = (void*)(r0_data +1); - } - ct_data = (eckd_count_t *)last_data; - - last_ccw = fcp->cpaddr; - - switch (flags) { - case 0x03: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - break; - case 0x01: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, + if ( fcp != NULL ) { + fcp->device = device; + last_data = fcp->data; + DE_data = (DE_eckd_data_t *) last_data; + last_data = (void*)(DE_data +1); + LO_data = (LO_eckd_data_t *) last_data; + last_data = (void*)(LO_data +1); + if ( flags & 0x2 ) { + ha_data = (eckd_home_t *) last_data; + last_data = (void*)(ha_data +1); + } + if ( flags & 0x1 ) { + r0_data = (eckd_count_t *) last_data; + last_data = (void*)(r0_data +1); + } + ct_data = (eckd_count_t *)last_data; + + last_ccw = fcp->cpaddr; + + switch (flags) { + case 0x03: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,device->sizes.bp_block ); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + case 0x01: + define_extent (last_ccw, DE_data, trk, trk, DASD_ECKD_CCW_WRITE_RECORD_ZERO, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - memset (r0_data, 0, sizeof (eckd_count_t)); - break; - case 0x00: - define_extent (last_ccw, DE_data, trk, trk, - DASD_ECKD_CCW_WRITE_CKD, device); - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - locate_record (last_ccw, LO_data, trk, 0, wrccws, - DASD_ECKD_CCW_WRITE_CKD, device); - LO_data->length = bs; - last_ccw->flags = CCW_FLAG_CC; - last_ccw++; - break; - default: - PRINT_WARN ("Unknown format flags...%d\n", flags); - return -EINVAL; - } - if (flags & 0x02) { - PRINT_WARN ("Unsupported format flag...%d\n", flags); - return -EINVAL; - } - if (flags & 0x01) { /* write record zero */ - r0_data->cyl = cyl; - r0_data->head = head; - r0_data->record = 0; - r0_data->kl = 0; - r0_data->dl = 8; - last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; - last_ccw->count = 8; - last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; - last_ccw->cda = (void *) __pa (r0_data); - last_ccw++; - } - /* write remaining records */ - for (i = 0; i < rpt; i++, last_ccw++) { - memset (ct_data + i, 0, sizeof (eckd_count_t)); - (ct_data + i)->cyl = cyl; - (ct_data + i)->head = head; - (ct_data + i)->record = i + 1; - (ct_data + i)->kl = 0; - (ct_data + i)->dl = bs; - last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; - last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; - last_ccw->count = 8; - last_ccw->cda = (void *) __pa (ct_data + i); - } - (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); - fcp->device = device; - do { -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - DECLARE_WAITQUEUE (wait,current); -#else - struct wait_queue wait = {current, NULL}; -#endif /* LINUX_VERSION_CODE */ - unsigned long flags; - int cs; - - retries = 1; - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); - atomic_set(&fcp->status,CQR_STATUS_QUEUED); - do { - rc = dasd_eckd_discipline.start_IO (fcp); - } while ( rc && retries-- ); - if ( rc && retries == 0 ) + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,device->sizes.bp_block); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + memset (r0_data, 0, sizeof (eckd_count_t)); break; -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - add_wait_queue (&device->wait_q, &wait); -#endif /* LINUX_VERSION_CODE */ - do { - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - schedule (); - s390irq_spin_lock_irqsave (device->devinfo.irq, flags); - cs = atomic_read (&fcp->status); - } while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR)); -#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) - remove_wait_queue (&device->wait_q, &wait); -#endif /* LINUX_VERSION_CODE */ - s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags); - } while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) && - retries--); - if ( retries == 0 ) - rc = -EIO; - ccw_free_request (fcp); - return rc; -} - -static int -dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata) -{ - int rc = 0; - int i; - format_data_t fd; - dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private; - int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1; - int intensity; - kdev_t kdev = device->kdev; - int nr_tracks, blocksize; - - if (fdata==NULL) { - fd.start_unit = 0; - fd.stop_unit = last_track; - fd.blksize = 4096; - } else { - memcpy (&fd, fdata, sizeof (format_data_t)); - if (fd.stop_unit == -1) { - fd.stop_unit = last_track; - } - if (fd.blksize == 0) { - fd.blksize = 4096; - } - } - if (fd.start_unit > fd.stop_unit) { - return -EINVAL; - } - if (fd.start_unit > last_track ) { - return -EINVAL; - } - if (fd.stop_unit > last_track ) { - return -EINVAL; - } - switch(fd.blksize) { - case 512: - case 1024: - case 2048: - case 4096: - break; - default: - return -EINVAL; - } - fd.intensity = 0x0; - intensity = fd.intensity; - set_blocksize(kdev, fd.blksize); - printk (KERN_INFO PRINTK_HEADER - "Formatting device %04X from track %d to %d with bs %d\n", - device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize); - nr_tracks = fd.stop_unit-fd.start_unit+1; - for (i = 0; i <= nr_tracks; i++) { - /* print 20 messages per format cmd at all */ - if ( i % (nr_tracks / 20) == 0 ) { - printk (KERN_INFO PRINTK_HEADER - "Format %04X Cylinder: %d Track %d Intensity %d\n", - device->devinfo.devno, - (i+fd.start_unit) / private->rdc_data.trk_per_cyl, - (i+fd.start_unit) % private->rdc_data.trk_per_cyl, - intensity); - } - do { - if ( i == 0 ) { - blocksize = 8; - } else { - blocksize = fd.blksize; - } - rc = dasd_eckd_format_track (device, - (i % nr_tracks) + fd.start_unit , - blocksize, intensity); - /* fix VM controlled minidisk */ - if ( rc ) { - if ( intensity ) { - intensity = intensity >> 1; - } - printk (KERN_WARNING PRINTK_HEADER - "decreasing format intensity to %d\n", - intensity); - } - } while ( rc && intensity > 0); - if (rc) { - printk (KERN_WARNING PRINTK_HEADER - "Formatting of device %04X Cylinder %d Track %d failed...exiting\n", - device->devinfo.devno, - i / private->rdc_data.trk_per_cyl, - i % private->rdc_data.trk_per_cyl); + case 0x04: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_CKD, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_CKD, device,0); + LO_data->length = bs; + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; break; - } - } - printk ( KERN_INFO PRINTK_HEADER - "Formatting of device %04X completed from track %d to %d with bs %d\n", - device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize); - return rc; + case 0x00: + define_extent (last_ccw, DE_data, trk, trk, + DASD_ECKD_CCW_WRITE_CKD, device); + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + locate_record (last_ccw, LO_data, trk, 0, wrccws, + DASD_ECKD_CCW_WRITE_CKD, device,device->sizes.bp_block); + LO_data->length = bs; + last_ccw->flags = CCW_FLAG_CC; + last_ccw++; + break; + default: + PRINT_WARN ("Unknown format flags...%d\n", flags); + return NULL; + } + if (flags & 0x02 ) { + PRINT_WARN ("Unsupported format flag...%d\n", flags); + return NULL; + } + if (flags & 0x01) { /* write record zero */ + r0_data->cyl = cyl; + r0_data->head = head; + r0_data->record = 0; + r0_data->kl = 0; + r0_data->dl = 8; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO; + last_ccw->count = 8; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->cda = (__u32) __pa (r0_data); + last_ccw++; + } + /* write remaining records */ + for (i = 0; i < rpt; i++) { + memset (ct_data + i, 0, sizeof (eckd_count_t)); + (ct_data + i)->cyl = cyl; + (ct_data + i)->head = head; + (ct_data + i)->record = i + 1; + (ct_data + i)->kl = 0; + (ct_data + i)->dl = bs; + last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD; + last_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI; + last_ccw->count = 8; + last_ccw->cda = (__u32) __pa (ct_data + i); + last_ccw ++; + } + (last_ccw-1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC); + fcp->device = device; + atomic_set(&fcp->status,CQR_STATUS_FILLED); + } + return fcp; } static dasd_era_t @@ -781,8 +737,9 @@ dasd_eckd_examine_error (ccw_req_t *cqr, devstat_t * stat) stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) return dasd_era_none; - switch (device->devinfo.sid_data.cu_model) { + switch (device->devinfo.sid_data.cu_type) { case 0x3990: + case 0x2105: return dasd_3990_erp_examine (cqr, stat); case 0x9343: return dasd_9343_erp_examine (cqr, stat); @@ -838,20 +795,20 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req) /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) + if (bh->b_size > byt_per_blk) + for (size = 0; size < bh->b_size; size += byt_per_blk) bhct++; else bhct++; } - + rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 2 + bhct, - sizeof (DE_eckd_data_t) + - sizeof (LO_eckd_data_t)); - if ( ! rw_cp ) { - return NULL; - } + sizeof (DE_eckd_data_t) + + sizeof (LO_eckd_data_t)); + if (!rw_cp) { + return NULL; + } DE_data = rw_cp->data; LO_data = rw_cp->data + sizeof (DE_eckd_data_t); ccw = rw_cp->cpaddr; @@ -860,17 +817,17 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req) ccw->flags = CCW_FLAG_CC; ccw++; locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1, - req->nr_sectors >> shift, rw_cmd, device); + req->nr_sectors >> shift, rw_cmd, device,device->sizes.bp_block); ccw->flags = CCW_FLAG_CC; for (bh = req->bh; bh != NULL;) { if (bh->b_size > byt_per_blk) { - for (size = 0; size < bh->b_size; size += byt_per_blk) { - ccw++; - ccw->flags = CCW_FLAG_CC; - ccw->cmd_code = rw_cmd; - ccw->count = byt_per_blk; - ccw->cda = (void *) __pa (bh->b_data + size); - } + for (size = 0; size < bh->b_size; size += byt_per_blk) { + ccw++; + ccw->flags = CCW_FLAG_CC; + ccw->cmd_code = rw_cmd; + ccw->count = byt_per_blk; + ccw->cda = (__u32) __pa (bh->b_data + size); + } bh = bh->b_reqnext; } else { /* group N bhs to fit into byt_per_blk */ for (size = 0; bh != NULL && size < byt_per_blk;) { @@ -878,22 +835,23 @@ dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req) ccw->flags = CCW_FLAG_DC; ccw->cmd_code = rw_cmd; ccw->count = bh->b_size; - ccw->cda = (void *) __pa (bh->b_data); + ccw->cda = (__u32) __pa (bh->b_data); size += bh->b_size; bh = bh->b_reqnext; - } + } if (size != byt_per_blk) { - PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors); + PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors); ccw_free_request (rw_cp); - return NULL; - } + return NULL; + } ccw->flags = CCW_FLAG_CC; } } ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC); rw_cp->device = device; - rw_cp->expires = 5 * 0xf424000; /* 5 seconds */ + rw_cp->expires = 60 * (unsigned long long)0xf4240000; /* 60 seconds */ rw_cp->req = req; + rw_cp->retries = 2; atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED); return rw_cp; } @@ -924,7 +882,7 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req) for (sct = 0; sct < 8; sct++) { len += sprintf ( page + len," %2d:0x%02x", 8 * sl + sct, sense[8 * sl + sct]); - } + } len += sprintf ( page + len,"\n"); } if (sense[27] & 0x80) { @@ -938,8 +896,8 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req) len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER "32 Byte: Format: %x Exception class %x\n", sense[6] & 0x0f, sense[22] >> 4); - } - } + } + } return page; } @@ -964,11 +922,43 @@ dasd_discipline_t dasd_eckd_discipline = { int dasd_eckd_init( void ) { int rc = 0; + int i; printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_eckd_discipline.name); ASCEBC(dasd_eckd_discipline.ebcname,4); dasd_discipline_enq(&dasd_eckd_discipline); - +#ifdef CONFIG_DASD_DYNAMIC + for ( i=0; i #include #include +#include #include "dasd.h" #include "dasd_fba.h" @@ -40,6 +41,20 @@ dasd_fba_private_t { dasd_fba_characteristics_t rdc_data; } dasd_fba_private_t; +static +devreg_t dasd_fba_known_devices[] = { + { + ci : { hc: { ctype: 0x6310, dtype: 0x9336 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + }, + { + ci : { hc: { ctype: 0x3880, dtype: 0x3370 } }, + flag: DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE, + oper_func: dasd_oper_handler + } +}; + static inline void define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw, int blksize, int beg, int nr) @@ -86,7 +101,7 @@ dasd_fba_id_check ( dev_info_t *info ) return 0; if ( info->sid_data.cu_type == 0x6310 ) if ( info->sid_data.dev_type == 0x9336 ) - return 0; + return 0; return -ENODEV; } @@ -247,17 +262,17 @@ dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req) /* count bhs to prevent errors, when bh smaller than block */ bhct = 0; for (bh = req->bh; bh; bh = bh->b_reqnext) { - if (bh->b_size > byt_per_blk) - for (size = 0; size < bh->b_size; size += byt_per_blk) + if (bh->b_size > byt_per_blk) + for (size = 0; size < bh->b_size; size += byt_per_blk) bhct++; else bhct++; } - + rw_cp = dasd_alloc_request (dasd_fba_discipline.name, 2 + bhct, - sizeof (DE_fba_data_t) + - sizeof (LO_fba_data_t)); + sizeof (DE_fba_data_t) + + sizeof (LO_fba_data_t)); if (!rw_cp) { return NULL; } @@ -326,7 +341,7 @@ dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req) int len; if ( page == NULL ) { return NULL; -} + } len = sprintf ( page, KERN_WARNING PRINTK_HEADER "device %04X on irq %d: I/O status report:\n", @@ -352,15 +367,48 @@ dasd_discipline_t dasd_fba_discipline = { int_handler: dasd_int_handler }; + int dasd_fba_init( void ) { - int rc = 0; + int rc = 0; + int i; printk ( KERN_INFO PRINTK_HEADER "%s discipline initializing\n", dasd_fba_discipline.name); ASCEBC(dasd_fba_discipline.ebcname,4); dasd_discipline_enq(&dasd_fba_discipline); +#ifdef CONFIG_DASD_DYNAMIC + for ( i=0; i * Bugreports.to..: * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a @@ -15,7 +15,6 @@ #include #include - #ifdef PRINTK_HEADER #undef PRINTK_HEADER #endif @@ -33,6 +32,7 @@ EXPORT_SYMBOL(ccw_free_request); /* pointer to list of allocated requests */ static ccw_req_t *ccwreq_actual = NULL; +static spinlock_t ccwchain_lock = SPIN_LOCK_UNLOCKED; /* pointer to debug area */ static debug_info_t *debug_area = NULL; @@ -56,12 +56,16 @@ static kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES]; static void dechain ( ccw_req_t *request ) { + long flags; + /* Sanity checks */ if ( request == NULL ) { printk( KERN_WARNING PRINTK_HEADER "Trying to deallocate NULL request\n"); return; } + + spin_lock_irqsave(&ccwchain_lock,flags); /* first deallocate request from list of allocates requests */ if ( request -> int_next && request -> int_prev ) { if ( request -> int_next == request -> int_prev ) { @@ -75,6 +79,7 @@ dechain ( ccw_req_t *request ) } } else if ( request -> int_next || request -> int_prev ) { } + spin_unlock_irqrestore(&ccwchain_lock,flags); return; } @@ -90,13 +95,14 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) ccw_req_t * request = NULL; int cachind = 0; int size_needed = 0; + long flags; debug_text_event ( debug_area, 1, "ALLC"); if ( magic ) { debug_text_event ( debug_area, 1, magic); } - debug_event ( debug_area, 1, cplength); - debug_event ( debug_area, 1, datasize); + debug_int_event ( debug_area, 1, cplength); + debug_int_event ( debug_area, 1, datasize); /* Sanity checks */ if ( cplength == 0 ) { @@ -140,7 +146,7 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) /* Try to fulfill the request from a cache */ while ( cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */ if ( ccw_cache[cachind] == NULL ){ - printk("cache=%p index %d\n",cachind,cachind); + printk(KERN_WARNING PRINTK_HEADER "NULL cache found! cache=%p index %d\n",ccw_cache[cachind],cachind); } request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC ); if ( request != NULL ) { @@ -148,13 +154,13 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) request->cache = ccw_cache[cachind]; break; } else { - printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache"); + printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache\n"); } cachind++; } /* if no success, fall back to kmalloc */ if ( request == NULL ) { - printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc"); + printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc\n"); request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC ); if ( request != NULL ) { memset ( request, 0, sizeof(ccw_req_t)); @@ -162,7 +168,7 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) } /* Initialize request */ if ( request == NULL ) { - printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request"); + printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request\n"); } else { if ( request -> cache != NULL ) { /* Three cases when coming from a cache */ @@ -215,6 +221,7 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) request -> cplength = cplength; request -> datasize = datasize; /* enqueue request to list of allocated requests */ + spin_lock_irqsave(&ccwchain_lock,flags); if ( ccwreq_actual == NULL ) { /* queue empty */ ccwreq_actual = request; request->int_prev = ccwreq_actual; @@ -225,8 +232,9 @@ ccw_alloc_request ( char *magic, int cplength, int datasize ) request->int_prev->int_next = request; request->int_next->int_prev = request; } + spin_unlock_irqrestore(&ccwchain_lock,flags); } - debug_event ( debug_area, 1, (long)request); + debug_int_event ( debug_area, 1, (long)request); return request; } @@ -242,7 +250,7 @@ ccw_free_request ( ccw_req_t * request ) int slabsize; debug_text_event ( debug_area, 1, "FREE"); - debug_event ( debug_area, 1, (long)request); + debug_int_event ( debug_area, 1, (long)request); /* Sanity checks */ if ( request == NULL ) { printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n"); @@ -256,7 +264,7 @@ ccw_free_request ( ccw_req_t * request ) if ( request ->cpaddr ) { kfree ( request -> cpaddr ); } - dechain ( request); + dechain (request); kfree ( request ); } else { /* Find which area has been allocated by kmalloc */ @@ -300,26 +308,28 @@ ccwcache_init (void) int cachind; /* allocate a debug area */ - debug_area = debug_register( "ccwcache", 2, 4); + debug_area = debug_register( "ccwcache", 2, 4,4); if ( ! debug_area ) { printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" ); } else { printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area ); } + debug_register_view(debug_area,&debug_hex_view); + debug_register_view(debug_area,&debug_ebcdic_view); debug_text_event ( debug_area, 0, "INIT"); /* First allocate the kmem caches */ for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) { int slabsize = SMALLEST_SLAB << cachind; debug_text_event ( debug_area, 1, "allc"); - debug_event ( debug_area, 1, slabsize); + debug_int_event ( debug_area, 1, slabsize); sprintf ( ccw_cache_name[cachind], "%s%d%c", ccw_name_template, slabsize, 0); ccw_cache[cachind] = kmem_cache_create( ccw_cache_name[cachind], slabsize, 0, SLAB_HWCACHE_ALIGN, NULL, NULL ); - debug_event ( debug_area, 1, (long)ccw_cache[cachind]); + debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]); if ( ! ccw_cache [cachind] ) { printk (KERN_WARNING PRINTK_HEADER "Allocation of CCW cache failed\n"); } @@ -345,7 +355,7 @@ ccwcache_cleanup (void) } } } - debug_unregister( debug_area ,"ccwcache"); + debug_unregister( debug_area ); } #ifdef MODULE diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index bfd9b95566d4..c8ac10dfea05 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -5,6 +5,10 @@ * S390 version * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * + * Updated: + * Aug-2000: Added tab support + * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) */ #include @@ -45,6 +49,8 @@ #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ #define RAW3215_BH_PENDING 256 /* indication for bh scheduling */ +#define TAB_STOP_SIZE 8 /* tab stop size */ + struct _raw3215_info; /* forward declaration ... */ int raw3215_condevice = -1; /* preset console device */ @@ -87,6 +93,7 @@ typedef struct _raw3215_info { char *message; /* pending message from raw3215_irq */ int msg_dstat; /* dstat for pending message */ int msg_cstat; /* cstat for pending message */ + int line_pos; /* position on the line (for tabs) */ } raw3215_info; static raw3215_info *raw3215[NR_3215]; /* array of 3215 devices structures */ @@ -103,6 +110,8 @@ static int tty3215_refcount; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +extern void tod_wait(unsigned long usecs); + __initfunc(void con3215_setup(char *str, char *ints)) { int vdev; @@ -167,7 +176,7 @@ static void raw3215_mk_read_req(raw3215_info *raw) ccw->cmd_code = 0x0A; /* read inquiry */ ccw->flags = 0x20; /* ignore incorrect length */ ccw->count = 160; - ccw->cda = (void *) virt_to_phys(raw->inbuf); + ccw->cda = (__u32) __pa(raw->inbuf); } /* @@ -178,7 +187,7 @@ static void raw3215_mk_read_req(raw3215_info *raw) */ static void raw3215_mk_write_req(raw3215_info *raw) { - raw3215_req *req; + raw3215_req *req; ccw1_t *ccw; int len, count, ix, lines; @@ -186,28 +195,28 @@ static void raw3215_mk_write_req(raw3215_info *raw) return; /* check if there is a queued write request */ req = raw->queued_write; - if (req == NULL) { + if (req == NULL) { /* no queued write request, use new req structure */ - req = raw3215_alloc_req(); + req = raw3215_alloc_req(); req->type = RAW3215_WRITE; - req->info = raw; + req->info = raw; raw->queued_write = req; } else { raw->written -= req->len; -} + } ccw = req->ccws; req->start = (raw->head - raw->count + raw->written) & (RAW3215_BUFFER_SIZE - 1); -/* + /* * now we have to count newlines. We can at max accept * RAW3215_MAX_NEWLINE newlines in a single ssch due to * a restriction in VM - */ + */ lines = 0; ix = req->start; while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) { - if (raw->buffer[ix] == '\n') + if (raw->buffer[ix] == 0x15) lines++; ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); } @@ -226,21 +235,20 @@ static void raw3215_mk_write_req(raw3215_info *raw) ccw[-1].flags |= 0x40; /* use command chaining */ ccw->cmd_code = 0x01; /* write, auto carrier return */ ccw->flags = 0x20; /* ignore incorrect length ind. */ - ccw->cda = - (void *) virt_to_phys(raw->buffer + ix); + ccw->cda = (__u32) __pa(raw->buffer + ix); count = len; if (ix + count > RAW3215_BUFFER_SIZE) - count = RAW3215_BUFFER_SIZE-ix; + count = RAW3215_BUFFER_SIZE - ix; ccw->count = count; len -= count; ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1); ccw++; } -/* + /* * Add a NOP to the channel program. 3215 devices are purely * emulated and its much better to avoid the channel end * interrupt in this case. - */ + */ if (ccw > req->ccws) ccw[-1].flags |= 0x40; /* use command chaining */ ccw->cmd_code = 0x03; /* NOP */ @@ -319,7 +327,7 @@ extern inline void raw3215_try_io(raw3215_info *raw) if ((raw->queued_write->delayable == 0) || (raw->flags & RAW3215_FLUSHING)) { /* execute write requests bigger than minimum size */ - raw3215_start_io(raw); + raw3215_start_io(raw); if (raw->flags & RAW3215_TIMER_RUNS) { del_timer(&raw->timer); raw->flags &= ~RAW3215_TIMER_RUNS; @@ -459,7 +467,7 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ && raw->tty != NULL) { tty = raw->tty; - count = 160 - req->residual; + count = 160 - req->residual; if (MACHINE_IS_P390) { slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE); if (count > slen) @@ -517,7 +525,7 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs) } else if (req->type == RAW3215_WRITE) { raw->count -= req->len; raw->written -= req->len; - } + } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); /* check for empty wait */ @@ -530,7 +538,7 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs) raw3215_sched_bh(raw); break; default: - /* Strange interrupt, I'll do my best to clean up */ + /* Strange interrupt, I'll do my best to clean up */ if ((raw = raw3215_find_info(irq)) == NULL) return; /* That shouldn't happen ... */ if (req != NULL && req->type != RAW3215_FREE) { @@ -540,17 +548,45 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs) } raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); - } - raw->message = KERN_WARNING - "Spurious interrupt in in raw3215_irq " - "(dev %i, dev sts 0x%2x, sch sts 0x%2x)"; - raw->msg_dstat = dstat; - raw->msg_cstat = cstat; + } + raw->message = KERN_WARNING + "Spurious interrupt in in raw3215_irq " + "(dev %i, dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; raw3215_sched_bh(raw); } return; } +/* + * Wait until length bytes are available int the output buffer. + * Has to be called with the s390irq lock held. Can be called + * disabled. + */ +void raw3215_make_room(raw3215_info *raw, unsigned int length) +{ + while (RAW3215_BUFFER_SIZE - raw->count < length) { + /* there might be a request pending */ + raw->flags |= RAW3215_FLUSHING; + raw3215_mk_write_req(raw); + raw3215_try_io(raw); + raw->flags &= ~RAW3215_FLUSHING; + if (wait_cons_dev(raw->irq) != 0) { + /* that shouldn't happen */ + raw->count = 0; + raw->written = 0; + } + /* Enough room freed up ? */ + if (RAW3215_BUFFER_SIZE - raw->count >= length) + break; + /* there might be another cpu waiting for the lock */ + s390irq_spin_unlock(raw->irq); + tod_wait(100); + s390irq_spin_lock(raw->irq); + } +} + /* * String write routine for 3215 devices */ @@ -569,16 +605,7 @@ raw3215_write(raw3215_info *raw, const char *str, RAW3215_BUFFER_SIZE : length; length -= count; - while (RAW3215_BUFFER_SIZE - raw->count < count) { - /* there might be a request pending */ - raw3215_mk_write_req(raw); - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } - } + raw3215_make_room(raw, count); /* copy string to output buffer and convert it to EBCDIC */ if (from_user) { @@ -599,6 +626,7 @@ raw3215_write(raw3215_info *raw, const char *str, raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; + raw->line_pos += c; str += c; count -= c; ret += c; @@ -615,6 +643,7 @@ raw3215_write(raw3215_info *raw, const char *str, raw->head = (raw->head + c) & (RAW3215_BUFFER_SIZE - 1); raw->count += c; + raw->line_pos += c; str += c; count -= c; ret += c; @@ -622,8 +651,8 @@ raw3215_write(raw3215_info *raw, const char *str, } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); - /* start or queue request */ - raw3215_try_io(raw); + /* start or queue request */ + raw3215_try_io(raw); } s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -634,29 +663,35 @@ raw3215_write(raw3215_info *raw, const char *str, /* * Put character routine for 3215 devices */ + static void raw3215_putchar(raw3215_info *raw, unsigned char ch) { unsigned long flags; + unsigned int length, i; s390irq_spin_lock_irqsave(raw->irq, flags); - while (RAW3215_BUFFER_SIZE - raw->count < 1) { - /* there might be a request pending */ - raw3215_mk_write_req(raw); - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } + if (ch == '\t') { + length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE); + raw->line_pos += length; + ch = ' '; + } else if (ch == '\n') { + length = 1; + raw->line_pos = 0; + } else { + length = 1; + raw->line_pos++; } + raw3215_make_room(raw, length); - raw->buffer[raw->head] = (char) _ascebc[(int) ch]; - raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); - raw->count++; + for (i = 0; i < length; i++) { + raw->buffer[raw->head] = (char) _ascebc[(int) ch]; + raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1); + raw->count++; + } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); - /* start or queue request */ - raw3215_try_io(raw); + /* start or queue request */ + raw3215_try_io(raw); } s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -690,6 +725,7 @@ static int raw3215_startup(raw3215_info *raw) if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT, "3215 terminal driver", &raw->devstat) != 0) return -1; + raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; s390irq_spin_lock_irqsave(raw->irq, flags); set_cons_dev(raw->irq); @@ -739,12 +775,12 @@ raw3215_find_dev(int number) while (count <= number && irq != -ENODEV) { if (get_dev_info(irq, &dinfo) == -ENODEV) break; - if (dinfo.devno == raw3215_condevice || + if (dinfo.devno == raw3215_condevice || dinfo.sid_data.cu_type == 0x3215) { - count++; + count++; if (count > number) - return irq; -} + return irq; + } irq = get_irq_next(irq); } return -1; /* console not found */ @@ -762,7 +798,8 @@ int con3215_activate(void) if (!MACHINE_IS_VM && !MACHINE_IS_P390) return 0; raw = raw3215[0]; /* 3215 console is the first one */ - if (raw->irq == -1) /* now console device found in con3215_init */ + if (raw == NULL || raw->irq == -1) + /* console device not found in con3215_init */ return -1; return raw3215_startup(raw); } @@ -774,11 +811,24 @@ static void con3215_write(struct console *co, const char *str, unsigned int count) { raw3215_info *raw; + int i; if (count <= 0) return; - raw = raw3215[0]; /* console 3215 is the first one */ - raw3215_write(raw, str, 0, count); + raw = raw3215[0]; /* console 3215 is the first one */ + while (count > 0) { + for (i = 0; i < count; i++) + if (str[i] == '\t' || str[i] == '\n') + break; + raw3215_write(raw, str, 0, i); + count -= i; + str += i; + if (count > 0) { + raw3215_putchar(raw, *str); + count--; + str++; + } + } } kdev_t con3215_device(struct console *c) @@ -797,17 +847,7 @@ void con3215_unblank(void) raw = raw3215[0]; /* console 3215 is the first one */ s390irq_spin_lock_irqsave(raw->irq, flags); - while (raw->count > 0) { - /* there might be a request pending */ - raw->flags |= RAW3215_FLUSHING; - raw3215_try_io(raw); - if (wait_cons_dev(raw->irq) != 0) { - /* that shouldn't happen */ - raw->count = 0; - raw->written = 0; - } - raw->flags &= ~RAW3215_FLUSHING; - } + raw3215_make_room(raw, RAW3215_BUFFER_SIZE); s390irq_spin_unlock_irqrestore(raw->irq, flags); } @@ -914,7 +954,12 @@ static int tty3215_write_room(struct tty_struct *tty) raw3215_info *raw; raw = (raw3215_info *) tty->driver_data; - return RAW3215_BUFFER_SIZE - raw->count; + + /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */ + if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0) + return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE; + else + return 0; } /* @@ -924,7 +969,7 @@ static int tty3215_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { raw3215_info *raw; - int ret; + int ret = 0; if (!tty) return 0; @@ -1062,8 +1107,8 @@ __initfunc (long con3215_init(long kmem_start, long kmem_end)) if (!MACHINE_IS_VM && !MACHINE_IS_P390) return kmem_start; if (MACHINE_IS_VM) { - cpcmd("TERM CONMODE 3215", NULL, 0); - cpcmd("TERM AUTOCR OFF", NULL, 0); + cpcmd("TERM CONMODE 3215", NULL, 0); + cpcmd("TERM AUTOCR OFF", NULL, 0); } kmem_start = (kmem_start + 7) & -8L; diff --git a/drivers/s390/char/hwc.h b/drivers/s390/char/hwc.h index 2ed34ce04288..ed46a4a85a30 100644 --- a/drivers/s390/char/hwc.h +++ b/drivers/s390/char/hwc.h @@ -1,13 +1,13 @@ /* * drivers/s390/char/hwc.h - * + * * * S390 version * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Peschke * - * - * + * + * */ #ifndef __HWC_H__ @@ -109,29 +109,29 @@ typedef struct { go_t; -typedef struct { - go_t go; +typedef struct { + go_t go; } __attribute__ ((packed)) mdb_body_t; typedef struct { _MDB_HEADER - mdb_body_t mdb_body; + mdb_body_t mdb_body; } __attribute__ ((packed)) mdb_t; typedef struct { _EBUF_HEADER - mdb_t mdb; + mdb_t mdb; } __attribute__ ((packed)) msgbuf_t; typedef struct { _HWCB_HEADER - msgbuf_t msgbuf; + msgbuf_t msgbuf; } __attribute__ ((packed)) write_hwcb_t; @@ -144,27 +144,27 @@ mto_t; static write_hwcb_t write_hwcb_template = { - sizeof(write_hwcb_t), - 0x00, + sizeof (write_hwcb_t), + 0x00, { 0x00, - 0x00, - 0x00 + 0x00, + 0x00 }, - 0x0000, - { - sizeof(msgbuf_t), - ET_Msg, - 0x00, - 0x0000, - { - sizeof(mdb_t), + 0x0000, + { + sizeof (msgbuf_t), + ET_Msg, + 0x00, + 0x0000, + { + sizeof (mdb_t), 0x0001, 0xD4C4C240, 0x00000001, - { - { - sizeof(go_t), + { + { + sizeof (go_t), 0x0001 } @@ -175,38 +175,38 @@ static write_hwcb_t write_hwcb_template = static mto_t mto_template = { - sizeof(mto_t), + sizeof (mto_t), 0x0004, - LTF_EndText, - 0x00 + LTF_EndText, + 0x00 }; typedef u32 _hwcb_mask_t; typedef struct { _HWCB_HEADER - u16 _reserved; - u16 mask_length; - _hwcb_mask_t cp_receive_mask; - _hwcb_mask_t cp_send_mask; - _hwcb_mask_t hwc_receive_mask; - _hwcb_mask_t hwc_send_mask; + u16 _reserved; + u16 mask_length; + _hwcb_mask_t cp_receive_mask; + _hwcb_mask_t cp_send_mask; + _hwcb_mask_t hwc_receive_mask; + _hwcb_mask_t hwc_send_mask; } __attribute__ ((packed)) init_hwcb_t; static init_hwcb_t init_hwcb_template = { - sizeof(init_hwcb_t), + sizeof (init_hwcb_t), 0x00, { 0x00, - 0x00, - 0x00 + 0x00, + 0x00 }, - 0x0000, - 0x0000, - sizeof(_hwcb_mask_t), + 0x0000, + 0x0000, + sizeof (_hwcb_mask_t), ET_OpCmd_Mask | ET_PMsgCmd_Mask, ET_Msg_Mask }; @@ -238,12 +238,12 @@ read_hwcb_t; static read_hwcb_t read_hwcb_template = { PAGE_SIZE, - 0x00, + 0x00, { - 0x00, - 0x00, - 0x80 + 0x00, + 0x00, + 0x80 } }; -#endif /* __HWC_H__ */ +#endif /* __HWC_H__ */ diff --git a/drivers/s390/char/hwc_con.c b/drivers/s390/char/hwc_con.c index ca46ad7c8181..39b8444b68bc 100644 --- a/drivers/s390/char/hwc_con.c +++ b/drivers/s390/char/hwc_con.c @@ -18,16 +18,16 @@ #include "hwc_rw.h" -extern void hwc_tty_init(void); +extern void hwc_tty_init (void); #ifdef CONFIG_HWC_CONSOLE -#define hwc_console_major 4 +#define hwc_console_major 4 #define hwc_console_minor 0 -#define hwc_console_name "console" +#define hwc_console_name "console" -void hwc_console_write(struct console *, const char *, unsigned int); -kdev_t hwc_console_device(struct console *); +void hwc_console_write (struct console *, const char *, unsigned int); +kdev_t hwc_console_device (struct console *); void hwc_console_unblank (void); #define HWC_CON_PRINT_HEADER "hwc console driver: " @@ -39,36 +39,36 @@ struct console hwc_console = hwc_console_write, NULL, hwc_console_device, - NULL, + NULL, hwc_console_unblank, - NULL, + NULL, CON_PRINTBUFFER, 0, 0, NULL }; - + void hwc_console_write ( - struct console *console, - const char *message, - unsigned int count) + struct console *console, + const char *message, + unsigned int count) { if (console->device (console) != hwc_console.device (&hwc_console)) { - hwc_printk(KERN_WARNING HWC_CON_PRINT_HEADER - "hwc_console_write() called with wrong " - "device number"); + hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER + "hwc_console_write() called with wrong " + "device number"); return; } - hwc_write(0, message, count); + hwc_write (0, message, count); } kdev_t hwc_console_device (struct console * c) { - return MKDEV(hwc_console_major, hwc_console_minor); + return MKDEV (hwc_console_major, hwc_console_minor); } void @@ -77,26 +77,26 @@ hwc_console_unblank (void) hwc_unblank (); } -#endif +#endif -__initfunc(unsigned long hwc_console_init(unsigned long kmem_start)) +__initfunc (unsigned long hwc_console_init (unsigned long kmem_start)) { #ifdef CONFIG_3215 - if (MACHINE_IS_VM) - return kmem_start; + if (MACHINE_IS_VM) + return kmem_start; #endif if (MACHINE_IS_P390) return kmem_start; - if (hwc_init(&kmem_start) == 0) { + if (hwc_init (&kmem_start) == 0) { hwc_tty_init (); #ifdef CONFIG_HWC_CONSOLE - register_console(&hwc_console); -#endif + register_console (&hwc_console); +#endif } else panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !"); diff --git a/drivers/s390/char/hwc_rw.c b/drivers/s390/char/hwc_rw.c index c2de696c5a07..07a0ea50a3b3 100644 --- a/drivers/s390/char/hwc_rw.c +++ b/drivers/s390/char/hwc_rw.c @@ -6,11 +6,11 @@ * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Peschke * + * * - * - * - * - * + * + * + * */ #include @@ -50,6 +50,8 @@ #undef BUFFER_STRESS_TEST +#define MEASURE_HWC_OUTPUT + typedef struct { unsigned char *next; unsigned short int mto_char_sum; @@ -115,7 +117,7 @@ hwcb_list_t; static unsigned char _obuf[MAX_HWCB_ROOM]; static unsigned char - _page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); + _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))); typedef u32 kmem_pages_t; @@ -179,39 +181,42 @@ static struct { { { }, - { - 8, - 0, - 80, - CODE_ASCII, - 1, - 50, - MAX_KMEM_PAGES, + { + 8, + 0, + 80, + CODE_ASCII, + 1, + 50, + MAX_KMEM_PAGES, - 0, + 0, - 0x6c + 0x6c, + 0, + 0, + 0 }, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - _obuf, - 0, - 0, - 0, - _page, - 0, - NULL, - 0, - 0, - 0, - 0, + NULL, + NULL, + 0, + 0, + 0, + 0, + 0, + 0, + _obuf, + 0, + 0, + 0, + _page, + 0, + NULL, + 0, + 0, + 0, + 0, 0, NULL @@ -225,9 +230,9 @@ static unsigned char psw_mask __attribute__ ((aligned (8))); #define IMMEDIATE_WRITE 1 static signed int do_hwc_write (int from_user, unsigned char *, - unsigned int, - unsigned char, - unsigned char); + unsigned int, + unsigned char, + unsigned char); static asmlinkage int internal_print (char write_time, char *fmt,...) @@ -236,10 +241,10 @@ internal_print (char write_time, char *fmt,...) int i; unsigned char buf[512]; - va_start(args, fmt); - i = vsprintf(buf, fmt, args); - va_end(args); - return do_hwc_write(0, buf, i, CODE_ASCII, write_time); + va_start (args, fmt); + i = vsprintf (buf, fmt, args); + va_end (args); + return do_hwc_write (0, buf, i, CODE_ASCII, write_time); } int @@ -250,18 +255,18 @@ hwc_printk (const char *fmt,...) unsigned char buf[512]; unsigned long flags; int retval; - - spin_lock_irqsave(&hwc_data.lock, flags); - i = vsprintf(buf, fmt, args); - va_end(args); - retval = do_hwc_write(0, buf, i, CODE_ASCII, IMMEDIATE_WRITE); - - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); + + i = vsprintf (buf, fmt, args); + va_end (args); + retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE); + + spin_unlock_irqrestore (&hwc_data.lock, flags); return retval; } - + #ifdef DUMP_HWCB_INPUT static void @@ -275,46 +280,46 @@ dump_storage_area (unsigned char *area, unsigned short int count) old_final_nl = hwc_data.ioctls.final_nl; hwc_data.ioctls.final_nl = 1; - - internal_print(DELAYED_WRITE, "\n%8x ", area); + + internal_print (DELAYED_WRITE, "\n%8x ", area); for (index = 0; index < count; index++) { - + if (area[index] <= 0xF) - internal_print(DELAYED_WRITE, "0%x", area[index]); + internal_print (DELAYED_WRITE, "0%x", area[index]); else internal_print (DELAYED_WRITE, "%x", area[index]); - + if ((index & 0xF) == 0xF) - internal_print(DELAYED_WRITE, "\n%8x ", - &area[index + 1]); - else if ((index & 3) == 3) - internal_print(DELAYED_WRITE, " "); + internal_print (DELAYED_WRITE, "\n%8x ", + &area[index + 1]); + else if ((index & 3) == 3) + internal_print (DELAYED_WRITE, " "); } - - internal_print(IMMEDIATE_WRITE, "\n"); + + internal_print (IMMEDIATE_WRITE, "\n"); hwc_data.ioctls.final_nl = old_final_nl; } -#endif +#endif static inline u32 service_call ( - u32 hwc_command_word, - unsigned char hwcb[]) + u32 hwc_command_word, + unsigned char hwcb[]) { unsigned int condition_code = 1; - __asm__ __volatile__("L 1, 0(0,%0) \n\t" - "LRA 2, 0(0,%1) \n\t" - ".long 0xB2200012 \n\t" - : - :"a"(&hwc_command_word), "a"(hwcb) - :"1", "2", "memory"); + __asm__ __volatile__ ("L 1, 0(0,%0) \n\t" + "LRA 2, 0(0,%1) \n\t" + ".long 0xB2200012 \n\t" + : + :"a" (&hwc_command_word), "a" (hwcb) + :"1", "2", "memory"); - __asm__ __volatile__("IPM %0 \n\t" - "SRL %0, 28 \n\t" - :"=r"(condition_code)); + __asm__ __volatile__ ("IPM %0 \n\t" + "SRL %0, 28 \n\t" + :"=r" (condition_code)); return condition_code; } @@ -324,8 +329,8 @@ ext_int_param (void) { u32 param; - __asm__ __volatile__("L %0,128(0,0)\n\t" - :"=r"(param)); + __asm__ __volatile__ ("L %0,128(0,0)\n\t" + :"=r" (param)); return ((unsigned char *) param); } @@ -337,14 +342,14 @@ prepare_write_hwcb (void) if (!BUF_HWCB) return -ENOMEM; - + BUF_HWCB_MTO = 0; BUF_HWCB_CHAR = 0; hwcb = (write_hwcb_t *) BUF_HWCB; - memcpy(hwcb, &write_hwcb_template, sizeof(write_hwcb_t)); - + memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t)); + if (!hwc_data.write_nonprio && hwc_data.write_prio) hwcb->msgbuf.type = ET_PMsgCmd; @@ -363,27 +368,27 @@ sane_write_hwcb (void) if (!OUT_HWCB) return -ENOMEM; - - if ((unsigned long)OUT_HWCB & 0xFFF) { + + if ((unsigned long) OUT_HWCB & 0xFFF) { bad_addr = OUT_HWCB; #ifdef DUMP_HWC_WRITE_LIST_ERROR - __asm__("LHI 1,0xe30\n\t" - "LRA 2,0(0,%0) \n\t" - "J .+0 \n\t" - : - :"a"(bad_addr) - :"1", "2"); -#endif - + __asm__ ("LHI 1,0xe30\n\t" + "LRA 2,0(0,%0) \n\t" + "J .+0 \n\t" + : + : "a" (bad_addr) + : "1", "2"); +#endif + hwc_data.kmem_pages = 0; - if ((unsigned long)BUF_HWCB & 0xFFF) { + if ((unsigned long) BUF_HWCB & 0xFFF) { lost_hwcb = hwc_data.hwcb_count; lost_msg = ALL_HWCB_MTO; lost_char = ALL_HWCB_CHAR; - + OUT_HWCB = NULL; BUF_HWCB = NULL; ALL_HWCB_MTO = 0; @@ -399,27 +404,27 @@ sane_write_hwcb (void) ALL_HWCB_CHAR = BUF_HWCB_CHAR; hwc_data.hwcb_count = 1; page = (unsigned long) BUF_HWCB; - + if (page >= hwc_data.kmem_start && - page < hwc_data.kmem_end) { - + page <= hwc_data.kmem_end) { + page_nr = (int) - ((page - hwc_data.kmem_start) >> 12); - set_bit(page_nr, &hwc_data.kmem_pages); + ((page - hwc_data.kmem_start) >> 12); + set_bit (page_nr, &hwc_data.kmem_pages); } } - - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER "found invalid HWCB at address 0x%x. List corrupted. " - "Lost %i HWCBs with %i characters within up to %i " - "messages. Saved %i HWCB with last %i characters i" - "within up to %i messages.\n", - (unsigned int)bad_addr, - lost_hwcb, lost_char, lost_msg, - hwc_data.hwcb_count, - ALL_HWCB_CHAR, ALL_HWCB_MTO); + "Lost %i HWCBs with %i characters within up to %i " + "messages. Saved %i HWCB with last %i characters i" + "within up to %i messages.\n", + (unsigned int) bad_addr, + lost_hwcb, lost_char, lost_msg, + hwc_data.hwcb_count, + ALL_HWCB_CHAR, ALL_HWCB_MTO); } return 0; } @@ -430,18 +435,18 @@ reuse_write_hwcb (void) int retval; if (hwc_data.hwcb_count < 2) -#ifdef DUMP_HWC_WRITE_LIST_ERROR - __asm__("LHI 1,0xe31\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(BUF_HWCB), "a"(OUT_HWCB) - :"1", "2", "3"); +#ifdef DUMP_HWC_WRITE_LIST_ERROR + __asm__ ("LHI 1,0xe31\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (BUF_HWCB), "a" (OUT_HWCB) + : "1", "2", "3"); #else return -EPERM; -#endif - +#endif + if (hwc_data.current_hwcb == OUT_HWCB) { if (hwc_data.hwcb_count > 2) { @@ -471,34 +476,34 @@ reuse_write_hwcb (void) ALL_HWCB_MTO -= BUF_HWCB_MTO; ALL_HWCB_CHAR -= BUF_HWCB_CHAR; - retval = prepare_write_hwcb(); + retval = prepare_write_hwcb (); if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb) - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "reached my own limit of " - "allowed buffer space for output (%i HWCBs = %li " - "bytes), skipped content of oldest HWCB %i time(s) " - "(%i lines = %i characters)\n", - hwc_data.ioctls.max_hwcb, - hwc_data.ioctls.max_hwcb * PAGE_SIZE, - BUF_HWCB_TIMES_LOST, - BUF_HWCB_MTO_LOST, - BUF_HWCB_CHAR_LOST); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "reached my own limit of " + "allowed buffer space for output (%i HWCBs = %li " + "bytes), skipped content of oldest HWCB %i time(s) " + "(%i lines = %i characters)\n", + hwc_data.ioctls.max_hwcb, + hwc_data.ioctls.max_hwcb * PAGE_SIZE, + BUF_HWCB_TIMES_LOST, + BUF_HWCB_MTO_LOST, + BUF_HWCB_CHAR_LOST); else internal_print ( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "page allocation failed, " - "could not expand buffer for output (currently in " - "use: %i HWCBs = %li bytes), skipped content of " + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "page allocation failed, " + "could not expand buffer for output (currently in " + "use: %i HWCBs = %li bytes), skipped content of " "oldest HWCB %i time(s) (%i lines = %i characters)\n", - hwc_data.hwcb_count, - hwc_data.hwcb_count * PAGE_SIZE, - BUF_HWCB_TIMES_LOST, - BUF_HWCB_MTO_LOST, - BUF_HWCB_CHAR_LOST); + hwc_data.hwcb_count, + hwc_data.hwcb_count * PAGE_SIZE, + BUF_HWCB_TIMES_LOST, + BUF_HWCB_MTO_LOST, + BUF_HWCB_CHAR_LOST); return retval; } @@ -508,16 +513,16 @@ allocate_write_hwcb (void) { unsigned char *page; int page_nr; - + if (hwc_data.hwcb_count == hwc_data.ioctls.max_hwcb) return -ENOMEM; - - page_nr = find_first_zero_bit(&hwc_data.kmem_pages, MAX_KMEM_PAGES); + + page_nr = find_first_zero_bit (&hwc_data.kmem_pages, MAX_KMEM_PAGES); if (page_nr < hwc_data.ioctls.kmem_hwcb) { page = (unsigned char *) - (hwc_data.kmem_start + (page_nr << 12)); - set_bit(page_nr, &hwc_data.kmem_pages); + (hwc_data.kmem_start + (page_nr << 12)); + set_bit (page_nr, &hwc_data.kmem_pages); } else page = (unsigned char *) __get_free_page (GFP_ATOMIC); @@ -526,7 +531,7 @@ allocate_write_hwcb (void) if (!OUT_HWCB) OUT_HWCB = page; - else + else BUF_HWCB_NEXT = page; BUF_HWCB = page; @@ -535,7 +540,7 @@ allocate_write_hwcb (void) hwc_data.hwcb_count++; - prepare_write_hwcb(); + prepare_write_hwcb (); BUF_HWCB_TIMES_LOST = 0; BUF_HWCB_MTO_LOST = 0; @@ -543,13 +548,13 @@ allocate_write_hwcb (void) #ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - "*** " HWC_RW_PRINT_HEADER - "page #%i at 0x%x for buffering allocated. ***\n", - hwc_data.hwcb_count, page); + internal_print ( + DELAYED_WRITE, + "*** " HWC_RW_PRINT_HEADER + "page #%i at 0x%x for buffering allocated. ***\n", + hwc_data.hwcb_count, page); -#endif +#endif return 0; } @@ -559,54 +564,53 @@ release_write_hwcb (void) { unsigned long page; int page_nr; - - if (!hwc_data.hwcb_count) - return -ENODATA; - - if (hwc_data.hwcb_count == 1) { - - prepare_write_hwcb(); - - ALL_HWCB_CHAR = 0; - ALL_HWCB_MTO = 0; - BUF_HWCB_TIMES_LOST = 0; - BUF_HWCB_MTO_LOST = 0; - BUF_HWCB_CHAR_LOST = 0; + + if (!hwc_data.hwcb_count) + return -ENODATA; + + if (hwc_data.hwcb_count == 1) { + + prepare_write_hwcb (); + + ALL_HWCB_CHAR = 0; + ALL_HWCB_MTO = 0; + BUF_HWCB_TIMES_LOST = 0; + BUF_HWCB_MTO_LOST = 0; + BUF_HWCB_CHAR_LOST = 0; } else { - page = (unsigned long) OUT_HWCB; - - ALL_HWCB_MTO -= OUT_HWCB_MTO; - ALL_HWCB_CHAR -= OUT_HWCB_CHAR; - hwc_data.hwcb_count--; - - OUT_HWCB = OUT_HWCB_NEXT; - - if (page >= hwc_data.kmem_start && - page < hwc_data.kmem_end) { - -/* memset((void *) page, 0, PAGE_SIZE); */ - - page_nr = (int) ((page - hwc_data.kmem_start) >> 12); - clear_bit(page_nr, &hwc_data.kmem_pages); + page = (unsigned long) OUT_HWCB; + + ALL_HWCB_MTO -= OUT_HWCB_MTO; + ALL_HWCB_CHAR -= OUT_HWCB_CHAR; + hwc_data.hwcb_count--; + + OUT_HWCB = OUT_HWCB_NEXT; + + if (page >= hwc_data.kmem_start && + page <= hwc_data.kmem_end) { + /*memset((void *) page, 0, PAGE_SIZE); */ + + page_nr = (int) ((page - hwc_data.kmem_start) >> 12); + clear_bit (page_nr, &hwc_data.kmem_pages); } else - free_page(page); + free_page (page); #ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - "*** " HWC_RW_PRINT_HEADER - "page at 0x%x released, %i pages still in use ***\n", - page, hwc_data.hwcb_count); + internal_print ( + DELAYED_WRITE, + "*** " HWC_RW_PRINT_HEADER + "page at 0x%x released, %i pages still in use ***\n", + page, hwc_data.hwcb_count); -#endif - } +#endif + } return 0; } static int add_mto ( - unsigned char *message, - unsigned short int count) + unsigned char *message, + unsigned short int count) { unsigned short int mto_size; write_hwcb_t *hwcb; @@ -619,32 +623,38 @@ add_mto ( if (BUF_HWCB == hwc_data.current_hwcb) return -ENOMEM; - mto_size = sizeof(mto_t) + count; + mto_size = sizeof (mto_t) + count; hwcb = (write_hwcb_t *) BUF_HWCB; - + if ((MAX_HWCB_ROOM - hwcb->length) < mto_size) return -ENOMEM; mto = (mto_t *) (((unsigned long) hwcb) + hwcb->length); - memcpy(mto, &mto_template, sizeof(mto_t)); + memcpy (mto, &mto_template, sizeof (mto_t)); - dest = (void *) (((unsigned long) mto) + sizeof(mto_t)); + dest = (void *) (((unsigned long) mto) + sizeof (mto_t)); - memcpy(dest, message, count); + memcpy (dest, message, count); mto->length += count; - - hwcb->length += mto_size; - hwcb->msgbuf.length += mto_size; - hwcb->msgbuf.mdb.length += mto_size; + + hwcb->length += mto_size; + hwcb->msgbuf.length += mto_size; + hwcb->msgbuf.mdb.length += mto_size; BUF_HWCB_MTO++; ALL_HWCB_MTO++; BUF_HWCB_CHAR += count; ALL_HWCB_CHAR += count; +#ifdef MEASURE_HWC_OUTPUT + + hwc_data.ioctls.measured_lines++; + hwc_data.ioctls.measured_chars += count; +#endif + return count; } @@ -659,38 +669,41 @@ write_event_data_1 (void) if (hwc_data.current_servc) return -EBUSY; - - retval = sane_write_hwcb(); + + retval = sane_write_hwcb (); if (retval < 0) return retval; if (!OUT_HWCB_MTO) return -ENODATA; - condition_code = service_call(HWC_CMDW_WRITEDATA, OUT_HWCB); + condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB); -#ifdef DUMP_HWC_WRITE_ERROR +#ifdef DUMP_HWC_WRITE_ERROR if (condition_code != HWC_COMMAND_INITIATED) - __asm__("LHI 1,0xe20\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(&condition_code), "a"(OUT_HWCB) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe20\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (&condition_code), "a" (OUT_HWCB) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_WRITEDATA; - hwc_data.current_hwcb = OUT_HWCB; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_WRITEDATA; + hwc_data.current_hwcb = OUT_HWCB; + retval = condition_code; +#ifdef MEASURE_HWC_OUTPUT + hwc_data.ioctls.measured_wcalls++; +#endif + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -700,9 +713,9 @@ static void flush_hwcbs (void) { while (hwc_data.hwcb_count > 1) - release_write_hwcb(); + release_write_hwcb (); - release_write_hwcb(); + release_write_hwcb (); hwc_data.flags &= ~HWC_FLUSH; } @@ -716,7 +729,7 @@ write_event_data_2 (void) #ifdef DUMP_HWC_WRITE_ERROR unsigned char *param; - param = ext_int_param(); + param = ext_int_param (); if (param != hwc_data.current_hwcb) { internal_print ( DELAYED_WRITE, @@ -734,42 +747,42 @@ write_event_data_2 (void) #ifdef DUMP_HWC_WRITE_LIST_ERROR if (((unsigned char *) hwcb) != hwc_data.current_hwcb) { - __asm__("LHI 1,0xe22\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" - "J .+0 \n\t" - : - :"a"(OUT_HWCB), - "a"(hwc_data.current_hwcb), - "a"(BUF_HWCB), + __asm__ ("LHI 1,0xe22\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LRA 5,0(0,%3)\n\t" + "J .+0 \n\t" + : + : "a" (OUT_HWCB), + "a" (hwc_data.current_hwcb), + "a" (BUF_HWCB), "a" (hwcb) - :"1", "2", "3", "4", "5"); + : "1", "2", "3", "4", "5"); } #endif #ifdef DUMP_HWC_WRITE_ERROR if (hwcb->response_code != 0x0020) { - __asm__("LHI 1,0xe21\n\t" - "LRA 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LH 5,0(0,%3)\n\t" - "SRL 5,8(0)\n\t" - "J .+0 \n\t" - : - :"a"(OUT_HWCB), "a"(hwc_data.current_hwcb), - "a"(BUF_HWCB), - "a"(&(hwc_data.hwcb_count)) - :"1", "2", "3", "4", "5"); + __asm__ ("LHI 1,0xe21\n\t" + "LRA 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LH 5,0(0,%3)\n\t" + "SRL 5,8(0)\n\t" + "J .+0 \n\t" + : + : "a" (OUT_HWCB), "a" (hwc_data.current_hwcb), + "a" (BUF_HWCB), + "a" (&(hwc_data.hwcb_count)) + : "1", "2", "3", "4", "5"); } -#endif +#endif if (hwcb->response_code == 0x0020) { retval = OUT_HWCB_CHAR; - release_write_hwcb(); + release_write_hwcb (); } else { internal_print ( DELAYED_WRITE, @@ -787,53 +800,53 @@ write_event_data_2 (void) hwc_data.current_hwcb = NULL; if (hwc_data.flags & HWC_FLUSH) - flush_hwcbs(); + flush_hwcbs (); return retval; } static void do_put_line ( - unsigned char * message, - unsigned short count) + unsigned char *message, + unsigned short count) { - if (add_mto(message, count) != count) { - - if (allocate_write_hwcb() < 0) - reuse_write_hwcb(); - -#ifdef DUMP_HWC_WRITE_LIST_ERROR - if (add_mto(message, count) != count) - __asm__("LHI 1,0xe32\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "LRA 4,0(0,%2)\n\t" - "LRA 5,0(0,%3)\n\t" - "J .+0 \n\t" - : - :"a"(message), "a"(&hwc_data.kmem_pages), - "a"(BUF_HWCB), "a"(OUT_HWCB) - :"1", "2", "3", "4", "5"); + if (add_mto (message, count) != count) { + + if (allocate_write_hwcb () < 0) + reuse_write_hwcb (); + +#ifdef DUMP_HWC_WRITE_LIST_ERROR + if (add_mto (message, count) != count) + __asm__ ("LHI 1,0xe32\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "LRA 4,0(0,%2)\n\t" + "LRA 5,0(0,%3)\n\t" + "J .+0 \n\t" + : + : "a" (message), "a" (&hwc_data.kmem_pages), + "a" (BUF_HWCB), "a" (OUT_HWCB) + : "1", "2", "3", "4", "5"); #else - add_mto(message, count); -#endif + add_mto (message, count); +#endif } } static void put_line ( - unsigned char * message, - unsigned short count) + unsigned char *message, + unsigned short count) { - + if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) { - del_timer(&hwc_data.write_timer); + del_timer (&hwc_data.write_timer); hwc_data.flags &= ~HWC_TIMER_RUNS; } hwc_data.obuf_start += count; - do_put_line(message, count); + do_put_line (message, count); hwc_data.obuf_start -= count; } @@ -844,39 +857,39 @@ set_alarm (void) write_hwcb_t *hwcb; if ((!BUF_HWCB) || (BUF_HWCB == hwc_data.current_hwcb)) - allocate_write_hwcb(); + allocate_write_hwcb (); hwcb = (write_hwcb_t *) BUF_HWCB; hwcb->msgbuf.mdb.mdb_body.go.general_msg_flags |= GMF_SndAlrm; -} +} static void hwc_write_timeout (unsigned long data) { unsigned long flags; - - spin_lock_irqsave(&hwc_data.lock, flags); - + + spin_lock_irqsave (&hwc_data.lock, flags); + hwc_data.obuf_start = hwc_data.obuf_count; if (hwc_data.obuf_count) - put_line(hwc_data.obuf, hwc_data.obuf_count); + put_line (hwc_data.obuf, hwc_data.obuf_count); hwc_data.obuf_start = 0; hwc_data.obuf_cursor = 0; hwc_data.obuf_count = 0; - - write_event_data_1(); - spin_unlock_irqrestore(&hwc_data.lock, flags); + write_event_data_1 (); + + spin_unlock_irqrestore (&hwc_data.lock, flags); } static int do_hwc_write ( - int from_user, + int from_user, unsigned char *msg, - unsigned int count, - unsigned char code, - unsigned char write_time) + unsigned int count, + unsigned char code, + unsigned char write_time) { unsigned int i_msg = 0; unsigned short int spaces = 0; @@ -889,18 +902,18 @@ do_hwc_write ( if (hwc_data.obuf_start) { obuf_cursor = 0; obuf_count = 0; - obuf_columns = MIN(hwc_data.ioctls.columns, - MAX_MESSAGE_SIZE - hwc_data.obuf_start); + obuf_columns = MIN (hwc_data.ioctls.columns, + MAX_MESSAGE_SIZE - hwc_data.obuf_start); } else { obuf_cursor = hwc_data.obuf_cursor; obuf_count = hwc_data.obuf_count; obuf_columns = hwc_data.ioctls.columns; } - + for (i_msg = 0; i_msg < count; i_msg++) { if (from_user) - get_user(orig_ch, msg + i_msg); + get_user (orig_ch, msg + i_msg); else orig_ch = msg[i_msg]; if (code == CODE_EBCDIC) @@ -909,42 +922,42 @@ do_hwc_write ( ch = orig_ch; processed_characters++; - + if ((obuf_cursor == obuf_columns) && (ch != '\n') && (ch != '\t')) { - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_columns); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_columns); obuf_cursor = 0; obuf_count = 0; } switch (ch) { - case '\n' : + case '\n': - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; break; - case '\a' : + case '\a': hwc_data.obuf_start += obuf_count; - set_alarm(); + set_alarm (); hwc_data.obuf_start -= obuf_count; break; - case '\t' : + case '\t': do { if (obuf_cursor < obuf_columns) { hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor] - = 0x20; + obuf_cursor] + = 0x20; obuf_cursor++; } else break; @@ -952,47 +965,47 @@ do_hwc_write ( break; - case '\f' : - case '\v' : + case '\f': + case '\v': spaces = obuf_cursor; - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_count = obuf_cursor; while (spaces) { hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor - spaces] - = 0x20; + obuf_cursor - spaces] + = 0x20; spaces--; } break; - case '\b' : + case '\b': if (obuf_cursor) obuf_cursor--; break; - case '\r' : + case '\r': obuf_cursor = 0; break; - case 0x00 : + case 0x00: - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; goto out; - default: + default: - if (isprint(ch)) + if (isprint (ch)) hwc_data.obuf[hwc_data.obuf_start + - obuf_cursor++] - = (code == CODE_ASCII) ? + obuf_cursor++] + = (code == CODE_ASCII) ? (MACHINE_IS_VM ? _ascebc[orig_ch] : _ascebc_500[orig_ch]) : @@ -1006,9 +1019,9 @@ do_hwc_write ( if (hwc_data.obuf_start || (hwc_data.ioctls.final_nl == 0)) { - - put_line(&hwc_data.obuf[hwc_data.obuf_start], - obuf_count); + + put_line (&hwc_data.obuf[hwc_data.obuf_start], + obuf_count); obuf_cursor = 0; obuf_count = 0; } else { @@ -1018,34 +1031,34 @@ do_hwc_write ( if (hwc_data.flags & HWC_TIMER_RUNS) { hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl*HZ/10; + jiffies + + hwc_data.ioctls.final_nl * HZ / 10; } else { - init_timer(&hwc_data.write_timer); + init_timer (&hwc_data.write_timer); hwc_data.write_timer.function = - hwc_write_timeout; + hwc_write_timeout; hwc_data.write_timer.data = - (unsigned long)NULL; + (unsigned long) NULL; hwc_data.write_timer.expires = - jiffies + - hwc_data.ioctls.final_nl*HZ/10; - add_timer(&hwc_data.write_timer); + jiffies + + hwc_data.ioctls.final_nl * HZ / 10; + add_timer (&hwc_data.write_timer); hwc_data.flags |= HWC_TIMER_RUNS; } } else; - } + } } else; -out : + out: if (!hwc_data.obuf_start) { hwc_data.obuf_cursor = obuf_cursor; hwc_data.obuf_count = obuf_count; } if (write_time == IMMEDIATE_WRITE) - write_event_data_1(); + write_event_data_1 (); return processed_characters; } @@ -1055,14 +1068,14 @@ hwc_write (int from_user, const unsigned char *msg, unsigned int count) { unsigned long flags; int retval; - - spin_lock_irqsave(&hwc_data.lock, flags); + + spin_lock_irqsave (&hwc_data.lock, flags); retval = do_hwc_write (from_user, (unsigned char *) msg, count, hwc_data.ioctls.code, - IMMEDIATE_WRITE); + IMMEDIATE_WRITE); - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); return retval; } @@ -1073,15 +1086,15 @@ hwc_chars_in_buffer (unsigned char flag) unsigned short int number = 0; unsigned long flags; - spin_lock_irqsave(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); if (flag & IN_HWCB) number += ALL_HWCB_CHAR; - + if (flag & IN_WRITE_BUF) number += hwc_data.obuf_cursor; - - spin_unlock_irqrestore(&hwc_data.lock, flags); + + spin_unlock_irqrestore (&hwc_data.lock, flags); return number; } @@ -1092,7 +1105,7 @@ nr_setbits (kmem_pages_t arg) int i; int nr = 0; - for (i = 0; i < (sizeof(arg) << 3); i++) { + for (i = 0; i < (sizeof (arg) << 3); i++) { if (arg & 1) nr++; arg >>= 1; @@ -1107,24 +1120,24 @@ hwc_write_room (unsigned char flag) unsigned int number = 0; unsigned long flags; write_hwcb_t *hwcb; - - spin_lock_irqsave(&hwc_data.lock, flags); - if (flag & IN_HWCB) { + spin_lock_irqsave (&hwc_data.lock, flags); + + if (flag & IN_HWCB) { if (BUF_HWCB) { hwcb = (write_hwcb_t *) BUF_HWCB; - number += MAX_HWCB_ROOM - hwcb->length; + number += MAX_HWCB_ROOM - hwcb->length; } number += (hwc_data.ioctls.kmem_hwcb - - nr_setbits(hwc_data.kmem_pages)) * - (MAX_HWCB_ROOM - - (sizeof(write_hwcb_t) + sizeof(mto_t))); + nr_setbits (hwc_data.kmem_pages)) * + (MAX_HWCB_ROOM - + (sizeof (write_hwcb_t) + sizeof (mto_t))); } - if (flag & IN_WRITE_BUF) - number += MAX_HWCB_ROOM - hwc_data.obuf_cursor; + if (flag & IN_WRITE_BUF) + number += MAX_HWCB_ROOM - hwc_data.obuf_cursor; - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); return number; } @@ -1134,19 +1147,19 @@ hwc_flush_buffer (unsigned char flag) { unsigned long flags; - spin_lock_irqsave(&hwc_data.lock, flags); + spin_lock_irqsave (&hwc_data.lock, flags); if (flag & IN_HWCB) { if (hwc_data.current_servc != HWC_CMDW_WRITEDATA) - flush_hwcbs(); + flush_hwcbs (); else hwc_data.flags |= HWC_FLUSH; } if (flag & IN_WRITE_BUF) { - hwc_data.obuf_cursor = 0; + hwc_data.obuf_cursor = 0; hwc_data.obuf_count = 0; } - spin_unlock_irqrestore(&hwc_data.lock, flags); + spin_unlock_irqrestore (&hwc_data.lock, flags); } unsigned short int @@ -1170,7 +1183,7 @@ seperate_cases (unsigned char *buf, unsigned short int count) i_out++; - i_in++; + i_in++; } else _case = ~_case; @@ -1179,7 +1192,7 @@ seperate_cases (unsigned char *buf, unsigned short int count) if (_case) { - if (hwc_data.ioctls.tolower) + if (hwc_data.ioctls.tolower) buf[i_out] = _ebc_toupper[buf[i_in]]; else @@ -1203,43 +1216,43 @@ gds_vector_name (u16 id, unsigned char name[]) int retval = 0; switch (id) { - case GDS_ID_MDSMU : - name = "Multiple Domain Support Message Unit"; - break; - case GDS_ID_MDSRouteInfo : - name = "MDS Routing Information"; - break; - case GDS_ID_AgUnWrkCorr : - name = "Agent Unit of Work Correlator"; - break; - case GDS_ID_SNACondReport : - name = "SNA Condition Report"; - break; - case GDS_ID_CPMSU : - name = "CP Management Services Unit"; - break; - case GDS_ID_RoutTargInstr : - name = "Routing and Targeting Instructions"; - break; - case GDS_ID_OpReq : - name = "Operate Request"; - break; - case GDS_ID_TextCmd : - name = "Text Command"; - break; + case GDS_ID_MDSMU: + name = "Multiple Domain Support Message Unit"; + break; + case GDS_ID_MDSRouteInfo: + name = "MDS Routing Information"; + break; + case GDS_ID_AgUnWrkCorr: + name = "Agent Unit of Work Correlator"; + break; + case GDS_ID_SNACondReport: + name = "SNA Condition Report"; + break; + case GDS_ID_CPMSU: + name = "CP Management Services Unit"; + break; + case GDS_ID_RoutTargInstr: + name = "Routing and Targeting Instructions"; + break; + case GDS_ID_OpReq: + name = "Operate Request"; + break; + case GDS_ID_TextCmd: + name = "Text Command"; + break; - default : - name = "unknown GDS variable"; - retval = -EINVAL; + default: + name = "unknown GDS variable"; + retval = -EINVAL; } return retval; } -#endif +#endif inline static gds_vector_t * find_gds_vector ( - gds_vector_t *start, void *end, u16 id) + gds_vector_t * start, void *end, u16 id) { gds_vector_t *vec; gds_vector_t *retval = NULL; @@ -1247,31 +1260,31 @@ find_gds_vector ( vec = start; while (((void *) vec) < end) { - if (vec->gds_id == id) { + if (vec->gds_id == id) { #ifdef DUMP_HWCB_INPUT int retval_name; unsigned char name[64]; - retval_name = gds_vector_name(id, name); - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "%s at 0x%x up to 0x%x, length: %d", - name, - (unsigned long) vec, - ((unsigned long) vec) + vec->length - 1, - vec->length); + retval_name = gds_vector_name (id, name); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "%s at 0x%x up to 0x%x, length: %d", + name, + (unsigned long) vec, + ((unsigned long) vec) + vec->length - 1, + vec->length); if (retval_name < 0) - internal_print( - IMMEDIATE_WRITE, - ", id: 0x%x\n", - vec->gds_id); + internal_print ( + IMMEDIATE_WRITE, + ", id: 0x%x\n", + vec->gds_id); else internal_print ( - IMMEDIATE_WRITE, - "\n"); -#endif + IMMEDIATE_WRITE, + "\n"); +#endif retval = vec; break; @@ -1284,7 +1297,7 @@ find_gds_vector ( inline static gds_subvector_t * find_gds_subvector ( - gds_subvector_t *start, void *end, u8 key) + gds_subvector_t * start, void *end, u8 key) { gds_subvector_t *subvec; gds_subvector_t *retval = NULL; @@ -1292,12 +1305,12 @@ find_gds_subvector ( subvec = start; while (((void *) subvec) < end) { - if (subvec->key == key) { + if (subvec->key == key) { retval = subvec; break; } subvec = (gds_subvector_t *) - (((unsigned long) subvec) + subvec->length); + (((unsigned long) subvec) + subvec->length); } return retval; @@ -1311,17 +1324,17 @@ get_input (void *start, void *end) count = ((unsigned long) end) - ((unsigned long) start); if (hwc_data.ioctls.tolower) - EBC_TOLOWER(start, count); + EBC_TOLOWER (start, count); if (hwc_data.ioctls.delim) - count = seperate_cases(start, count); + count = seperate_cases (start, count); if (hwc_data.ioctls.echo) - do_hwc_write(0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); + do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE); if (hwc_data.ioctls.code == CODE_ASCII) { if (MACHINE_IS_VM) - EBCASC(start, count); + EBCASC (start, count); else EBCASC_500 (start, count); } @@ -1343,15 +1356,15 @@ eval_selfdeftextmsg (gds_subvector_t * start, void *end) subvec = start; while (((void *) subvec) < end) { - subvec = find_gds_subvector(subvec, end, 0x30); + subvec = find_gds_subvector (subvec, end, 0x30); if (!subvec) break; subvec_data = (void *) - (((unsigned long) subvec) + - sizeof(gds_subvector_t)); + (((unsigned long) subvec) + + sizeof (gds_subvector_t)); subvec_end = (void *) - (((unsigned long) subvec) + subvec->length); - retval += get_input(subvec_data, subvec_end); + (((unsigned long) subvec) + subvec->length); + retval += get_input (subvec_data, subvec_end); subvec = (gds_subvector_t *) subvec_end; } @@ -1369,16 +1382,16 @@ eval_textcmd (gds_subvector_t * start, void *end) subvec = start; while (((void *) subvec) < end) { - subvec = find_gds_subvector( - subvec, end, GDS_KEY_SelfDefTextMsg); + subvec = find_gds_subvector ( + subvec, end, GDS_KEY_SelfDefTextMsg); if (!subvec) break; subvec_data = (gds_subvector_t *) - (((unsigned long) subvec) + - sizeof(gds_subvector_t)); + (((unsigned long) subvec) + + sizeof (gds_subvector_t)); subvec_end = (void *) - (((unsigned long) subvec) + subvec->length); - retval += eval_selfdeftextmsg(subvec_data, subvec_end); + (((unsigned long) subvec) + subvec->length); + retval += eval_selfdeftextmsg (subvec_data, subvec_end); subvec = (gds_subvector_t *) subvec_end; } @@ -1396,13 +1409,13 @@ eval_cpmsu (gds_vector_t * start, void *end) vec = start; while (((void *) vec) < end) { - vec = find_gds_vector(vec, end, GDS_ID_TextCmd); + vec = find_gds_vector (vec, end, GDS_ID_TextCmd); if (!vec) break; vec_data = (gds_subvector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval += eval_textcmd(vec_data, vec_end); + retval += eval_textcmd (vec_data, vec_end); vec = (gds_vector_t *) vec_end; } @@ -1417,12 +1430,12 @@ eval_mdsmu (gds_vector_t * start, void *end) void *vec_end; int retval = 0; - vec = find_gds_vector(start, end, GDS_ID_CPMSU); + vec = find_gds_vector (start, end, GDS_ID_CPMSU); if (vec) { vec_data = (gds_vector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval = eval_cpmsu(vec_data, vec_end); + retval = eval_cpmsu (vec_data, vec_end); } return retval; } @@ -1435,12 +1448,12 @@ eval_evbuf (gds_vector_t * start, void *end) void *vec_end; int retval = 0; - vec = find_gds_vector(start, end, GDS_ID_MDSMU); + vec = find_gds_vector (start, end, GDS_ID_MDSMU); if (vec) { vec_data = (gds_vector_t *) - (((unsigned long) vec) + sizeof(gds_vector_t)); + (((unsigned long) vec) + sizeof (gds_vector_t)); vec_end = (void *) (((unsigned long) vec) + vec->length); - retval = eval_mdsmu(vec_data, vec_end); + retval = eval_mdsmu (vec_data, vec_end); } return retval; } @@ -1456,39 +1469,39 @@ process_evbufs (void *start, void *end) evbuf = (evbuf_t *) start; while (((void *) evbuf) < end) { evbuf_data = (gds_vector_t *) - (((unsigned long) evbuf) + sizeof(evbuf_t)); + (((unsigned long) evbuf) + sizeof (evbuf_t)); evbuf_end = (void *) (((unsigned long) evbuf) + evbuf->length); switch (evbuf->type) { - case ET_OpCmd : - case ET_CntlProgOpCmd : - case ET_PMsgCmd : + case ET_OpCmd: + case ET_CntlProgOpCmd: + case ET_PMsgCmd: #ifdef DUMP_HWCB_INPUT - - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "event buffer " - "at 0x%x up to 0x%x, length: %d\n", - (unsigned long) evbuf, - (unsigned long) (evbuf_end - 1), - evbuf->length); - dump_storage_area((void *)evbuf, evbuf->length); + + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "event buffer " + "at 0x%x up to 0x%x, length: %d\n", + (unsigned long) evbuf, + (unsigned long) (evbuf_end - 1), + evbuf->length); + dump_storage_area ((void *) evbuf, evbuf->length); #endif - retval += eval_evbuf(evbuf_data, evbuf_end); - break; - case ET_StateChange : - - retval = -ENOSYS; - break; - default : - printk( - KERN_WARNING - HWC_RW_PRINT_HEADER - "unconditional read: " - "unknown event buffer found, " - "type 0x%x", - evbuf->type); - retval = -ENOSYS; + retval += eval_evbuf (evbuf_data, evbuf_end); + break; + case ET_StateChange: + + retval = -ENOSYS; + break; + default: + printk ( + KERN_WARNING + HWC_RW_PRINT_HEADER + "unconditional read: " + "unknown event buffer found, " + "type 0x%x", + evbuf->type); + retval = -ENOSYS; } evbuf = (evbuf_t *) evbuf_end; } @@ -1501,40 +1514,40 @@ unconditional_read_1 (void) unsigned short int condition_code; read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; int retval; - + if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio)) return -EOPNOTSUPP; if (hwc_data.current_servc) return -EBUSY; - - memset(hwcb, 0x00, PAGE_SIZE); - memcpy(hwcb, &read_hwcb_template, sizeof(read_hwcb_t)); - condition_code = service_call(HWC_CMDW_READDATA, hwc_data.page); + memset (hwcb, 0x00, PAGE_SIZE); + memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t)); -#ifdef DUMP_HWC_READ_ERROR + condition_code = service_call (HWC_CMDW_READDATA, hwc_data.page); + +#ifdef DUMP_HWC_READ_ERROR if (condition_code == HWC_NOT_OPERATIONAL) - __asm__("LHI 1,0xe40\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0 \n\t" - : - :"a"(&condition_code), "a"(hwc_data.page) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe40\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0 \n\t" + : + : "a" (&condition_code), "a" (hwc_data.page) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_READDATA; - hwc_data.current_hwcb = hwc_data.page; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_READDATA; + hwc_data.current_hwcb = hwc_data.page; + retval = condition_code; + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -1545,33 +1558,33 @@ unconditional_read_2 (void) { read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page; -#ifdef DUMP_HWC_READ_ERROR +#ifdef DUMP_HWC_READ_ERROR if ((hwcb->response_code != 0x0020) && (hwcb->response_code != 0x0220) && (hwcb->response_code != 0x60F0) && (hwcb->response_code != 0x62F0)) - __asm__("LHI 1,0xe41\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(hwc_data.page), "a"(&(hwcb->response_code)) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe41\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (hwc_data.page), "a" (&(hwcb->response_code)) + : "1", "2", "3"); +#endif hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; switch (hwcb->response_code) { - case 0x0020 : - case 0x0220 : - return process_evbufs( - (void *) (((unsigned long) hwcb) + sizeof(read_hwcb_t)), - (void *) (((unsigned long) hwcb) + hwcb->length)); + case 0x0020: + case 0x0220: + return process_evbufs ( + (void *) (((unsigned long) hwcb) + sizeof (read_hwcb_t)), + (void *) (((unsigned long) hwcb) + hwcb->length)); - case 0x60F0 : - case 0x62F0 : + case 0x60F0: + case 0x62F0: internal_print ( IMMEDIATE_WRITE, HWC_RW_PRINT_HEADER @@ -1581,67 +1594,67 @@ unconditional_read_2 (void) hwcb->response_code); return 0; - case 0x0100 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: HWCB boundary violation - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x0100: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: HWCB boundary violation - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x0300 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: " + case 0x0300: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " "insufficient HWCB length - this must not occur in a " - "correct driver, please contact author\n"); + "correct driver, please contact author\n"); return -EIO; - case 0x01F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: " - "invalid command - this must not occur in a correct " - "driver, please contact author\n"); + case 0x01F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: " + "invalid command - this must not occur in a correct " + "driver, please contact author\n"); return -EIO; - case 0x40F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: invalid function code - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x40F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: invalid function code - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x70F0 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: invalid selection mask - this " - "must not occur in a correct driver, please contact " - "author\n"); + case 0x70F0: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: invalid selection mask - this " + "must not occur in a correct driver, please contact " + "author\n"); return -EIO; - case 0x0040 : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER - "unconditional read: HWC equipment check - don't " - "know how to handle this case\n"); + case 0x0040: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER + "unconditional read: HWC equipment check - don't " + "know how to handle this case\n"); return -EIO; - - default : - internal_print( - IMMEDIATE_WRITE, - HWC_RW_PRINT_HEADER + + default: + internal_print ( + IMMEDIATE_WRITE, + HWC_RW_PRINT_HEADER "unconditional read: invalid response code %x - this " - "must not occur in a correct driver, please contact " - "author\n", - hwcb->response_code); + "must not occur in a correct driver, please contact " + "author\n", + hwcb->response_code); return -EIO; } } @@ -1651,32 +1664,32 @@ write_event_mask_1 (void) { unsigned int condition_code; int retval; - - condition_code = service_call(HWC_CMDW_WRITEMASK, hwc_data.page); + + condition_code = service_call (HWC_CMDW_WRITEMASK, hwc_data.page); #ifdef DUMP_HWC_INIT_ERROR if (condition_code == HWC_NOT_OPERATIONAL) - __asm__("LHI 1,0xe10\n\t" - "L 2,0(0,%0)\n\t" - "LRA 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(&condition_code), "a"(hwc_data.page) - :"1", "2", "3"); -#endif + __asm__ ("LHI 1,0xe10\n\t" + "L 2,0(0,%0)\n\t" + "LRA 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (&condition_code), "a" (hwc_data.page) + : "1", "2", "3"); +#endif switch (condition_code) { - case HWC_COMMAND_INITIATED : - hwc_data.current_servc = HWC_CMDW_WRITEMASK; - hwc_data.current_hwcb = hwc_data.page; - retval = condition_code; - break; - case HWC_BUSY : - retval = -EBUSY; - break; - default : - retval = -EIO; + case HWC_COMMAND_INITIATED: + hwc_data.current_servc = HWC_CMDW_WRITEMASK; + hwc_data.current_hwcb = hwc_data.page; + retval = condition_code; + break; + case HWC_BUSY: + retval = -EBUSY; + break; + default: + retval = -EIO; } return retval; @@ -1690,10 +1703,10 @@ write_event_mask_2 (void) if (hwcb->hwc_receive_mask & ET_Msg_Mask) hwc_data.write_nonprio = 1; - + if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask) hwc_data.write_prio = 1; - + if (hwcb->hwc_send_mask & ET_OpCmd_Mask) { internal_print (DELAYED_WRITE, HWC_RW_PRINT_HEADER @@ -1710,16 +1723,16 @@ write_event_mask_2 (void) (!hwc_data.write_nonprio) || ((!hwc_data.read_nonprio) && (!hwc_data.read_prio))) #ifdef DUMP_HWC_INIT_ERROR - __asm__("LHI 1,0xe11\n\t" - "LRA 2,0(0,%0)\n\t" - "L 3,0(0,%1)\n\t" - "J .+0\n\t" - : - :"a"(hwcb), "a"(&(hwcb->response_code)) - :"1", "2", "3"); + __asm__ ("LHI 1,0xe11\n\t" + "LRA 2,0(0,%0)\n\t" + "L 3,0(0,%1)\n\t" + "J .+0\n\t" + : + : "a" (hwcb), "a" (&(hwcb->response_code)) + : "1", "2", "3"); #else retval = -EIO; -#endif +#endif hwc_data.current_servc = 0; hwc_data.current_hwcb = NULL; @@ -1732,7 +1745,7 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) { int retval = 0; hwc_ioctls_t tmp; - + if (ioctls->width_htab > MAX_MESSAGE_SIZE) { if (correct) tmp.width_htab = MAX_MESSAGE_SIZE; @@ -1742,7 +1755,7 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) tmp.width_htab = ioctls->width_htab; tmp.echo = ioctls->echo; - + if (ioctls->columns > MAX_MESSAGE_SIZE) { if (correct) tmp.columns = MAX_MESSAGE_SIZE; @@ -1750,21 +1763,21 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) retval = -EINVAL; } else tmp.columns = ioctls->columns; - + switch (ioctls->code) { - case CODE_EBCDIC : - case CODE_ASCII : - tmp.code = ioctls->code; - break; - default : - if (correct) - tmp.code = CODE_ASCII; + case CODE_EBCDIC: + case CODE_ASCII: + tmp.code = ioctls->code; + break; + default: + if (correct) + tmp.code = CODE_ASCII; else retval = -EINVAL; } - + tmp.final_nl = ioctls->final_nl; - + if (ioctls->max_hwcb < 2) { if (correct) tmp.max_hwcb = 2; @@ -1772,9 +1785,9 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) retval = -EINVAL; } else tmp.max_hwcb = ioctls->max_hwcb; - + tmp.tolower = ioctls->tolower; - + if (ioctls->kmem_hwcb > ioctls->max_hwcb) { if (correct) tmp.kmem_hwcb = ioctls->max_hwcb; @@ -1782,7 +1795,7 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) retval = -EINVAL; } else tmp.kmem_hwcb = ioctls->kmem_hwcb; - + if (ioctls->kmem_hwcb > MAX_KMEM_PAGES) { if (correct) ioctls->kmem_hwcb = MAX_KMEM_PAGES; @@ -1797,6 +1810,10 @@ set_hwc_ioctls (hwc_ioctls_t * ioctls, char correct) } tmp.delim = ioctls->delim; + tmp.measured_lines = ioctls->measured_lines; + tmp.measured_chars = ioctls->measured_chars; + tmp.measured_wcalls = ioctls->measured_wcalls; + if (!(retval < 0)) hwc_data.ioctls = tmp; @@ -1864,7 +1881,7 @@ hwc_init (unsigned long *kmem_start) if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0) panic ("Couldn't request external interrupts 0x2401"); - spin_lock_init(&hwc_data.lock); + spin_lock_init (&hwc_data.lock); #ifdef USE_VM_DETECTION @@ -1880,7 +1897,7 @@ hwc_init (unsigned long *kmem_start) hwc_data.init_ioctls.delim = 0; } #endif - retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1); + retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); *kmem_start = (*kmem_start + PAGE_SIZE - 1) & -4096L; hwc_data.kmem_start = *kmem_start; @@ -1889,26 +1906,26 @@ hwc_init (unsigned long *kmem_start) retval = do_hwc_init (); - ctl_set_bit(0, 9); + ctl_set_bit (0, 9); -#ifdef BUFFER_STRESS_TEST +#ifdef BUFFER_STRESS_TEST - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "use %i bytes for buffering.\n", - hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "use %i bytes for buffering.\n", + hwc_data.ioctls.kmem_hwcb * PAGE_SIZE); for (i = 0; i < 500; i++) { hwcb = (init_hwcb_t *) BUF_HWCB; - internal_print( - DELAYED_WRITE, - HWC_RW_PRINT_HEADER - "This is stress test message #%i, free: %i bytes\n", - i, - MAX_HWCB_ROOM - (hwcb->length + sizeof(mto_t))); + internal_print ( + DELAYED_WRITE, + HWC_RW_PRINT_HEADER + "This is stress test message #%i, free: %i bytes\n", + i, + MAX_HWCB_ROOM - (hwcb->length + sizeof (mto_t))); } -#endif +#endif return /*retval */ 0; } @@ -1956,34 +1973,34 @@ do_hwc_interrupt (struct pt_regs *regs, __u16 code) " temporary breakdown\n"); } } else { - spin_lock(&hwc_data.lock); + spin_lock (&hwc_data.lock); - if (!hwc_data.current_servc) { + if (!hwc_data.current_servc) { - unconditional_read_1(); + unconditional_read_1 (); - } else { + } else { - switch (hwc_data.current_servc) { + switch (hwc_data.current_servc) { - case HWC_CMDW_WRITEMASK : + case HWC_CMDW_WRITEMASK: - write_event_mask_2(); + write_event_mask_2 (); break; - - case HWC_CMDW_WRITEDATA : - write_event_data_2(); + case HWC_CMDW_WRITEDATA: + + write_event_data_2 (); break; - case HWC_CMDW_READDATA : + case HWC_CMDW_READDATA: - unconditional_read_2(); + unconditional_read_2 (); break; - } + } - write_event_data_1(); - } + write_event_data_1 (); + } if (hwc_data.calls != NULL) if (hwc_data.calls->wake_up != NULL) (hwc_data.calls->wake_up) (); @@ -1996,7 +2013,7 @@ hwc_unblank (void) { spin_lock (&hwc_data.lock); - spin_unlock(&hwc_data.lock); + spin_unlock (&hwc_data.lock); asm volatile ("STCTL 0,0,%0":"=m" (cr0)); cr0_save = cr0; @@ -2021,39 +2038,45 @@ hwc_ioctl (unsigned int cmd, unsigned long arg) int retval = 0; unsigned long flags; unsigned int obuf; - - spin_lock_irqsave(&hwc_data.lock, flags); - + + spin_lock_irqsave (&hwc_data.lock, flags); + switch (cmd) { - case TIOCHWCSHTAB : - if (get_user(tmp.width_htab, (ioctl_htab_t *) arg)) + case TIOCHWCSMEAS: + hwc_data.ioctls.measured_lines = 0; + hwc_data.ioctls.measured_chars = 0; + hwc_data.ioctls.measured_wcalls = 0; + break; + + case TIOCHWCSHTAB: + if (get_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; break; - - case TIOCHWCSECHO : - if (get_user(tmp.echo, (ioctl_echo_t *) arg)) + + case TIOCHWCSECHO: + if (get_user (tmp.echo, (ioctl_echo_t *) arg)) goto fault; break; - - case TIOCHWCSCOLS : - if (get_user(tmp.columns, (ioctl_cols_t *) arg)) + + case TIOCHWCSCOLS: + if (get_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; - - case TIOCHWCSCODE : - if (get_user(tmp.code, (ioctl_code_t *) arg)) + + case TIOCHWCSCODE: + if (get_user (tmp.code, (ioctl_code_t *) arg)) goto fault; break; - - case TIOCHWCSNL : - if (get_user(tmp.final_nl, (ioctl_nl_t *) arg)) + + case TIOCHWCSNL: + if (get_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; - case TIOCHWCSOBUF : - if (get_user(obuf, (unsigned int *) arg)) + case TIOCHWCSOBUF: + if (get_user (obuf, (unsigned int *) arg)) goto fault; if (obuf & 0xFFF) tmp.max_hwcb = (((obuf | 0xFFF) + 1) >> 12); @@ -2061,93 +2084,108 @@ hwc_ioctl (unsigned int cmd, unsigned long arg) tmp.max_hwcb = (obuf >> 12); break; - case TIOCHWCSCASE : - if (get_user(tmp.tolower, (ioctl_case_t *) arg)) + case TIOCHWCSCASE: + if (get_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; - - case TIOCHWCSDELIM : - if (get_user(tmp.delim, (ioctl_delim_t *) arg)) + + case TIOCHWCSDELIM: + if (get_user (tmp.delim, (ioctl_delim_t *) arg)) goto fault; break; - case TIOCHWCSINIT : - retval = set_hwc_ioctls(&hwc_data.init_ioctls, 1); + case TIOCHWCSINIT: + retval = set_hwc_ioctls (&hwc_data.init_ioctls, 1); break; - case TIOCHWCGHTAB : - if (put_user(tmp.width_htab, (ioctl_htab_t *) arg)) + case TIOCHWCGMEASL: + if (put_user (tmp.measured_lines, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGECHO : - if (put_user(tmp.echo, (ioctl_echo_t *) arg)) + case TIOCHWCGMEASC: + if (put_user (tmp.measured_chars, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGCOLS : - if (put_user(tmp.columns, (ioctl_cols_t *) arg)) + case TIOCHWCGMEASS: + if (put_user (tmp.measured_wcalls, (ioctl_meas_t *) arg)) goto fault; break; - case TIOCHWCGCODE : - if (put_user(tmp.code, (ioctl_code_t *) arg)) + case TIOCHWCGHTAB: + if (put_user (tmp.width_htab, (ioctl_htab_t *) arg)) goto fault; + break; + case TIOCHWCGECHO: + if (put_user (tmp.echo, (ioctl_echo_t *) arg)) + goto fault; break; - case TIOCHWCGNL : - if (put_user(tmp.final_nl, (ioctl_nl_t *) arg)) + case TIOCHWCGCOLS: + if (put_user (tmp.columns, (ioctl_cols_t *) arg)) goto fault; break; - case TIOCHWCGOBUF : - if (put_user(tmp.max_hwcb, (ioctl_obuf_t *) arg)) + case TIOCHWCGCODE: + if (put_user (tmp.code, (ioctl_code_t *) arg)) goto fault; + break; - case TIOCHWCGKBUF : - if (put_user(tmp.kmem_hwcb, (ioctl_obuf_t *) arg)) + case TIOCHWCGNL: + if (put_user (tmp.final_nl, (ioctl_nl_t *) arg)) goto fault; break; - case TIOCHWCGCASE : - if (put_user(tmp.tolower, (ioctl_case_t *) arg)) + case TIOCHWCGOBUF: + if (put_user (tmp.max_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; - - case TIOCHWCGDELIM : - if (put_user(tmp.delim, (ioctl_delim_t *) arg)) + + case TIOCHWCGKBUF: + if (put_user (tmp.kmem_hwcb, (ioctl_obuf_t *) arg)) goto fault; break; -#if 0 - - case TIOCHWCGINIT : - if (put_user(&hwc_data.init_ioctls, (hwc_ioctls_t *) arg)) + + case TIOCHWCGCASE: + if (put_user (tmp.tolower, (ioctl_case_t *) arg)) goto fault; break; - case TIOCHWCGCURR : - if (put_user(&hwc_data.ioctls, (hwc_ioctls_t *) arg)) + case TIOCHWCGDELIM: + if (put_user (tmp.delim, (ioctl_delim_t *) arg)) + goto fault; + break; +#if 0 + + case TIOCHWCGINIT: + if (put_user (&hwc_data.init_ioctls, (hwc_ioctls_t *) arg)) + goto fault; + break; + + case TIOCHWCGCURR: + if (put_user (&hwc_data.ioctls, (hwc_ioctls_t *) arg)) goto fault; break; #endif - - default : + + default: goto noioctlcmd; } - if (_IOC_DIR(cmd) == _IOC_WRITE) - retval = set_hwc_ioctls(&tmp, 0); + if (_IOC_DIR (cmd) == _IOC_WRITE) + retval = set_hwc_ioctls (&tmp, 0); goto out; - fault: - retval = -EFAULT; - goto out; - noioctlcmd: - retval = -ENOIOCTLCMD; - out: - spin_unlock_irqrestore(&hwc_data.lock, flags); - return retval; + fault: + retval = -EFAULT; + goto out; + noioctlcmd: + retval = -ENOIOCTLCMD; + out: + spin_unlock_irqrestore (&hwc_data.lock, flags); + return retval; } diff --git a/drivers/s390/char/hwc_rw.h b/drivers/s390/char/hwc_rw.h index bd72a591fbb9..6ef3b23ebeaa 100644 --- a/drivers/s390/char/hwc_rw.h +++ b/drivers/s390/char/hwc_rw.h @@ -31,6 +31,7 @@ typedef signed char ioctl_nl_t; typedef unsigned short int ioctl_obuf_t; typedef unsigned char ioctl_case_t; typedef unsigned char ioctl_delim_t; +typedef unsigned long ioctl_meas_t; typedef struct { ioctl_htab_t width_htab; @@ -39,9 +40,12 @@ typedef struct { ioctl_code_t code; ioctl_nl_t final_nl; ioctl_obuf_t max_hwcb; - ioctl_obuf_t kmem_hwcb; + ioctl_obuf_t kmem_hwcb; ioctl_case_t tolower; ioctl_delim_t delim; + ioctl_meas_t measured_lines; + ioctl_meas_t measured_chars; + ioctl_meas_t measured_wcalls; } hwc_ioctls_t; static hwc_ioctls_t _hwc_ioctls; @@ -64,6 +68,8 @@ static hwc_ioctls_t _hwc_ioctls; #define TIOCHWCSCASE _IOW(HWC_IOCTL_LETTER, 7, _hwc_ioctls.tolower) +#define TIOCHWCSMEAS _IO(HWC_IOCTL_LETTER, 8) + #define TIOCHWCSDELIM _IOW(HWC_IOCTL_LETTER, 9, _hwc_ioctls.delim) #define TIOCHWCGHTAB _IOR(HWC_IOCTL_LETTER, 10, _hwc_ioctls.width_htab) @@ -82,11 +88,17 @@ static hwc_ioctls_t _hwc_ioctls; #define TIOCHWCGCASE _IOR(HWC_IOCTL_LETTER, 17, _hwc_ioctls.tolower) -#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.delim) +#define TIOCHWCGDELIM _IOR(HWC_IOCTL_LETTER, 18, _hwc_ioctls.delim) + +#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 19, _hwc_ioctls.max_hwcb) + +#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls) -#define TIOCHWCGKBUF _IOR(HWC_IOCTL_LETTER, 20, _hwc_ioctls.max_hwcb) +#define TIOCHWCGMEASL _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls.measured_lines) -#define TIOCHWCGCURR _IOR(HWC_IOCTL_LETTER, 21, _hwc_ioctls) +#define TIOCHWCGMEASC _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars) + +#define TIOCHWCGMEASS _IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls) #define CODE_ASCII 0x0 #define CODE_EBCDIC 0x1 @@ -117,4 +129,4 @@ extern signed int hwc_unregister_calls (hwc_high_level_calls_t *); #endif -#endif +#endif diff --git a/drivers/s390/char/hwc_tty.c b/drivers/s390/char/hwc_tty.c index d32cad5ef248..488058d95913 100644 --- a/drivers/s390/char/hwc_tty.c +++ b/drivers/s390/char/hwc_tty.c @@ -43,22 +43,22 @@ typedef struct { static hwc_tty_data_struct hwc_tty_data = { /* NULL/0 */ }; static struct tty_driver hwc_tty_driver; -static struct tty_struct * hwc_tty_table[1]; -static struct termios * hwc_tty_termios[1]; -static struct termios * hwc_tty_termios_locked[1]; +static struct tty_struct *hwc_tty_table[1]; +static struct termios *hwc_tty_termios[1]; +static struct termios *hwc_tty_termios_locked[1]; static int hwc_tty_refcount = 0; -extern struct termios tty_std_termios; +extern struct termios tty_std_termios; void hwc_tty_wake_up (void); void hwc_tty_input (unsigned char *, unsigned int); static int hwc_tty_open (struct tty_struct *tty, - struct file *filp) + struct file *filp) { - if (MINOR(tty->device) - tty->driver.minor_start) + if (MINOR (tty->device) - tty->driver.minor_start) return -ENODEV; tty->driver_data = &hwc_tty_data; @@ -75,10 +75,10 @@ hwc_tty_open (struct tty_struct *tty, static void hwc_tty_close (struct tty_struct *tty, - struct file *filp) + struct file *filp) { - if (MINOR(tty->device) != tty->driver.minor_start) { - printk(KERN_WARNING HWC_TTY_PRINT_HEADER + if (MINOR (tty->device) != tty->driver.minor_start) { + printk (KERN_WARNING HWC_TTY_PRINT_HEADER "do not close hwc tty because of wrong device number"); return; } @@ -95,40 +95,40 @@ hwc_tty_write_room (struct tty_struct *tty) { int retval; - retval = hwc_write_room(IN_BUFS_TOTAL); + retval = hwc_write_room (IN_BUFS_TOTAL); return retval; } static int hwc_tty_write (struct tty_struct *tty, - int from_user, - const unsigned char *buf, - int count) + int from_user, + const unsigned char *buf, + int count) { int retval; if (hwc_tty_data.buf_count > 0) { - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; } - retval = hwc_write(from_user, buf, count); + retval = hwc_write (from_user, buf, count); return retval; } static void hwc_tty_put_char (struct tty_struct *tty, - unsigned char ch) + unsigned char ch) { unsigned long flags; - spin_lock_irqsave(&hwc_tty_data.lock, flags); + spin_lock_irqsave (&hwc_tty_data.lock, flags); if (hwc_tty_data.buf_count >= HWC_TTY_BUF_SIZE) { - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; } hwc_tty_data.buf[hwc_tty_data.buf_count] = ch; hwc_tty_data.buf_count++; - spin_unlock_irqrestore(&hwc_tty_data.lock, flags); + spin_unlock_irqrestore (&hwc_tty_data.lock, flags); } static void @@ -136,10 +136,10 @@ hwc_tty_flush_chars (struct tty_struct *tty) { unsigned long flags; - spin_lock_irqsave(&hwc_tty_data.lock, flags); - hwc_write(0, hwc_tty_data.buf, hwc_tty_data.buf_count); + spin_lock_irqsave (&hwc_tty_data.lock, flags); + hwc_write (0, hwc_tty_data.buf, hwc_tty_data.buf_count); hwc_tty_data.buf_count = 0; - spin_unlock_irqrestore(&hwc_tty_data.lock, flags); + spin_unlock_irqrestore (&hwc_tty_data.lock, flags); } static int @@ -147,7 +147,7 @@ hwc_tty_chars_in_buffer (struct tty_struct *tty) { int retval; - retval = hwc_chars_in_buffer(IN_BUFS_TOTAL); + retval = hwc_chars_in_buffer (IN_BUFS_TOTAL); return retval; } @@ -159,15 +159,15 @@ hwc_tty_flush_buffer (struct tty_struct *tty) static int hwc_tty_ioctl ( - struct tty_struct *tty, - struct file * file, - unsigned int cmd, - unsigned long arg) + struct tty_struct *tty, + struct file *file, + unsigned int cmd, + unsigned long arg) { unsigned long count; - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; switch (cmd) { case TIOCHWCTTYSINTRC: @@ -186,8 +186,8 @@ hwc_tty_ioctl ( (long) hwc_tty_data.ioctl.intr_char_size); default: - return hwc_ioctl(cmd, arg); -} + return hwc_ioctl (cmd, arg); + } } void @@ -256,22 +256,22 @@ hwc_tty_input (unsigned char *buf, unsigned int count) hwc_tty_data.ioctl.intr_char_size) == 0) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = INTR_CHAR(tty); + *tty->flip.char_buf_ptr++ = INTR_CHAR (tty); } else if (count == 2 && ( strncmp (buf, "^d", 2) == 0 || strncmp (buf, "\0252d", 2) == 0)) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = EOF_CHAR(tty); + *tty->flip.char_buf_ptr++ = EOF_CHAR (tty); } else if (count == 2 && ( strncmp (buf, "^z", 2) == 0 || strncmp (buf, "\0252z", 2) == 0)) { tty->flip.count++; *tty->flip.flag_buf_ptr++ = TTY_NORMAL; - *tty->flip.char_buf_ptr++ = SUSP_CHAR(tty); + *tty->flip.char_buf_ptr++ = SUSP_CHAR (tty); } else { - memcpy(tty->flip.char_buf_ptr, buf, count); + memcpy (tty->flip.char_buf_ptr, buf, count); if (count < 2 || ( strncmp (buf + count - 2, "^n", 2) || strncmp (buf + count - 2, "\0252n", 2))) { @@ -279,12 +279,12 @@ hwc_tty_input (unsigned char *buf, unsigned int count) count++; } else count -= 2; - memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count); + memset (tty->flip.flag_buf_ptr, TTY_NORMAL, count); tty->flip.char_buf_ptr += count; tty->flip.flag_buf_ptr += count; tty->flip.count += count; } - tty_flip_buffer_push(tty); + tty_flip_buffer_push (tty); hwc_tty_wake_up (); } #endif @@ -293,7 +293,7 @@ hwc_tty_input (unsigned char *buf, unsigned int count) void hwc_tty_init (void) { - memset (&hwc_tty_driver, 0, sizeof(struct tty_driver)); + memset (&hwc_tty_driver, 0, sizeof (struct tty_driver)); memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct)); hwc_tty_driver.magic = TTY_DRIVER_MAGIC; hwc_tty_driver.driver_name = "tty_hwc"; @@ -310,7 +310,7 @@ hwc_tty_init (void) hwc_tty_driver.init_termios.c_lflag = ISIG | ECHO; hwc_tty_driver.flags = TTY_DRIVER_REAL_RAW; hwc_tty_driver.refcount = &hwc_tty_refcount; - + hwc_tty_driver.table = hwc_tty_table; hwc_tty_driver.termios = hwc_tty_termios; hwc_tty_driver.termios_locked = hwc_tty_termios_locked; @@ -324,20 +324,20 @@ hwc_tty_init (void) hwc_tty_driver.chars_in_buffer = hwc_tty_chars_in_buffer; hwc_tty_driver.flush_buffer = hwc_tty_flush_buffer; hwc_tty_driver.ioctl = hwc_tty_ioctl; - + hwc_tty_driver.throttle = NULL; hwc_tty_driver.unthrottle = NULL; hwc_tty_driver.send_xchar = NULL; hwc_tty_driver.set_termios = NULL; hwc_tty_driver.set_ldisc = NULL; - hwc_tty_driver.stop = NULL; - hwc_tty_driver.start = NULL; + hwc_tty_driver.stop = NULL; + hwc_tty_driver.start = NULL; hwc_tty_driver.hangup = NULL; hwc_tty_driver.break_ctl = NULL; hwc_tty_driver.wait_until_sent = NULL; hwc_tty_driver.read_proc = NULL; hwc_tty_driver.write_proc = NULL; - if (tty_register_driver(&hwc_tty_driver)) - panic("Couldn't register hwc_tty driver\n"); + if (tty_register_driver (&hwc_tty_driver)) + panic ("Couldn't register hwc_tty driver\n"); } diff --git a/drivers/s390/idals.c b/drivers/s390/idals.c new file mode 100644 index 000000000000..cd81d8ffe866 --- /dev/null +++ b/drivers/s390/idals.c @@ -0,0 +1,79 @@ +/* + * File...........: linux/drivers/s390x/idals.c + * Author(s)......: Holger Smolinski + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a + + * History of changes + * 07/24/00 new file + */ + +#include +#include +#include +#include + +#ifdef PRINTK_HEADER +#undef PRINTK_HEADER +#endif +#define PRINTK_HEADER "idals:" + +/* a name template for the cache-names */ +static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */ +/* the cache's names */ +static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; +/* the caches itself*/ +static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; + +void +free_idal ( ccw1_t *cp ) +{ + idaw_t *idal; + unsigned long upper2k,lower2k; + int nridaws,cacheind; + if ( cp -> flags & CCW_FLAG_IDA ) { + idal = cp -> cda; + lower2k = *idal & 0xfffffffffffff800; + upper2k = (*idal + cp -> count - 1) & 0xfffffffffffff800; + nridaws = ((upper2k - lower2k) >> 11) + 1; + for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ ); + kmem_cache_free ( idal_cache[cacheind], idal ); + } +} + +int +idal_support_init ( void ) +{ + int rc=0; + int cachind; + + for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { + int slabsize = 8 << cachind; + sprintf ( idal_cache_name[cachind], + "%s%d%c", idal_name_template, slabsize, 0); + idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], + slabsize, 0, + SLAB_HWCACHE_ALIGN | SLAB_DMA, + NULL, NULL ); + if ( ! idal_cache [cachind] ) { + printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n"); + } + } + + return rc; +} + +void idal_support_cleanup ( void ) +{ + int cachind; + + /* Shrink the caches, if available */ + for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) { + if ( idal_cache[cachind] ) { + if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) { + idal_cache[cachind] = NULL; + } + } + } + +} diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 2c2a182b66ba..4d4dbb54bf14 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -7,6 +7,10 @@ M_OBJS := ifeq ($(CONFIG_CTC),y) O_OBJS += ctc.o +else + ifeq ($(CONFIG_CTC),m) + M_OBJS += ctc.o + endif endif ifeq ($(CONFIG_IUCV),y) diff --git a/drivers/s390/net/ctc.c b/drivers/s390/net/ctc.c index 1b7580ad9812..9a828e262169 100644 --- a/drivers/s390/net/ctc.c +++ b/drivers/s390/net/ctc.c @@ -1,4 +1,6 @@ /* + * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $ + * * drivers/s390/net/ctc.c * CTC / ESCON network driver * @@ -7,7 +9,11 @@ * Author(s): Dieter Wellerdiek (wel@de.ibm.com) * * 2.3 Updates Martin Schwidefsky (schwidefsky@de.ibm.com) - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + * + * Modularization & Bugfixes by Fritz Elfert (fritz.elfert@millenux.de) + * + * Bugfixes by Jochen Röhrig (roehrig@de.ibm.com) * * * Description of the Kernel Parameter @@ -16,50 +22,142 @@ * order or doesn't want to have automatic channel selection on, you can do * this with the "ctc= kernel keyword". * - * ctc=0,0xrrrr,0xwwww,ddddd + * ctc=0,0xrrrr,0xwwww,ddddd * * Where: * - * "rrrr" is the read channel address - * "wwww" is the write channel address - * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 - * to escon7 for ESCON channels). + * "rrrr" is the read channel address + * "wwww" is the write channel address + * "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0 + * to escon7 for ESCON channels). * * To switch the automatic channel selection off use the ctc= keyword with * parameter "noauto". This may be necessary if you 3271 devices or other devices * which use the ctc device type and model, but operate with a different protocol. * - * ctc=noauto + * ctc=noauto + * + * $Log: ctc.c,v $ + * Revision 1.25.2.5 2000/10/11 15:08:59 bird + * ctc_tx(): Quick fix of possible underflow when calculating free block space + * + * Revision 1.25.2.4 2000/09/25 16:40:56 bird + * Some more debug information + * + * Revision 1.25.2.3 2000/09/20 13:28:19 bird + * - ctc_open(): fixed bug + * - ctc_release(): added timer for terminating in case of halt_io()-hang + * + * Revision 1.25.2.2 2000/09/20 09:48:27 bird + * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in + * instead of direct waiting on a wait queue + * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check(): + * print more debug information + * + * Revision 1.25.2.1 2000/09/19 09:09:56 bird + * Merged in changes from 1.25 to 1.26 + * + * Revision 1.25 2000/09/08 09:22:11 bird + * Proper cleanup and bugfixes in ctc_probe() + * + * Revision 1.24 2000/08/30 15:14:38 bird + * Some bugfixes and simplifications in ctc_probe() + * + * Revision 1.23 2000/08/28 16:50:35 bird + * - Suppress warning if discarding initial handshake block + * - Removed strstr() (now exported in arch/s390/kernel/s390_ksyms.c) + * + * Revision 1.22 2000/08/28 11:33:21 felfert + * Remove some dead code in ctc_open(). + * + * Revision 1.21 2000/08/28 09:31:06 bird + * init_module(): fixed pointer arithmetic (device name) + * + * Revision 1.20 2000/08/25 20:11:56 bird + * Didn´t build as non-module. + * + * Revision 1.19 2000/08/25 19:48:46 felfert + * Modularized version. + * + * Revision 1.18 2000/08/25 19:34:29 bird + * extract_channel_id(): + * - check for valid channel id; + * return -EINVAL in case of violation * - * Change History + * ctc_setup(): + * - check for valid channel id; + * return without doing anything in case of violation + * + * ctc_irq_bh(): + * - check for valid block length and packet length; + * discard block in case of invalid values + * (solves infinite loop problem that occurs if (for some unknown reason) + * the packet length = 0) + * + * Revision 1.17 2000/08/25 09:22:51 bird + * ctc_buffer_alloc(): + * fixed kmalloc()-bug (allocated buffer of wrong size) + * + * Revision 1.16 2000/08/24 17:46:19 bird + * ctc_write_retry(): + * - removed (presumably useless) loop for cleaning up the proc_anchor list. + * - inserted warning if proc_anchor (unexpectedly) != NULL + * + * Revision 1.15 2000/08/24 15:25:04 bird + * ctc_read_retry(): + * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set + * - removed some useless debug-messages + * ctc_write_retry(): + * - lock ctc->irq *bevore* testing whether the CTC_STOP-flag is set + * + * Revision 1.14 2000/08/24 09:34:47 felfert + * Fixed bug in ctc_release: + * - ctc_unprotect_busy_irqrestore was called with wrong parameter. + * + * + * Old Change History * 0.50 Initial release shipped * 0.51 Bug fixes - * - CTC / ESCON network device can now handle up to 64 channels - * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON - * - 3088-62 info message suppressed - OSA/D - * - channel: def ffffffed ... error message suppressed - * - CTC / ESCON device was not recoverable after a lost connection with - * IFCONFIG dev DOWN and IFCONFIG dev UP - * - Possibility to switch the automatic selection off - * - Minor bug fixes + * - CTC / ESCON network device can now handle up to 64 channels + * - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON + * - 3088-62 info message suppressed - OSA/D + * - channel: def ffffffed ... error message suppressed + * - CTC / ESCON device was not recoverable after a lost connection with + * IFCONFIG dev DOWN and IFCONFIG dev UP + * - Possibility to switch the automatic selection off + * - Minor bug fixes * 0.52 Bug fixes - * - Subchannel check message enhanced - * - Read / Write retry routine check for CTC_STOP added + * - Subchannel check message enhanced + * - Read / Write retry routine check for CTC_STOP added * 0.53 Enhancement - * - Connect time changed from 150 to 300 seconds - * This gives more a better chance to connect during IPL + * - Connect time changed from 150 to 300 seconds + * This gives more a better chance to connect during IPL * 0.54 Bug fixes - * - Out of memory message enhanced - * - Zero buffer problem in ctc_irq_hb solved - * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop, - * which could end in a out of memory situation. + * - Out of memory message enhanced + * - Zero buffer problem in ctc_irq_hb solved + * A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop, + * which could end in a out of memory situation. * 0.55 Bug fixes - * - Connect problems with systems which IPL later - * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently - * not available. When systemB comes up it is nearly inpossible to setup a - * connection. + * - Connect problems with systems which IPL later + * SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently + * not available. When systemB comes up it is nearly inpossible to setup a + * connection. + * + * 0.56 Bug fixes + * - ctc_open(): In case of failure stop read/write-retry timers before + * freeing buffers (stops kernel panics due to NULL-pointer + * dereferences in ctc_read_retry()) + * - Added some sanity checks concerning NULL-pointer dereferences + * - Added some comments + * + * 0.57 Bug fixes + * - CTC / ESCON network device can now handle up to 256 channels + * - ctc_read_retry(): added sanity check: if ctc->free_anchor == NULL + * print a warning and simply return */ + #include +#include #include #include #include @@ -78,6 +176,7 @@ #include #include #include +#include #include #include @@ -85,56 +184,67 @@ #include +#ifdef MODULE +MODULE_AUTHOR("(C) 2000 IBM Corp. by Dieter Wellerdiek (wel@de.ibm.com)"); +MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver"); +MODULE_PARM(setup,"s"); +MODULE_PARM_DESC(setup, +"One or more definitions in the same format like the kernel parameter line for ctc.\n" +"E.g.: \"ctc=0,0x700,0x701,ctc0 ctc=0,0x702,0x703,ctc1\".\n"); + +char *setup = NULL; +#endif + //#define DEBUG /* Redefine message level, so that all messages occur on 3215 console in DEBUG mode */ -#ifdef DEBUG - #undef KERN_INFO - #undef KERN_WARNING - #undef KERN_DEBUG - #define KERN_INFO KERN_EMERG - #define KERN_WARNING KERN_EMERG - #define KERN_DEBUG KERN_EMERG -#endif - - -#define CCW_CMD_WRITE 0x01 -#define CCW_CMD_READ 0x02 -#define CCW_CMD_SET_EXTENDED 0xc3 -#define CCW_CMD_PREPARE 0xe3 - -#define MAX_CHANNEL_DEVICES 64 -#define MAX_ADAPTERS 8 -#define CTC_DEFAULT_MTU_SIZE 1500 -#define READ 0 -#define WRITE 1 -#define CTC 0 -#define ESCON 1 -#define CHANNEL_MEDIA 2 -#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */ - -#define TB_TX 0 /* sk buffer handling in process */ -#define TB_STOP 1 /* network device stop in process */ -#define TB_RETRY 2 /* retry in process */ -#define TB_NOBUFFER 3 /* no buffer on free queue */ +#ifdef DEBUG + #undef KERN_INFO + #undef KERN_WARNING + #undef KERN_DEBUG + #define KERN_INFO KERN_EMERG + #define KERN_WARNING KERN_EMERG + #define KERN_DEBUG KERN_EMERG +#endif + + +#define CCW_CMD_WRITE 0x01 +#define CCW_CMD_READ 0x02 +#define CCW_CMD_SET_EXTENDED 0xc3 +#define CCW_CMD_PREPARE 0xe3 + +#define MAX_CHANNEL_DEVICES 256 +#define MAX_ADAPTERS 8 +#define CTC_DEFAULT_MTU_SIZE 1500 +#define READ 0 +#define WRITE 1 +#define CTC 0 +#define ESCON 1 +#define CHANNEL_MEDIA 2 +#define CTC_BLOCKS 8 /* 8 blocks * 2 times * 64k = 1M */ + +#define TB_TX 0 /* sk buffer handling in process */ +#define TB_STOP 1 /* network device stop in process */ +#define TB_RETRY 2 /* retry in process */ +#define TB_NOBUFFER 3 /* no buffer on free queue */ /* state machine codes used in ctc_irq_handler */ -#define CTC_STOP 0 -#define CTC_START_HALT_IO 1 -#define CTC_START_SET_X_MODE 2 -#define CTC_START_SELECT 4 -#define CTC_START_READ_TEST 32 -#define CTC_START_READ 33 -#define CTC_START_WRITE_TEST 64 -#define CTC_START_WRITE 65 +#define CTC_STOP 0 +#define CTC_START_HALT_IO 1 +#define CTC_START_SET_X_MODE 2 +#define CTC_START_SELECT 4 +#define CTC_START_READ_TEST 32 +#define CTC_START_READ 33 +#define CTC_START_WRITE_TEST 64 +#define CTC_START_WRITE 65 typedef enum { - channel_type_none, /* Device is not a channel */ - channel_type_undefined, /* Device is a channel but we don't know anything about it */ - channel_type_ctca, /* Device is a CTC/A and we can deal with it */ - channel_type_escon, /* Device is a ESCON channel and we can deal with it */ - channel_type_unsupported /* Device is a unsupported model */ + channel_type_none, /* Device is not a channel */ + channel_type_undefined, /* Device is a channel but we don't know anything about it */ + channel_type_ctca, /* Device is a CTC/A and we can deal with it */ + channel_type_escon, /* Device is a ESCON channel and we can deal with it */ + channel_type_unsupported /* Device is a unsupported model */ } channel_type_t; @@ -144,30 +254,39 @@ typedef enum { * */ -static int channel_tab_initialized = 0; /* channel[] structure initialized */ +static long channel_tab_initialized = 0; /* channel[] structure initialized */ struct devicelist { - unsigned int devno; - __u8 flag; -#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */ + unsigned int devno; + __u8 flag; +#define CHANNEL_IN_USE 0x08 /* - Show that channel is in use */ }; static struct { - struct devicelist list[MAX_CHANNEL_DEVICES]; - int count; - int left; + struct devicelist list[MAX_CHANNEL_DEVICES]; + int count; + int left; } channel[CHANNEL_MEDIA]; static int ctc_no_auto = 0; +#if LINUX_VERSION_CODE>=0x020300 +typedef struct net_device net_device; +#else +typedef struct device net_device; +typedef struct wait_queue* wait_queue_head_t; +#define init_waitqueue_head(nothing) +#endif + struct adapterlist{ - unsigned int devno[2]; - __u16 protocol; + unsigned int devno[2]; + __u16 protocol; + net_device *netdev; }; -static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ +static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC / 1 = ESCON */ /* @@ -176,51 +295,43 @@ static struct adapterlist ctc_adapter[CHANNEL_MEDIA][MAX_ADAPTERS]; /* 0 = CTC */ struct buffer { - struct buffer *next; - int packets; - struct block *block; + struct buffer *next; + int packets; + struct block *block; }; -#if LINUX_VERSION_CODE>=0x020300 -typedef struct net_device net_device; -#else -typedef struct device net_device; -typedef struct wait_queue* wait_queue_head_t; -#define DECLARE_WAITQUEUE(waitqname,waitqtask) struct wait_queue waitqname = {waitqtask, NULL } -#define init_waitqueue_head(nothing) -#endif - - struct channel { - unsigned int devno; - int irq; - unsigned long IO_active; - ccw1_t ccw[3]; - __u32 state; - int buffer_count; - struct buffer *free_anchor; - struct buffer *proc_anchor; - devstat_t *devstat; - net_device *dev; /* backward pointer to the network device */ + unsigned int devno; + int irq; + unsigned long IO_active; + ccw1_t ccw[3]; + __u32 state; + int buffer_count; + struct buffer *free_anchor; + struct buffer *proc_anchor; + devstat_t *devstat; + net_device *dev; /* backward pointer to the network device */ wait_queue_head_t wait; - struct tq_struct tq; - struct timer_list timer; - unsigned long flag_a; /* atomic flags */ -#define CTC_BH_ACTIVE 0 - __u8 last_dstat; - __u8 flag; -#define CTC_WRITE 0x01 /* - Set if this is a write channel */ -#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ + struct tq_struct tq; + int initial_block_received; /* only used for read channel */ + struct timer_list timer; + unsigned long flag_a; /* atomic flags */ +#define CTC_BH_ACTIVE 0 + __u8 last_dstat; + __u8 flag; +#define CTC_WRITE 0x01 /* - Set if this is a write channel */ +#define CTC_WAKEUP 0x02 /* - Set if this channel should wake up from waiting for an event */ +#define CTC_TIMER 0x80 /* - Set if timer made the wake_up */ }; -struct ctc_priv { - struct net_device_stats stats; +struct ctc_priv { + struct net_device_stats stats; #if LINUX_VERSION_CODE>=0x02032D - int tbusy; + unsigned long tbusy; #endif - struct channel channel[2]; - __u16 protocol; + struct channel channel[2]; + __u16 protocol; }; /* @@ -230,16 +341,16 @@ struct ctc_priv { #define PACKET_HEADER_LENGTH 6 struct packet { - __u16 length; - __u16 type; - __u16 unused; - __u8 data; + __u16 length; + __u16 type; + __u16 unused; + __u8 data; }; #define BLOCK_HEADER_LENGTH 2 struct block { - __u16 length; - struct packet data; + __u16 length; + struct packet data; }; #if LINUX_VERSION_CODE>=0x02032D @@ -275,7 +386,7 @@ static __inline__ int ctc_check_busy(net_device *dev) static __inline__ void ctc_setbit_busy(int nr,net_device *dev) { set_bit(nr,&(((struct ctc_priv *)dev->priv)->tbusy)); - netif_stop_queue(dev); + netif_stop_queue(dev); } static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) @@ -318,17 +429,17 @@ static __inline__ int ctc_check_busy(net_device *dev) static __inline__ void ctc_setbit_busy(int nr,net_device *dev) { - set_bit(nr,(void *)&dev->tbusy); + set_bit(nr,&dev->tbusy); } static __inline__ void ctc_clearbit_busy(int nr,net_device *dev) { - clear_bit(nr,(void *)&dev->tbusy); + clear_bit(nr,&dev->tbusy); } static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) { - return(test_and_set_bit(nr,(void *)&dev->tbusy)); + return(test_and_set_bit(nr,&dev->tbusy)); } #endif @@ -338,9 +449,9 @@ static __inline__ int ctc_test_and_setbit_busy(int nr,net_device *dev) /* Interrupt handler */ static void ctc_irq_handler(int irq, void *initparm, struct pt_regs *regs); -static void ctc_irq_bh(struct channel *ctc); -static void ctc_read_retry (struct channel *ctc); -static void ctc_write_retry (struct channel *ctc); +static void ctc_irq_bh(void *data); +static void ctc_read_retry (unsigned long data); +static void ctc_write_retry (unsigned long data); /* Functions for the DEV methods */ @@ -348,7 +459,7 @@ int ctc_probe(net_device *dev); static int ctc_open(net_device *dev); -static void ctc_timer (struct channel *ctc); +static void ctc_timer (unsigned long data); static int ctc_release(net_device *dev); static int ctc_tx(struct sk_buff *skb, net_device *dev); static int ctc_change_mtu(net_device *dev, int new_mtu); @@ -369,36 +480,56 @@ static channel_type_t channel_check_for_type (senseid_t *id); static void channel_sort(struct devicelist list[], int n); +/* + * misc. + */ +static void print_banner(void) { + static int printed = 0; + char vbuf[] = "$Revision: 1.25.2.5 $"; + char *version = vbuf; + + if (printed) + return; + if ((version = strchr(version, ':'))) { + char *p = strchr(version + 1, '$'); + if (p) + *p = '\0'; + } else + version = " ??? "; + printk(KERN_INFO "CTC driver Version%s initialized\n", version); + printed = 1; +} + /* * initialize the channel[].list */ static void channel_init(void) { - int m; + int m; #ifdef DEBUG - int c; + int c; #endif - if (!test_and_set_bit(0, (void *)& channel_tab_initialized)){ - channel_scan(); - for (m = 0; m < CHANNEL_MEDIA; m++) { - channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); - channel[m].left = channel[m].count; - } - if (channel[CTC].count == 0 && channel[ESCON].count == 0) - printk(KERN_INFO "channel: no Channel devices recognized\n"); - else - printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", - channel[CTC].count, channel[ESCON].count); + if (!test_and_set_bit(0, &channel_tab_initialized)){ + channel_scan(); + for (m = 0; m < CHANNEL_MEDIA; m++) { + channel_sort (channel[m].list, MAX_CHANNEL_DEVICES); + channel[m].left = channel[m].count; + } + if (channel[CTC].count == 0 && channel[ESCON].count == 0) + printk(KERN_INFO "channel: no Channel devices recognized\n"); + else + printk(KERN_INFO "channel: %d Parallel channel found - %d ESCON channel found\n", + channel[CTC].count, channel[ESCON].count); #ifdef DEBUG - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", - m, c, channel[m].list[c].devno); - } - } + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (c = 0; c < channel[m].count; c++){ + printk(KERN_DEBUG "channel: Adapter=%x Entry=%x devno=%04x\n", + m, c, channel[m].list[c].devno); + } + } #endif - } + } } @@ -407,38 +538,37 @@ static void channel_init(void) */ static void channel_scan(void) { - int m; - int c; - int irq; - dev_info_t temp; - - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ - channel[m].list[c].devno = -ENODEV; - } - } - - for (irq = 0; irq < NR_IRQS; irq++) { - /* CTC/A */ - if (channel[CTC].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_ctca) { - channel[CTC].list[channel[CTC].count].devno = temp.devno; - channel[CTC].count++; - } - } - - /* ESCON */ - if (channel[ESCON].count < MAX_CHANNEL_DEVICES ) { - if (get_dev_info(irq, &temp) == 0 && - channel_check_for_type(&temp.sid_data) == channel_type_escon) { - channel[ESCON].list[channel[ESCON].count].devno = temp.devno; - channel[ESCON].count++; - - } - } - } -} + int m; + int c; + int irq; + dev_info_t temp; + + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (c = 0; c < MAX_CHANNEL_DEVICES; c++){ + channel[m].list[c].devno = -ENODEV; + } + } + + for (irq = 0; irq < NR_IRQS; irq++) { + if (get_dev_info_by_irq(irq, &temp) == 0) { + if ((temp.status == DEVSTAT_NOT_OPER) || + (temp.status == DEVSTAT_DEVICE_OWNED)) + continue; + /* CTC/A */ + if ((channel[CTC].count < MAX_CHANNEL_DEVICES ) && + (channel_check_for_type(&temp.sid_data) == channel_type_ctca)) { + channel[CTC].list[channel[CTC].count].devno = temp.devno; + channel[CTC].count++; + } + /* ESCON */ + if ((channel[ESCON].count < MAX_CHANNEL_DEVICES ) && + (channel_check_for_type(&temp.sid_data) == channel_type_escon)) { + channel[ESCON].list[channel[ESCON].count].devno = temp.devno; + channel[ESCON].count++; + } + } + } +} /* @@ -446,17 +576,17 @@ static void channel_scan(void) */ static int channel_free(int media, int devno) { - int i; - - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) { - channel[media].list[i].flag &= ~CHANNEL_IN_USE; - return 0; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; + int i; + + for (i = 0; i < channel[media].count; i++) { + if ((devno == channel[media].list[i].devno) && + ((channel[media].list[i].flag & CHANNEL_IN_USE) != 0x00)) { + channel[media].list[i].flag &= ~CHANNEL_IN_USE; + return 0; + } + } + printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); + return -ENODEV; } @@ -465,17 +595,17 @@ static int channel_free(int media, int devno) */ static int channel_get(int media, int devno) { - int i; - - for (i = 0; i < channel[media].count; i++) { - if ((devno == channel[media].list[i].devno) && - ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) { - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); - return -ENODEV; + int i; + + for (i = 0; i < channel[media].count; i++) { + if ((devno == channel[media].list[i].devno) && + ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00)) { + channel[media].list[i].flag |= CHANNEL_IN_USE; + return channel[media].list[i].devno; + } + } + printk(KERN_WARNING "channel: dev %04x is not a channel or in use\n", devno); + return -ENODEV; } @@ -485,18 +615,18 @@ static int channel_get(int media, int devno) */ static int channel_get_next(int media) { - int i; + int i; - for (i = 0; i < channel[media].count; i++) { - if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) { + for (i = 0; i < channel[media].count; i++) { + if ((channel[media].list[i].flag & CHANNEL_IN_USE) == 0x00) { #ifdef DEBUG - printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno); + printk(KERN_DEBUG "channel: picked=%04x\n", channel[media].list[i].devno); #endif - channel[media].list[i].flag |= CHANNEL_IN_USE; - return channel[media].list[i].devno; - } - } - return -ENODEV; + channel[media].list[i].flag |= CHANNEL_IN_USE; + return channel[media].list[i].devno; + } + } + return -ENODEV; } @@ -505,7 +635,7 @@ static int channel_get_next(int media) */ static int channel_left(int media) { - return channel[media].left; + return channel[media].left; } @@ -514,38 +644,38 @@ static int channel_left(int media) */ static channel_type_t channel_check_for_type (senseid_t *id) { - channel_type_t type; + channel_type_t type; - switch (id->cu_type) { - case 0x3088: + switch (id->cu_type) { + case 0x3088: - switch (id->cu_model) { - case 0x08: - type = channel_type_ctca; /* 3088-08 ==> CTCA */ - break; + switch (id->cu_model) { + case 0x08: + type = channel_type_ctca; /* 3088-08 ==> CTCA */ + break; - case 0x1F: - type = channel_type_escon; /* 3088-1F ==> ESCON channel */ - break; + case 0x1F: + type = channel_type_escon; /* 3088-1F ==> ESCON channel */ + break; - case 0x01: /* 3088-01 ==> P390 OSA emulation */ - case 0x60: /* 3088-60 ==> OSA/2 adapter */ - case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */ - case 0x62: /* 3088-62 ==> OSA/D device */ - type = channel_type_unsupported; - break; - - default: - type = channel_type_undefined; - printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model); - } - break; - - default: - type = channel_type_none; - - } - return type; + case 0x01: /* 3088-01 ==> P390 OSA emulation */ + case 0x60: /* 3088-60 ==> OSA/2 adapter */ + case 0x61: /* 3088-61 ==> CISCO 7206 CLAW protocol ESCON connected */ + case 0x62: /* 3088-62 ==> OSA/D device */ + type = channel_type_unsupported; + break; + + default: + type = channel_type_undefined; + printk(KERN_INFO "channel: Unknown model found 3088-%02x\n",id->cu_model); + } + break; + + default: + type = channel_type_none; + + } + return type; } @@ -554,22 +684,22 @@ static channel_type_t channel_check_for_type (senseid_t *id) */ static void channel_sort(struct devicelist list[], int n) { - int i; - int sorted = 0; - struct devicelist tmp; - - while (!sorted) { - sorted = 1; - - for (i = 0; i < n-1; i++) { - if (list[i].devno > list[i+1].devno) { - tmp = list[i]; - list[i] = list[i+1]; - list[i+1] = tmp; - sorted = 0; - } - } - } + int i; + int sorted = 0; + struct devicelist tmp; + + while (!sorted) { + sorted = 1; + + for (i = 0; i < n-1; i++) { + if (list[i].devno > list[i+1].devno) { + tmp = list[i]; + list[i] = list[i+1]; + list[i+1] = tmp; + sorted = 0; + } + } + } } @@ -580,182 +710,216 @@ static void channel_sort(struct devicelist list[], int n) static int inline extract_channel_id(char *name) { - if (name[0] == 'c') - return (name[3]-'0'); - else - return (name[5]-'0'); + int rv = -1; + + if (name[0] == 'c') + rv = name[3]-'0'; + else + rv = name[5]-'0'; + + if ((rv < 0) || (rv >= MAX_ADAPTERS)) + rv= -EINVAL; + + return rv; } static int inline extract_channel_media(char *name) { - if (name[0] == 'c') - return CTC; - else - return ESCON; + if (name[0] == 'c') + return CTC; + else + return ESCON; } static void ctc_tab_init(void) -{ - int m; - int i; - static int t; - - if (t == 0){ - for (m = 0; m < CHANNEL_MEDIA; m++) { - for (i = 0; i < MAX_ADAPTERS; i++) { - ctc_adapter[m][i].devno[WRITE] = -ENODEV; - ctc_adapter[m][i].devno[READ] = -ENODEV; - } - } - t = 1; - } +{ + int m; + int i; + static int t; + + if (t == 0){ + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (i = 0; i < MAX_ADAPTERS; i++) { + ctc_adapter[m][i].devno[WRITE] = -ENODEV; + ctc_adapter[m][i].devno[READ] = -ENODEV; + ctc_adapter[m][i].netdev = NULL; + } + } + t = 1; + } } static int ctc_buffer_alloc(struct channel *ctc) { - - struct buffer *p; - struct buffer *q; - - p = kmalloc(sizeof(p), GFP_KERNEL); - if (p == NULL) - return -ENOMEM; - else { - p->next = NULL; - p->packets = 0; - p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); - if (p->block == NULL) { - kfree(p); - return -ENOMEM; - } - p->block->length = 0; - } + + struct buffer *p; + struct buffer *q; + + p = kmalloc(sizeof(struct buffer), GFP_KERNEL); + if (p == NULL) + return -ENOMEM; + else { + p->next = NULL; + p->packets = 0; + p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4); + if (p->block == NULL) { + kfree(p); + return -ENOMEM; + } + p->block->length = 0; + } - if (ctc->free_anchor == NULL) - ctc->free_anchor = p; - else { - q = ctc->free_anchor; - while (q->next != NULL) - q = q->next; - q->next = p; - } - ctc->buffer_count++; + if (ctc->free_anchor == NULL) + ctc->free_anchor = p; + else { + q = ctc->free_anchor; + while (q->next != NULL) + q = q->next; + q->next = p; + } + ctc->buffer_count++; return 0; } static int ctc_buffer_free(struct channel *ctc) { - - struct buffer *p; - - - if (ctc->free_anchor == NULL) - return -ENOMEM; - - p = ctc->free_anchor; - ctc->free_anchor = p->next; - free_pages((__u32)p->block, 4); - kfree(p); - - return 0; + + struct buffer *p; + + + if (ctc->free_anchor == NULL) + return -ENOMEM; + + p = ctc->free_anchor; + ctc->free_anchor = p->next; + free_pages((unsigned long)p->block, 4); + kfree(p); + + return 0; } -static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to) { - - struct buffer *p = NULL; - struct buffer *q = NULL; +static int inline ctc_buffer_swap(struct buffer **from, struct buffer **to, net_device *dev) { + + struct buffer *p = NULL; + struct buffer *q = NULL; - if (*from == NULL) - return -ENOMEM; - - p = *from; - *from = p->next; - p->next = NULL; - - if (*to == NULL) - *to = p; - else { - q = *to; - while (q->next != NULL) - q = q->next; - q->next = p; - - } - return 0; + if (*from == NULL) + { + printk(KERN_DEBUG + "%s: %s(): Trying to swap buffer from empty list - doing nothing\n", dev ? dev->name : "", __FUNCTION__); + + return -ENOMEM; + } + + p = *from; + *from = p->next; + p->next = NULL; + + if (*to == NULL) + *to = p; + else { + q = *to; + while (q->next != NULL) + q = q->next; + q->next = p; + + } + return 0; } - +#ifdef MODULE + static void ctc_setup(char *dev_name,int *ints) +# define ctc_setup_return return +#else +# if LINUX_VERSION_CODE>=0x020300 + static int __init ctc_setup(char *dev_name) +# define ctc_setup_return return(1) +# else + __initfunc(void ctc_setup(char *dev_name,int *ints)) +# define ctc_setup_return return +# endif +#endif /* * ctc_setup function * this function is called for each ctc= keyword passed into the kernel * * valid parameter are: ctc=n,0xnnnn,0xnnnn,ctcx - * where n is the channel protocol always 0 - * 0xnnnn is the cu number read - * 0xnnnn is the cu number write - * ctcx can be ctc0 to ctc7 or escon0 to escon7 + * where n is the channel protocol always 0 + * 0xnnnn is the cu number read + * 0xnnnn is the cu number write + * ctcx can be ctc0 to ctc7 or escon0 to escon7 */ -#if LINUX_VERSION_CODE>=0x020300 -static int __init ctc_setup(char *dev_name) -#else -__initfunc(void ctc_setup(char *dev_name,int *ints)) -#endif + { - struct adapterlist tmp; + struct adapterlist tmp; + int id; #if LINUX_VERSION_CODE>=0x020300 #define CTC_MAX_PARMS 4 - int ints[CTC_MAX_PARMS+1]; - get_options(dev_name,CTC_MAX_PARMS,ints); - #define ctc_setup_return return(1) -#else - #define ctc_setup_return return + int ints[CTC_MAX_PARMS+1]; + dev_name = get_options(dev_name, CTC_MAX_PARMS, ints); #endif - ctc_tab_init(); - - ctc_no_auto = 1; - - if (!strcmp(dev_name,"noauto")) { - printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); - ctc_setup_return; - } - - tmp.devno[WRITE] = -ENODEV; - tmp.devno[READ] = -ENODEV; - - switch (ints[0]) { - - case 3: /* write channel passed */ - tmp.devno[WRITE] = ints[3]; - - case 2: /* read channel passed */ - tmp.devno[READ] = ints[2]; - if (tmp.devno[WRITE] == -ENODEV) - tmp.devno[WRITE] = tmp.devno[READ] + 1; - - case 1: /* protocol type passed */ - tmp.protocol = ints[1]; - if (tmp.protocol == 0) { - break; - } else { - printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name); - ctc_setup_return; - } - break; - - default: - printk(KERN_WARNING "ctc: wrong number of parameter passed\n"); - ctc_setup_return; - } - ctc_adapter[extract_channel_media(dev_name)][extract_channel_id(dev_name)] = tmp; + ctc_tab_init(); + + ctc_no_auto = 1; + + if (!dev_name) { /* happens if device name is not specified in + parameter line (cf. init/main.c:get_options() */ + printk(KERN_WARNING + "ctc: %s(): Device name not specified\n", + __FUNCTION__); + ctc_setup_return; + } + + if (!strcmp(dev_name,"noauto")) { + printk(KERN_INFO "ctc: automatic channel selection deactivated\n"); + ctc_setup_return; + } + + if ((id = extract_channel_id(dev_name)) == -EINVAL) + { + printk(KERN_WARNING + "ctc: %s(): Invalid device name specified: %s\n", + __FUNCTION__, dev_name); + ctc_setup_return; + } + + tmp.devno[WRITE] = -ENODEV; + tmp.devno[READ] = -ENODEV; + + switch (ints[0]) { + + case 3: /* write channel passed */ + tmp.devno[WRITE] = ints[3]; + + case 2: /* read channel passed */ + tmp.devno[READ] = ints[2]; + if (tmp.devno[WRITE] == -ENODEV) + tmp.devno[WRITE] = tmp.devno[READ] + 1; + + case 1: /* protocol type passed */ + tmp.protocol = ints[1]; + if (tmp.protocol == 0) { + break; + } else { + printk(KERN_WARNING "%s: wrong Channel protocol type passed\n", dev_name); + ctc_setup_return; + } + break; + + default: + printk(KERN_WARNING "ctc: wrong number of parameter passed\n"); + ctc_setup_return; + } + ctc_adapter[extract_channel_media(dev_name)][id] = tmp; #ifdef DEBUG - printk(DEBUG "%s: protocol=%x read=%04x write=%04x\n", - dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]); -#endif - ctc_setup_return; - + printk(KERN_DEBUG "%s: protocol=%x read=%04x write=%04x\n", + dev_name, tmp.protocol, tmp.devno[READ], tmp.devno[WRITE]); +#endif + ctc_setup_return; + } #if LINUX_VERSION_CODE>=0x020300 __setup("ctc=", ctc_setup); @@ -763,102 +927,131 @@ __setup("ctc=", ctc_setup); /* * ctc_probe - * this function is called for each channel network device, - * which is defined in the /init/main.c + * this function is called for each channel network device, + * which is defined in the /init/main.c */ int ctc_probe(net_device *dev) -{ - int rc; - int c; - int i; - int m; - - struct ctc_priv *privptr; - - /* Only the first time the ctc_probe gets control */ - if (channel_tab_initialized == 0) { - channel_init(); - - - } - - ctc_tab_init(); - - m = extract_channel_media(dev->name); - i = extract_channel_id(dev->name); - - if (channel_left(m) <=1) - return -ENODEV; - - if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV)) - return -ENODEV; - - dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - memset(dev->priv, 0, sizeof(struct ctc_priv)); - privptr = (struct ctc_priv *) (dev->priv); - - - for (c = 0; c < 2; c++) { - - privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL); - if (privptr->channel[c].devstat == NULL){ - if (i == WRITE) - kfree(privptr->channel[READ].devstat); - return -ENOMEM; - } - memset(privptr->channel[c].devstat, 0, sizeof(devstat_t)); - - if (ctc_no_auto == 0) - ctc_adapter[m][i].devno[c] = channel_get_next(m); - else - ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); - - if ( ctc_adapter[m][i].devno[c] != -ENODEV){ - rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), - (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, - privptr->channel[c].devstat); - if (rc) { - printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); - return -EBUSY; - } - } else { - if (i == WRITE) { - free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat); - channel_free(m, ctc_adapter[m][i].devno[READ]); - kfree(privptr->channel[READ].devstat); - } - kfree(privptr->channel[i].devstat); - return -ENODEV; - } - } - - privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; - privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); - privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; - privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); - privptr->protocol = ctc_adapter[m][i].protocol; - channel[m].left = channel[m].left - 2; - - printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", - dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, - privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); - - dev->mtu = CTC_DEFAULT_MTU_SIZE; - dev->hard_start_xmit = ctc_tx; - dev->open = ctc_open; - dev->stop = ctc_release; - dev->get_stats = ctc_stats; - dev->change_mtu = ctc_change_mtu; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_SLIP; - dev->tx_queue_len = 100; - dev_init_buffers(dev); - dev->flags = IFF_POINTOPOINT | IFF_NOARP; - - return 0; +{ + int rc; + int c; + int i; + int m; + struct ctc_priv *privptr; + + /* Only the first time the ctc_probe gets control */ + if (channel_tab_initialized == 0) { + channel_init(); + } + + ctc_tab_init(); + + m = extract_channel_media(dev->name); + i = extract_channel_id(dev->name); + + if (channel_left(m) <= 1) + return -ENODEV; + + if (i < 0 || i >= MAX_ADAPTERS) + return -ENODEV; + + if (ctc_no_auto == 1 && (ctc_adapter[m][i].devno[READ] == -ENODEV || ctc_adapter[m][i].devno[WRITE] == -ENODEV)) + return -ENODEV; + + dev->priv = kmalloc(sizeof(struct ctc_priv), GFP_KERNEL|GFP_DMA); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct ctc_priv)); + privptr = (struct ctc_priv *) (dev->priv); + + + for (c = 0; c < 2; c++) { + devstat_t *devstat; + unsigned int devno; + + privptr->channel[c].devstat = kmalloc(sizeof(devstat_t), GFP_KERNEL); + devstat = privptr->channel[c].devstat; + if (devstat == NULL) { + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + kfree(dev->priv); + dev->priv = NULL; + return -ENOMEM; + } + + memset(devstat, 0, sizeof(devstat_t)); + + if (ctc_no_auto == 0) { + ctc_adapter[m][i].devno[c] = channel_get_next(m); + devno = ctc_adapter[m][i].devno[c]; + } + else { + ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); + devno = ctc_adapter[m][i].devno[c]; + } + + + if (devno != -ENODEV) { + rc = request_irq(get_irq_by_devno(devno), + ctc_irq_handler, SA_INTERRUPT, dev->name, + devstat); + if (rc) { + printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), + privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + channel_free(m, devno); + kfree(devstat); + kfree(dev->priv); + dev->priv = NULL; + return -EBUSY; + } + } else { + if (c == 1) { + free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[0]), privptr->channel[0].devstat); + channel_free(m, ctc_adapter[m][i].devno[0]); + kfree(privptr->channel[0].devstat); + } + kfree(devstat); + kfree(dev->priv); + dev->priv = NULL; + return -ENODEV; + } + } + + privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; + privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); + privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; + privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); + privptr->channel[READ].dev = privptr->channel[WRITE].dev = dev; + privptr->protocol = ctc_adapter[m][i].protocol; + channel[m].left = channel[m].left - 2; + + print_banner(); + printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", + dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, + privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); + + dev->mtu = CTC_DEFAULT_MTU_SIZE; + dev->hard_start_xmit = ctc_tx; + dev->open = ctc_open; + dev->stop = ctc_release; + dev->get_stats = ctc_stats; + dev->change_mtu = ctc_change_mtu; + dev->hard_header_len = 6; + dev->addr_len = 0; + dev->type = ARPHRD_SLIP; + dev->tx_queue_len = 100; + dev_init_buffers(dev); + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + ctc_adapter[m][i].netdev = dev; + + return 0; } @@ -867,456 +1060,563 @@ int ctc_probe(net_device *dev) * */ -static void inline ccw_check_return_code (net_device *dev, int return_code) +static void inline ccw_check_return_code (net_device *dev, int return_code, char *caller) { - if (return_code != 0) { - switch (return_code) { - case -EBUSY: - printk(KERN_INFO "%s: Busy !\n", dev->name); - break; - case -ENODEV: - printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name); - break; - case -EIO: - printk(KERN_EMERG "%s: Status pending... \n", dev->name); - break; - default: - printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", - dev->name, return_code); - } - } + if (return_code != 0) { + switch (return_code) { + case -EBUSY: + printk(KERN_INFO "%s: %s: Busy !\n", dev->name, caller); + break; + case -ENODEV: + printk(KERN_EMERG "%s: %s: Invalid device called for IO\n", dev->name, caller); + break; + case -EIO: + printk(KERN_EMERG "%s: %s: Status pending... \n", dev->name, caller); + break; + default: + printk(KERN_EMERG "%s: %s: Unknown error in Do_IO %04x\n", + dev->name, caller, return_code); + } + } } -static void inline ccw_check_unit_check (net_device *dev, char sense) +static void inline ccw_check_unit_check (net_device *dev, char sense, char *caller) { #ifdef DEBUG - printk(KERN_INFO "%s: Unit Check with sense code: %02x\n", - dev->name, sense); + printk(KERN_INFO "%s: %s: Unit Check with sense code: %02x\n", + dev->name, caller, sense); #endif - if (sense & 0x40) { + if (sense & 0x40) { #ifdef DEBUG - if (sense & 0x01) - printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name); - else - printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name); + if (sense & 0x01) + printk(KERN_DEBUG "%s: %s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name, caller); + else + printk(KERN_DEBUG "%s: %s: System reset occured (remote side)\n", dev->name, caller); #endif - } else if (sense & 0x20) { - if (sense & 0x04) - printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name); - else - printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name); - } else if (sense & 0x10) { - if (sense & 0x20) - printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name); - else - printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name); - } + } else if (sense & 0x20) { + if (sense & 0x04) + printk(KERN_WARNING "%s: %s: Data-streaming timeout)\n", dev->name, caller); + else + printk(KERN_WARNING "%s: %s: Data-transfer parity error\n", dev->name, caller); + } else if (sense & 0x10) { + if (sense & 0x20) + printk(KERN_WARNING "%s: %s: Hardware malfunction (remote side)\n", dev->name, caller); + else + printk(KERN_WARNING "%s: %s: Read-data parity error (remote side)\n", dev->name, caller); + } } - + static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - struct channel *ctc = NULL; - struct ctc_priv *privptr = NULL; - net_device *dev = NULL; - - /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, - {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */ - - ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL}, - {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + struct channel *ctc = NULL; + struct ctc_priv *privptr = NULL; + net_device *dev = NULL; + + /* ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, + {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; */ + + static ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, 0}, + {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, 0}}; - devstat_t *devstat = ((devstat_t *)initparm); + devstat_t *devstat = ((devstat_t *)initparm); - /* Bypass all 'unsolicited interrupts' */ - if (devstat->intparm == 0) { + /* Bypass all 'unsolicited interrupts' */ + if (devstat->intparm == 0) { #ifdef DEBUG - printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received c-%02x d-%02x f-%02x\n", - devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); + printk(KERN_DEBUG "ctc: unsolicited interrupt for device: %04x received cstat: %02x dstat: %02x flag: %02x\n", + devstat->devno, devstat->cstat, devstat->dstat, devstat->flag); #endif - /* FIXME - find the related intparm!!! No IO outstanding!!!! */ - return; - } - - ctc = (struct channel *) (devstat->intparm); - dev = (net_device *) ctc->dev; - privptr = dev->priv; + /* FIXME - find the related intparm!!! No IO outstanding!!!! */ + return; + } + + ctc = (struct channel *) (devstat->intparm); + if(ctc==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler ctc=NULL irq=%d\n",irq); + return; + } + + dev = (net_device *) ctc->dev; + if(dev==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler dev=NULL irq=%d, ctc=0x%p\n", + irq, ctc); + return; + } + + privptr = dev->priv; + if(privptr==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler privptr=NULL " + "irq=%d, ctc=0x%p, dev=0x%p\n", irq, ctc, privptr); + return; + } #ifdef DEBUG - printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", - dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state); + printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", + dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state); #endif - /* Check for good subchannel return code, otherwise error message */ - if (devstat->cstat) { - printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", - dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag); - return; - } + /* Check for good subchannel return code, otherwise error message */ + if (devstat->cstat) { + printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x %02x %02x\n", + dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag); + return; + } - /* Check the reason-code of a unit check */ - if (devstat->dstat & DEV_STAT_UNIT_CHECK) - ccw_check_unit_check(dev, devstat->ii.sense.data[0]); + /* Check the reason-code of a unit check */ + if (devstat->dstat & DEV_STAT_UNIT_CHECK) + ccw_check_unit_check(dev, devstat->ii.sense.data[0], __FUNCTION__ "()"); - /* State machine to bring the connection up / down and to restart */ + /* State machine to bring the connection up / down and to restart */ - ctc->last_dstat = devstat->dstat; + ctc->last_dstat = devstat->dstat; - switch (ctc->state) { + switch (ctc->state) { - case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - wake_up(&ctc->wait); /* wake up ctc_release */ - return; + case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_STOP"); +#endif + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_release */ + return; - case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - - ctc->state = CTC_START_SET_X_MODE; - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_HALT_IO"); +#endif + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + + ctc->state = CTC_START_SET_X_MODE; + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + return; - - case CTC_START_SET_X_MODE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || - (devstat->ii.sense.data[0] & 0x40) != 0x40) { - wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ - return; - } - } - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - ctc->state = CTC_START_SELECT; + + case CTC_START_SET_X_MODE: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SET_X_MODE"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || + (devstat->ii.sense.data[0] & 0x40) != 0x40) { + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ + return; + } + } + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + ctc->state = CTC_START_SELECT; - case CTC_START_SELECT: - if (!ctc->flag & CTC_WRITE) { - ctc->state = CTC_START_READ_TEST; - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - wake_up(&ctc->wait); /* wake up ctc_open (READ) */ - - } else { - ctc->state = CTC_START_WRITE_TEST; - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ - ctc->free_anchor->block->length = 0; - ctc->ccw[1].count = 2; /* Transfer only length */ - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - return; - - - case CTC_START_READ_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); + case CTC_START_SELECT: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_SELECT"); +#endif + if(ctc->free_anchor==NULL) + { + printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_SELECT ctc_free_anchor=NULL " + "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); + return; + } + if (!(ctc->flag & CTC_WRITE)) { + ctc->state = CTC_START_READ_TEST; + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[2]"); + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (READ) */ + + } else { + ctc->state = CTC_START_WRITE_TEST; + /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ + ctc->free_anchor->block->length = 0; + ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */ + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[3]"); + } + return; + + + case CTC_START_READ_TEST: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ_TEST"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + init_timer(&ctc->timer); + ctc->timer.function = ctc_read_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 10*HZ; + add_timer(&ctc->timer); #ifdef DEBUG - printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); + printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); #endif - } - return; - } - - if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - if ((devstat->dstat & DEV_STAT_ATTENTION) && - (devstat->dstat & DEV_STAT_BUSY)) { - printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); - } - wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ - return; - } - - ctc->state = CTC_START_READ; - set_bit(0, (void *)&ctc->IO_active); - - /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ - /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ - - - case CTC_START_READ: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - privptr->stats.rx_errors++; + } + return; + } + + if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { + if ((devstat->dstat & DEV_STAT_ATTENTION) && + (devstat->dstat & DEV_STAT_BUSY)) { + printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); + } + privptr->channel[WRITE].flag |= CTC_WAKEUP; + wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ + return; + } + + ctc->state = CTC_START_READ; + set_bit(0, &ctc->IO_active); + + /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ + /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ + + + case CTC_START_READ: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_READ"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + privptr->stats.rx_errors++; /* Need protection here cos we are in the read irq */ /* handler the tbusy is for the write subchannel */ ctc_protect_busy(dev); - ctc_setbit_busy(TB_RETRY,dev); + ctc_setbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_read_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 30*HZ; - add_timer(&ctc->timer); - printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); - } - return; - } - - if(!devstat->flag & DEVSTAT_FINAL_STATUS) - return; + init_timer(&ctc->timer); + ctc->timer.function = ctc_read_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 30*HZ; + add_timer(&ctc->timer); + printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); + } + return; + } + + if(!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; ctc_protect_busy(dev); ctc_clearbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - - if (ctc->free_anchor != NULL) { - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } else { - clear_bit(0, (void *)&ctc->IO_active); + ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); + + if (ctc->free_anchor != NULL) { + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[4]"); + } else { + clear_bit(0, &ctc->IO_active); #ifdef DEBUG - printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name); + printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name); #endif - } - - if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) { - queue_task(&ctc->tq, &tq_immediate); - mark_bh(IMMEDIATE_BH); - } - return; - - - case CTC_START_WRITE_TEST: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || - (devstat->ii.sense.data[0] & 0x40) == 0x40 || - devstat->ii.sense.data[0] == 0 ) { - init_timer(&ctc->timer); - ctc->timer.function = (void *)ctc_write_retry; - ctc->timer.data = (__u32)ctc; - ctc->timer.expires = jiffies + 10*HZ; - add_timer(&ctc->timer); + } + + if (test_and_set_bit(CTC_BH_ACTIVE, &ctc->flag_a) == 0) { + queue_task(&ctc->tq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + } + return; + + + case CTC_START_WRITE_TEST: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE_TEST"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || + (devstat->ii.sense.data[0] & 0x40) == 0x40 || + devstat->ii.sense.data[0] == 0 ) { + init_timer(&ctc->timer); + ctc->timer.function = ctc_write_retry; + ctc->timer.data = (unsigned long)ctc; + ctc->timer.expires = jiffies + 10*HZ; + add_timer(&ctc->timer); #ifdef DEBUG - printk(KERN_DEBUG "%s: write connection restarted\n",dev->name); + printk(KERN_DEBUG "%s: write connection restarted\n",dev->name); #endif - } - return; - } - - ctc->state = CTC_START_WRITE; - wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ - return; + } + return; + } + + ctc->state = CTC_START_WRITE; + ctc->flag |= CTC_WAKEUP; + wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ + return; - case CTC_START_WRITE: - if (devstat->dstat & DEV_STAT_UNIT_CHECK) { - privptr->stats.tx_errors += ctc->proc_anchor->packets; + case CTC_START_WRITE: +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__, "CTC_START_WRITE"); +#endif + if (devstat->dstat & DEV_STAT_UNIT_CHECK) { + privptr->stats.tx_errors += ctc->proc_anchor->packets; #ifdef DEBUG - printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name); + printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name); #endif - } else { - if (!devstat->flag & DEVSTAT_FINAL_STATUS) - return; - privptr->stats.tx_packets += ctc->proc_anchor->packets; - } - - ctc->proc_anchor->block->length = 0; - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - ctc_clearbit_busy(TB_NOBUFFER,dev); - if (ctc->proc_anchor != NULL) { + } else { + if (!(devstat->flag & DEVSTAT_FINAL_STATUS)) + return; + privptr->stats.tx_packets += ctc->proc_anchor->packets; + } + + ctc->proc_anchor->block->length = 0; + ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); + ctc_clearbit_busy(TB_NOBUFFER, dev); + if (ctc->proc_anchor != NULL) { #ifdef DEBUG - printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); + printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); #endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - - } - - if (ctc->free_anchor->block->length != 0) { - if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { - /* set transmission to busy */ - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - ctc_clearbit_busy(TB_TX,dev); + ctc->ccw[1].count = ctc->proc_anchor->block->length; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[5]"); + dev->trans_start = jiffies; + return; + + } + if (ctc->free_anchor==NULL) { + printk(KERN_CRIT "ctc:ctc_irq_handler CTC_START_WRITE ctc_free_anchor=NULL " + "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr); + return; + } + if (ctc->free_anchor->block->length != 0) { + if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { + /* set transmission to busy */ + ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev); + ctc_clearbit_busy(TB_TX,dev); #ifdef DEBUG - printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); + printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); #endif - ctc->ccw[1].count = ctc->proc_anchor->block->length; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - dev->trans_start = jiffies; - return; - } - } - - clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */ - return; + ctc->ccw[1].count = ctc->proc_anchor->block->length; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[6]"); + dev->trans_start = jiffies; + return; + } + } + + clear_bit(0, &ctc->IO_active); /* set by ctc_tx or ctc_bh */ + return; - default: - printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); - return; - } + default: + printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); + return; + } } -static void ctc_irq_bh (struct channel *ctc) +static void ctc_irq_bh (void *data) { - int rc = 0; - __u16 data_len; - __u32 parm; - - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; - struct ctc_priv *privptr; - struct packet *lp; - struct sk_buff *skb; - - dev = (net_device *) ctc->dev; - privptr = (struct ctc_priv *) dev->priv; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + struct ctc_priv *privptr = (struct ctc_priv *) dev->priv; + + int rc = 0; + __u16 data_len; + __u32 parm; + + __u8 flags = 0x00; + unsigned long saveflags; + struct block *block; + struct packet *lp; + struct sk_buff *skb; + #ifdef DEBUG - printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state); + printk(KERN_DEBUG "%s: %s(): initial_block_received = %d\n" ,dev->name, __FUNCTION__, ctc->initial_block_received); + printk(KERN_DEBUG "%s: bh routine - state-%02x\n" ,dev->name, ctc->state); #endif - while (ctc->proc_anchor != NULL) { - - if (ctc->proc_anchor->block->length != 0) { - - lp = &ctc->proc_anchor->block->data; - while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) { - data_len = lp->length - PACKET_HEADER_LENGTH; - skb = dev_alloc_skb(data_len); - if (skb) { - memcpy(skb_put(skb, data_len),&lp->data, data_len); - skb->mac.raw = skb->data; - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */ - netif_rx(skb); - privptr->stats.rx_packets++; - } else { - privptr->stats.rx_dropped++; - printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name); - } - (__u8 *)lp += lp->length; - } - } - - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - - if (test_and_set_bit(0, (void *)&ctc->IO_active) == 0) { + while (ctc->proc_anchor != NULL) { + block = ctc->proc_anchor->block; + if (block->length < BLOCK_HEADER_LENGTH) { + if(block->length == 0 && !ctc->initial_block_received) + ctc->initial_block_received = 1; + else + printk(KERN_INFO "%s: %s(): discarding block at 0x%p: " + "block length=%d<%d=block header length\n", + dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH); + } + else { + lp = &block->data; + while ((__u8 *) lp < (__u8 *) block + block->length) { + if(lp->length < PACKET_HEADER_LENGTH) { + printk(KERN_INFO "%s: %s(): discarding rest of block at 0x%p (block length=%d:) " + "packet at 0x%p, packet length=%d<%d=packet header length\n", + dev->name, __FUNCTION__, + block, block->length, lp, lp->length, PACKET_HEADER_LENGTH); + break; + } + + data_len = lp->length - PACKET_HEADER_LENGTH; +#ifdef DEBUG + printk(KERN_DEBUG "%s: %s(): block=0x%p, block->length=%d, lp=0x%p, " + "lp->length=%d, data_len=%d\n", + dev->name, __FUNCTION__, block, block->length, lp, lp->length, data_len); +#endif + skb = dev_alloc_skb(data_len); + if (skb) { + memcpy(skb_put(skb, data_len),&lp->data, data_len); + skb->mac.raw = skb->data; + skb->dev = dev; + skb->protocol = htons(ETH_P_IP); + skb->ip_summed = CHECKSUM_UNNECESSARY; /* no UC happened!!! */ + netif_rx(skb); + privptr->stats.rx_packets++; + } else { + privptr->stats.rx_dropped++; + printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name); + } + (__u8 *)lp += lp->length; + } + } + + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev); + + if (test_and_set_bit(0, &ctc->IO_active) == 0) { +#ifdef DEBUG + printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); +#endif + if(ctc->free_anchor==NULL || ctc->free_anchor->block==NULL) + { + printk(KERN_CRIT "ctc: bad anchor free_anchor " + "ctc=0x%p, ctc->free_anchor=0x%p, ctc->irq=%d\n", + ctc, ctc->free_anchor, ctc->irq); + } + else + { + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + } + } + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + } + clear_bit(CTC_BH_ACTIVE, &ctc->flag_a); #ifdef DEBUG - printk(KERN_DEBUG "%s: HOT READ started in bh routine\n" ,dev->name); + printk(KERN_DEBUG "%s: end bh routine - state-%02x\n" ,dev->name, ctc->state); #endif - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - if (rc != 0) - ccw_check_return_code(dev, rc); - } - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - } - clear_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a); - return; + return; } -static void ctc_read_retry (struct channel *ctc) +static void ctc_read_retry (unsigned long data) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; + - dev = (net_device *) ctc->dev; - #ifdef DEBUG - printk(KERN_DEBUG "%s: read retry - state-%02x\n" ,dev->name, ctc->state); -#endif - if (ctc->state == CTC_STOP) - return; - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->free_anchor->block->length = 0; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + printk(KERN_DEBUG "%s: read retry - state-%02x\n", + dev->name, ctc->state); +#endif + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + if (ctc->state != CTC_STOP) { + if (!ctc->free_anchor) { + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + printk(KERN_WARNING + "%s: %s(): ctc->free_anchor=NULL, ctc=0x%p\n", + dev->name, __FUNCTION__, ctc); + return; + } + + ctc->free_anchor->block->length = 0; + ctc->ccw[1].cda = __pa(ctc->free_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags); + } + + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + return; } -static void ctc_write_retry (struct channel *ctc) +static void ctc_write_retry (unsigned long data) { - int rc = 0; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - net_device *dev; + struct channel *ctc = (struct channel *) data; + net_device *dev = (net_device *) ctc->dev; + int rc = 0; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; - dev = (net_device *) ctc->dev; #ifdef DEBUG - printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); -#endif - if (ctc->state == CTC_STOP) - return; - - while (ctc->proc_anchor != NULL) { - ctc->proc_anchor->block->length = 0; - ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); - } - - ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); - s390irq_spin_lock_irqsave(ctc->irq, saveflags); - ctc->ccw[1].count = 2; - ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); - parm = (__u32) ctc; - rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); - s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); - return; + printk(KERN_DEBUG "%s: write retry - state-%02x\n" ,dev->name, ctc->state); +#endif + + if (ctc->proc_anchor != NULL) { + printk(KERN_WARNING "%s: %s(): ctc->proc_anchor != NULL\n" ,dev->name, __FUNCTION__); + } + + s390irq_spin_lock_irqsave(ctc->irq, saveflags); + + if (ctc->state != CTC_STOP) + { + ctc->ccw[1].count = 2; + ctc->ccw[1].cda = __pa(ctc->proc_anchor->block); + parm = (__u32)(long) ctc; + rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); + } + + s390irq_spin_unlock_irqrestore(ctc->irq, saveflags); + + if (rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + return; } @@ -1327,123 +1627,139 @@ static void ctc_write_retry (struct channel *ctc) */ static int ctc_open(net_device *dev) { - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - struct timer_list timer; - - - ctc_set_busy(dev); - - privptr = (struct ctc_priv *) (dev->priv); - - privptr->channel[READ].flag = 0x00; - privptr->channel[WRITE].flag = CTC_WRITE; - - for (i = 0; i < 2; i++) { - for (j = 0; j < CTC_BLOCKS; j++) { - rc = ctc_buffer_alloc(&privptr->channel[i]); - if (rc != 0) - return -ENOMEM; - } - init_waitqueue_head(&privptr->channel[i].wait); - privptr->channel[i].tq.next = NULL; - privptr->channel[i].tq.sync = 0; - privptr->channel[i].tq.routine = (void *)(void *)ctc_irq_bh; - privptr->channel[i].tq.data = &privptr->channel[i]; - - privptr->channel[i].dev = dev; - - privptr->channel[i].flag_a = 0; - privptr->channel[i].IO_active = 0; - - privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE; - privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[0].count = 0; - privptr->channel[i].ccw[0].cda = NULL; - if (i == READ) { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */ - privptr->channel[i].ccw[1].cda = NULL; - } else { - privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE; - privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC; - privptr->channel[i].ccw[1].count = 0; - privptr->channel[i].ccw[1].cda = NULL; - } - privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */ - privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI; - privptr->channel[i].ccw[2].count = 0; - privptr->channel[i].ccw[2].cda = NULL; - - privptr->channel[i].flag &= ~CTC_TIMER; - init_timer(&timer); - timer.function = (void *)ctc_timer; - timer.data = (__u32)&privptr->channel[i]; - timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ - add_timer(&timer); - - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_START_HALT_IO; - rc = halt_IO(privptr->channel[i].irq, parm, flags); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if(rc != 0) - ccw_check_return_code(dev, rc); - if((privptr->channel[i].flag & CTC_TIMER) == 0x00) - del_timer(&timer); - } - - if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || - (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { + int rc, wait_rc; + int i, ii; + int j; + __u8 flags = 0x00; + unsigned long saveflags; + __u32 parm; + struct ctc_priv *privptr; + struct timer_list timer; + + + ctc_set_busy(dev); + + privptr = (struct ctc_priv *) (dev->priv); + + privptr->channel[READ].flag = 0x00; + privptr->channel[WRITE].flag = CTC_WRITE; + + for (i = 0; i < 2; i++) { + privptr->channel[i].free_anchor = NULL; + privptr->channel[i].proc_anchor = NULL;; + for (j = 0; j < CTC_BLOCKS; j++) { + rc = ctc_buffer_alloc(&privptr->channel[i]); + if (rc != 0) + return -ENOMEM; + } + init_waitqueue_head(&privptr->channel[i].wait); + privptr->channel[i].tq.next = NULL; + privptr->channel[i].tq.sync = 0; + privptr->channel[i].tq.routine = ctc_irq_bh; + privptr->channel[i].tq.data = &privptr->channel[i]; + + privptr->channel[i].initial_block_received = 0; + + privptr->channel[i].dev = dev; + + privptr->channel[i].flag_a = 0; + privptr->channel[i].IO_active = 0; + + privptr->channel[i].ccw[0].cmd_code = CCW_CMD_PREPARE; + privptr->channel[i].ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC; + privptr->channel[i].ccw[0].count = 0; + privptr->channel[i].ccw[0].cda = 0; + if (i == READ) { + privptr->channel[i].ccw[1].cmd_code = CCW_CMD_READ; + privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI; + privptr->channel[i].ccw[1].count = 0xffff; /* MAX size */ + privptr->channel[i].ccw[1].cda = 0; + } else { + privptr->channel[i].ccw[1].cmd_code = CCW_CMD_WRITE; + privptr->channel[i].ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC; + privptr->channel[i].ccw[1].count = 0; + privptr->channel[i].ccw[1].cda = 0; + } + privptr->channel[i].ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE+DE */ + privptr->channel[i].ccw[2].flags = CCW_FLAG_SLI; + privptr->channel[i].ccw[2].count = 0; + privptr->channel[i].ccw[2].cda = 0; + + privptr->channel[i].flag &= ~(CTC_TIMER | CTC_WAKEUP); + init_timer(&timer); + timer.function = ctc_timer; + timer.data = (unsigned long)&privptr->channel[i]; + timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ + add_timer(&timer); + + s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); + parm = (unsigned long) &privptr->channel[i]; + privptr->channel[i].state = CTC_START_HALT_IO; + rc = halt_IO(privptr->channel[i].irq, parm, flags); + s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); + + wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + + if(rc != 0) + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + + if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */ + for (ii=0; ii<=i; ii++) { + + del_timer(&privptr->channel[ii].timer); + + for (j=0; privptr->channel[ii].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[ii]); + + if (privptr->channel[ii].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + return -ERESTARTSYS; + } + } + + if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) || + (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) { #ifdef DEBUG - printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); + printk(KERN_DEBUG "%s: channel problems during open - read: %02x - write: %02x\n", + dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); #endif - printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name); - - for (i = 0; i < 2; i++) { - /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - parm = (unsigned long) &privptr->channel[i]; - privptr->channel[i].state = CTC_STOP; - rc = halt_IO(privptr->channel[i].irq, parm, flags); / - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - if (rc != 0) - ccw_check_return_code(dev, rc); */ - for (j = 0; j < CTC_BLOCKS; j++) - ctc_buffer_free(&privptr->channel[i]); - } - return -EIO; - } - - printk(KERN_INFO "%s: connected with remote side\n",dev->name); - ctc_clear_busy(dev); - return 0; + printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name); + + for (i = 0; i < 2; i++) { + del_timer(&privptr->channel[i].timer); + + for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[i]); + + if (privptr->channel[i].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + return -EIO; + } + + printk(KERN_INFO "%s: connected with remote side\n",dev->name); + ctc_clear_busy(dev); + MOD_INC_USE_COUNT; + return 0; } -static void ctc_timer (struct channel *ctc) +static void ctc_timer (unsigned long data) { + struct channel *ctc = (struct channel *) data; #ifdef DEBUG - net_device *dev; - - dev = (net_device *) ctc->dev; - printk(KERN_DEBUG "%s: timer return\n" ,dev->name); + net_device *dev = (net_device *) ctc->dev; + printk(KERN_DEBUG "%s: timer return\n" ,dev->name); #endif - ctc->flag |= CTC_TIMER; - wake_up(&ctc->wait); - return; + ctc->flag |= (CTC_TIMER|CTC_WAKEUP); + wake_up(&ctc->wait); + return; } /* @@ -1452,49 +1768,75 @@ static void ctc_timer (struct channel *ctc) */ static int ctc_release(net_device *dev) { - int rc; - int i; - int j; - __u8 flags = 0x00; - __u32 saveflags; - __u32 parm; - struct ctc_priv *privptr; - DECLARE_WAITQUEUE(wait, current); - - privptr = (struct ctc_priv *) dev->priv; - - ctc_protect_busy_irqsave(dev,saveflags); - ctc_setbit_busy(TB_STOP,dev); - ctc_unprotect_busy_irqrestore(dev,flags); - for (i = 0; i < 2; i++) { - s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); - del_timer(&privptr->channel[READ].timer); - privptr->channel[i].state = CTC_STOP; - parm = (__u32) &privptr->channel[i]; - rc = halt_IO (privptr->channel[i].irq, parm, flags ); - add_wait_queue(&privptr->channel[i].wait, &wait); - current->state = TASK_INTERRUPTIBLE; - s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); - schedule(); - remove_wait_queue(&privptr->channel[i].wait, &wait); - if (rc != 0) { - ccw_check_return_code(dev, rc); - } - - for (j = 0; j < CTC_BLOCKS; j++) { - ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor); - ctc_buffer_free(&privptr->channel[i]); - } - } - - if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & - ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { - printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n", - dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); - return -EIO; - } - - return 0; + int rc; + int i; + int j; + __u8 flags = 0x00; + unsigned long saveflags; + __u32 parm; + struct ctc_priv *privptr; + struct timer_list timer; + + privptr = (struct ctc_priv *) dev->priv; + + ctc_protect_busy_irqsave(dev, saveflags); + ctc_setbit_busy(TB_STOP,dev); + ctc_unprotect_busy_irqrestore(dev, saveflags); + + for (i = 0; i < 2; i++) { + privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER); + init_timer(&timer); + timer.function = ctc_timer; + timer.data = (unsigned long)&privptr->channel[i]; + timer.expires = jiffies + 300*HZ; /* time to connect with the remote side */ + add_timer(&timer); + + s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags); + del_timer(&privptr->channel[i].timer); + privptr->channel[i].state = CTC_STOP; + parm = (__u32)(long) &privptr->channel[i]; + rc = halt_IO (privptr->channel[i].irq, parm, flags ); + s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags); + + wait_event(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP); + + del_timer(&timer); + + if (rc != 0) { + ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]"); + } + + if(privptr->channel[i].flag & CTC_TIMER) + { + printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n", + dev->name, __FUNCTION__); + } + + + for (j=0; privptr->channel[i].proc_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_swap(&privptr->channel[i].proc_anchor, &privptr->channel[i].free_anchor, dev); + + if (privptr->channel[i].proc_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to move more than maximal number %d of blocks to free list\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + + for (j=0; privptr->channel[i].free_anchor != NULL && j < CTC_BLOCKS; j++) + ctc_buffer_free(&privptr->channel[i]); + + if (privptr->channel[i].free_anchor != NULL) + printk(KERN_WARNING "%s: %s(): trying to free more than maximal number %d of blocks\n", + dev->name, __FUNCTION__, CTC_BLOCKS); + } + + if (((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & + ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { + printk(KERN_WARNING "%s: channel problems during close - read: %02x - write: %02x\n", + dev->name, privptr->channel[READ].last_dstat, privptr->channel[WRITE].last_dstat); + return -EIO; + } + + MOD_DEC_USE_COUNT; + return 0; } @@ -1505,80 +1847,80 @@ static int ctc_release(net_device *dev) */ static int ctc_tx(struct sk_buff *skb, net_device *dev) { - int rc=0,rc2; - __u32 parm; - __u8 flags = 0x00; - __u32 saveflags; - struct ctc_priv *privptr; - struct packet *lp; - + int rc=0,rc2; + __u32 parm; + __u8 flags = 0x00; + unsigned long saveflags; + struct ctc_priv *privptr; + struct packet *lp; + - privptr = (struct ctc_priv *) (dev->priv); - - if (skb == NULL) { - printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name); - privptr->stats.tx_dropped++; - return -EIO; - } - - s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags); - if (ctc_check_busy(dev)) { - rc=-EBUSY; + privptr = (struct ctc_priv *) (dev->priv); + + if (skb == NULL) { + printk(KERN_WARNING "%s: NULL pointer as sk_buffer passed\n", dev->name); + privptr->stats.tx_dropped++; + return -EIO; + } + + s390irq_spin_lock_irqsave(privptr->channel[WRITE].irq, saveflags); + if (ctc_check_busy(dev)) { + rc=-EBUSY; goto Done; - } + } - if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */ - rc=-EBUSY; + if (ctc_test_and_setbit_busy(TB_TX,dev)) { /* set transmission to busy */ + rc=-EBUSY; goto Done; - } + } - if (65535 - privptr->channel[WRITE].free_anchor->block->length - PACKET_HEADER_LENGTH <= skb->len + PACKET_HEADER_LENGTH + 2) { + if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) { #ifdef DEBUG - printk(KERN_DEBUG "%s: early swap\n", dev->name); + printk(KERN_DEBUG "%s: early swap\n", dev->name); #endif - - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor); - if (privptr->channel[WRITE].free_anchor == NULL){ - ctc_setbit_busy(TB_NOBUFFER,dev); - rc=-EBUSY; + + ctc_buffer_swap(&privptr->channel[WRITE].free_anchor, &privptr->channel[WRITE].proc_anchor, dev); + if (privptr->channel[WRITE].free_anchor == NULL){ + ctc_setbit_busy(TB_NOBUFFER,dev); + rc=-EBUSY; goto Done2; - } - } - - if (privptr->channel[WRITE].free_anchor->block->length == 0) { - privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; - privptr->channel[WRITE].free_anchor->packets = 0; - } - - - (__u8 *)lp = (__u8 *) &privptr->channel[WRITE].free_anchor->block->length + privptr->channel[WRITE].free_anchor->block->length; - privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; - lp->length = skb->len + PACKET_HEADER_LENGTH; - lp->type = 0x0800; - lp->unused = 0; - memcpy(&lp->data, skb->data, skb->len); - (__u8 *) lp += lp->length; - lp->length = 0; - dev_kfree_skb(skb); - privptr->channel[WRITE].free_anchor->packets++; - - if (test_and_set_bit(0, (void *)&privptr->channel[WRITE].IO_active) == 0) { - ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor); - privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length; - privptr->channel[WRITE].ccw[1].cda = (char *)virt_to_phys(privptr->channel[WRITE].proc_anchor->block); - parm = (__u32) &privptr->channel[WRITE]; - rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags ); - if (rc2 != 0) - ccw_check_return_code(dev, rc2); - dev->trans_start = jiffies; - } - if (privptr->channel[WRITE].free_anchor == NULL) - ctc_setbit_busy(TB_NOBUFFER,dev); + } + } + + if (privptr->channel[WRITE].free_anchor->block->length == 0) { + privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; + privptr->channel[WRITE].free_anchor->packets = 0; + } + + + (__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length; + privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH; + lp->length = skb->len + PACKET_HEADER_LENGTH; + lp->type = 0x0800; + lp->unused = 0; + memcpy(&lp->data, skb->data, skb->len); + (__u8 *) lp += lp->length; + lp->length = 0; + dev_kfree_skb(skb); + privptr->channel[WRITE].free_anchor->packets++; + + if (test_and_set_bit(0, &privptr->channel[WRITE].IO_active) == 0) { + ctc_buffer_swap(&privptr->channel[WRITE].free_anchor,&privptr->channel[WRITE].proc_anchor, dev); + privptr->channel[WRITE].ccw[1].count = privptr->channel[WRITE].proc_anchor->block->length; + privptr->channel[WRITE].ccw[1].cda = __pa(privptr->channel[WRITE].proc_anchor->block); + parm = (__u32)(long) &privptr->channel[WRITE]; + rc2 = do_IO (privptr->channel[WRITE].irq, &privptr->channel[WRITE].ccw[0], parm, 0xff, flags ); + if (rc2 != 0) + ccw_check_return_code(dev, rc2, __FUNCTION__ "()[1]"); + dev->trans_start = jiffies; + } + if (privptr->channel[WRITE].free_anchor == NULL) + ctc_setbit_busy(TB_NOBUFFER,dev); Done2: - ctc_clearbit_busy(TB_TX,dev); + ctc_clearbit_busy(TB_TX,dev); Done: s390irq_spin_unlock_irqrestore(privptr->channel[WRITE].irq, saveflags); - return(rc); + return(rc); } @@ -1586,15 +1928,15 @@ Done: * ctc_change_mtu * * S/390 can handle MTU sizes from 576 to 32760 for VM, VSE - * 576 to 65527 for OS/390 + * 576 to 65527 for OS/390 * */ static int ctc_change_mtu(net_device *dev, int new_mtu) { - if ((new_mtu < 576) || (new_mtu > 65528)) - return -EINVAL; - dev->mtu = new_mtu; - return 0; + if ((new_mtu < 576) || (new_mtu > 65528)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; } @@ -1604,18 +1946,129 @@ static int ctc_change_mtu(net_device *dev, int new_mtu) */ struct net_device_stats *ctc_stats(net_device *dev) { - struct ctc_priv *privptr; + struct ctc_priv *privptr; - privptr = dev->priv; - return &privptr->stats; + privptr = dev->priv; + return &privptr->stats; } - /* Module code goes here */ -/* - free_irq(privptr->channel[i].irq, privptr->channel[i].devstat); - kfree(privptr->channel[i].devstat); +#ifdef MODULE +void cleanup_module(void) { + int m; + int i; + int c; + + /* we are called if all interfaces are down only, so no need + * to bother around with locking stuff + */ + for (m = 0; m < CHANNEL_MEDIA; m++) { + for (i = 0; i < MAX_ADAPTERS; i++) + if (ctc_adapter[m][i].netdev) { + struct ctc_priv *privptr = ctc_adapter[m][i].netdev->priv; + + unregister_netdev(ctc_adapter[m][i].netdev); + for (c = 0; c < 2; c++) { + free_irq(privptr->channel[c].irq, privptr->channel[c].devstat); + kfree(privptr->channel[c].devstat); + } + kfree(privptr); + kfree(ctc_adapter[m][i].netdev); + } + } + printk(KERN_INFO "CTC driver unloaded\n"); +} + +static char *parse_opts(char *str, int *ints) { + char *cur = str; + int i = 1; + + while (cur && (*cur == '-' || isdigit(*cur)) && i <= 10) { + ints[i++] = simple_strtoul(cur, NULL, 0); + if ((cur = strchr(cur, ',')) != NULL) + cur++; + } + ints[0] = i - 1; + return(cur); +} + +int init_module(void) { + char *p = setup; /* This string is set by insmod, it is writeable */ + int cnt; + int itype; + int activated; + int ints[10]; + + print_banner(); + + /** + * Parse setup string just like in init/main.c + */ + while (p && *p) { + char *q = strstr(p, "ctc="); + if (q) { + /** + * Found "ctc=" in string + */ + q += 4; + if ((p = parse_opts(q, ints))) { + /** + * p is now pointing to the first non-number parameter + * + */ + if ((q = strchr(p, ' '))) + *q = '\0'; + ctc_setup(p, ints); + if (q) + p = q + 1; + else + p = NULL; + } + } else + p = NULL; + } + + activated = 0; + for (itype = 0; itype < 2; itype++) { + cnt = 0; + do { + net_device *dev = kmalloc(sizeof(net_device) + 11 /* name + trailing zero */ , GFP_KERNEL); + if (!dev) { + return -ENOMEM; + } + memset((unsigned char *)dev, 0, sizeof(net_device)); + dev->name = (unsigned char *)dev + sizeof(net_device); + sprintf(dev->name, "%s%d", (itype) ? "escon" : "ctc", cnt++); + if (ctc_probe(dev) == 0) { + if (register_netdev(dev) != 0) { + struct ctc_priv *privptr = dev->priv; + int m = extract_channel_media(dev->name); + int i = extract_channel_id(dev->name); + + printk(KERN_WARNING "ctc: Couldn't register %s\n", dev->name); + free_irq(privptr->channel[READ].irq, privptr->channel[READ].devstat); + kfree(privptr->channel[READ].devstat); + free_irq(privptr->channel[WRITE].irq, privptr->channel[WRITE].devstat); + kfree(privptr->channel[WRITE].devstat); + channel_free(m, ctc_adapter[m][i].devno[READ]); + channel_free(m, ctc_adapter[m][i].devno[WRITE]); + kfree(dev->priv); + kfree(dev); + } else + activated++; + } else { + kfree(dev); + cnt = MAX_ADAPTERS; + } + } while (cnt < MAX_ADAPTERS); + } + if (!activated) { + printk(KERN_WARNING "ctc: No devices registered\n"); + return -ENODEV; + } + return 0; +} +#endif -*/ /* --- This is the END my friend --- */ diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c index fcac4037c8fe..e6c12b8e0acf 100644 --- a/drivers/s390/net/iucv.c +++ b/drivers/s390/net/iucv.c @@ -9,7 +9,7 @@ * * * 2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * Martin Schwidefsky (schwidefsky@de.ibm.com) + * Martin Schwidefsky (schwidefsky@de.ibm.com) * Alan Altmark (Alan_Altmark@us.ibm.com) * @@ -504,12 +504,15 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code) printk( "iucv: extern_int_buffer:\n"); dumpit((char *)&extern_int_buffer[0],40); #endif - + if (extern_int_buffer->iptype == 0x01) dev = get_device_from_userid(&((char*) extern_int_buffer)[8]); else dev = get_device_from_pathid(extern_int_buffer->ippathid); + if (dev == NULL) + return; + netif_enter_interrupt(dev); /* lock ! */ privptr = (struct iucv_priv *)(dev->priv); @@ -608,7 +611,7 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code) printk( "message pending.\n"); #endif rcvptr = &privptr->receive_buffer[0]; - + /* re-set receive buffer */ memset(privptr->receive_buffer,0,privptr->receive_buffer_len); len = privptr->receive_buffer_len; diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 4fc640297b00..cb7156446e43 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1,4 +1,4 @@ -/* $Id: envctrl.c,v 1.9.2.1 2000/05/02 04:23:33 davem Exp $ +/* $Id: envctrl.c,v 1.9.2.2 2000/11/08 09:43:04 davem Exp $ * envctrl.c: Temperature and Fan monitoring on Machines providing it. * * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) @@ -11,6 +11,9 @@ * http://www-eu2.semiconductors.com/pip/PCF8584P * http://www-eu2.semiconductors.com/pip/PCF8574AP * http://www-eu2.semiconductors.com/pip/PCF8591P + * + * EB - Added support for CP1500 Global Address and PS/Voltage monitoring. + * Eric Brower * */ @@ -74,15 +77,16 @@ * Firmware definitions. */ #define PCF8584_MAX_CHANNELS 8 +#define PCF8584_GLOBALADDR_TYPE 6 /* global address monitor */ #define PCF8584_FANSTAT_TYPE 3 /* fan status monitor */ #define PCF8584_VOLTAGE_TYPE 2 /* voltage monitor */ -#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/ +#define PCF8584_TEMP_TYPE 1 /* temperature monitor*/ /* Monitor type of i2c child device. * Driver definitions. */ -#define ENVCTRL_NOMON 0 -#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ +#define ENVCTRL_NOMON 0 +#define ENVCTRL_CPUTEMP_MON 1 /* cpu temperature monitor */ #define ENVCTRL_CPUVOLTAGE_MON 2 /* voltage monitor */ #define ENVCTRL_FANSTAT_MON 3 /* fan status monitor */ #define ENVCTRL_ETHERTEMP_MON 4 /* ethernet temperarture */ @@ -90,6 +94,7 @@ #define ENVCTRL_VOLTAGESTAT_MON 5 /* voltage status monitor */ #define ENVCTRL_MTHRBDTEMP_MON 6 /* motherboard temperature */ #define ENVCTRL_SCSITEMP_MON 7 /* scsi temperarture */ +#define ENVCTRL_GLOBALADDR_MON 8 /* global address */ /* Child device type. * Driver definitions. @@ -111,6 +116,15 @@ #define ENVCTRL_MAX_CPU 4 #define CHANNEL_DESC_SZ 256 +/* Mask values for combined GlobalAddress/PowerStatus node */ +#define ENVCTRL_GLOBALADDR_ADDR_MASK 0x1F +#define ENVCTRL_GLOBALADDR_PSTAT_MASK 0x60 + +/* Node 0x70 ignored on CompactPCI CP1400/1500 platforms + * (see envctrl_init_i2c_child) + */ +#define ENVCTRL_CPCI_IGNORED_NODE 0x70 + struct pcf8584_reg { unsigned char data; unsigned char csr; @@ -198,7 +212,7 @@ static void envtrl_i2c_test_pin(void) int limit = 1000000; while (--limit > 0) { - if(!(envctrl_readb(&i2c->csr) & STATUS_PIN)) + if (!(envctrl_readb(&i2c->csr) & STATUS_PIN)) break; udelay(1); } @@ -472,6 +486,31 @@ static int envctrl_i2c_fan_status(struct i2c_child_t *pchild, return 1; } +/* Function Description: Read global addressing line. + * Return : Always 1 byte. Status stored in bufdata. + */ +static int envctrl_i2c_globaladdr(struct i2c_child_t *pchild, + unsigned char data, + char *bufdata) +{ + /* Translatation table is not necessary, as global + * addr is the integer value of the GA# bits. + * + * NOTE: MSB is documented as zero, but I see it as '1' always.... + * + * ----------------------------------------------- + * | 0 | FAL | DEG | GA4 | GA3 | GA2 | GA1 | GA0 | + * ----------------------------------------------- + * GA0 - GA4 integer value of Global Address (backplane slot#) + * DEG 0 = cPCI Power supply output is starting to degrade + * 1 = cPCI Power supply output is OK + * FAL 0 = cPCI Power supply has failed + * 1 = cPCI Power supply output is OK + */ + bufdata[0] = (data & ENVCTRL_GLOBALADDR_ADDR_MASK); + return 1; +} + /* Function Description: Read voltage and power supply status. * Return : Always 1 byte. Status stored in bufdata. */ @@ -598,9 +637,19 @@ envctrl_read(struct file *file, char *buf, size_t count, loff_t *ppos) copy_to_user((unsigned char*)buf, data, ret); break; + case ENVCTRL_RD_GLOBALADDRESS: + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON))) + return 0; + data[0] = envctrl_i2c_read_8574(pchild->addr); + ret = envctrl_i2c_globaladdr(pchild, data[0], data); + copy_to_user((unsigned char*)buf, data, ret); + break; + case ENVCTRL_RD_VOLTAGE_STATUS: if (!(pchild = envctrl_get_i2c_child(ENVCTRL_VOLTAGESTAT_MON))) - return 0; + /* If voltage monitor not present, check for CPCI equivalent */ + if (!(pchild = envctrl_get_i2c_child(ENVCTRL_GLOBALADDR_MON))) + return 0; data[0] = envctrl_i2c_read_8574(pchild->addr); ret = envctrl_i2c_voltage_status(pchild, data[0], data); copy_to_user((unsigned char*)buf, data, ret); @@ -631,6 +680,7 @@ envctrl_ioctl(struct inode *inode, struct file *file, case ENVCTRL_RD_VOLTAGE_STATUS: case ENVCTRL_RD_ETHERNET_TEMPERATURE: case ENVCTRL_RD_SCSI_TEMPERATURE: + case ENVCTRL_RD_GLOBALADDRESS: file->private_data = (void *)(long)cmd; break; @@ -729,9 +779,6 @@ static void envctrl_set_mon(struct i2c_child_t *pchild, if (!(strcmp(chnl_desc,"temp,ethernet"))) pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; - - if (!(strcmp(chnl_desc,"temp,ethernet"))) - pchild->mon_type[chnl_no] = ENVCTRL_ETHERTEMP_MON; } /* Function Description: Initialize monitor channel with channel desc, @@ -785,6 +832,39 @@ static void envctrl_init_fanstat(struct i2c_child_t *pchild) pchild->mon_type[0] = ENVCTRL_FANSTAT_MON; } +/* Function Description: Initialize child device for global addressing line. + * Return: None. + */ +static void envctrl_init_globaladdr(struct i2c_child_t *pchild) +{ + int i; + + /* Voltage/PowerSupply monitoring is piggybacked + * with Global Address on CompactPCI. See comments + * within envctrl_i2c_globaladdr for bit assignments. + * + * The mask is created here by assigning mask bits to each + * bit position that represents PCF8584_VOLTAGE_TYPE data. + * Channel numbers are not consecutive within the globaladdr + * node (why?), so we use the actual counter value as chnls_mask + * index instead of the chnl_array[x].chnl_no value. + * + * NOTE: This loop could be replaced with a constant representing + * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK). + */ + for (i = 0; i < pchild->total_chnls; i++) { + if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) { + pchild->voltage_mask |= chnls_mask[i]; + } + } + + /* We only need to know if this child has global addressing + * line monitored. We dont care which channels since we know + * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK). + */ + pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON; +} + /* Initialize child device monitoring voltage status. */ static void envctrl_init_voltage_status(struct i2c_child_t *pchild) { @@ -832,6 +912,26 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, } } + /* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04) + * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is + * "For Factory Use Only." + * + * We ignore the node on these platforms by assigning the + * 'NULL' monitor type. + */ + if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) { + int len; + char prop[56]; + + len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop)); + if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len))) { + for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) { + pchild->mon_type[len] = ENVCTRL_NOMON; + } + return; + } + } + /* Get the monitor channels. */ len = prom_getproperty(node, "channels-in-use", (char *)pchild->chnl_array, PCF8584_MAX_CHANNELS*sizeof(struct pcf8584_channel)); @@ -843,6 +943,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child, envctrl_init_adc(pchild, node); break; + case PCF8584_GLOBALADDR_TYPE: + envctrl_init_globaladdr(pchild); + i = pchild->total_chnls; + break; + case PCF8584_FANSTAT_TYPE: envctrl_init_fanstat(pchild); i = pchild->total_chnls; @@ -942,6 +1047,18 @@ done: envctrl_dev.minor); } + /* Note above traversal routine post-incremented 'i' to accomodate + * a next child device, so we decrement before reverse-traversal of + * child devices. + */ + printk("envctrl: initialized "); + for (--i; i >= 0; --i) { + printk("[%s 0x%lx]%s", + (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : + ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), + i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); + } + return 0; #else return -ENODEV; diff --git a/drivers/sound/awacs_defs.h b/drivers/sound/awacs_defs.h index e30bb608c5da..1ccc277e0d7a 100644 --- a/drivers/sound/awacs_defs.h +++ b/drivers/sound/awacs_defs.h @@ -62,12 +62,18 @@ struct awacs_regs { #define MASK_ADDR_VOLC MASK_ADDR4 /* Volume Control C -- Speaker */ #define MASK_ADDR_VOLSPK MASK_ADDR4 +/* additional registers of screamer */ +#define MASK_ADDR5 (0x5 << 12) /* Expanded Data Mode Address 5 */ +#define MASK_ADDR6 (0x6 << 12) /* Expanded Data Mode Address 6 */ +#define MASK_ADDR7 (0x7 << 12) /* Expanded Data Mode Address 7 */ + + /* Address 0 Bit Masks & Macros */ /* ------- - --- ----- - ------ */ #define MASK_GAINRIGHT (0xf) /* Gain Right Mask */ #define MASK_GAINLEFT (0xf << 4) /* Gain Left Mask */ -#define MASK_GAINLINE (0x1 << 8) /* Change Gain for Line??? */ -#define MASK_GAINMIC (0x0 << 8) /* Change Gain for Mic??? */ +#define MASK_GAINLINE (0x1 << 8) /* Disable Mic preamp */ +#define MASK_GAINMIC (0x0 << 8) /* Enable Mic preamp */ #define MASK_MUX_CD (0x1 << 9) /* Select CD in MUX */ #define MASK_MUX_MIC (0x1 << 10) /* Select Mic in MUX */ diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 084de211e520..3369df47e7cb 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -179,6 +179,9 @@ static int awacs_spkr_vol; static struct device_node* awacs_node; static int awacs_revision; +int awacs_is_screamer = 0; +int awacs_device_id = 0; +int awacs_has_iic = 0; #define AWACS_BURGUNDY 100 /* fake revision # for burgundy */ /* @@ -191,7 +194,7 @@ static volatile struct dbdma_cmd *awacs_tx_cmds; * Cached values of AWACS registers (we can't read them). * Except on the burgundy. XXX */ -int awacs_reg[5]; +int awacs_reg[8]; #define HAS_16BIT_TABLES #undef HAS_8BIT_TABLES @@ -3400,6 +3403,11 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when) awacs_write(awacs_reg[1] | MASK_ADDR1); awacs_write(awacs_reg[2] | MASK_ADDR2); awacs_write(awacs_reg[4] | MASK_ADDR4); + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE); enable_irq(awacs_irq); enable_irq(awacs_tx_irq); @@ -4702,7 +4710,7 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, size = bufSize << 10; sq_setup(numBufs, size, sound_buffers); sq.max_active = nbufs; - return 0; + return IOCTL_OUT(arg,size | numBufs << 16); case SNDCTL_DSP_GETOSPACE: info.fragments = sq.max_active - sq.count; info.fragstotal = sq.max_active; @@ -4711,9 +4719,11 @@ static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd, if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; - - default: - return mixer_ioctl(inode, file, cmd, arg); + case SNDCTL_DSP_GETCAPS: + data = 1; /* Revision level of this ioctl() */ + return IOCTL_OUT(arg, data); + default: + return mixer_ioctl(inode, file, cmd, arg); } return -EINVAL; } @@ -5015,7 +5025,14 @@ void __init dmasound_init(void) awacs_subframe = *prop; if (device_is_compatible(sound, "burgundy")) awacs_revision = AWACS_BURGUNDY; - + /* This should be verified on older screamers */ + if (device_is_compatible(sound, "screamer")) + awacs_is_screamer = 1; + prop = (unsigned int *)get_property(sound, "device-id", 0); + if (prop != 0) + awacs_device_id = *prop; + awacs_has_iic = (find_devices("perch") != NULL); + /* look for a property saying what sample rates are available */ for (i = 0; i < 8; ++i) @@ -5077,17 +5094,29 @@ void __init dmasound_init(void) awacs_tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(awacs_tx_cmd_space); awacs_reg[0] = MASK_MUX_CD; - awacs_reg[1] = MASK_LOOPTHRU | MASK_PAROUT; + /* FIXME: Only machines with external SRS module need MASK_PAROUT */ + awacs_reg[1] = MASK_LOOPTHRU; + if (awacs_has_iic || awacs_device_id == 0x5 || /*awacs_device_id == 0x8 + || */awacs_device_id == 0xb) + awacs_reg[1] |= MASK_PAROUT; /* get default volume from nvram */ vol = (~nvram_read_byte(0x1308) & 7) << 1; awacs_reg[2] = vol + (vol << 6); awacs_reg[4] = vol + (vol << 6); + awacs_reg[5] = 0; + awacs_reg[6] = 0; + awacs_reg[7] = 0; out_le32(&awacs->control, 0x11); awacs_write(awacs_reg[0] + MASK_ADDR0); awacs_write(awacs_reg[1] + MASK_ADDR1); awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); - + if (awacs_is_screamer) { + awacs_write(awacs_reg[5] + MASK_ADDR5); + awacs_write(awacs_reg[6] + MASK_ADDR6); + awacs_write(awacs_reg[7] + MASK_ADDR7); + } + /* Initialize recent versions of the awacs */ if (awacs_revision == 0) { awacs_revision = diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 13bf863a041e..a6e46f600c00 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -49,6 +49,7 @@ comment 'USB Devices' fi dep_tristate ' USB Digi International AccelePort USB Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL + dep_tristate ' USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL fi bool ' USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL fi diff --git a/drivers/usb/keybdev.c b/drivers/usb/keybdev.c index 6bb1123875a0..45eaa9e8a8f7 100644 --- a/drivers/usb/keybdev.c +++ b/drivers/usb/keybdev.c @@ -37,7 +37,7 @@ #include #include -#if defined(__i386__) || defined(__alpha__) || defined(__mips__) +#if defined(__i386__) || defined(__alpha__) || defined(__mips__) || defined(__powerpc__) static int x86_sysrq_alt = 0; @@ -59,8 +59,45 @@ static unsigned short x86_keycodes[256] = { 332,340,341,342,343,344,345,346,356,359,365,368,369,370,371,372 }; +#ifdef CONFIG_INPUT_ADBHID +extern int mac_hid_keyboard_sends_linux_keycodes(void); + +static unsigned char mac_keycodes[256] = { + 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, + 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, + 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, + 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 55, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102 +}; + +#ifdef CONFIG_INPUT_MOUSEDEV +extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int); +#endif /* CONFIG_INPUT_MOUSEDEV */ +#endif /* CONFIG_INPUT_ADBHID */ + static int emulate_raw(unsigned int keycode, int down) { +#ifdef CONFIG_INPUT_ADBHID +#ifdef CONFIG_INPUT_MOUSEDEV + if (mac_hid_mouse_emulate_buttons(1, keycode, down)) + return 0; +#endif /* CONFIG_INPUT_MOUSEDEV */ + if (!mac_hid_keyboard_sends_linux_keycodes()) { + if (keycode > 255 || !mac_keycodes[keycode]) + return -1; + + handle_scancode(mac_keycodes[keycode] & 0x7f, down); + + return 0; + } +#endif /* CONFIG_INPUT_ADBHID */ if (keycode > 255 || !x86_keycodes[keycode]) return -1; @@ -92,28 +129,6 @@ static int emulate_raw(unsigned int keycode, int down) return 0; } -#elif defined(CONFIG_MAC_KEYBOARD) - -static unsigned char mac_keycodes[128] = - { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, - 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54,128, 1, - 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, - 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, - 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, - 84, 85, 82, 65, 42, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, - 76,125, 75,105,124, 0,115, 62,116, 59, 60,119, 61,121,114,117, - 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 0, 55, 55 }; - -static int emulate_raw(unsigned int keycode, int down) -{ - if (keycode > 127 || !mac_keycodes[keycode]) - return -1; - - handle_scancode(mac_keycodes[keycode] & 0x7f, down); - - return 0; -} - #endif static struct input_handler keybdev_handler; diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 6632b6c9a307..c262023a7b7f 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KEYSPAN) += keyspan.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o +obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o # Objects that export symbols. export-objs := usbserial.o diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c new file mode 100644 index 000000000000..c56dbf624c5b --- /dev/null +++ b/drivers/usb/serial/belkin_sa.c @@ -0,0 +1,561 @@ +/* + * Belkin USB Serial Adapter Driver + * + * Copyright (C) 2000 + * William Greathouse (wgreathouse@smva.com) + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * TODO: + * -- Add true modem contol line query capability. Currently we track the + * states reported by the interrupt and the states we request. + * -- Add error reporting back to application for UART error conditions. + * Just point me at how to implement this and I'll do it. I've put the + * framework in, but haven't analyzed the "tty_flip" interface yet. + * -- Add support for flush commands + * -- Add everything that is missing :) + * + * (11/06/2000) gkh + * - Added support for the old Belkin and Peracom devices. + * - Made the port able to be opened multiple times. + * - Added some defaults incase the line settings are things these devices + * can't support. + * + * 18-Oct-2000 William Greathouse + * Released into the wild (linux-usb-devel) + * + * 17-Oct-2000 William Greathouse + * Add code to recognize firmware version and set hardware flow control + * appropriately. Belkin states that firmware prior to 3.05 does not + * operate correctly in hardware handshake mode. I have verified this + * on firmware 2.05 -- for both RTS and DTR input flow control, the control + * line is not reset. The test performed by the Belkin Win* driver is + * to enable hardware flow control for firmware 2.06 or greater and + * for 1.00 or prior. I am only enabling for 2.06 or greater. + * + * 12-Oct-2000 William Greathouse + * First cut at supporting Belkin USB Serial Adapter F5U103 + * I did not have a copy of the original work to support this + * adapter, so pardon any stupid mistakes. All of the information + * I am using to write this driver was acquired by using a modified + * UsbSnoop on Windows2000 and from examining the other USB drivers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_USB_SERIAL_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif +#include + +#include "usb-serial.h" +#include "belkin_sa.h" + +/* function prototypes for a Belkin USB Serial Adapter F5U103 */ +static int belkin_sa_startup (struct usb_serial *serial); +static void belkin_sa_shutdown (struct usb_serial *serial); +static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); +static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); +static void belkin_sa_read_int_callback (struct urb *urb); +static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); +static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); +static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); + +/* All of the device info needed for the Belkin serial converter */ +static __u16 belkin_sa_vendor_id = BELKIN_SA_VID; +static __u16 belkin_sa_product_id = BELKIN_SA_PID; +struct usb_serial_device_type belkin_sa_device = { + name: "Belkin F5U103 USB Serial Adapter", + idVendor: &belkin_sa_vendor_id, /* the Belkin vendor ID */ + idProduct: &belkin_sa_product_id, /* the Belkin F5U103 product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + + +/* This driver also supports the "old" school Belkin single port adaptor */ +static __u16 belkin_old_vendor_id = BELKIN_OLD_VID; +static __u16 belkin_old_product_id = BELKIN_OLD_PID; +struct usb_serial_device_type belkin_old_device = { + name: "Belkin USB Serial Adapter", + idVendor: &belkin_old_vendor_id, /* the Belkin vendor ID */ + idProduct: &belkin_old_product_id, /* the Belkin product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + +/* this driver also works for the Peracom single port adapter */ +static __u16 peracom_vendor_id = PERACOM_VID; +static __u16 peracom_product_id = PERACOM_PID; +struct usb_serial_device_type peracom_device = { + name: "Peracom single port USB Serial Adapter", + idVendor: &peracom_vendor_id, /* the Peracom vendor ID */ + idProduct: &peracom_product_id, /* the Peracom product id */ + needs_interrupt_in: MUST_HAVE, /* this device must have an interrupt in endpoint */ + needs_bulk_in: MUST_HAVE, /* this device must have a bulk in endpoint */ + needs_bulk_out: MUST_HAVE, /* this device must have a bulk out endpoint */ + num_interrupt_in: 1, + num_bulk_in: 1, + num_bulk_out: 1, + num_ports: 1, + open: belkin_sa_open, + close: belkin_sa_close, + read_int_callback: belkin_sa_read_int_callback, /* How we get the status info */ + ioctl: belkin_sa_ioctl, + set_termios: belkin_sa_set_termios, + break_ctl: belkin_sa_break_ctl, + startup: belkin_sa_startup, + shutdown: belkin_sa_shutdown, +}; + + +struct belkin_sa_private { + unsigned long control_state; + unsigned char last_lsr; + unsigned char last_msr; + int bad_flow_control; +}; + + +/* + * *************************************************************************** + * Belkin USB Serial Adapter F5U103 specific driver functions + * *************************************************************************** + */ + +#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */ + +/* assumes that struct usb_serial *serial is available */ +#define BSA_USB_CMD(c,v) usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), \ + (c), BELKIN_SA_SET_REQUEST_TYPE, \ + (v), 0, NULL, 0, WDR_TIMEOUT) + +/* do some startup allocations not currently performed by usb_serial_probe() */ +static int belkin_sa_startup (struct usb_serial *serial) +{ + struct usb_device *dev = serial->dev; + struct belkin_sa_private *priv; + + /* allocate the private data structure */ + serial->port->private = kmalloc(sizeof(struct belkin_sa_private), GFP_KERNEL); + if (!serial->port->private) + return (-1); /* error */ + priv = (struct belkin_sa_private *)serial->port->private; + /* set initial values for control structures */ + priv->control_state = 0; + priv->last_lsr = 0; + priv->last_msr = 0; + /* see comments at top of file */ + priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0; + info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control); + + init_waitqueue_head(&serial->port->write_wait); + + return (0); +} + + +static void belkin_sa_shutdown (struct usb_serial *serial) +{ + int i; + + dbg (__FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + while (serial->port[i].open_count > 0) { + belkin_sa_close (&serial->port[i], NULL); + } + /* My special items, the standard routines free my urbs */ + if (serial->port->private) + kfree(serial->port->private); + } +} + + +static int belkin_sa_open (struct usb_serial_port *port, struct file *filp) +{ + unsigned long flags; + + dbg(__FUNCTION__" port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + ++port->open_count; + MOD_INC_USE_COUNT; + + if (!port->active) { + port->active = 1; + + /*Start reading from the device*/ + /* TODO: Look at possibility of submitting mulitple URBs to device to + * enhance buffering. Win trace shows 16 initial read URBs. + */ + port->read_urb->dev = port->serial->dev; + if (usb_submit_urb(port->read_urb)) + err("usb_submit_urb(read bulk) failed"); + + port->interrupt_in_urb->dev = port->serial->dev; + if (usb_submit_urb(port->interrupt_in_urb)) + err(" usb_submit_urb(read int) failed"); + } + + spin_unlock_irqrestore (&port->port_lock, flags); + + return 0; +} /* belkin_sa_open */ + + +static void belkin_sa_close (struct usb_serial_port *port, struct file *filp) +{ + unsigned long flags; + + dbg(__FUNCTION__" port %d", port->number); + + spin_lock_irqsave (&port->port_lock, flags); + + --port->open_count; + MOD_DEC_USE_COUNT; + + if (port->open_count <= 0) { + /* shutdown our bulk reads and writes */ + usb_unlink_urb (port->write_urb); + usb_unlink_urb (port->read_urb); + usb_unlink_urb (port->interrupt_in_urb); /* wgg - do I need this? I think so. */ + port->active = 0; + } + + spin_unlock_irqrestore (&port->port_lock, flags); +} /* belkin_sa_close */ + + +static void belkin_sa_read_int_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + struct usb_serial *serial; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + /* the urb might have been killed. */ + if (urb->status) + return; + + if (port_paranoia_check (port, "belkin_sa_read_interrupt")) return; + + serial = port->serial; + if (serial_paranoia_check (serial, "belkin_sa_read_interrupt")) return; + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + /* Handle known interrupt data */ + /* ignore data[0] and data[1] */ + + priv->last_msr = data[BELKIN_SA_MSR_INDEX]; + + /* Record Control Line states */ + if (priv->last_msr & BELKIN_SA_MSR_DSR) + priv->control_state |= TIOCM_DSR; + else + priv->control_state &= ~TIOCM_DSR; + + if (priv->last_msr & BELKIN_SA_MSR_CTS) + priv->control_state |= TIOCM_CTS; + else + priv->control_state &= ~TIOCM_CTS; + + if (priv->last_msr & BELKIN_SA_MSR_RI) + priv->control_state |= TIOCM_RI; + else + priv->control_state &= ~TIOCM_RI; + + if (priv->last_msr & BELKIN_SA_MSR_CD) + priv->control_state |= TIOCM_CD; + else + priv->control_state &= ~TIOCM_CD; + + /* Now to report any errors */ + priv->last_lsr = data[BELKIN_SA_LSR_INDEX]; +#if 0 + /* + * fill in the flip buffer here, but I do not know the relation + * to the current/next receive buffer or characters. I need + * to look in to this before committing any code. + */ + if (priv->last_lsr & BELKIN_SA_LSR_ERR) { + tty = port->tty; + /* Overrun Error */ + if (priv->last_lsr & BELKIN_SA_LSR_OE) { + } + /* Parity Error */ + if (priv->last_lsr & BELKIN_SA_LSR_PE) { + } + /* Framing Error */ + if (priv->last_lsr & BELKIN_SA_LSR_FE) { + } + /* Break Indicator */ + if (priv->last_lsr & BELKIN_SA_LSR_BI) { + } + } +#endif + + /* INT urbs are automatically re-submitted */ +} + +static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios) +{ + struct usb_serial *serial = port->serial; + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + unsigned int iflag = port->tty->termios->c_iflag; + unsigned int cflag = port->tty->termios->c_cflag; + unsigned int old_iflag = old_termios->c_iflag; + unsigned int old_cflag = old_termios->c_cflag; + __u16 urb_value; /* Will hold the new flags */ + + /* Set the baud rate */ + if( (cflag&CBAUD) != (old_cflag&CBAUD) ) { + /* reassert DTR and (maybe) RTS on transition from B0 */ + if( (old_cflag&CBAUD) == B0 ) { + priv->control_state |= (TIOCM_DTR|TIOCM_RTS); + if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 1) < 0) + err("Set DTR error"); + /* don't set RTS if using hardware flow control */ + if (!(old_cflag&CRTSCTS) ) + if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0) + err("Set RTS error"); + } + + switch(cflag & CBAUD) { + case B0: /* handled below */ break; + case B300: urb_value = BELKIN_SA_BAUD(300); break; + case B600: urb_value = BELKIN_SA_BAUD(600); break; + case B1200: urb_value = BELKIN_SA_BAUD(1200); break; + case B2400: urb_value = BELKIN_SA_BAUD(2400); break; + case B4800: urb_value = BELKIN_SA_BAUD(4800); break; + case B9600: urb_value = BELKIN_SA_BAUD(9600); break; + case B19200: urb_value = BELKIN_SA_BAUD(19200); break; + case B38400: urb_value = BELKIN_SA_BAUD(38400); break; + case B57600: urb_value = BELKIN_SA_BAUD(57600); break; + case B115200: urb_value = BELKIN_SA_BAUD(115200); break; + case B230400: urb_value = BELKIN_SA_BAUD(230400); break; + default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600"); + urb_value = BELKIN_SA_BAUD(9600); break; + } + if ((cflag & CBAUD) != B0 ) { + if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0) + err("Set baudrate error"); + } else { + /* Disable flow control */ + if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0) + err("Disable flowcontrol error"); + + /* Drop RTS and DTR */ + priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); + if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0) + err("DTR LOW error"); + if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0) + err("RTS LOW error"); + } + } + + /* set the parity */ + if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) { + if (cflag & PARENB) + urb_value = (cflag & PARODD) ? BELKIN_SA_PARITY_ODD : BELKIN_SA_PARITY_EVEN; + else + urb_value = BELKIN_SA_PARITY_NONE; + if (BSA_USB_CMD(BELKIN_SA_SET_PARITY_REQUEST, urb_value) < 0) + err("Set parity error"); + } + + /* set the number of data bits */ + if( (cflag&CSIZE) != (old_cflag&CSIZE) ) { + switch (cflag & CSIZE) { + case CS5: urb_value = BELKIN_SA_DATA_BITS(5); break; + case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break; + case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break; + case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break; + default: err("CSIZE was not CS5-CS8, using default of 8"); + urb_value = BELKIN_SA_DATA_BITS(8); + break; + } + if (BSA_USB_CMD(BELKIN_SA_SET_DATA_BITS_REQUEST, urb_value) < 0) + err("Set data bits error"); + } + + /* set the number of stop bits */ + if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) { + urb_value = (cflag & CSTOPB) ? BELKIN_SA_STOP_BITS(2) : BELKIN_SA_STOP_BITS(1); + if (BSA_USB_CMD(BELKIN_SA_SET_STOP_BITS_REQUEST, urb_value) < 0) + err("Set stop bits error"); + } + + /* Set flow control */ + if( (iflag&IXOFF) != (old_iflag&IXOFF) + || (iflag&IXON) != (old_iflag&IXON) + || (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) { + urb_value = 0; + if ((iflag & IXOFF) || (iflag & IXON)) + urb_value |= (BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); + else + urb_value &= ~(BELKIN_SA_FLOW_OXON | BELKIN_SA_FLOW_IXON); + + if (cflag & CRTSCTS) + urb_value |= (BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); + else + urb_value &= ~(BELKIN_SA_FLOW_OCTS | BELKIN_SA_FLOW_IRTS); + + if (priv->bad_flow_control) + urb_value &= ~(BELKIN_SA_FLOW_IRTS); + + if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, urb_value) < 0) + err("Set flow control error"); + } +} /* belkin_sa_set_termios */ + + +static void belkin_sa_break_ctl( struct usb_serial_port *port, int break_state ) +{ + struct usb_serial *serial = port->serial; + + if (BSA_USB_CMD(BELKIN_SA_SET_BREAK_REQUEST, break_state ? 1 : 0) < 0) + err("Set break_ctl %d", break_state); +} + + +static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg) +{ + struct usb_serial *serial = port->serial; + __u16 urb_value; /* Will hold the new flags */ + struct belkin_sa_private *priv = (struct belkin_sa_private *)port->private; + int ret, mask; + + /* Based on code from acm.c and others */ + switch (cmd) { + case TIOCMGET: + return put_user(priv->control_state, (unsigned long *) arg); + break; + + case TIOCMSET: /* Turns on and off the lines as specified by the mask */ + case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */ + case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */ + if ((ret = get_user(mask, (unsigned long *) arg))) return ret; + + if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) { + /* RTS needs set */ + urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) || (cmd == TIOCMBIS) ? 1 : 0; + if (urb_value) + priv->control_state |= TIOCM_RTS; + else + priv->control_state &= ~TIOCM_RTS; + + if ((ret = BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, urb_value)) < 0) { + err("Set RTS error %d", ret); + return(ret); + } + } + + if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) { + /* DTR needs set */ + urb_value = ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) || (cmd == TIOCMBIS) ? 1 : 0; + if (urb_value) + priv->control_state |= TIOCM_DTR; + else + priv->control_state &= ~TIOCM_DTR; + if ((ret = BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, urb_value)) < 0) { + err("Set DTR error %d", ret); + return(ret); + } + } + break; + + case TIOCMIWAIT: + /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/ + /* TODO */ + return( 0 ); + + case TIOCGICOUNT: + /* return count of modemline transitions */ + /* TODO */ + return 0; + + default: + dbg("belkin_sa_ioctl arg not supported - 0x%04x",cmd); + return(-ENOIOCTLCMD); + break; + } + return 0; +} /* belkin_sa_ioctl */ + + +static int __init belkin_sa_init (void) +{ + usb_serial_register (&belkin_sa_device); + usb_serial_register (&belkin_old_device); + usb_serial_register (&peracom_device); + return 0; +} + + +static void __exit belkin_sa_exit (void) +{ + usb_serial_deregister (&belkin_sa_device); + usb_serial_deregister (&belkin_old_device); + usb_serial_deregister (&peracom_device); +} + + +module_init (belkin_sa_init); +module_exit(belkin_sa_exit); + +MODULE_DESCRIPTION("USB Belkin Serial converter driver"); diff --git a/drivers/usb/serial/belkin_sa.h b/drivers/usb/serial/belkin_sa.h new file mode 100644 index 000000000000..ee36038634da --- /dev/null +++ b/drivers/usb/serial/belkin_sa.h @@ -0,0 +1,113 @@ +/* + * Definitions for Belkin USB Serial Adapter Driver + * + * Copyright (C) 2000 + * William Greathouse (wgreathouse@smva.com) + * + * This program is largely derived from work by the linux-usb group + * and associated source files. Please see the usb/serial files for + * individual credits and copyrights. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * See Documentation/usb/usb-serial.txt for more information on using this driver + * + * (11/06/2000) gkh + * Added old Belkin and Peracom device ids, which this driver supports + * + * 12-Oct-2000 William Greathouse + * First cut at supporting Belkin USB Serial Adapter F5U103 + * I did not have a copy of the original work to support this + * adapter, so pardon any stupid mistakes. All of the information + * I am using to write this driver was acquired by using a modified + * UsbSnoop on Windows2000. + * + */ + +#ifndef __LINUX_USB_SERIAL_BSA_H +#define __LINUX_USB_SERIAL_BSA_H + +#define BELKIN_SA_VID 0x050d /* Vendor Id */ +#define BELKIN_SA_PID 0x0103 /* Product Id */ + +#define BELKIN_OLD_VID 0x056c /* Belkin's "old" vendor id */ +#define BELKIN_OLD_PID 0x8007 /* Belkin's "old" single port serial converter's id */ + +#define PERACOM_VID 0x0565 /* Peracom's vendor id */ +#define PERACOM_PID 0x0001 /* Peracom's single port serial converter's id */ + +/* Vendor Request Interface */ +#define BELKIN_SA_SET_BAUDRATE_REQUEST 0 /* Set baud rate */ +#define BELKIN_SA_SET_STOP_BITS_REQUEST 1 /* Set stop bits (1,2) */ +#define BELKIN_SA_SET_DATA_BITS_REQUEST 2 /* Set data bits (5,6,7,8) */ +#define BELKIN_SA_SET_PARITY_REQUEST 3 /* Set parity (None, Even, Odd) */ + +#define BELKIN_SA_SET_DTR_REQUEST 10 /* Set DTR state */ +#define BELKIN_SA_SET_RTS_REQUEST 11 /* Set RTS state */ +#define BELKIN_SA_SET_BREAK_REQUEST 12 /* Set BREAK state */ + +#define BELKIN_SA_SET_FLOW_CTRL_REQUEST 16 /* Set flow control mode */ + + +#ifdef WHEN_I_LEARN_THIS +#define BELKIN_SA_SET_MAGIC_REQUEST 17 /* I don't know, possibly flush */ + /* (always in Wininit sequence before flow control) */ +#define BELKIN_SA_RESET xx /* Reset the port */ +#define BELKIN_SA_GET_MODEM_STATUS xx /* Force return of modem status register */ +#endif + +#define BELKIN_SA_SET_REQUEST_TYPE 0x40 + +#define BELKIN_SA_BAUD(b) (230400/b) + +#define BELKIN_SA_STOP_BITS(b) (b-1) + +#define BELKIN_SA_DATA_BITS(b) (b-5) + +#define BELKIN_SA_PARITY_NONE 0 +#define BELKIN_SA_PARITY_EVEN 1 +#define BELKIN_SA_PARITY_ODD 2 +#define BELKIN_SA_PARITY_MARK 3 +#define BELKIN_SA_PARITY_SPACE 4 + +#define BELKIN_SA_FLOW_NONE 0x0000 /* No flow control */ +#define BELKIN_SA_FLOW_OCTS 0x0001 /* use CTS input to throttle output */ +#define BELKIN_SA_FLOW_ODSR 0x0002 /* use DSR input to throttle output */ +#define BELKIN_SA_FLOW_IDSR 0x0004 /* use DSR input to enable receive */ +#define BELKIN_SA_FLOW_IDTR 0x0008 /* use DTR output for input flow control */ +#define BELKIN_SA_FLOW_IRTS 0x0010 /* use RTS output for input flow control */ +#define BELKIN_SA_FLOW_ORTS 0x0020 /* use RTS to indicate data available to send */ +#define BELKIN_SA_FLOW_ERRSUB 0x0040 /* ???? guess ???? substitute inline errors */ +#define BELKIN_SA_FLOW_OXON 0x0080 /* use XON/XOFF for output flow control */ +#define BELKIN_SA_FLOW_IXON 0x0100 /* use XON/XOFF for input flow control */ + +/* + * It seems that the interrupt pipe is closely modelled after the + * 16550 register layout. This is probably because the adapter can + * be used in a "DOS" environment to simulate a standard hardware port. + */ +#define BELKIN_SA_LSR_INDEX 2 /* Line Status Register */ +#define BELKIN_SA_LSR_RDR 0x01 /* receive data ready */ +#define BELKIN_SA_LSR_OE 0x02 /* overrun error */ +#define BELKIN_SA_LSR_PE 0x04 /* parity error */ +#define BELKIN_SA_LSR_FE 0x08 /* framing error */ +#define BELKIN_SA_LSR_BI 0x10 /* break indicator */ +#define BELKIN_SA_LSR_THE 0x20 /* transmit holding register empty */ +#define BELKIN_SA_LSR_TE 0x40 /* transmit register empty */ +#define BELKIN_SA_LSR_ERR 0x80 /* OE | PE | FE | BI */ + +#define BELKIN_SA_MSR_INDEX 3 /* Modem Status Register */ +#define BELKIN_SA_MSR_DCTS 0x01 /* Delta CTS */ +#define BELKIN_SA_MSR_DDSR 0x02 /* Delta DSR */ +#define BELKIN_SA_MSR_DRI 0x04 /* Delta RI */ +#define BELKIN_SA_MSR_DCD 0x08 /* Delta CD */ +#define BELKIN_SA_MSR_CTS 0x10 /* Current CTS */ +#define BELKIN_SA_MSR_DSR 0x20 /* Current DSR */ +#define BELKIN_SA_MSR_RI 0x40 /* Current RI */ +#define BELKIN_SA_MSR_CD 0x80 /* Current CD */ + +#endif /* __LINUX_USB_SERIAL_BSA_H */ + diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 2a340c4bd31f..94e4eb92e6d2 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -56,10 +56,13 @@ #include static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data); +static void dl_del_list (ohci_t * ohci, unsigned int frame); #ifdef CONFIG_PMAC_PBOOK +#include #include #include +#include #endif @@ -540,6 +543,14 @@ static int sohci_unlink_urb (urb_t * urb) urb_priv_t * urb_priv = urb->hcpriv; urb_priv->state = URB_DEL; + /* we need to do this *before* we can possibly + * get the interrupt which will wake us up. */ + if (!(urb->transfer_flags & USB_ASYNC_UNLINK) + && !in_interrupt() && !ohci->disabled) { + add_wait_queue (&op_wakeup, &wait); + current->state = TASK_UNINTERRUPTIBLE; + } + /* we want to delete the TDs of an URB from an ed * request the deletion, it will be handled at the * next USB-frame */ @@ -549,13 +560,34 @@ static int sohci_unlink_urb (urb_t * urb) urb_priv->ed->state |= ED_URB_DEL; spin_unlock_irqrestore (&usb_ed_lock, flags); if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { - usb_dec_dev_use (urb->dev); - add_wait_queue (&op_wakeup, &wait); - current->state = TASK_UNINTERRUPTIBLE; - if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ - err("unlink URB timeout!"); - remove_wait_queue (&op_wakeup, &wait); - urb->status = -ENOENT; + if (ohci->disabled) { + /* Need to handle that case */ + } else if (in_interrupt()) { + volatile u16* frame_p = (volatile u16*)&ohci->hcca.frame_no; + u16 frame_prev, frame, count; + count = 0; + writel (OHCI_INTR_SF, &ohci->regs->intrdisable); + frame_prev = le16_to_cpu(*frame_p) & 1; + do { + mb(); + frame = le16_to_cpu(*frame_p) & 1; + if (frame != frame_prev) { + if (ohci->ed_rm_list[!frame] != NULL) + dl_del_list (ohci, !frame); + frame_prev = frame; + count++; + } + } while(count < 2); + writel (OHCI_INTR_SF, &ohci->regs->intrenable); + urb->status = -ENOENT; + usb_dec_dev_use (urb->dev); + } else { + if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ + err("unlink URB timeout!"); + remove_wait_queue (&op_wakeup, &wait); + urb->status = -ENOENT; + usb_dec_dev_use (urb->dev); + } } else { /* usb_dec_dev_use done in dl_del_list() */ urb->status = -EINPROGRESS; @@ -718,10 +750,11 @@ static int ep_link (ohci_t * ohci, ed_t * edi) volatile ed_t * ed = edi; ed->state = ED_OPER; + ed->hwNextED = 0; + wmb(); switch (ed->type) { case CTRL: - ed->hwNextED = 0; if (ohci->ed_controltail == NULL) { writel (virt_to_bus (ed), &ohci->regs->ed_controlhead); } else { @@ -732,7 +765,6 @@ static int ep_link (ohci_t * ohci, ed_t * edi) break; case BULK: - ed->hwNextED = 0; if (ohci->ed_bulktail == NULL) { writel (virt_to_bus (ed), &ohci->regs->ed_bulkhead); } else { @@ -748,7 +780,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi) ed->int_interval = interval; int_branch = ep_int_ballance (ohci, interval, load); ed->int_branch = int_branch; - + for (i = 0; i < ep_rev (6, interval); i += inter) { inter = 1; for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i) + int_branch]); @@ -756,6 +788,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi) ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); ed->hwNextED = *ed_p; + wmb(); *ed_p = cpu_to_le32 (virt_to_bus (ed)); } #ifdef DEBUG @@ -764,7 +797,6 @@ static int ep_link (ohci_t * ohci, ed_t * edi) break; case ISO: - ed->hwNextED = 0; ed->int_interval = 1; if (ohci->ed_isotail != NULL) { ohci->ed_isotail->hwNextED = cpu_to_le32 (virt_to_bus (ed)); @@ -774,7 +806,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi) inter = 1; for (ed_p = &(ohci->hcca.int_table[ep_rev (5, i)]); *ed_p != 0; - ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) + ed_p = &(((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->hwNextED)) inter = ep_rev (6, ((ed_t *) bus_to_virt (le32_to_cpup (ed_p)))->int_interval); *ed_p = cpu_to_le32 (virt_to_bus (ed)); } @@ -1005,6 +1037,7 @@ static void td_fill (unsigned int info, void * data, int len, urb_t * urb, int i td->hwNextTD = cpu_to_le32 (virt_to_bus (td_pt)); td->hwPSW [0] = cpu_to_le16 ((virt_to_bus (data) & 0x0FFF) | 0xE000); td_pt->hwNextTD = 0; + wmb(); td->ed->hwTailP = td->hwNextTD; td->next_dl_td = NULL; //td_pt; @@ -1047,6 +1080,7 @@ static void td_submit_urb (urb_t * urb) TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; td_fill (info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt); cnt++; + wmb(); writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ break; @@ -1067,6 +1101,7 @@ static void td_submit_urb (urb_t * urb) info = usb_pipeout (urb->pipe)? TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; td_fill (info, NULL, 0, urb, cnt++); + wmb(); writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ break; @@ -1808,7 +1843,8 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r) } if (ints & OHCI_INTR_WDH) { - writel (OHCI_INTR_WDH, ®s->intrdisable); + writel (OHCI_INTR_WDH, ®s->intrdisable); + (void)readl(®s->intrdisable); // PCI write posting will hurt you dl_done_list (ohci, dl_reverse_done_list (ohci)); writel (OHCI_INTR_WDH, ®s->intrenable); } @@ -1821,6 +1857,7 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r) if (ints & OHCI_INTR_SF) { unsigned int frame = le16_to_cpu (ohci->hcca.frame_no) & 1; writel (OHCI_INTR_SF, ®s->intrdisable); + (void)readl(®s->intrdisable); // PCI write posting will hurt you if (ohci->ed_rm_list[!frame] != NULL) { dl_del_list (ohci, !frame); } @@ -1932,6 +1969,7 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base) if (!ohci) { return -ENOMEM; } + ohci->pci_dev = dev; INIT_LIST_HEAD (&ohci->ohci_hcd_list); list_add (&ohci->ohci_hcd_list, &ohci_hcd_list); @@ -2004,19 +2042,43 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when) { struct list_head * ohci_l; ohci_t * ohci; - - for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) { - ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list); - + + for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; + ohci_l = ohci_l->next) { + struct device_node* node; + ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list); + node = find_pci_device_OFnode(ohci->pci_dev->bus->number, + ohci->pci_dev->devfn); switch (when) { case PBOOK_SLEEP_NOW: + /* We should make sure processing of current frames have + * finished and WDH has been porcessed + */ + dbg("USB suspend: %p", ohci->regs); disable_irq (ohci->irq); - writel (ohci->hc_control = OHCI_USB_SUSPEND, &ohci->regs->control); - wait_ms (10); + + ohci->hc_control &= ~(OHCI_CTRL_CLE | OHCI_CTRL_BLE | OHCI_CTRL_PLE | OHCI_CTRL_IE); + writel (ohci->hc_control, &ohci->regs->control); + writel (OHCI_INTR_SF, &ohci->regs->intrstatus); + (void)readl(&ohci->regs->intrstatus); + mdelay(2); + + ohci->hc_control = OHCI_USB_SUSPEND; + writel (ohci->hc_control, &ohci->regs->control); + mdelay (10); + ohci->disabled = 1; + if (node) + feature_set_usb_power(node, 0); break; case PBOOK_WAKE: - writel (ohci->hc_control = OHCI_USB_RESUME, &ohci->regs->control); - wait_ms (20); + /* did we suspend, or were we powered off? */ + if (node) + feature_set_usb_power(node, 1); + mdelay(100); + ohci->disabled = 0; + ohci->hc_control = OHCI_USB_RESUME; + writel (ohci->hc_control, &ohci->regs->control); + mdelay (35); ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; writel (ohci->hc_control, &ohci->regs->control); enable_irq (ohci->irq); @@ -2027,7 +2089,7 @@ static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when) } static struct pmu_sleep_notifier ohci_sleep_notifier = { - ohci_sleep_notify, SLEEP_LEVEL_MISC, + ohci_sleep_notify, SLEEP_LEVEL_USB, }; #endif /* CONFIG_PMAC_PBOOK */ @@ -2096,11 +2158,11 @@ static int __init ohci_hcd_init (void) { int ret = -ENODEV; struct pci_dev * dev = NULL; - + while ((dev = pci_find_class (PCI_CLASS_SERIAL_USB_OHCI, dev))) { if (hc_start_ohci(dev) >= 0) ret = 0; } - + #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier (&ohci_sleep_notifier); #endif diff --git a/drivers/usb/usb-ohci.h b/drivers/usb/usb-ohci.h index 3ac5dafb24cb..806be5255589 100644 --- a/drivers/usb/usb-ohci.h +++ b/drivers/usb/usb-ohci.h @@ -410,6 +410,7 @@ typedef struct ohci { struct usb_bus * bus; struct usb_device * dev[128]; struct virt_root_hub rh; + struct pci_dev *pci_dev; } ohci_t; diff --git a/drivers/video/aty128.h b/drivers/video/aty128.h index a01b99e031eb..c475b19522d3 100644 --- a/drivers/video/aty128.h +++ b/drivers/video/aty128.h @@ -43,10 +43,12 @@ #define OVR_CLR 0x0230 #define OVR_WID_LEFT_RIGHT 0x0234 #define OVR_WID_TOP_BOTTOM 0x0238 +#define LVDS_GEN_CNTL 0x02d0 #define DDA_CONFIG 0x02e0 #define DDA_ON_OFF 0x02e4 #define VGA_DDA_CONFIG 0x02e8 #define VGA_DDA_ON_OFF 0x02ec +#define CRTC2_GEN_CNTL 0x03f8 #define OV0_SCALE_CNTL 0x0420 #define SUBPIC_CNTL 0x0540 #define PM4_BUFFER_OFFSET 0x0700 @@ -218,6 +220,7 @@ #define PLL_WR_EN 0x00000080 +/* PLL registers */ #define CLK_PIN_CNTL 0x0001 #define PPLL_CNTL 0x0002 #define PPLL_REF_DIV 0x0003 @@ -236,6 +239,7 @@ #define AGP_PLL_CNTL 0x0010 #define FCP_CNTL 0x0012 #define PLL_TEST_CNTL 0x0013 +#define POWER_MANAGEMENT 0x002f #define PPLL_RESET 0x01 #define PPLL_ATOMIC_UPDATE_EN 0x10000 @@ -266,7 +270,8 @@ #define DAC_MASK 0xFF000000 #define DAC_BLANKING 0x00000004 #define DAC_RANGE_CNTL 0x00000003 -#define PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PALETTE_ACCESS_CNTL 0x00000020 +#define DAC_PDWN 0x00008000 /* GEN_RESET_CNTL bit constants */ #define SOFT_RESET_GUI 0x00000001 @@ -339,4 +344,42 @@ #define DP_SRC_HOST 0x00000300 #define DP_SRC_HOST_BYTEALIGN 0x00000400 +/* LVDS_GEN_CNTL constants */ +#define LVDS_BL_MOD_LEVEL_MASK 0x0000ff00 +#define LVDS_BL_MOD_LEVEL_SHIFT 8 +#define LVDS_BL_MOD_EN 0x00010000 +#define LVDS_DIGION 0x00040000 +#define LVDS_BLON 0x00080000 +#define LVDS_ON 0x00000001 +#define LVDS_DISPLAY_DIS 0x00000002 +#define LVDS_PANEL_TYPE_2PIX_PER_CLK 0x00000004 +#define LVDS_PANEL_24BITS_TFT 0x00000008 +#define LVDS_FRAME_MOD_NO 0x00000000 +#define LVDS_FRAME_MOD_2_LEVELS 0x00000010 +#define LVDS_FRAME_MOD_4_LEVELS 0x00000020 +#define LVDS_EN 0x00000080 + +/* CRTC2_GEN_CNTL constants */ +#define CRTC2_EN 0x02000000 + +/* POWER_MANAGEMENT constants */ +#define PWR_MGT_ON 0x00000001 +#define PWR_MGT_MODE_MASK 0x00000006 +#define PWR_MGT_MODE_PIN 0x00000000 +#define PWR_MGT_MODE_REGISTER 0x00000002 +#define PWR_MGT_MODE_TIMER 0x00000004 +#define PWR_MGT_MODE_PCI 0x00000006 +#define PWR_MGT_AUTO_PWR_UP_EN 0x00000008 +#define PWR_MGT_ACTIVITY_PIN_ON 0x00000010 +#define PWR_MGT_STANDBY_POL 0x00000020 +#define PWR_MGT_SUSPEND_POL 0x00000040 +#define PWR_MGT_SELF_REFRESH 0x00000080 +#define PWR_MGT_ACTIVITY_PIN_EN 0x00000100 +#define PWR_MGT_KEYBD_SNOOP 0x00000200 +#define PWR_MGT_TRISTATE_MEM_EN 0x00000800 +#define PWR_MGT_SELW4MS 0x00001000 +#define PWR_MGT_SLOWDOWN_MCLK 0x00002000 + +#define PMI_PMSCR_REG 0x60 + #endif /* REG_RAGE128_H */ diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c index 329a3d51ef26..c7de4a3ea6b4 100644 --- a/drivers/video/aty128fb.c +++ b/drivers/video/aty128fb.c @@ -50,6 +50,9 @@ #include #include #include