summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS17
-rw-r--r--Documentation/Configure.help76
-rw-r--r--Documentation/ioctl-number.txt4
-rw-r--r--MAINTAINERS12
-rw-r--r--Makefile4
-rw-r--r--arch/alpha/kernel/ptrace.c2
-rw-r--r--arch/alpha/kernel/signal.c4
-rw-r--r--arch/i386/boot/setup.S2
-rw-r--r--arch/i386/defconfig3
-rw-r--r--arch/i386/kernel/ptrace.c2
-rw-r--r--arch/i386/kernel/signal.c4
-rw-r--r--arch/i386/kernel/smp.c3
-rw-r--r--arch/i386/mm/init.c10
-rw-r--r--arch/m68k/Makefile4
-rw-r--r--arch/m68k/amiga/amikeyb.c18
-rw-r--r--arch/m68k/amiga/zorro.c2
-rw-r--r--arch/m68k/boot/Makefile65
-rw-r--r--arch/m68k/boot/amiga/bootstrap.c335
-rw-r--r--arch/m68k/boot/amiga/bootstrap.h149
-rw-r--r--arch/m68k/boot/amiga/linuxboot.c1692
-rw-r--r--arch/m68k/boot/amiga/linuxboot.h455
-rw-r--r--arch/m68k/boot/atari/bootp.c814
-rw-r--r--arch/m68k/boot/atari/bootp.h44
-rw-r--r--arch/m68k/boot/atari/bootstrap.c1602
-rw-r--r--arch/m68k/boot/atari/bootstrap.h171
-rw-r--r--arch/m68k/boot/atari/ethlance.c435
-rw-r--r--arch/m68k/boot/atari/ethlance.h7
-rw-r--r--arch/m68k/boot/atari/sysvars.h22
-rw-r--r--arch/m68k/config.in5
-rw-r--r--arch/m68k/defconfig3
-rw-r--r--arch/m68k/ifpsp060/iskeleton.S1
-rw-r--r--arch/m68k/kernel/console.c10
-rw-r--r--arch/m68k/kernel/entry.S2
-rw-r--r--arch/m68k/kernel/head.S3
-rw-r--r--arch/m68k/kernel/process.c5
-rw-r--r--arch/m68k/kernel/sys_m68k.c178
-rw-r--r--arch/mips/boot/Makefile1
-rw-r--r--arch/mips/config.in2
-rw-r--r--arch/mips/kernel/irixsig.c8
-rw-r--r--arch/mips/kernel/ptrace.c2
-rw-r--r--arch/mips/kernel/signal.c6
-rw-r--r--arch/mips/kernel/syscalls.h4
-rw-r--r--arch/mips/kernel/sysirix.c8
-rw-r--r--arch/mips/kernel/traps.c2
-rw-r--r--arch/mips/lib/dump_tlb.c44
-rw-r--r--arch/mips/mm/r4xx0.c4
-rw-r--r--arch/ppc/Makefile63
-rw-r--r--arch/ppc/boot/Makefile57
-rw-r--r--arch/ppc/boot/cortstrip.c73
-rw-r--r--arch/ppc/boot/gzip.h2
-rw-r--r--arch/ppc/boot/head.S1
-rw-r--r--arch/ppc/boot/inflate.c2
-rw-r--r--arch/ppc/boot/misc.c90
-rw-r--r--arch/ppc/boot/mk_type41.c208
-rw-r--r--arch/ppc/boot/mkprep.c337
-rw-r--r--arch/ppc/boot/piggyback.c64
-rw-r--r--arch/ppc/boot/unzip.c2
-rw-r--r--arch/ppc/boot/vreset.c1093
-rw-r--r--arch/ppc/config.in75
-rw-r--r--arch/ppc/kernel/Makefile45
-rw-r--r--arch/ppc/kernel/head.S2866
-rw-r--r--arch/ppc/kernel/irq.c810
-rw-r--r--arch/ppc/kernel/ksyms.c36
-rw-r--r--arch/ppc/kernel/misc.S697
-rw-r--r--arch/ppc/kernel/mk_defs.c261
-rw-r--r--arch/ppc/kernel/pci.c326
-rw-r--r--arch/ppc/kernel/port_io.c181
-rw-r--r--arch/ppc/kernel/ppc_asm.tmpl47
-rw-r--r--arch/ppc/kernel/process.c716
-rw-r--r--arch/ppc/kernel/ptrace.c158
-rw-r--r--arch/ppc/kernel/setup.c409
-rw-r--r--arch/ppc/kernel/signal.c208
-rw-r--r--arch/ppc/kernel/stubs.c58
-rw-r--r--arch/ppc/kernel/support.c84
-rw-r--r--arch/ppc/kernel/syscalls.c201
-rw-r--r--arch/ppc/kernel/time.c465
-rw-r--r--arch/ppc/kernel/traps.c154
-rw-r--r--arch/ppc/kernel/usercpy.c116
-rw-r--r--arch/ppc/ld.script36
-rw-r--r--arch/ppc/lib/Makefile36
-rw-r--r--arch/ppc/mm/Makefile6
-rw-r--r--arch/ppc/mm/fault.c264
-rw-r--r--arch/ppc/mm/init.c1558
-rw-r--r--arch/sparc/defconfig7
-rw-r--r--arch/sparc/kernel/sys_sunos.c7
-rw-r--r--arch/sparc/mm/srmmu.c9
-rw-r--r--arch/sparc/mm/sun4c.c9
-rw-r--r--arch/sparc64/defconfig5
-rw-r--r--arch/sparc64/kernel/Makefile20
-rw-r--r--arch/sparc64/kernel/auxio.c3
-rw-r--r--arch/sparc64/kernel/cpu.c9
-rw-r--r--arch/sparc64/kernel/devices.c2
-rw-r--r--arch/sparc64/kernel/entry.S4
-rw-r--r--arch/sparc64/kernel/ioctl32.c19
-rw-r--r--arch/sparc64/kernel/ioport.c4
-rw-r--r--arch/sparc64/kernel/irq.c229
-rw-r--r--arch/sparc64/kernel/process.c66
-rw-r--r--arch/sparc64/kernel/setup.c8
-rw-r--r--arch/sparc64/kernel/smp.c136
-rw-r--r--arch/sparc64/kernel/time.c63
-rw-r--r--arch/sparc64/lib/locks.S118
-rw-r--r--arch/sparc64/mm/Makefile14
-rw-r--r--arch/sparc64/mm/init.c13
-rw-r--r--arch/sparc64/mm/ultra.S3
-rw-r--r--arch/sparc64/prom/console.c4
-rw-r--r--arch/sparc64/prom/misc.c4
-rw-r--r--arch/sparc64/prom/p1275.c4
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/block/acsi.c7
-rw-r--r--drivers/block/acsi_slm.c13
-rw-r--r--drivers/block/genhd.c8
-rw-r--r--drivers/char/Config.in1
-rw-r--r--drivers/char/Makefile10
-rw-r--r--drivers/char/fbmem.c3
-rw-r--r--drivers/char/keyboard.c5
-rw-r--r--drivers/char/lp.c11
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/pc110pad.c4
-rw-r--r--drivers/char/pc110pad.h2
-rw-r--r--drivers/char/pc_keyb.c74
-rw-r--r--drivers/char/pc_keyb.h6
-rw-r--r--drivers/char/psaux.c114
-rw-r--r--drivers/char/sysrq.c48
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/vga.c22
-rw-r--r--drivers/misc/parport_arc.c3
-rw-r--r--drivers/misc/parport_init.c9
-rw-r--r--drivers/misc/parport_pc.c20
-rw-r--r--drivers/misc/parport_procfs.c9
-rw-r--r--drivers/misc/parport_share.c35
-rw-r--r--drivers/net/myri_sbus.c10
-rw-r--r--drivers/net/plip.c18
-rw-r--r--drivers/net/soundmodem/sm_sbc.c5
-rw-r--r--drivers/net/soundmodem/sm_wss.c5
-rw-r--r--drivers/pnp/parport_probe.c8
-rw-r--r--drivers/sbus/char/Makefile2
-rw-r--r--drivers/sbus/char/creator.c6
-rw-r--r--drivers/sbus/char/suncons.c4
-rw-r--r--drivers/sbus/char/tcx.c8
-rw-r--r--drivers/sbus/char/weitek.c4
-rw-r--r--drivers/sbus/sbus.c7
-rw-r--r--drivers/scsi/53c7,8xx.c364
-rw-r--r--drivers/scsi/53c7,8xx.h2
-rw-r--r--drivers/scsi/Config.in9
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/README.aic7xxx44
-rw-r--r--drivers/scsi/aic7xxx.c7361
-rw-r--r--drivers/scsi/aic7xxx.h9
-rw-r--r--drivers/scsi/aic7xxx.seq1127
-rw-r--r--drivers/scsi/aic7xxx_asm.c734
-rw-r--r--drivers/scsi/aic7xxx_proc.c42
-rw-r--r--drivers/scsi/aic7xxx_reg.h1154
-rw-r--r--drivers/scsi/atari_scsi.c32
-rw-r--r--drivers/scsi/eata.h41
-rw-r--r--drivers/scsi/esp.c20
-rw-r--r--drivers/scsi/ppa.c26
-rw-r--r--drivers/scsi/ppa.h2
-rw-r--r--drivers/sgi/char/sgicons.c3
-rw-r--r--fs/autofs/autofs_i.h6
-rw-r--r--fs/autofs/dir.c18
-rw-r--r--fs/autofs/inode.c14
-rw-r--r--fs/autofs/root.c70
-rw-r--r--fs/autofs/symlink.c5
-rw-r--r--fs/binfmt_aout.c1
-rw-r--r--fs/binfmt_misc.c1
-rw-r--r--fs/buffer.c384
-rw-r--r--fs/dcache.c50
-rw-r--r--fs/devices.c4
-rw-r--r--fs/dquot.c10
-rw-r--r--fs/ext2/ialloc.c12
-rw-r--r--fs/ext2/namei.c12
-rw-r--r--fs/fat/cache.c3
-rw-r--r--fs/fat/fatfs_syms.c1
-rw-r--r--fs/fat/misc.c3
-rw-r--r--fs/hpfs/hpfs_fs.c29
-rw-r--r--fs/inode.c89
-rw-r--r--fs/namei.c100
-rw-r--r--fs/nfs/dir.c35
-rw-r--r--fs/nfs/nfsroot.c5
-rw-r--r--fs/pipe.c1
-rw-r--r--fs/proc/array.c5
-rw-r--r--fs/proc/link.c17
-rw-r--r--fs/proc/openpromfs.c79
-rw-r--r--fs/proc/root.c8
-rw-r--r--fs/romfs/inode.c44
-rw-r--r--fs/super.c3
-rw-r--r--fs/ufs/ufs_namei.c9
-rw-r--r--fs/vfat/namei.c238
-rw-r--r--include/asm-alpha/keyboard.h6
-rw-r--r--include/asm-i386/keyboard.h6
-rw-r--r--include/asm-i386/smp_lock.h4
-rw-r--r--include/asm-m68k/serial.h2
-rw-r--r--include/asm-mips/ioctls.h4
-rw-r--r--include/asm-mips/keyboard.h6
-rw-r--r--include/asm-ppc/atomic.h119
-rw-r--r--include/asm-ppc/bitops.h178
-rw-r--r--include/asm-ppc/bugs.h6
-rw-r--r--include/asm-ppc/byteorder.h60
-rw-r--r--include/asm-ppc/cache.h3
-rw-r--r--include/asm-ppc/checksum.h14
-rw-r--r--include/asm-ppc/current.h12
-rw-r--r--include/asm-ppc/delay.h27
-rw-r--r--include/asm-ppc/dma.h11
-rw-r--r--include/asm-ppc/errno.h2
-rw-r--r--include/asm-ppc/ide.h107
-rw-r--r--include/asm-ppc/init.h21
-rw-r--r--include/asm-ppc/io.h182
-rw-r--r--include/asm-ppc/ioctls.h4
-rw-r--r--include/asm-ppc/irq.h6
-rw-r--r--include/asm-ppc/keyboard.h30
-rw-r--r--include/asm-ppc/mc146818rtc.h128
-rw-r--r--include/asm-ppc/mmu.h95
-rw-r--r--include/asm-ppc/mmu_context.h56
-rw-r--r--include/asm-ppc/nvram.h3
-rw-r--r--include/asm-ppc/page.h32
-rw-r--r--include/asm-ppc/pgtable.h253
-rw-r--r--include/asm-ppc/ppc_machine.h56
-rw-r--r--include/asm-ppc/processor.h119
-rw-r--r--include/asm-ppc/ptrace.h82
-rw-r--r--include/asm-ppc/semaphore.h70
-rw-r--r--include/asm-ppc/smp.h2
-rw-r--r--include/asm-ppc/socket.h9
-rw-r--r--include/asm-ppc/string.h41
-rw-r--r--include/asm-ppc/system.h63
-rw-r--r--include/asm-ppc/termbits.h41
-rw-r--r--include/asm-ppc/termios.h222
-rw-r--r--include/asm-ppc/uaccess.h339
-rw-r--r--include/asm-ppc/unistd.h183
-rw-r--r--include/asm-sparc/fbio.h43
-rw-r--r--include/asm-sparc/smp.h2
-rw-r--r--include/asm-sparc64/oplib.h5
-rw-r--r--include/asm-sparc64/pgtable.h64
-rw-r--r--include/asm-sparc64/semaphore.h25
-rw-r--r--include/asm-sparc64/smp.h52
-rw-r--r--include/asm-sparc64/smp_lock.h64
-rw-r--r--include/asm-sparc64/softirq.h8
-rw-r--r--include/asm-sparc64/spinlock.h106
-rw-r--r--include/asm-sparc64/system.h108
-rw-r--r--include/linux/dcache.h10
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/miscdevice.h1
-rw-r--r--include/linux/mm.h3
-rw-r--r--include/linux/msdos_fs.h7
-rw-r--r--include/linux/msdos_fs_sb.h3
-rw-r--r--include/linux/parport.h10
-rw-r--r--include/linux/proc_fs.h2
-rw-r--r--include/linux/sched.h21
-rw-r--r--include/linux/selection.h14
-rw-r--r--include/linux/sysrq.h17
-rw-r--r--init/main.c4
-rw-r--r--kernel/exit.c31
-rw-r--r--kernel/ksyms.c1
-rw-r--r--kernel/sched.c5
-rw-r--r--lib/vsprintf.c38
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/simp.c2
-rw-r--r--net/Changes6
-rw-r--r--net/ax25/ax25_ip.c2
-rw-r--r--net/ax25/ax25_route.c2
-rw-r--r--net/core/dev.c5
-rw-r--r--net/ipv4/ip_fragment.c5
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/tcp.c25
-rw-r--r--net/ipv4/tcp_ipv4.c4
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/ipv6/tcp_ipv6.c5
268 files changed, 14831 insertions, 20028 deletions
diff --git a/CREDITS b/CREDITS
index c903f985a..616d29e2b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -335,6 +335,15 @@ S: Rue de la Chapelle 51
S: 4850 Moresnet
S: Belgium
+N: Cort Dougan
+E: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~cort/
+D: PowerPC PReP port
+S: Computer Science Department
+S: New Mexico Tech
+S: Socorro NM 87801
+S: USA
+
N: Thomas Dunbar
E: tdunbar@vtaix.cc.vt.edu
D: TeX & METAFONT hacking/maintenance
@@ -912,6 +921,14 @@ N: Peter MacDonald
D: SLS distribution
D: Initial implementation of VC's, pty's and select()
+N: Paul Mackerras
+E: paulus@cs.anu.edu.au
+D: Linux port for PCI Power Macintosh
+S: Dept. of Computer Science
+S: Australian National University
+S: Canberra ACT 0200
+S: AUSTRALIA
+
N: James B. MacLean
E: macleajb@ednet.ns.ca
W: http://www.ednet.ns.ca/~macleajb/dosemu.html
diff --git a/Documentation/Configure.help b/Documentation/Configure.help
index a9274b91a..8310f1eea 100644
--- a/Documentation/Configure.help
+++ b/Documentation/Configure.help
@@ -1679,20 +1679,62 @@ CONFIG_SCSI_AHA1740
want to compile it as a module, say M here and read
Documentation/modules.txt.
-Adaptec AHA274X/284X/294X support
+Adaptec AIC7xxx support (includes 274x/284x/294x)
CONFIG_SCSI_AIC7XXX
Information about this SCSI host adapter is contained in
drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
- (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it
- doesn't work out of the box, you may have to change some settings in
- drivers/scsi/aic7xxx.h. It has been reported that the "wide
- negotiation" on these cards is not quite working and should be
- disabled. Note that the AHA2920 SCSI host adapter is *not* supported
- by this driver; choose "Future Domain 16xx SCSI support" instead. If
- you want to compile this driver a module ( = code which can be
- inserted in and removed from the running kernel whenever you want),
- say M here and read Documentation/modules.txt. The module will be
- called aic7xxx.o.
+ (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that
+ the AHA2920 SCSI host adapter is *not* supported by this driver; choose
+ "Future Domain 16xx SCSI support" instead. If you want to compile this
+ driver as module ( = code which can be inserted in and removed from the
+ running kernel whenever you want), say M here and read Documentation/
+ modules.txt. The module will be called aic7xxx.o.
+
+Enable tagged command queueing
+CONFIG_AIC7XXX_TAGGED_QUEUEING
+ This option allows you to enable tagged command queueing for this
+ driver. Some scsi devices do not properly support this
+ feature. Tagged command queueing will improve performance.
+
+Maximum number of commands per LUN
+ CONFIG_AIC7XXX_CMDS_PER_LUN
+ This option allows you to set the maximum number of commands queued
+ per LUN. If tagged queueing is enabled, then you may want to try
+ increasing AIC7XXX_CMDS_PER_LUN to more than 2. By default, we limit
+ the SCBs per LUN to 2 with or without tagged queueing enabled. If
+ tagged queueing is disabled, the sequencer will keep the 2nd SCB in
+ the input queue until the first one completes - so it is OK to to have
+ more than 1 SCB queued. If tagged queueing is enabled, then the
+ sequencer will attempt to send the 2nd SCB to the device while the
+ first SCB is executing and the device is disconnected. For adapters
+ limited to 4 SCBs, you may want to actually decrease the commands per
+ LUN to 1, if you often have more than 2 devices active at the same
+ time. This will allocate 1 SCB for each device and ensure that there
+ will always be a free SCB for up to 4 devices active at the same time.
+ When SCB paging is enabled, set the commands per LUN to 8 or higher
+ (see SCB paging support below). Note that if AIC7XXX_CMDS_PER_LUN is
+ not defined and tagged queueing is enabled, the driver will attempt to
+ set the commands per LUN using its own heuristic based on the number
+ of available SCBs.
+
+Enable SCB paging
+CONFIG_AIC7XXX_PAGE_ENABLE
+ This option enables SCB paging. This will increase performance when
+ tagged queueing is enabled. Note that you should increase the
+ AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices allow at
+ least this many. Note that EISA and VLB controllers do not support
+ SCB paging due to chip limitations; enabling it on these controllers
+ has no effect.
+
+Collect statistics to report in /proc
+CONFIG_AIC7XXX_PROC_STATS
+ This option enables collection of SCSI transfer statistics for the
+ /proc filesystem. This does affect performance since it has to
+ maintain statistics.
+
+Delay in seconds after SCSI bus reset
+CONFIG_AIC7XXX_RESET_DELAY
+ This option sets the delay in seconds after a SCSI bus reset.
BusLogic SCSI support
CONFIG_SCSI_BUSLOGIC
@@ -4653,6 +4695,18 @@ CONFIG_RTC
have a use for such a device (such as periodic data sampling), then
say Y here, and go read the file Documentation/rtc.txt for details.
+/dev/nvram support
+CONFIG_NVRAM
+ If you say Y here and create a character special file /dev/nvram
+ with major number 10 and minor number 144 using mknod ("man mknod"),
+ you get access to the non-volatile memory in the real time clock
+ (RTC). This is conventionally called "CMOS RAM" on PCs and "NVRAM"
+ on Ataris. /dev/nvram may be used to view settings there, or to
+ change them (with some utility). It could also be used to frequently
+ save a few bits of very important data, that may not be lost over
+ power-off and for which writing to disk is too insecure. On Atari
+ machines, /dev/nvram is always configured and needs not be selected.
+
ARC console time
CONFIG_RTC_ARC
If you boot your Alpha using the ARC firmware, say Y here. This option
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 790bb18c7..e86a2ad1a 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -1,5 +1,5 @@
Ioctl Numbers
-10 Apr 1997
+25 Jul 1997
Michael Chastain
<mec@shout.net>
@@ -119,3 +119,5 @@ Code Seq# Include File Comments
<mailto:b.kohl@ipn-b.comlink.apc.org>
0xA0 all Small Device Project in development:
<mailto:khollis@northwest.com>
+0xA3 90-9F DoubleTalk driver in development:
+ <mailto:jrv@vanzandt.mv.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index d0d12290c..e6764e5c1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -452,6 +452,18 @@ W: http://www.cyberelk.demon.co.uk/parport.html
W: http://www.cage.curtin.edu.au/~campbell/parbus/
S: Maintained
+LINUX FOR POWERPC (PREP)
+P: Cort Dougan
+M: cort@cs.nmt.edu
+W: http://www.cs.nmt.edu/~linuxppc/
+S: Maintained
+
+LINUX FOR POWER MACINTOSH
+P: Paul Mackerras
+M: paulus@cs.anu.edu.au
+L: linux-pmac@samba.anu.edu.au
+S: Maintained
+
FPU EMULATOR
P: Bill Metzenthen
M: billm@suburbia.net
diff --git a/Makefile b/Makefile
index f242bfa4f..3542de66e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 47
+SUBLEVEL = 48
ARCH = mips
@@ -191,6 +191,7 @@ vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
$(LIBS) \
-o vmlinux
$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aU] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
+ elf2ecoff vmlinux /tmpu/miguel/vmlinux.ecoff
symlinks:
rm -f include/asm
@@ -340,7 +341,6 @@ clean: archclean
mrproper: clean
rm -f include/linux/autoconf.h include/linux/version.h
rm -f drivers/sound/local.h drivers/sound/.defines
- rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
rm -f drivers/char/uni_hash.tbl drivers/char/conmakehash
rm -f drivers/net/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
rm -f drivers/net/soundmodem/sm_tbl_{hapn4800,psk4800}.h
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index c388f0b51..84cde1b4f 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -650,7 +650,7 @@ asmlinkage void syscall_trace(void)
goto out;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 5c3eb79ef..9f71e6146 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -315,7 +315,7 @@ asmlinkage int do_signal(unsigned long oldmask,
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
if (!(signr = current->exit_code))
@@ -354,7 +354,7 @@ asmlinkage int do_signal(unsigned long oldmask,
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
single_stepping |= ptrace_cancel_bpt(current);
continue;
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 7553ce943..edc0fe0ff 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -272,8 +272,8 @@ loader_ok:
! and fall into the old memory detection code to populate the
! compatability slot.
- pop ebx
oldstylemem:
+ pop ebx
#endif
mov ah,#0x88
int 0x15
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 430d6b971..e3e50886c 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -139,6 +139,7 @@ CONFIG_SCSI_OMIT_FLASHPOINT=y
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
@@ -171,6 +172,7 @@ CONFIG_EEXPRESS_PRO100=y
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_SLIP is not set
@@ -234,6 +236,7 @@ CONFIG_82C710_MOUSE=y
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
#
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 0dfffd672..c8a7f986e 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -577,7 +577,7 @@ asmlinkage void syscall_trace(void)
return;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 3141c5318..f5af47201 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -346,7 +346,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -386,7 +386,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 5a020b723..d187128e1 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -156,6 +156,9 @@ volatile unsigned long smp_idle_map=0; /* Map for idle processors */
volatile unsigned long smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
volatile int smp_process_available=0;
+const char lk_lockmsg[] = "lock from interrupt context at %p\n";
+
+
/*#define SMP_DEBUG*/
#ifdef SMP_DEBUG
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index c8371aa81..8f2852a48 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -209,7 +209,7 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
pgd_val(pg_dir[0]) = 0;
/* Map whole memory from 0xC0000000 */
-
+ pg_dir += 768;
while (address < end_mem) {
/*
* If we're running on a Pentium CPU, we can use the 4MB
@@ -224,13 +224,13 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
set_in_cr4(X86_CR4_PSE);
wp_works_ok = 1;
- __pe = _PAGE_TABLE + _PAGE_4M + __pa(address);
+ __pe = _KERNPG_TABLE + _PAGE_4M + __pa(address);
/* Make it "global" too if supported */
if (x86_capability & X86_FEATURE_PGE) {
set_in_cr4(X86_CR4_PGE);
__pe += _PAGE_GLOBAL;
}
- pgd_val(pg_dir[768]) = _PAGE_TABLE + _PAGE_4M + __pa(address);
+ pgd_val(*pg_dir) = __pe;
pg_dir++;
address += 4*1024*1024;
continue;
@@ -239,13 +239,13 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
* We're on a [34]86, use normal page tables.
* pg_table is physical at this point
*/
- pg_table = (pte_t *) (PAGE_MASK & pgd_val(pg_dir[768]));
+ pg_table = (pte_t *) (PAGE_MASK & pgd_val(*pg_dir));
if (!pg_table) {
pg_table = (pte_t *) __pa(start_mem);
start_mem += PAGE_SIZE;
}
- pgd_val(pg_dir[768]) = _PAGE_TABLE | (unsigned long) pg_table;
+ pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table;
pg_dir++;
/* now change pg_table to kernel virtual addresses */
pg_table = (pte_t *) __va(pg_table);
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 7548a8dc8..94257b578 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -79,8 +79,6 @@ CORE_FILES := $(CORE_FILES) arch/m68k/ifpsp060/ifpsp.o
SUBDIRS := $(SUBDIRS) arch/m68k/ifpsp060
endif
-MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-
lilo: vmlinux
if [ -f $(INSTALL_PATH)/vmlinux ]; then mv -f $(INSTALL_PATH)/vmlinux $(INSTALL_PATH)/vmlinux.old; fi
if [ -f $(INSTALL_PATH)/System.map ]; then mv -f $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
@@ -106,7 +104,5 @@ bootstrap: dummy
archclean:
rm -f vmlinux.gz
- @$(MAKEBOOT) clean
archdep:
- $(MAKEBOOT) dep
diff --git a/arch/m68k/amiga/amikeyb.c b/arch/m68k/amiga/amikeyb.c
index 06fe55d29..5a102a12c 100644
--- a/arch/m68k/amiga/amikeyb.c
+++ b/arch/m68k/amiga/amikeyb.c
@@ -195,7 +195,7 @@ static void amikeyb_rep(unsigned long ignore)
static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
- unsigned char scancode, break_flag;
+ unsigned char scancode, break_flag, keycode;
static int reset_warning = 0;
/* save frame for register dump */
@@ -207,6 +207,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
/* switch SP pin to output for handshake */
ciaa.cra |= 0x40;
+#if 0 // No longer used
/*
* On receipt of the second RESET_WARNING, we must not pull KDAT high
* again to delay the hard reset as long as possible.
@@ -222,6 +223,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
} else
/* Probably a mistake, cancel the alert */
reset_warning = 0;
+#endif
/* wait until 85 us have expired */
udelay(85);
@@ -237,27 +239,27 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
* Check make/break first
*/
break_flag = scancode & BREAK_MASK;
- scancode &= (unsigned char )~BREAK_MASK;
+ keycode = scancode & (unsigned char)~BREAK_MASK;
- if (scancode == AMIKEY_CAPS) {
+ if (keycode == AMIKEY_CAPS) {
/* if the key is CAPS, fake a press/release. */
handle_scancode(AMIKEY_CAPS);
handle_scancode(BREAK_MASK | AMIKEY_CAPS);
- } else if (scancode < 0x78) {
+ } else if (keycode < 0x78) {
/* handle repeat */
if (break_flag) {
del_timer(&amikeyb_rep_timer);
rep_scancode = 0;
} else {
del_timer(&amikeyb_rep_timer);
- rep_scancode = scancode;
+ rep_scancode = keycode;
amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
}
- handle_scancode(break_flag | scancode);
+ handle_scancode(scancode);
} else
- switch (scancode) {
+ switch (keycode) {
case 0x78:
reset_warning = 1;
break;
@@ -288,7 +290,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
#endif
default:
printk(KERN_WARNING "amikeyb: unknown keyboard communication code 0x%02x\n",
- break_flag | scancode);
+ scancode);
break;
}
}
diff --git a/arch/m68k/amiga/zorro.c b/arch/m68k/amiga/zorro.c
index d64ad8ce3..1da948134 100644
--- a/arch/m68k/amiga/zorro.c
+++ b/arch/m68k/amiga/zorro.c
@@ -730,7 +730,7 @@ int zorro_find(int manuf, int prod, int part, int index)
{
int key;
struct ConfigDev *cd;
-
+
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO))
return(0);
diff --git a/arch/m68k/boot/Makefile b/arch/m68k/boot/Makefile
index 822030ebb..e69de29bb 100644
--- a/arch/m68k/boot/Makefile
+++ b/arch/m68k/boot/Makefile
@@ -1,65 +0,0 @@
-#
-# linux/arch/m68k/boot/Makefile
-#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-
-ifdef CONFIG_AMIGA
-AMIGA_BOOTSTRAP = amiga_bootstrap
-AMIGA_BOOTOBJS := amiga/bootstrap.o amiga/linuxboot.o
-AMIGA_HOSTCC = m68k-cbm-amigados-gcc
-AMIGA_HOSTINC = -I$(TOPDIR)/include
-AMIGA_HOSTFLAGS=-m68030 -O2 -Wall -Dlinux
-endif
-
-ifdef CONFIG_ATARI
-ATARI_BOOTSTRAP = atari_bootstrap
-ATARI_BOOTOBJS := atari/bootstrap.o
-ATARI_HOSTCC = m68k-mint-gcc
-ATARI_HOSTINC = -I$(TOPDIR)/include
-ATARI_HOSTFLAGS = -m68030 -m68881 -Dlinux -O2 -Wall
-
-# BOOTP/TFTP support in bootstrap?
-# USE_BOOTP = y
-
-ifdef USE_BOOTP
-ATARI_BOOTOBJS += atari/bootp.o
-ATARI_HOSTFLAGS += -DUSE_BOOTP
-
-# low-level Ethernet drivers:
-
-# Lance (RieblCard, PAM-VME)
-ATARI_BOOTOBJS += atari/ethlance.o
-ATARI_HOSTFLAGS += -DETHLL_LANCE
-
-endif
-endif
-
-ifdef CONFIG_ATARI
-atari_bootstrap: $(ATARI_BOOTOBJS)
- $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -o $@ $(ATARI_BOOTOBJS)
- rm -f ../../../bootstrap
- ln $@ ../../../bootstrap
-endif
-
-ifdef CONFIG_AMIGA
-amiga_bootstrap: $(AMIGA_BOOTOBJS)
- $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -o $@ -s -noixemul $(AMIGA_BOOTOBJS)
- rm -f ../../../bootstrap
- ln $@ ../../../bootstrap
-endif
-
-$(AMIGA_BOOTOBJS): %.o: %.c
- $(AMIGA_HOSTCC) $(AMIGA_HOSTINC) $(AMIGA_HOSTFLAGS) -c $< -o $@
-
-$(ATARI_BOOTOBJS): %.o: %.c
- $(ATARI_HOSTCC) $(ATARI_HOSTINC) $(ATARI_HOSTFLAGS) -c $< -o $@
-
-bootstrap: $(AMIGA_BOOTSTRAP) $(ATARI_BOOTSTRAP)
-
-clean:
- rm -f *.o amiga/*.o atari/*.o amiga_bootstrap atari_bootstrap \
- ../../../bootstrap
-
-dep:
diff --git a/arch/m68k/boot/amiga/bootstrap.c b/arch/m68k/boot/amiga/bootstrap.c
index 41ac75ada..e69de29bb 100644
--- a/arch/m68k/boot/amiga/bootstrap.c
+++ b/arch/m68k/boot/amiga/bootstrap.c
@@ -1,335 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.c -- This program loads the Linux/m68k
-** kernel into an Amiga and launches
-** it.
-**
-** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
-**
-** Modified 11-May-94 by Geert Uytterhoeven
-** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-** - A3640 MapROM check
-** Modified 31-May-94 by Geert Uytterhoeven
-** - Memory thrash problem solved
-** Modified 07-March-95 by Geert Uytterhoeven
-** - Memory block sizes are rounded to a multiple of 256K instead of 1M
-** This _requires_ >0.9pl5 to work!
-** (unless all block sizes are multiples of 1M :-)
-** Modified 11-July-95 by Andreas Schwab
-** - Support for ELF kernel (untested!)
-** Modified 10-Jan-96 by Geert Uytterhoeven
-** - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-** - Rewritten option parsing
-** - New parameter passing to linuxboot() (linuxboot_args)
-** Modified 6-Oct-96 by Geert Uytterhoeven
-** - Updated for the new boot information structure
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <sys/file.h>
-#include <unistd.h>
-
-/* required Linux/m68k include files */
-#define __KERNEL_STRICT_NAMES /* This is ugly, I know */
-#define _LINUX_POSIX_TYPES_H
-#include <asm/posix_types.h>
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-/* Amiga bootstrap include files */
-#include "linuxboot.h"
-#include "bootstrap.h"
-
-
-/* Library Bases */
-long __oslibversion = 36;
-extern const struct ExecBase *SysBase;
-
-static const char *memfile_name = NULL;
-
-static int model = AMI_UNKNOWN;
-
-static const char *ProgramName;
-
-struct linuxboot_args args;
-
-
- /*
- * Function Prototypes
- */
-
-static void Usage(void) __attribute__ ((noreturn));
-int main(int argc, char *argv[]);
-static void Puts(const char *str);
-static long GetChar(void);
-static void PutChar(char c);
-static void Printf(const char *fmt, ...);
-static int Open(const char *path);
-static int Seek(int fd, int offset);
-static int Read(int fd, char *buf, int count);
-static void Close(int fd);
-static int FileSize(const char *path);
-static void Sleep(u_long micros);
-
-
-static void Usage(void)
-{
- fprintf(stderr,
- "Linux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n\n"
- "Usage: %s [options] [kernel command line]\n\n"
- "Basic options:\n"
- " -h, --help Display this usage information\n"
- " -k, --kernel file Use kernel image `file' (default is `vmlinux')\n"
- " -r, --ramdisk file Use ramdisk image `file'\n"
- "Advanced options:\n"
- " -d, --debug Enable debug mode\n"
- " -b, --baud speed Set the serial port speed (default is 9600)\n"
- " -m, --memfile file Use memory file `file'\n"
- " -v, --keep-video Don't reset the video mode\n"
- " -t, --model id Set the Amiga model to `id'\n"
- " -p, --processor cfm Set the processor type to `cfm\n\n",
- ProgramName);
- exit(EXIT_FAILURE);
-}
-
-
-int main(int argc, char *argv[])
-{
- int i;
- int processor = 0, debugflag = 0, keep_video = 0;
- u_int baud = 0;
- const char *kernel_name = NULL;
- const char *ramdisk_name = NULL;
- char commandline[CL_SIZE] = "";
-
- ProgramName = argv[0];
- while (--argc) {
- argv++;
- if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help"))
- Usage();
- else if (!strcmp(argv[0], "-k") || !strcmp(argv[0], "--kernel"))
- if (--argc && !kernel_name) {
- kernel_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-r") || !strcmp(argv[0], "--ramdisk"))
- if (--argc && !ramdisk_name) {
- ramdisk_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--debug"))
- debugflag = 1;
- else if (!strcmp(argv[0], "-b") || !strcmp(argv[0], "--baud"))
- if (--argc && !baud) {
- baud = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-m") || !strcmp(argv[0], "--memfile"))
- if (--argc && !memfile_name) {
- memfile_name = argv[1];
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-v") || !strcmp(argv[0], "--keep-video"))
- keep_video = 1;
- else if (!strcmp(argv[0], "-t") || !strcmp(argv[0], "--model"))
- if (--argc && !model) {
- model = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--processor"))
- if (--argc && !processor) {
- processor = atoi(argv[1]);
- argv++;
- } else
- Usage();
- else
- break;
- }
- if (!kernel_name)
- kernel_name = "vmlinux";
-
- SysBase = *(struct ExecBase **)4;
-
- /*
- * Join command line options
- */
- i = 0;
- while (argc--) {
- if ((i+strlen(*argv)+1) < CL_SIZE) {
- i += strlen(*argv) + 1;
- if (commandline[0])
- strcat(commandline, " ");
- strcat(commandline, *argv++);
- }
- }
-
- memset(&args.bi, 0, sizeof(args.bi));
- if (processor) {
- int cpu = processor/100%10;
- int fpu = processor/10%10;
- int mmu = processor%10;
- if (cpu)
- args.bi.cputype = 1<<(cpu-1);
- if (fpu)
- args.bi.fputype = 1<<(fpu-1);
- if (mmu)
- args.bi.mmutype = 1<<(mmu-1);
- }
- /*
- * If we have a memory file, read the memory information from it
- */
- if (memfile_name) {
- FILE *fp;
- int i;
-
- if ((fp = fopen(memfile_name, "r")) == NULL) {
- perror("open memory file");
- fprintf(stderr, "Cannot open memory file %s\n", memfile_name);
- return(FALSE);
- }
-
- if (fscanf(fp, "%lu", &args.bi.chip_size) != 1) {
- fprintf(stderr, "memory file does not contain chip memory size\n");
- fclose(fp);
- return(FALSE);
- }
-
- for (i = 0; i < NUM_MEMINFO; i++)
- if (fscanf(fp, "%lx %lu", &args.bi.memory[i].addr,
- &args.bi.memory[i].size) != 2)
- break;
-
- fclose(fp);
- args.bi.num_memory = i;
- }
- strncpy(args.bi.command_line, commandline, CL_SIZE);
- args.bi.command_line[CL_SIZE-1] = '\0';
- if (model != AMI_UNKNOWN)
- args.bi.model = model;
-
- args.kernelname = kernel_name;
- args.ramdiskname = ramdisk_name;
- args.debugflag = debugflag;
- args.keep_video = keep_video;
- args.reset_boards = 1;
- args.baud = baud;
- args.puts = Puts;
- args.getchar = GetChar;
- args.putchar = PutChar;
- args.printf = Printf;
- args.open = Open;
- args.seek = Seek;
- args.read = Read;
- args.close = Close;
- args.filesize = FileSize;
- args.sleep = Sleep;
-
- /* Do The Right Stuff */
- linuxboot(&args);
-
- /* if we ever get here, something went wrong */
- exit(EXIT_FAILURE);
-}
-
-
- /*
- * Routines needed by linuxboot
- */
-
-static void Puts(const char *str)
-{
- fputs(str, stderr);
- fflush(stderr);
-}
-
-static long GetChar(void)
-{
- return(getchar());
-}
-
-static void PutChar(char c)
-{
- fputc(c, stderr);
- fflush(stderr);
-}
-
-static void Printf(const char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- fflush(stderr);
-}
-
-static int Open(const char *path)
-{
- return(open(path, O_RDONLY));
-}
-
-static int Seek(int fd, int offset)
-{
- return(lseek(fd, offset, SEEK_SET));
-}
-
-
-static int Read(int fd, char *buf, int count)
-{
- return(read(fd, buf, count));
-}
-
-static void Close(int fd)
-{
- close(fd);
-}
-
-static int FileSize(const char *path)
-{
- int fd, size = -1;
-
- if ((fd = open(path, O_RDONLY)) != -1) {
- size = lseek(fd, 0, SEEK_END);
- close(fd);
- }
- return(size);
-}
-
-static void Sleep(u_long micros)
-{
- struct MsgPort *TimerPort;
- struct timerequest *TimerRequest;
-
- if ((TimerPort = CreateMsgPort())) {
- if ((TimerRequest = CreateIORequest(TimerPort,
- sizeof(struct timerequest)))) {
- if (!OpenDevice("timer.device", UNIT_VBLANK,
- (struct IORequest *)TimerRequest, 0)) {
- TimerRequest->io_Command = TR_ADDREQUEST;
- TimerRequest->io_Flags = IOF_QUICK;
- TimerRequest->tv_secs = micros/1000000;
- TimerRequest->tv_micro = micros%1000000;
- DoIO((struct IORequest *)TimerRequest);
- CloseDevice((struct IORequest *)TimerRequest);
- }
- DeleteIORequest(TimerRequest);
- }
- DeleteMsgPort(TimerPort);
- }
-}
diff --git a/arch/m68k/boot/amiga/bootstrap.h b/arch/m68k/boot/amiga/bootstrap.h
index 4d072cc75..e69de29bb 100644
--- a/arch/m68k/boot/amiga/bootstrap.h
+++ b/arch/m68k/boot/amiga/bootstrap.h
@@ -1,149 +0,0 @@
-/*
-** linux/arch/m68k/boot/amiga/bootstrap.h -- This file is part of the Amiga
-** bootloader.
-**
-** Copyright 1993, 1994 by Hamish Macdonald
-**
-** Some minor additions by Michael Rausch 1-11-94
-** Modified 11-May-94 by Geert Uytterhoeven
-** (Geert.Uytterhoeven@cs.kuleuven.ac.be)
-** - inline Supervisor() call
-** Modified 10-Jan-96 by Geert Uytterhoeven
-** - The real Linux/m68k boot code moved to linuxboot.[ch]
-** Modified 9-Sep-96 by Geert Uytterhoeven
-** - const library bases
-** - fixed register naming for m68k-cbm-amigados-gcc
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-
-struct MsgPort {
- u_char fill1[15];
- u_char mp_SigBit;
- u_char fill2[18];
-};
-
-struct IOStdReq {
- u_char fill1[20];
- struct Device *io_Device;
- u_char fill2[4];
- u_short io_Command;
- u_char io_Flags;
- char io_Error;
- u_long io_Actual;
- u_long io_Length;
- void *io_Data;
- u_char fill4[4];
-};
-
-#define IOF_QUICK (1<<0)
-
-struct timerequest {
- u_char fill1[28];
- u_short io_Command;
- u_char io_Flags;
- u_char fill2[1];
- u_long tv_secs;
- u_long tv_micro;
-};
-
-#define UNIT_VBLANK 1
-#define TR_ADDREQUEST 9
-
-
-struct Library;
-struct IORequest;
-
-
-static __inline char OpenDevice(u_char *devName, u_long unit,
- struct IORequest *ioRequest, u_long flags)
-{
- register char _res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register u_char *a0 __asm("a0") = devName;
- register u_long d0 __asm("d0") = unit;
- register struct IORequest *a1 __asm("a1") = ioRequest;
- register u_long d1 __asm("d1") = flags;
-
- __asm __volatile ("jsr a6@(-0x1bc)"
- : "=r" (_res)
- : "r" (a6), "r" (a0), "r" (a1), "r" (d0), "r" (d1)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void CloseDevice(struct IORequest *ioRequest)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct IORequest *a1 __asm("a1") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x1c2)"
- : /* no output */
- : "r" (a6), "r" (a1)
- : "a0","a1","d0","d1", "memory");
-}
-
-static __inline char DoIO(struct IORequest *ioRequest)
-{
- register char _res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct IORequest *a1 __asm("a1") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x1c8)"
- : "=r" (_res)
- : "r" (a6), "r" (a1)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void *CreateIORequest(struct MsgPort *port, u_long size)
-{
- register struct Library *_res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct MsgPort *a0 __asm("a0") = port;
- register u_long d0 __asm("d0") = size;
-
- __asm __volatile ("jsr a6@(-0x28e)"
- : "=r" (_res)
- : "r" (a6), "r" (a0), "r" (d0)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void DeleteIORequest(void *ioRequest)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register void *a0 __asm("a0") = ioRequest;
-
- __asm __volatile ("jsr a6@(-0x294)"
- : /* no output */
- : "r" (a6), "r" (a0)
- : "a0","a1","d0","d1", "memory");
-}
-
-static __inline struct MsgPort *CreateMsgPort(void)
-{
- register struct MsgPort *_res __asm("d0");
- register const struct ExecBase *a6 __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x29a)"
- : "=r" (_res)
- : "r" (a6)
- : "a0","a1","d0","d1", "memory");
- return(_res);
-}
-
-static __inline void DeleteMsgPort(struct MsgPort *port)
-{
- register const struct ExecBase *a6 __asm("a6") = SysBase;
- register struct MsgPort *a0 __asm("a0") = port;
-
- __asm __volatile ("jsr a6@(-0x2a0)"
- : /* no output */
- : "r" (a6), "r" (a0)
- : "a0","a1","d0","d1", "memory");
-}
diff --git a/arch/m68k/boot/amiga/linuxboot.c b/arch/m68k/boot/amiga/linuxboot.c
index 74b873bf2..e69de29bb 100644
--- a/arch/m68k/boot/amiga/linuxboot.c
+++ b/arch/m68k/boot/amiga/linuxboot.c
@@ -1,1692 +0,0 @@
-/*
- * linux/arch/m68k/boot/amiga/linuxboot.c -- Generic routine to boot Linux/m68k
- * on Amiga, used by both Amiboot and
- * Amiga-Lilo.
- *
- * Created 1996 by Geert Uytterhoeven
- *
- *
- * This file is based on the original bootstrap code (bootstrap.c):
- *
- * Copyright (C) 1993, 1994 Hamish Macdonald
- * Greg Harp
- *
- * with work by Michael Rausch
- * Geert Uytterhoeven
- * Frank Neumann
- * Andreas Schwab
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- * History:
- * 11 Jun 1997 Fix for unpadded gzipped ramdisks with bootinfo interface
- * version 1.0
- * 27 Mar 1997 FPU-less machines couldn't boot kernels that use bootinfo
- * interface version 1.0 (Geert)
- * 3 Feb 1997 Implemented kernel decompression (Geert, based on Roman's
- * code for ataboot)
- * 30 Dec 1996 Reverted the CPU detection to the old scheme
- * New boot parameter override scheme (Geert)
- * 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
- * 9 Sep 1996 Rewritten option parsing
- * New parameter passing to linuxboot() (linuxboot_args)
- * (Geert)
- * 18 Aug 1996 Updated for the new boot information structure (Geert)
- * 10 Jan 1996 The real Linux/m68k boot code moved to linuxboot.[ch]
- * (Geert)
- * 11 Jul 1995 Support for ELF kernel (untested!) (Andreas)
- * 7 Mar 1995 Memory block sizes are rounded to a multiple of 256K
- * instead of 1M (Geert)
- * 31 May 1994 Memory thrash problem solved (Geert)
- * 11 May 1994 A3640 MapROM check (Geert)
- */
-
-
-#ifndef __GNUC__
-#error GNU CC is required to compile this program
-#endif /* __GNUC__ */
-
-
-#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <linux/linkage.h>
-#include <asm/bootinfo.h>
-#include <asm/amigahw.h>
-#include <asm/page.h>
-
-#include "linuxboot.h"
-
-
-#undef custom
-#define custom ((*(volatile struct CUSTOM *)(CUSTOM_PHYSADDR)))
-
-/* a.out linkage conventions */
-#undef SYMBOL_NAME_STR
-#define SYMBOL_NAME_STR(X) "_"#X
-
-/* temporary stack size */
-#define TEMP_STACKSIZE (256)
-
-#define DEFAULT_BAUD (9600)
-
-extern char copyall, copyallend;
-
-static struct exec kexec;
-static Elf32_Ehdr kexec_elf;
-static const struct linuxboot_args *linuxboot_args;
-
-/* Bootinfo */
-struct amiga_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE (4096)
-static u_long bi_size;
-static union {
- struct bi_record record;
- u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-#define kernelname linuxboot_args->kernelname
-#define ramdiskname linuxboot_args->ramdiskname
-#define debugflag linuxboot_args->debugflag
-#define keep_video linuxboot_args->keep_video
-#define reset_boards linuxboot_args->reset_boards
-#define baud linuxboot_args->baud
-
-#define Puts linuxboot_args->puts
-#define GetChar linuxboot_args->getchar
-#define PutChar linuxboot_args->putchar
-#define Printf linuxboot_args->printf
-#define Open linuxboot_args->open
-#define Seek linuxboot_args->seek
-#define Read linuxboot_args->read
-#define Close linuxboot_args->close
-#define FileSize linuxboot_args->filesize
-#define Sleep linuxboot_args->sleep
-
- /*
- * Function Prototypes
- */
-
-static u_long get_chipset(void);
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu);
-static u_long get_model(u_long chipset);
-static int probe_resident(const char *name);
-static int probe_resource(const char *name);
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-static int check_bootinfo_version(const char *memptr);
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
- u_long start_mem, u_long kernel_size, u_long rd_dest,
- u_long rd_size) __attribute__ ((noreturn));
-asmlinkage u_long maprommed(void);
-#ifdef ZKERNEL
-static int load_zkernel(int fd);
-static int KRead(int fd, void *buf, int cnt);
-static int KSeek(int fd, int offset);
-static int KClose(int fd);
-#else
-#define KRead Read
-#define KSeek Seek
-#define KClose Close
-#endif
-
-
- /*
- * Reset functions for nasty Zorro boards
- */
-
-static void reset_rb3(const struct ConfigDev *cd);
-static void reset_piccolo(const struct ConfigDev *cd);
-static void reset_sd64(const struct ConfigDev *cd);
-static void reset_ariadne(const struct ConfigDev *cd);
-static void reset_hydra(const struct ConfigDev *cd);
-#if 0
-static void reset_a2060(const struct ConfigDev *cd);
-#endif
-
-struct boardreset {
- u_short manuf;
- u_short prod;
- const char *name;
- void (*reset)(const struct ConfigDev *cd);
-};
-
-static struct boardreset boardresetdb[] = {
- { MANUF_HELFRICH1, PROD_RAINBOW3, "Rainbow 3", reset_rb3 },
- { MANUF_HELFRICH2, PROD_PICCOLO_REG, "Piccolo", reset_piccolo },
- { MANUF_HELFRICH2, PROD_SD64_REG, "SD64", reset_sd64 },
- { MANUF_VILLAGE_TRONIC, PROD_ARIADNE, "Ariadne", reset_ariadne },
- { MANUF_HYDRA_SYSTEMS, PROD_AMIGANET, "Hydra", reset_hydra },
-#if 0
- { MANUF_COMMODORE, PROD_A2060, "A2060", reset_a2060 },
-#endif
-};
-#define NUM_BOARDRESET sizeof(boardresetdb)/sizeof(*boardresetdb)
-
-static void (*boardresetfuncs[ZORRO_NUM_AUTO])(const struct ConfigDev *cd);
-
-
-const char *amiga_models[] = {
- "Amiga 500", "Amiga 500+", "Amiga 600", "Amiga 1000", "Amiga 1200",
- "Amiga 2000", "Amiga 2500", "Amiga 3000", "Amiga 3000T", "Amiga 3000+",
- "Amiga 4000", "Amiga 4000T", "CDTV", "CD32", "Draco"
-};
-const u_long first_amiga_model = AMI_500;
-const u_long last_amiga_model = AMI_DRACO;
-
-
-#define MASK(model) (1<<AMI_##model)
-
-#define CLASS_A3000 (MASK(3000) | MASK(3000T))
-#define CLASS_A4000 (MASK(4000) | MASK(4000T))
-#define CLASS_ZKICK (MASK(500) | MASK(1000) | MASK(2000) | MASK(2500))
-
-
- /*
- * Boot the Linux/m68k Operating System
- */
-
-u_long linuxboot(const struct linuxboot_args *args)
-{
- int kfd = -1, rfd = -1, elf_kernel = 0, do_fast, do_chip;
- int i, j;
- const struct MemHeader *mnp;
- struct ConfigDev *cdp = NULL;
- char *memptr = NULL;
- u_long *stack = NULL;
- u_long fast_total, model_mask, startcodesize, start_mem, mem_size, rd_size;
- u_long kernel_size;
- u_int realbaud;
- u_long memreq = 0, text_offset = 0;
- Elf32_Phdr *kernel_phdrs = NULL;
- void (*startfunc)(void);
- u_short manuf;
- u_char prod;
- void *bi_ptr;
-
- linuxboot_args = args;
-
- /* print the greet message */
- Puts("\nLinux/m68k Amiga Bootstrap version " AMIBOOT_VERSION "\n");
- Puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n\n");
-
- /* Note: Initial values in bi override detected values */
- bi = args->bi;
-
- /* machine is Amiga */
- bi.machtype = MACH_AMIGA;
-
- /* determine chipset */
- if (!bi.chipset)
- bi.chipset = get_chipset();
-
- /* determine CPU, FPU and MMU type */
- if (!bi.cputype)
- get_processor(&bi.cputype, &bi.fputype, &bi.mmutype);
-
- /* determine Amiga model */
- if (!bi.model)
- bi.model = get_model(bi.chipset);
- model_mask = (bi.model != AMI_UNKNOWN) ? 1<<bi.model : 0;
-
- /* Memory & AutoConfig based on 'unix_boot.c' by C= */
-
- /* find all of the autoconfig boards in the system */
- if (!bi.num_autocon)
- for (i = 0; (cdp = (struct ConfigDev *)FindConfigDev(cdp, -1, -1)); i++)
- if (bi.num_autocon < ZORRO_NUM_AUTO)
- /* copy the contents of each structure into our boot info and
- count this device */
- memcpy(&bi.autocon[bi.num_autocon++], cdp,
- sizeof(struct ConfigDev));
- else
- Printf("Warning: too many AutoConfig devices. Ignoring device at "
- "0x%08lx\n", cdp->cd_BoardAddr);
-
- do_fast = bi.num_memory ? 0 : 1;
- do_chip = bi.chip_size ? 0 : 1;
- /* find out the memory in the system */
- for (mnp = (struct MemHeader *)SysBase->MemList.lh_Head;
- mnp->mh_Node.ln_Succ;
- mnp = (struct MemHeader *)mnp->mh_Node.ln_Succ) {
- struct MemHeader mh;
-
- /* copy the information */
- mh = *mnp;
-
- /* skip virtual memory */
- if (!(mh.mh_Attributes & MEMF_PUBLIC))
- continue;
-
- /* if we suspect that Kickstart is shadowed in an A3000,
- modify the entry to show 512K more at the top of RAM
- Check first for a MapROMmed A3640 board: overwriting the
- Kickstart image causes an infinite lock-up on reboot! */
- if ((mh.mh_Upper == (void *)0x07f80000) &&
- (model_mask & (CLASS_A3000 | CLASS_A4000)))
- if ((bi.cputype & CPU_68040) && Supervisor(maprommed))
- Puts("A3640 MapROM detected.\n");
- else if (model_mask & CLASS_A3000) {
- mh.mh_Upper = (void *)0x08000000;
- Puts("A3000 shadowed Kickstart detected.\n");
- }
-
- /* if we suspect that Kickstart is zkicked,
- modify the entry to show 512K more at the botton of RAM */
- if ((mh.mh_Lower == (void *)0x00280020) &&
- (model_mask & CLASS_ZKICK)) {
- mh.mh_Lower = (void *)0x00200000;
- Puts("ZKick detected.\n");
- }
-
- /* mask the memory limit values */
- mh.mh_Upper = (void *)((u_long)mh.mh_Upper & 0xfffff000);
- mh.mh_Lower = (void *)((u_long)mh.mh_Lower & 0xfffff000);
-
- /* if fast memory */
- if (do_fast && mh.mh_Attributes & MEMF_FAST) {
- /* set the size value to the size of this block and mask off to a
- 256K increment */
- u_long size = ((u_long)mh.mh_Upper-(u_long)mh.mh_Lower)&0xfffc0000;
- if (size > 0)
- if (bi.num_memory < NUM_MEMINFO) {
- /* record the start and size */
- bi.memory[bi.num_memory].addr = (u_long)mh.mh_Lower;
- bi.memory[bi.num_memory].size = size;
- /* count this block */
- bi.num_memory++;
- } else
- Printf("Warning: too many memory blocks. Ignoring block "
- "of %ldK at 0x%08x\n", size>>10,
- (u_long)mh.mh_Lower);
- } else if (do_chip && mh.mh_Attributes & MEMF_CHIP)
- /* if CHIP memory, record the size */
- bi.chip_size = (u_long)mh.mh_Upper;
- }
-
- /* get info from ExecBase */
- if (!bi.vblank)
- bi.vblank = SysBase->VBlankFrequency;
- if (!bi.psfreq)
- bi.psfreq = SysBase->PowerSupplyFrequency;
- if (!bi.eclock)
- bi.eclock = SysBase->ex_EClockFrequency;
-
- /* serial port */
- if (!bi.serper) {
- realbaud = baud ? baud : DEFAULT_BAUD;
- bi.serper = (5*bi.eclock+realbaud/2)/realbaud-1;
- }
-
- /* display Amiga model */
- if (bi.model >= first_amiga_model && bi.model <= last_amiga_model)
- Printf("%s ", amiga_models[bi.model-first_amiga_model]);
- else
- Puts("Amiga ");
-
- /* display the CPU type */
- Puts("CPU: ");
- switch (bi.cputype) {
- case CPU_68020:
- Puts("68020 (Do you have an MMU?)");
- break;
- case CPU_68030:
- Puts("68030");
- break;
- case CPU_68040:
- Puts("68040");
- break;
- case CPU_68060:
- Puts("68060");
- break;
- default:
- Puts("Insufficient for Linux. Aborting...\n");
- Printf("SysBase->AttnFlags = 0x%08lx\n", SysBase->AttnFlags);
- goto Fail;
- }
- switch (bi.fputype) {
- case FPU_68881:
- Puts(" with 68881 FPU");
- break;
- case FPU_68882:
- Puts(" with 68882 FPU");
- break;
- case FPU_68040:
- case FPU_68060:
- Puts(" with internal FPU");
- break;
- default:
- Puts(" without FPU");
- break;
- }
-
- /* display the chipset */
- switch (bi.chipset) {
- case CS_STONEAGE:
- Puts(", old or unknown chipset");
- break;
- case CS_OCS:
- Puts(", OCS");
- break;
- case CS_ECS:
- Puts(", ECS");
- break;
- case CS_AGA:
- Puts(", AGA chipset");
- break;
- }
-
- Puts("\n\n");
-
- /* display the command line */
- Printf("Command line is '%s'\n", bi.command_line);
-
- /* display the clock statistics */
- Printf("Vertical Blank Frequency: %ldHz\n", bi.vblank);
- Printf("Power Supply Frequency: %ldHz\n", bi.psfreq);
- Printf("EClock Frequency: %ldHz\n\n", bi.eclock);
-
- /* display autoconfig devices */
- if (bi.num_autocon) {
- Printf("Found %ld AutoConfig Device%s\n", bi.num_autocon,
- bi.num_autocon > 1 ? "s" : "");
- for (i = 0; i < bi.num_autocon; i++) {
- Printf("Device %ld: addr = 0x%08lx", i,
- (u_long)bi.autocon[i].cd_BoardAddr);
- boardresetfuncs[i] = NULL;
- if (reset_boards) {
- manuf = bi.autocon[i].cd_Rom.er_Manufacturer;
- prod = bi.autocon[i].cd_Rom.er_Product;
- for (j = 0; j < NUM_BOARDRESET; j++)
- if ((manuf == boardresetdb[j].manuf) &&
- (prod == boardresetdb[j].prod)) {
- Printf(" [%s - will be reset at kernel boot time]",
- boardresetdb[j].name);
- boardresetfuncs[i] = boardresetdb[j].reset;
- break;
- }
- }
- PutChar('\n');
- }
- } else
- Puts("No AutoConfig Devices Found\n");
-
- /* display memory */
- if (bi.num_memory) {
- Printf("\nFound %ld Block%sof Memory\n", bi.num_memory,
- bi.num_memory > 1 ? "s " : " ");
- for (i = 0; i < bi.num_memory; i++)
- Printf("Block %ld: 0x%08lx to 0x%08lx (%ldK)\n", i,
- bi.memory[i].addr, bi.memory[i].addr+bi.memory[i].size,
- bi.memory[i].size>>10);
- } else {
- Puts("No memory found?! Aborting...\n");
- goto Fail;
- }
-
- /* display chip memory size */
- Printf("%ldK of CHIP memory\n", bi.chip_size>>10);
-
- start_mem = bi.memory[0].addr;
- mem_size = bi.memory[0].size;
-
- /* tell us where the kernel will go */
- Printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
- /* verify that there is enough Chip RAM */
- if (bi.chip_size < 512*1024) {
- Puts("Not enough Chip RAM in this system. Aborting...\n");
- goto Fail;
- }
-
- /* verify that there is enough Fast RAM */
- for (fast_total = 0, i = 0; i < bi.num_memory; i++)
- fast_total += bi.memory[i].size;
- if (fast_total < 2*1024*1024) {
- Puts("Not enough Fast RAM in this system. Aborting...\n");
- goto Fail;
- }
-
- /* support for ramdisk */
- if (ramdiskname) {
- int size;
-
- if ((size = FileSize(ramdiskname)) == -1) {
- Printf("Unable to find size of ramdisk file `%s'\n", ramdiskname);
- goto Fail;
- }
- /* record ramdisk size */
- bi.ramdisk.size = size;
- } else
- bi.ramdisk.size = 0;
- rd_size = bi.ramdisk.size;
- bi.ramdisk.addr = (u_long)start_mem+mem_size-rd_size;
-
- /* create the bootinfo structure */
- if (!create_bootinfo())
- goto Fail;
-
- /* open kernel executable and read exec header */
- if ((kfd = Open(kernelname)) == -1) {
- Printf("Unable to open kernel file `%s'\n", kernelname);
- goto Fail;
- }
- if (KRead(kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec)) {
- Puts("Unable to read exec header from kernel file\n");
- goto Fail;
- }
-
-#ifdef ZKERNEL
- if (((unsigned char *)&kexec)[0] == 037 &&
- (((unsigned char *)&kexec)[1] == 0213 ||
- ((unsigned char *)&kexec)[1] == 0236)) {
- /* That's a compressed kernel */
- Puts("Kernel is compressed\n");
- if (load_zkernel(kfd)) {
- Puts("Decompression error -- aborting\n");
- goto Fail;
- }
- }
-#endif
-
- switch (N_MAGIC(kexec)) {
- case ZMAGIC:
- if (debugflag)
- Puts("\nLoading a.out (ZMAGIC) Linux/m68k kernel...\n");
- text_offset = N_TXTOFF(kexec);
- break;
-
- case QMAGIC:
- if (debugflag)
- Puts("\nLoading a.out (QMAGIC) Linux/m68k kernel...\n");
- text_offset = sizeof(kexec);
- /* the text size includes the exec header; remove this */
- kexec.a_text -= sizeof(kexec);
- break;
-
- default:
- /* Try to parse it as an ELF header */
- KSeek(kfd, 0);
- if ((KRead(kfd, (void *)&kexec_elf, sizeof(kexec_elf)) ==
- sizeof(kexec_elf)) &&
- (memcmp(&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)) {
- elf_kernel = 1;
- if (debugflag)
- Puts("\nLoading ELF Linux/m68k kernel...\n");
- /* A few plausibility checks */
- if ((kexec_elf.e_type != ET_EXEC) ||
- (kexec_elf.e_machine != EM_68K) ||
- (kexec_elf.e_version != EV_CURRENT)) {
- Puts("Invalid ELF header contents in kernel\n");
- goto Fail;
- }
- /* Load the program headers */
- if (!(kernel_phdrs =
- (Elf32_Phdr *)AllocMem(kexec_elf.e_phnum*sizeof(Elf32_Phdr),
- MEMF_FAST | MEMF_PUBLIC |
- MEMF_CLEAR))) {
- Puts("Unable to allocate memory for program headers\n");
- goto Fail;
- }
- KSeek(kfd, kexec_elf.e_phoff);
- if (KRead(kfd, (void *)kernel_phdrs,
- kexec_elf.e_phnum*sizeof(*kernel_phdrs)) !=
- kexec_elf.e_phnum*sizeof(*kernel_phdrs)) {
- Puts("Unable to read program headers from kernel file\n");
- goto Fail;
- }
- break;
- }
- Printf("Wrong magic number 0x%08lx in kernel header\n",
- N_MAGIC(kexec));
- goto Fail;
- }
-
- /* Load the kernel at one page after start of mem */
- start_mem += PAGE_SIZE;
- mem_size -= PAGE_SIZE;
- /* Align bss size to multiple of four */
- if (!elf_kernel)
- kexec.a_bss = (kexec.a_bss+3) & ~3;
-
- /* calculate the total required amount of memory */
- if (elf_kernel) {
- u_long min_addr = 0xffffffff, max_addr = 0;
- for (i = 0; i < kexec_elf.e_phnum; i++) {
- if (min_addr > kernel_phdrs[i].p_vaddr)
- min_addr = kernel_phdrs[i].p_vaddr;
- if (max_addr < kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz)
- max_addr = kernel_phdrs[i].p_vaddr+kernel_phdrs[i].p_memsz;
- }
- /* This is needed for newer linkers that include the header in
- the first segment. */
- if (min_addr == 0) {
- min_addr = PAGE_SIZE;
- kernel_phdrs[0].p_vaddr += PAGE_SIZE;
- kernel_phdrs[0].p_offset += PAGE_SIZE;
- kernel_phdrs[0].p_filesz -= PAGE_SIZE;
- kernel_phdrs[0].p_memsz -= PAGE_SIZE;
- }
- kernel_size = max_addr-min_addr;
- } else
- kernel_size = kexec.a_text+kexec.a_data+kexec.a_bss;
- memreq = kernel_size+bi_size+rd_size;
-#ifdef BOOTINFO_COMPAT_1_0
- if (sizeof(compat_bootinfo) > bi_size)
- memreq = kernel_size+sizeof(compat_bootinfo)+rd_size;
-#endif /* BOOTINFO_COMPAT_1_0 */
- if (!(memptr = (char *)AllocMem(memreq, MEMF_FAST | MEMF_PUBLIC |
- MEMF_CLEAR))) {
- Puts("Unable to allocate memory\n");
- goto Fail;
- }
-
- /* read the text and data segments from the kernel image */
- if (elf_kernel)
- for (i = 0; i < kexec_elf.e_phnum; i++) {
- if (KSeek(kfd, kernel_phdrs[i].p_offset) == -1) {
- Printf("Failed to seek to segment %ld\n", i);
- goto Fail;
- }
- if (KRead(kfd, memptr+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
- kernel_phdrs[i].p_filesz) != kernel_phdrs[i].p_filesz) {
- Printf("Failed to read segment %ld\n", i);
- goto Fail;
- }
- }
- else {
- if (KSeek(kfd, text_offset) == -1) {
- Puts("Failed to seek to text\n");
- goto Fail;
- }
- if (KRead(kfd, memptr, kexec.a_text) != kexec.a_text) {
- Puts("Failed to read text\n");
- goto Fail;
- }
- /* data follows immediately after text */
- if (KRead(kfd, memptr+kexec.a_text, kexec.a_data) != kexec.a_data) {
- Puts("Failed to read data\n");
- goto Fail;
- }
- }
- KClose(kfd);
- kfd = -1;
-
- /* Check kernel's bootinfo version */
- switch (check_bootinfo_version(memptr)) {
- case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
- bi_ptr = &bi_union.record;
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
- if (!create_compat_bootinfo())
- goto Fail;
- bi_ptr = &compat_bootinfo;
- bi_size = sizeof(compat_bootinfo);
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- goto Fail;
- }
-
- /* copy the bootinfo to the end of the kernel image */
- memcpy((void *)(memptr+kernel_size), bi_ptr, bi_size);
-
- if (ramdiskname) {
- if ((rfd = Open(ramdiskname)) == -1) {
- Printf("Unable to open ramdisk file `%s'\n", ramdiskname);
- goto Fail;
- }
- if (Read(rfd, memptr+kernel_size+bi_size, rd_size) != rd_size) {
- Puts("Failed to read ramdisk file\n");
- goto Fail;
- }
- Close(rfd);
- rfd = -1;
- }
-
- /* allocate temporary chip ram stack */
- if (!(stack = (u_long *)AllocMem(TEMP_STACKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
- Puts("Unable to allocate memory for stack\n");
- goto Fail;
- }
-
- /* allocate chip ram for copy of startup code */
- startcodesize = &copyallend-&copyall;
- if (!(startfunc = (void (*)(void))AllocMem(startcodesize,
- MEMF_CHIP | MEMF_CLEAR))) {
- Puts("Unable to allocate memory for startcode\n");
- goto Fail;
- }
-
- /* copy startup code to CHIP RAM */
- memcpy(startfunc, &copyall, startcodesize);
-
- if (debugflag) {
- if (bi.ramdisk.size)
- Printf("RAM disk at 0x%08lx, size is %ldK\n",
- (u_long)memptr+kernel_size+bi_size, bi.ramdisk.size>>10);
-
- if (elf_kernel) {
- PutChar('\n');
- for (i = 0; i < kexec_elf.e_phnum; i++)
- Printf("Kernel segment %ld at 0x%08lx, size %ld\n", i,
- start_mem+kernel_phdrs[i].p_vaddr-PAGE_SIZE,
- kernel_phdrs[i].p_memsz);
- Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
- } else {
- Printf("\nKernel text at 0x%08lx, code size 0x%08lx\n", start_mem,
- kexec.a_text);
- Printf("Kernel data at 0x%08lx, data size 0x%08lx\n",
- start_mem+kexec.a_text, kexec.a_data);
- Printf("Kernel bss at 0x%08lx, bss size 0x%08lx\n",
- start_mem+kexec.a_text+kexec.a_data, kexec.a_bss);
- Printf("Boot info at 0x%08lx\n", start_mem+kernel_size);
- }
- Printf("\nKernel entry is 0x%08lx\n", elf_kernel ? kexec_elf.e_entry :
- kexec.a_entry);
-
- Printf("ramdisk dest is 0x%08lx\n", bi.ramdisk.addr);
- Printf("ramdisk lower limit is 0x%08lx\n",
- (u_long)memptr+kernel_size+bi_size);
- Printf("ramdisk src top is 0x%08lx\n",
- (u_long)memptr+kernel_size+bi_size+rd_size);
-
- Puts("\nType a key to continue the Linux/m68k boot...");
- GetChar();
- PutChar('\n');
- }
-
- /* wait for things to settle down */
- Sleep(1000000);
-
- if (!keep_video)
- /* set graphics mode to a nice normal one */
- LoadView(NULL);
-
- Disable();
-
- /* reset nasty Zorro boards */
- if (reset_boards)
- for (i = 0; i < bi.num_autocon; i++)
- if (boardresetfuncs[i])
- boardresetfuncs[i](&bi.autocon[i]);
-
- /* Turn off all DMA */
- custom.dmacon = DMAF_ALL | DMAF_MASTER;
-
- /* turn off caches */
- CacheControl(0, ~0);
-
- /* Go into supervisor state */
- SuperState();
-
- /* turn off any mmu translation */
- disable_mmu();
-
- /* execute the copy-and-go code (from CHIP RAM) */
- start_kernel(startfunc, (char *)stack+TEMP_STACKSIZE, memptr, start_mem,
- kernel_size, bi.ramdisk.addr, rd_size);
-
- /* Clean up and exit in case of a failure */
-Fail:
- if (kfd != -1)
- KClose(kfd);
- if (rfd != -1)
- Close(rfd);
- if (memptr)
- FreeMem((void *)memptr, memreq);
- if (stack)
- FreeMem((void *)stack, TEMP_STACKSIZE);
- if (kernel_phdrs)
- FreeMem((void *)kernel_phdrs, kexec_elf.e_phnum*sizeof(Elf32_Phdr));
- return(FALSE);
-}
-
-
- /*
- * Determine the Chipset
- */
-
-static u_long get_chipset(void)
-{
- u_char cs;
- u_long chipset;
-
- if (GfxBase->Version >= 39)
- cs = SetChipRev(SETCHIPREV_BEST);
- else
- cs = GfxBase->ChipRevBits0;
- if ((cs & GFXG_AGA) == GFXG_AGA)
- chipset = CS_AGA;
- else if ((cs & GFXG_ECS) == GFXG_ECS)
- chipset = CS_ECS;
- else if ((cs & GFXG_OCS) == GFXG_OCS)
- chipset = CS_OCS;
- else
- chipset = CS_STONEAGE;
- return(chipset);
-}
-
-
- /*
- * Determine the CPU Type
- */
-
-static void get_processor(u_long *cpu, u_long *fpu, u_long *mmu)
-{
- *cpu = *fpu = 0;
-
- if (SysBase->AttnFlags & AFF_68060)
- *cpu = CPU_68060;
- else if (SysBase->AttnFlags & AFF_68040)
- *cpu = CPU_68040;
- else if (SysBase->AttnFlags & AFF_68030)
- *cpu = CPU_68030;
- else if (SysBase->AttnFlags & AFF_68020)
- *cpu = CPU_68020;
-
- if (*cpu == CPU_68040 || *cpu == CPU_68060) {
- if (SysBase->AttnFlags & AFF_FPU40)
- *fpu = *cpu;
- } else if (SysBase->AttnFlags & AFF_68882)
- *fpu = FPU_68882;
- else if (SysBase->AttnFlags & AFF_68881)
- *fpu = FPU_68881;
-
- *mmu = *cpu;
-}
-
- /*
- * Determine the Amiga Model
- */
-
-static u_long get_model(u_long chipset)
-{
- u_long model = AMI_UNKNOWN;
-
- if (debugflag)
- Puts("Amiga model identification:\n");
- if (probe_resource("draco.resource"))
- model = AMI_DRACO;
- else {
- if (debugflag)
- Puts(" Chipset: ");
- switch (chipset) {
- case CS_STONEAGE:
- if (debugflag)
- Puts("Old or unknown\n");
- goto OCS;
- break;
-
- case CS_OCS:
- if (debugflag)
- Puts("OCS\n");
-OCS: if (probe_resident("cd.device"))
- model = AMI_CDTV;
- else
- /* let's call it an A2000 (may be A500, A1000, A2500) */
- model = AMI_2000;
- break;
-
- case CS_ECS:
- if (debugflag)
- Puts("ECS\n");
- if (probe_resident("Magic 36.7") ||
- probe_resident("kickad 36.57") ||
- probe_resident("A3000 Bonus") ||
- probe_resident("A3000 bonus"))
- /* let's call it an A3000 (may be A3000T) */
- model = AMI_3000;
- else if (probe_resource("card.resource"))
- model = AMI_600;
- else
- /* let's call it an A2000 (may be A500[+], A1000, A2500) */
- model = AMI_2000;
- break;
-
- case CS_AGA:
- if (debugflag)
- Puts("AGA\n");
- if (probe_resident("A1000 Bonus") ||
- probe_resident("A4000 bonus"))
- model = probe_resident("NCR scsi.device") ? AMI_4000T :
- AMI_4000;
- else if (probe_resource("card.resource"))
- model = AMI_1200;
- else if (probe_resident("cd.device"))
- model = AMI_CD32;
- else
- model = AMI_3000PLUS;
- break;
- }
- }
- if (debugflag) {
- Puts("\nType a key to continue...");
- GetChar();
- Puts("\n\n");
- }
- return(model);
-}
-
-
- /*
- * Probe for a Resident Modules
- */
-
-static int probe_resident(const char *name)
-{
- const struct Resident *res;
-
- if (debugflag)
- Printf(" Module `%s': ", name);
- res = FindResident(name);
- if (debugflag)
- if (res)
- Printf("0x%08lx\n", res);
- else
- Puts("not present\n");
- return(res ? TRUE : FALSE);
-}
-
-
- /*
- * Probe for an available Resource
- */
-
-static int probe_resource(const char *name)
-{
- const void *res;
-
- if (debugflag)
- Printf(" Resource `%s': ", name);
- res = OpenResource(name);
- if (debugflag)
- if (res)
- Printf("0x%08lx\n", res);
- else
- Puts("not present\n");
- return(res ? TRUE : FALSE);
-}
-
-
- /*
- * Create the Bootinfo structure
- */
-
-static int create_bootinfo(void)
-{
- int i;
- struct bi_record *record;
-
- /* Initialization */
- bi_size = 0;
-
- /* Generic tags */
- if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
- return(0);
- if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
- return(0);
- if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
- return(0);
- if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
- return(0);
- for (i = 0; i < bi.num_memory; i++)
- if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
- return(0);
- if (bi.ramdisk.size)
- if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
- return(0);
- if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
- return(0);
-
- /* Amiga tags */
- if (!add_bi_record(BI_AMIGA_MODEL, sizeof(bi.model), &bi.model))
- return(0);
- for (i = 0; i < bi.num_autocon; i++)
- if (!add_bi_record(BI_AMIGA_AUTOCON, sizeof(bi.autocon[i]),
- &bi.autocon[i]))
- return(0);
- if (!add_bi_record(BI_AMIGA_CHIP_SIZE, sizeof(bi.chip_size), &bi.chip_size))
- return(0);
- if (!add_bi_record(BI_AMIGA_VBLANK, sizeof(bi.vblank), &bi.vblank))
- return(0);
- if (!add_bi_record(BI_AMIGA_PSFREQ, sizeof(bi.psfreq), &bi.psfreq))
- return(0);
- if (!add_bi_record(BI_AMIGA_ECLOCK, sizeof(bi.eclock), &bi.eclock))
- return(0);
- if (!add_bi_record(BI_AMIGA_CHIPSET, sizeof(bi.chipset), &bi.chipset))
- return(0);
- if (!add_bi_record(BI_AMIGA_SERPER, sizeof(bi.serper), &bi.serper))
- return(0);
-
- /* Trailer */
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = BI_LAST;
- bi_size += sizeof(bi_union.record.tag);
-
- return(1);
-}
-
-
- /*
- * Add a Record to the Bootinfo Structure
- */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
- struct bi_record *record;
- u_int size2;
-
- size2 = (sizeof(struct bi_record)+size+3)&-4;
- if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
- Puts("Can't add bootinfo record. Ask a wizard to enlarge me.\n");
- return(0);
- }
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = tag;
- record->size = size2;
- memcpy(record->data, data, size);
- bi_size += size2;
- return(1);
-}
-
-
- /*
- * Add a String Record to the Bootinfo Structure
- */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
- return(add_bi_record(tag, strlen(s)+1, (void *)s));
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
- /*
- * Create the Bootinfo structure for backwards compatibility mode
- */
-
-static int create_compat_bootinfo(void)
-{
- u_int i;
-
- compat_bootinfo.machtype = bi.machtype;
- if (bi.cputype & CPU_68020)
- compat_bootinfo.cputype = COMPAT_CPU_68020;
- else if (bi.cputype & CPU_68030)
- compat_bootinfo.cputype = COMPAT_CPU_68030;
- else if (bi.cputype & CPU_68040)
- compat_bootinfo.cputype = COMPAT_CPU_68040;
- else if (bi.cputype & CPU_68060)
- compat_bootinfo.cputype = COMPAT_CPU_68060;
- else {
- Printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
- return(0);
- }
- if (bi.fputype & FPU_68881)
- compat_bootinfo.cputype |= COMPAT_FPU_68881;
- else if (bi.fputype & FPU_68882)
- compat_bootinfo.cputype |= COMPAT_FPU_68882;
- else if (bi.fputype & FPU_68040)
- compat_bootinfo.cputype |= COMPAT_FPU_68040;
- else if (bi.fputype & FPU_68060)
- compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else if (bi.fputype) {
- Printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
- return(0);
- }
- compat_bootinfo.num_memory = bi.num_memory;
- if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
- Printf("Warning: using only %ld blocks of memory\n",
- COMPAT_NUM_MEMINFO);
- compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
- }
- for (i = 0; i < compat_bootinfo.num_memory; i++) {
- compat_bootinfo.memory[i].addr = bi.memory[i].addr;
- compat_bootinfo.memory[i].size = bi.memory[i].size;
- }
- if (bi.ramdisk.size) {
- bi.ramdisk.addr &= 0xfffffc00;
- compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
- compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
- } else {
- compat_bootinfo.ramdisk_size = 0;
- compat_bootinfo.ramdisk_addr = 0;
- }
- strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
- compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
- compat_bootinfo.bi_amiga.model = bi.model;
- compat_bootinfo.bi_amiga.num_autocon = bi.num_autocon;
- if (compat_bootinfo.bi_amiga.num_autocon > COMPAT_NUM_AUTO) {
- Printf("Warning: using only %ld AutoConfig devices\n",
- COMPAT_NUM_AUTO);
- compat_bootinfo.bi_amiga.num_autocon = COMPAT_NUM_AUTO;
- }
- for (i = 0; i < compat_bootinfo.bi_amiga.num_autocon; i++)
- compat_bootinfo.bi_amiga.autocon[i] = bi.autocon[i];
- compat_bootinfo.bi_amiga.chip_size = bi.chip_size;
- compat_bootinfo.bi_amiga.vblank = bi.vblank;
- compat_bootinfo.bi_amiga.psfreq = bi.psfreq;
- compat_bootinfo.bi_amiga.eclock = bi.eclock;
- compat_bootinfo.bi_amiga.chipset = bi.chipset;
- compat_bootinfo.bi_amiga.hw_present = 0;
- return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
- /*
- * Compare the Bootstrap and Kernel Versions
- */
-
-static int check_bootinfo_version(const char *memptr)
-{
- const struct bootversion *bv = (struct bootversion *)memptr;
- unsigned long version = 0;
- int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
- if (bv->magic == BOOTINFOV_MAGIC)
- for (i = 0; bv->machversions[i].machtype != 0; ++i)
- if (bv->machversions[i].machtype == MACH_AMIGA) {
- version = bv->machversions[i].version;
- break;
- }
- if (!version)
- Puts("Kernel has no bootinfo version info, assuming 0.0\n");
-
- kernel_major = BI_VERSION_MAJOR(version);
- kernel_minor = BI_VERSION_MINOR(version);
- boots_major = BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION);
- boots_minor = BI_VERSION_MINOR(AMIGA_BOOTI_VERSION);
- Printf("Bootstrap's bootinfo version: %ld.%ld\n", boots_major,
- boots_minor);
- Printf("Kernel's bootinfo version : %ld.%ld\n", kernel_major,
- kernel_minor);
-
- switch (kernel_major) {
- case BI_VERSION_MAJOR(AMIGA_BOOTI_VERSION):
- if (kernel_minor > boots_minor) {
- Puts("Warning: Bootinfo version of bootstrap and kernel "
- "differ!\n");
- Puts(" Certain features may not work.\n");
- }
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_AMIGA_BOOTI_VERSION):
- Puts("(using backwards compatibility mode)\n");
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- Printf("\nThis bootstrap is too %s for this kernel!\n",
- boots_major < kernel_major ? "old" : "new");
- return(0);
- }
- return(kernel_major);
-}
-
-
- /*
- * Call the copy-and-go-code
- */
-
-static void start_kernel(void (*startfunc)(), char *stackp, char *memptr,
- u_long start_mem, u_long kernel_size, u_long rd_dest,
- u_long rd_size)
-{
- register void (*a0)() __asm("a0") = startfunc;
- register char *a2 __asm("a2") = stackp;
- register char *a3 __asm("a3") = memptr;
- register u_long a4 __asm("a4") = start_mem;
- register u_long d0 __asm("d0") = rd_dest;
- register u_long d1 __asm("d1") = rd_size;
- register u_long d2 __asm("d2") = kernel_size;
- register u_long d3 __asm("d3") = bi_size;
-
- __asm __volatile ("movel a2,sp;"
- "jmp a0@"
- : /* no outputs */
- : "r" (a0), "r" (a2), "r" (a3), "r" (a4), "r" (d0),
- "r" (d1), "r" (d2), "r" (d3)
- /* no return */);
- /* fake a noreturn */
- for (;;);
-}
-
-
- /*
- * This assembler code is copied to chip ram, and then executed.
- * It copies the kernel to it's final resting place.
- *
- * It is called with:
- *
- * a3 = memptr
- * a4 = start_mem
- * d0 = rd_dest
- * d1 = rd_size
- * d2 = kernel_size
- * d3 = bi_size
- */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(copyall) ":
- | /* copy kernel text and data */
- movel a3,a0 | src = (u_long *)memptr;
- movel a0,a2 | limit = (u_long *)(memptr+kernel_size);
- addl d2,a2
- movel a4,a1 | dest = (u_long *)start_mem;
-1: cmpl a0,a2
- jeq 2f | while (src < limit)
- moveb a0@+,a1@+ | *dest++ = *src++;
- jra 1b
-2:
- | /* copy bootinfo to end of bss */
- movel a3,a0 | src = (u_long *)(memptr+kernel_size);
- addl d2,a0 | dest = end of bss (already in a1)
- movel d3,d7 | count = bi_size
- subql #1,d7
-1: moveb a0@+,a1@+ | while (--count > -1)
- dbra d7,1b | *dest++ = *src++
-
- | /* copy the ramdisk to the top of memory */
- movel a3,a0 | src = (u_long *)(memptr+kernel_size+bi_size);
- addl d2,a0
- addl d3,a0
- movel d0,a1 | dest = (u_long *)rd_dest;
- movel a0,a2 | limit = (u_long *)(memptr+kernel_size+
- addl d1,a2 | bi_size+rd_size);
-1: cmpl a0,a2
- jeq 2f | while (src > limit)
- moveb a0@+,a1@+ | *dest++ = *src++;
- jra 1b
-2:
- | /* jump to start of kernel */
- movel a4,a0 | jump_to (start_mem);
- jmp a0@
-"
-SYMBOL_NAME_STR(copyallend) ":
-");
-
-
- /*
- * Test for a MapROMmed A3640 Board
- */
-
-asm(".text\n"
-ALIGN_STR "\n"
-SYMBOL_NAME_STR(maprommed) ":
- oriw #0x0700,sr
- moveml #0x3f20,sp@-
- | /* Save cache settings */
- .long 0x4e7a1002 | movec cacr,d1 */
- | /* Save MMU settings */
- .long 0x4e7a2003 | movec tc,d2
- .long 0x4e7a3004 | movec itt0,d3
- .long 0x4e7a4005 | movec itt1,d4
- .long 0x4e7a5006 | movec dtt0,d5
- .long 0x4e7a6007 | movec dtt1,d6
- moveq #0,d0
- movel d0,a2
- | /* Disable caches */
- .long 0x4e7b0002 | movec d0,cacr
- | /* Disable MMU */
- .long 0x4e7b0003 | movec d0,tc
- .long 0x4e7b0004 | movec d0,itt0
- .long 0x4e7b0005 | movec d0,itt1
- .long 0x4e7b0006 | movec d0,dtt0
- .long 0x4e7b0007 | movec d0,dtt1
- lea 0x07f80000,a0
- lea 0x00f80000,a1
- movel a0@,d7
- cmpl a1@,d7
- jne 1f
- movel d7,d0
- notl d0
- movel d0,a0@
- nop | /* Thanks to Jörg Mayer! */
- cmpl a1@,d0
- jne 1f
- moveq #-1,d0 | /* MapROMmed A3640 present */
- movel d0,a2
-1: movel d7,a0@
- | /* Restore MMU settings */
- .long 0x4e7b2003 | movec d2,tc
- .long 0x4e7b3004 | movec d3,itt0
- .long 0x4e7b4005 | movec d4,itt1
- .long 0x4e7b5006 | movec d5,dtt0
- .long 0x4e7b6007 | movec d6,dtt1
- | /* Restore cache settings */
- .long 0x4e7b1002 | movec d1,cacr
- movel a2,d0
- moveml sp@+,#0x04fc
- rte
-");
-
-
- /*
- * Reset functions for nasty Zorro boards
- */
-
-static void reset_rb3(const struct ConfigDev *cd)
-{
- volatile u_char *rb3_reg = (u_char *)(cd->cd_BoardAddr+0x01002000);
-
- /* FN: If a Rainbow III board is present, reset it to disable */
- /* its (possibly activated) vertical blank interrupts as the */
- /* kernel is not yet prepared to handle them (level 6). */
-
- /* set RESET bit in special function register */
- *rb3_reg = 0x01;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit */
- *rb3_reg = 0x00;
-}
-
-static void reset_piccolo(const struct ConfigDev *cd)
-{
- volatile u_char *piccolo_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
- /* FN: the same stuff as above, for the Piccolo board. */
- /* this also has the side effect of resetting the board's */
- /* output selection logic to use the Amiga's display in single */
- /* monitor systems - which is currently what we want. */
-
- /* set RESET bit in special function register */
- *piccolo_reg = 0x01;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit */
- *piccolo_reg = 0x51;
-}
-
-static void reset_sd64(const struct ConfigDev *cd)
-{
- volatile u_char *sd64_reg = (u_char *)(cd->cd_BoardAddr+0x8000);
-
- /* FN: the same stuff as above, for the SD64 board. */
- /* just as on the Piccolo, this also resets the monitor switch */
-
- /* set RESET bit in special function register */
- *sd64_reg = 0x1f;
- /* actually, only a few cycles delay are required... */
- Sleep(1000000);
- /* clear reset bit AND switch monitor bit (0x20) */
- *sd64_reg = 0x4f;
-}
-
-static void reset_ariadne(const struct ConfigDev *cd)
-{
- volatile u_short *lance_rdp = (u_short *)(cd->cd_BoardAddr+0x0370);
- volatile u_short *lance_rap = (u_short *)(cd->cd_BoardAddr+0x0372);
- volatile u_short *lance_reset = (u_short *)(cd->cd_BoardAddr+0x0374);
-
- volatile u_char *pit_paddr = (u_char *)(cd->cd_BoardAddr+0x1004);
- volatile u_char *pit_pbddr = (u_char *)(cd->cd_BoardAddr+0x1006);
- volatile u_char *pit_pacr = (u_char *)(cd->cd_BoardAddr+0x100b);
- volatile u_char *pit_pbcr = (u_char *)(cd->cd_BoardAddr+0x100e);
- volatile u_char *pit_psr = (u_char *)(cd->cd_BoardAddr+0x101a);
-
- u_short in;
-
- Disable();
-
- /*
- * Reset the Ethernet part (Am79C960 PCnet-ISA)
- */
-
- in = *lance_reset; /* Reset Chip on Read Access */
- *lance_rap = 0x0000; /* PCnet-ISA Controller Status (CSR0) */
- *lance_rdp = 0x0400; /* STOP */
-
- /*
- * Reset the Parallel part (MC68230 PI/T)
- */
-
- *pit_pacr &= 0xfd; /* Port A Control Register */
- *pit_pbcr &= 0xfd; /* Port B Control Register */
- *pit_psr = 0x05; /* Port Status Register */
- *pit_paddr = 0x00; /* Port A Data Direction Register */
- *pit_pbddr = 0x00; /* Port B Data Direction Register */
-
- Enable();
-}
-
-static void reset_hydra(const struct ConfigDev *cd)
-{
- volatile u_char *nic_cr = (u_char *)(cd->cd_BoardAddr+0xffe1);
- volatile u_char *nic_isr = (u_char *)(cd->cd_BoardAddr+0xffe1 + 14);
- int n = 5000;
-
- Disable();
-
- *nic_cr = 0x21; /* nic command register: software reset etc. */
- while (((*nic_isr & 0x80) == 0) && --n) /* wait for reset to complete */
- ;
-
- Enable();
-}
-
-#if 0
-static void reset_a2060(const struct ConfigDev *cd)
-{
-#error reset_a2060: not yet implemented
-}
-#endif
-
-
-#ifdef ZKERNEL
-
-#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS)
-#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1)
-#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0; /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000 /* window size--must be a power of two, and */
- /* at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#define malloc(x) AllocVec(x, MEMF_FAST | MEMF_PUBLIC)
-#define free(x) FreeVec(x)
-
-#ifdef LILO
-#include "inflate.c"
-#else
-#include "../../../../lib/inflate.c"
-#endif
-
-static void gzip_mark(void **ptr)
-{
-}
-
-static void gzip_release(void **ptr)
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf(void)
-{
- if (exit_code)
- return -1;
-
- insize = Read(Zinfd, inbuf, INBUFSIZ);
- if (insize <= 0)
- return -1;
-
- inptr = 1;
- return(inbuf[0]);
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
- int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
- if (exit_code)
- return;
-
- if (chunk >= ZFILE_N_CHUNKS) {
- error("Compressed image too large! Aborting.\n");
- return;
- }
- if (!ZFile[chunk]) {
- if (!(ZFile[chunk] = (char *)AllocMem(ZFILE_CHUNK_SIZE,
- MEMF_FAST | MEMF_PUBLIC))) {
- error("Out of memory for decompresing kernel image\n");
- return;
- }
- }
- memcpy(ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt);
- Zwpos += outcnt;
-
-#define DISPLAY_BITS 10
- if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0)
- PutChar('.');
-
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void error(char *x)
-{
- Printf("\n%s", x);
- exit_code = 1;
-}
-
-static inline int call_sub(int (*func)(void), void *stackp)
-{
- register int _res __asm("d0");
- register int (*a0)(void) __asm("a0") = func;
- register int (*a1)(void) __asm("a1") = stackp;
-
- __asm __volatile ("movel sp,a2;"
- "movel a1,sp;"
- "jsr a0@;"
- "movel a2,sp"
- : "=r" (_res)
- : "r" (a0), "r" (a1)
- : "a0", "a1", "a2", "d0", "d1", "memory");
- return(_res);
-}
-
-static int load_zkernel(int fd)
-{
- int i, err = -1;
-#define ZSTACKSIZE (16384)
- u_long *zstack;
-
- for (i = 0; i < ZFILE_N_CHUNKS; ++i)
- ZFile[i] = NULL;
- Zinfd = fd;
- Seek(fd, 0);
-
- if (!(inbuf = (uch *)AllocMem(INBUFSIZ, MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip buffer\n");
- else {
- if (!(window = (uch *)AllocMem(WSIZE, MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip window\n");
- else {
- if (!(zstack = (u_long *)AllocMem(ZSTACKSIZE,
- MEMF_FAST | MEMF_PUBLIC)))
- Puts("Couldn't allocate gunzip stack\n");
- else {
- Puts("Uncompressing kernel image ");
- makecrc();
- if (!(err = call_sub(gunzip, (char *)zstack+ZSTACKSIZE)))
- Puts("done\n");
- ZFileSize = Zwpos;
- FreeMem(zstack, ZSTACKSIZE);
- }
- FreeMem(window, WSIZE);
- window = NULL;
- }
- FreeMem(inbuf, INBUFSIZ);
- inbuf = NULL;
- }
- Close(Zinfd); /* input file not needed anymore */
- return(err);
-}
-
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. (Roman)
- */
-
-static int KRead(int fd, void *buf, int cnt)
-{
- unsigned done = 0;
-
- if (!ZFileSize)
- return(Read(fd, buf, cnt));
-
- if (ZFpos + cnt > ZFileSize)
- cnt = ZFileSize - ZFpos;
-
- while (cnt > 0) {
- unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (ZFpos + n > endchunk)
- n = endchunk - ZFpos;
- memcpy(buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n);
- cnt -= n;
- buf += n;
- done += n;
- ZFpos += n;
-
- if (ZFpos == endchunk) {
- FreeMem(ZFile[chunk], ZFILE_CHUNK_SIZE);
- ZFile[chunk] = NULL;
- }
- }
-
- return(done);
-}
-
-
-static int KSeek(int fd, int offset)
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!ZFileSize)
- return(Seek(fd, offset));
-
- oldpos = ZFpos;
- ZFpos = offset;
- if (ZFpos < 0) {
- ZFpos = 0;
- return(-1);
- } else if (ZFpos > ZFileSize) {
- ZFpos = ZFileSize;
- return(-1);
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> ZFILE_CHUNK_BITS;
- newchunk = ZFpos >> ZFILE_CHUNK_BITS;
- while(oldchunk < newchunk) {
- if (ZFile[oldchunk]) {
- FreeMem(ZFile[oldchunk], ZFILE_CHUNK_SIZE);
- ZFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
- return(ZFpos);
-}
-
-
-static void free_zfile(void)
-{
- int i;
-
- for (i = 0; i < ZFILE_N_CHUNKS; ++i)
- if (ZFile[i]) {
- FreeMem(ZFile[i], ZFILE_CHUNK_SIZE);
- ZFile[i] = NULL;
- }
-}
-
-static int KClose(int fd)
-{
- if (ZFileSize) {
- free_zfile();
- ZFileSize = 0;
- } else
- Close(fd);
- return(0);
-}
-#endif /* ZKERNEL */
diff --git a/arch/m68k/boot/amiga/linuxboot.h b/arch/m68k/boot/amiga/linuxboot.h
index e04425a3a..e69de29bb 100644
--- a/arch/m68k/boot/amiga/linuxboot.h
+++ b/arch/m68k/boot/amiga/linuxboot.h
@@ -1,455 +0,0 @@
-/*
- * linux/arch/m68k/boot/amiga/linuxboot.h -- Generic routine to boot Linux/m68k
- * on Amiga, used by both Amiboot and
- * Amiga-Lilo.
- *
- * Created 1996 by Geert Uytterhoeven
- *
- *
- * This file is based on the original bootstrap code (bootstrap.c):
- *
- * Copyright (C) 1993, 1994 Hamish Macdonald
- * Greg Harp
- *
- * with work by Michael Rausch
- * Geert Uytterhoeven
- * Frank Neumann
- * Andreas Schwab
- *
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-
-#include <asm/setup.h>
-#include <linux/zorro.h>
-
-
- /*
- * Amiboot Version
- */
-
-#define AMIBOOT_VERSION "5.5"
-
-
- /*
- * Amiga Bootinfo Definitions
- *
- * All limits herein are `soft' limits, i.e. they don't put constraints
- * on the actual parameters in the kernel.
- */
-
-struct amiga_bootinfo {
- u_long machtype; /* machine type = MACH_AMIGA */
- u_long cputype; /* system CPU */
- u_long fputype; /* system FPU */
- u_long mmutype; /* system MMU */
- int num_memory; /* # of memory blocks found */
- struct mem_info memory[NUM_MEMINFO];/* memory description */
- struct mem_info ramdisk; /* ramdisk description */
- char command_line[CL_SIZE]; /* kernel command line parameters */
- u_long model; /* Amiga Model */
- int num_autocon; /* # of autoconfig devices found */
- struct ConfigDev autocon[ZORRO_NUM_AUTO]; /* autoconfig devices */
- u_long chip_size; /* size of chip memory (bytes) */
- u_char vblank; /* VBLANK frequency */
- u_char psfreq; /* power supply frequency */
- u_long eclock; /* EClock frequency */
- u_long chipset; /* native chipset present */
- u_short serper; /* serial port period */
-};
-
-
- /*
- * Parameters passed to linuxboot()
- */
-
-struct linuxboot_args {
- struct amiga_bootinfo bi; /* Initial values override detected values */
- const char *kernelname;
- const char *ramdiskname;
- int debugflag;
- int keep_video;
- int reset_boards;
- u_int baud;
- void (*puts)(const char *str);
- long (*getchar)(void);
- void (*putchar)(char c);
- void (*printf)(const char *fmt, ...);
- int (*open)(const char *path);
- int (*seek)(int fd, int offset);
- int (*read)(int fd, char *buf, int count);
- void (*close)(int fd);
- int (*filesize)(const char *path);
- void (*sleep)(u_long micros);
-};
-
-
- /*
- * Boot the Linux/m68k Operating System
- */
-
-extern u_long linuxboot(const struct linuxboot_args *args);
-
-
- /*
- * Amiga Models
- */
-
-extern const char *amiga_models[];
-extern const u_long first_amiga_model;
-extern const u_long last_amiga_model;
-
-
- /*
- * Exec Library Definitions
- */
-
-#define TRUE (1)
-#define FALSE (0)
-
-
-struct List {
- struct Node *lh_Head;
- struct Node *lh_Tail;
- struct Node *lh_TailPred;
- u_char lh_Type;
- u_char l_pad;
-};
-
-struct MemChunk {
- struct MemChunk *mc_Next; /* pointer to next chunk */
- u_long mc_Bytes; /* chunk byte size */
-};
-
-#define MEMF_PUBLIC (1<<0)
-#define MEMF_CHIP (1<<1)
-#define MEMF_FAST (1<<2)
-#define MEMF_LOCAL (1<<8)
-#define MEMF_CLEAR (1<<16)
-
-struct MemHeader {
- struct Node mh_Node;
- u_short mh_Attributes; /* characteristics of this region */
- struct MemChunk *mh_First; /* first free region */
- void *mh_Lower; /* lower memory bound */
- void *mh_Upper; /* upper memory bound+1 */
- u_long mh_Free; /* total number of free bytes */
-};
-
-struct ExecBase {
- u_char fill1[20];
- u_short Version;
- u_char fill2[274];
- u_short AttnFlags;
- u_char fill3[24];
- struct List MemList;
- u_char fill4[194];
- u_char VBlankFrequency;
- u_char PowerSupplyFrequency;
- u_char fill5[36];
- u_long ex_EClockFrequency;
- u_char fill6[60];
-};
-
-#define AFB_68020 (1)
-#define AFF_68020 (1<<AFB_68020)
-#define AFB_68030 (2)
-#define AFF_68030 (1<<AFB_68030)
-#define AFB_68040 (3)
-#define AFF_68040 (1<<AFB_68040)
-#define AFB_68881 (4)
-#define AFF_68881 (1<<AFB_68881)
-#define AFB_68882 (5)
-#define AFF_68882 (1<<AFB_68882)
-#define AFB_FPU40 (6) /* ONLY valid if AFB_68040 or AFB_68060 */
-#define AFF_FPU40 (1<<AFB_FPU40) /* is set; also set for 68060 FPU */
-#define AFB_68060 (7)
-#define AFF_68060 (1<<AFB_68060)
-
-struct Resident;
-
-
- /*
- * Graphics Library Definitions
- */
-
-struct GfxBase {
- u_char fill1[20];
- u_short Version;
- u_char fill2[194];
- u_short NormalDisplayRows;
- u_short NormalDisplayColumns;
- u_char fill3[16];
- u_char ChipRevBits0;
- u_char fill4[307];
-};
-
-#define GFXB_HR_AGNUS (0)
-#define GFXF_HR_AGNUS (1<<GFXB_HR_AGNUS)
-#define GFXB_HR_DENISE (1)
-#define GFXF_HR_DENISE (1<<GFXB_HR_DENISE)
-#define GFXB_AA_ALICE (2)
-#define GFXF_AA_ALICE (1<<GFXB_AA_ALICE)
-#define GFXB_AA_LISA (3)
-#define GFXF_AA_LISA (1<<GFXB_AA_LISA)
-
- /*
- * HiRes(=Big) Agnus present; i.e.
- * 1MB chipmem, big blits (none of interest so far) and programmable sync
- */
-#define GFXG_OCS (GFXF_HR_AGNUS)
- /*
- * HiRes Agnus/Denise present; we are running on ECS
- */
-#define GFXG_ECS (GFXF_HR_AGNUS|GFXF_HR_DENISE)
- /*
- * Alice and Lisa present; we are running on AGA
- */
-#define GFXG_AGA (GFXF_AA_ALICE|GFXF_AA_LISA)
-
-#define SETCHIPREV_BEST (0xffffffff)
-#define HIRES (0x8000)
-
-struct View;
-
-
- /*
- * Amiga Shared Library/Device Functions
- */
-
-extern const struct ExecBase *SysBase;
-
-#define LVOAllocMem (-0xc6)
-#define LVOAllocVec (-0x2ac)
-#define LVOCacheControl (-0x288)
-#define LVODisable (-0x78)
-#define LVOEnable (-0x7e)
-#define LVOFindResident (-0x60)
-#define LVOFreeMem (-0xd2)
-#define LVOFreeVec (-0x2b2)
-#define LVOOpenresource (-0x1f2)
-#define LVOSuperState (-0x96)
-#define LVOSupervisor (-0x1e)
-
-static __inline void *AllocMem(u_long byteSize, u_long requirements)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = byteSize;
- register u_long d1 __asm("d1") = requirements;
-
- __asm __volatile ("jsr a6@(-0xc6)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline void *AllocVec(u_long byteSize, u_long requirements)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = byteSize;
- register u_long d1 __asm("d1") = requirements;
-
- __asm __volatile ("jsr a6@(-0x2ac)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline u_long CacheControl(u_long cacheBits, u_long cacheMask)
-{
- register u_long _res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long d0 __asm("d0") = cacheBits;
- register u_long d1 __asm("d1") = cacheMask;
-
- __asm __volatile ("jsr a6@(-0x288)"
- : "=r" (_res)
- : "r" (_base), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline void Disable(void)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x78)"
- : /* no output */
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void Enable(void)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x7e)"
- : /* no output */
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline struct Resident *FindResident(const u_char *name)
-{
- register struct Resident *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register const u_char *a1 __asm("a1") = name;
-
- __asm __volatile ("jsr a6@(-0x60)"
- : "=r" (_res)
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
- return _res;
-}
-
-static __inline void FreeMem(void *memoryBlock, u_long byteSize)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register void *a1 __asm("a1") = memoryBlock;
- register u_long d0 __asm("d0") = byteSize;
-
- __asm __volatile ("jsr a6@(-0xd2)"
- : /* no output */
- : "r" (_base), "r" (a1), "r" (d0)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void FreeVec(void *memoryBlock)
-{
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register void *a1 __asm("a1") = memoryBlock;
-
- __asm __volatile ("jsr a6@(-0x2b2)"
- : /* no output */
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline void *OpenResource(const u_char *resName)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register const u_char *a1 __asm("a1") = resName;
-
- __asm __volatile ("jsr a6@(-0x1f2)"
- : "=r" (_res)
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
- return _res;
-}
-
-static __inline void *SuperState(void)
-{
- register void *_res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
-
- __asm __volatile ("jsr a6@(-0x96)"
- : "=r" (_res)
- : "r" (_base)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-static __inline u_long Supervisor(u_long (*userfunc)(void))
-{
- register u_long _res __asm("d0");
- register const struct ExecBase *_base __asm("a6") = SysBase;
- register u_long (*d7)() __asm("d7") = userfunc;
-
- __asm __volatile ("exg d7,a5;"
- "jsr a6@(-0x1e);"
- "exg d7,a5"
- : "=r" (_res)
- : "r" (_base), "r" (d7)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
-extern const struct ExpansionBase *ExpansionBase;
-
-#define LVOFindConfigDev (-0x48)
-
-static __inline struct ConfigDev *FindConfigDev(struct ConfigDev *oldConfigDev,
- long manufacturer, long product)
-{
- register struct ConfigDev *_res __asm("d0");
- register const struct ExpansionBase *_base __asm("a6") = ExpansionBase;
- register struct ConfigDev *a0 __asm("a0") = oldConfigDev;
- register long d0 __asm("d0") = manufacturer;
- register long d1 __asm("d1") = product;
-
- __asm __volatile ("jsr a6@(-0x48)"
- : "=r" (_res)
- : "r" (_base), "r" (a0), "r" (d0), "r" (d1)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
-extern const struct GfxBase *GfxBase;
-
-#define LVOLoadView (-0xde)
-#define LVOSetChipRev (-0x378)
-
-static __inline void LoadView(struct View *view)
-{
- register const struct GfxBase *_base __asm("a6") = GfxBase;
- register struct View *a1 __asm("a1") = view;
-
- __asm __volatile ("jsr a6@(-0xde)"
- : /* no output */
- : "r" (_base), "r" (a1)
- : "a0", "a1", "d0", "d1", "memory");
-}
-
-static __inline u_long SetChipRev(u_long want)
-{
- register u_long _res __asm("d0");
- register const struct GfxBase *_base __asm("a6") = GfxBase;
- register u_long d0 __asm("d0") = want;
-
- __asm __volatile ("jsr a6@(-0x378)"
- : "=r" (_res)
- : "r" (_base), "r" (d0)
- : "a0", "a1", "d0", "d1", "memory");
- return(_res);
-}
-
-
- /*
- * Bootstrap Support Functions
- */
-
-static __inline void disable_mmu(void)
-{
- if (SysBase->AttnFlags & AFF_68040)
- __asm __volatile ("moveq #0,d0;"
- ".long 0x4e7b0003;" /* movec d0,tc */
- ".long 0x4e7b0004;" /* movec d0,itt0 */
- ".long 0x4e7b0005;" /* movec d0,itt1 */
- ".long 0x4e7b0006;" /* movec d0,dtt0 */
- ".long 0x4e7b0007" /* movec d0,dtt1 */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- else {
- __asm __volatile ("subl #4,sp;"
- "pmove tc,sp@;"
- "bclr #7,sp@;"
- "pmove sp@,tc;"
- "addl #4,sp");
- if (SysBase->AttnFlags & AFF_68030)
- __asm __volatile ("clrl sp@-;"
- ".long 0xf0170800;" /* pmove sp@,tt0 */
- ".long 0xf0170c00;" /* pmove sp@,tt1 */
- "addql #4,sp");
- }
-}
diff --git a/arch/m68k/boot/atari/bootp.c b/arch/m68k/boot/atari/bootp.c
index affe636b8..e69de29bb 100644
--- a/arch/m68k/boot/atari/bootp.c
+++ b/arch/m68k/boot/atari/bootp.c
@@ -1,814 +0,0 @@
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bootp.h"
-
-
-/* --------------------------------------------------------------------- */
-/* Protocol Header Structures */
-
-struct etherhdr {
- HWADDR dst_addr;
- HWADDR src_addr;
- unsigned short type;
-};
-
-struct arphdr {
- unsigned short hrd; /* format of hardware address */
- unsigned short pro; /* format of protocol address */
- unsigned char hln; /* length of hardware address */
- unsigned char pln; /* length of protocol address */
- unsigned short op; /* ARP opcode (command) */
- unsigned char addr[0]; /* addresses (var len) */
-};
-
-struct iphdr {
- unsigned char version : 4;
- unsigned char ihl : 4;
- unsigned char tos;
- unsigned short tot_len;
- unsigned short id;
- unsigned short frag_off;
- unsigned char ttl;
- unsigned char protocol;
- unsigned short chksum;
- IPADDR src_addr;
- IPADDR dst_addr;
-};
-
-struct udphdr {
- unsigned short src_port;
- unsigned short dst_port;
- unsigned short len;
- unsigned short chksum;
-};
-
-struct bootp {
- unsigned char op; /* packet opcode type */
- unsigned char htype; /* hardware addr type */
- unsigned char hlen; /* hardware addr length */
- unsigned char hops; /* gateway hops */
- unsigned long xid; /* transaction ID */
- unsigned short secs; /* seconds since boot began */
- unsigned short unused;
- IPADDR ciaddr; /* client IP address */
- IPADDR yiaddr; /* 'your' IP address */
- IPADDR siaddr; /* server IP address */
- IPADDR giaddr; /* gateway IP address */
- unsigned char chaddr[16]; /* client hardware address */
- unsigned char sname[64]; /* server host name */
- unsigned char file[128]; /* boot file name */
- unsigned char vend[64]; /* vendor-specific area */
-};
-
-struct tftp_req {
- unsigned short opcode;
- char name[512];
-};
-
-struct tftp_data {
- unsigned short opcode;
- unsigned short nr;
- unsigned char data[512];
-};
-
-struct tftp_ack {
- unsigned short opcode;
- unsigned short nr;
-};
-
-struct tftp_error {
- unsigned short opcode;
- unsigned short errcode;
- char str[512];
-};
-
-
-typedef struct {
- struct etherhdr ether;
- struct arphdr arp;
-} ARP;
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
-} UDP;
-
-#define UDP_BOOTPS 67
-#define UDP_BOOTPC 68
-#define UDP_TFTP 69
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
- struct bootp bootp;
-} BOOTP;
-
-#define BOOTREQUEST 1
-#define BOOTREPLY 2
-#define BOOTP_RETRYS 5
-
-typedef struct {
- struct etherhdr ether;
- struct iphdr ip;
- struct udphdr udp;
- union tftp {
- unsigned short opcode;
- struct tftp_req req;
- struct tftp_data data;
- struct tftp_ack ack;
- struct tftp_error error;
- } tftp;
-} TFTP;
-
-#define TFTP_RRQ 1
-#define TFTP_WRQ 2
-#define TFTP_DATA 3
-#define TFTP_ACK 4
-#define TFTP_ERROR 5
-
-
-/* --------------------------------------------------------------------- */
-/* Addresses */
-
-static HWADDR MyHwaddr;
-static HWADDR ServerHwaddr;
-static IPADDR MyIPaddr;
-static IPADDR ServerIPaddr;
-
-static IPADDR IP_Unknown_Addr = 0x00000000;
-static IPADDR IP_Broadcast_Addr = 0xffffffff;
-static HWADDR Eth_Broadcast_Addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-
-#define HZ 200
-#define _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-/* --------------------------------------------------------------------- */
-/* Error Strings */
-
-static char *ErrStr[] = {
- "timeout",
- "general Ethernet transmit error",
- "general Ethernet receive error",
- "Ethernet framing error",
- "Ethernet overflow error",
- "Ethernet CRC error"
-};
-
-
-/* --------------------------------------------------------------------- */
-/* Kfile Emulation Definitions */
-
-#define KFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define KFILE_CHUNK_SIZE (1 << KFILE_CHUNK_BITS)
-#define KFILE_CHUNK_MASK (KFILE_CHUNK_SIZE-1)
-#define KFILE_N_CHUNKS (2*1024*1024/KFILE_CHUNK_SIZE)
-
-char *KFile[KFILE_N_CHUNKS];
-int KFileSize = 0;
-int KFpos = 0;
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static void free_kfile( void );
-static int bootp( char *image_name );
-static int tftp( char *image_name );
-static int udp_send( UDP *pkt, int len, int fromport, int toport );
-static unsigned short ip_checksum( struct iphdr *buf );
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport );
-static void print_ip( IPADDR addr );
-static void print_hw( HWADDR addr );
-static int check_ethif( void );
-static int eth_send( Packet *pkt, int len );
-static int eth_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-
-/* --------------------------------------------------------------------- */
-/* Interface to bootstrap.c */
-
-/* get_remote_kernel():
- * Perform all necessary steps to get the kernel image
- * from the boot server. If successfull (retval == 0), subsequent calls to
- * kread() can access the data. Fatal errors (i.e., retrying is useless)
- * return -2, others -1.
- */
-
-int get_remote_kernel( const char *kname /* optional */ )
-
-{ char image_name[256];
- int rv;
-
- /* Check if a Ethernet interface is present and determine the Ethernet
- * address */
- if (check_ethif() < 0) {
- printf( "No Ethernet interface found -- no remote boot possible.\n" );
- return( -2 );
- }
-
- /* Do a BOOTP request to find out our IP address and the kernel image's
- * name; we also learn the IP and Ethernet address of our server */
- if (kname)
- strcpy( image_name, kname );
- else
- *image_name = 0;
- if ((rv = bootp( image_name )) < 0)
- return( rv );
-
- /* Now start a TFTP connection to receive the kernel image */
- if ((rv = tftp( image_name )) < 0)
- return( rv );
-
- return( 0 );
-}
-
-
-/* ll_read(), ll_lseek(), ll_close():
- * Functions for accessing the received kernel image like with read(),
- * lseek(), close().
- */
-
-int ll_read( int fd, void *buf, unsigned cnt )
-
-{ unsigned done = 0;
-
- if (!KFileSize)
- return( read( fd, buf, cnt ) );
-
- if (KFpos + cnt > KFileSize)
- cnt = KFileSize - KFpos;
-
- while( cnt > 0 ) {
- unsigned chunk = KFpos >> KFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << KFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (KFpos + n > endchunk)
- n = endchunk - KFpos;
- memcpy( buf, KFile[chunk] + (KFpos & KFILE_CHUNK_MASK), n );
- cnt -= n;
- buf += n;
- done += n;
- KFpos += n;
-
- if (KFpos == endchunk) {
- free( KFile[chunk] );
- KFile[chunk] = NULL;
- }
- }
-
- return( done );
-}
-
-
-int ll_lseek( int fd, int where, int whence )
-
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!KFileSize)
- return( lseek( fd, where, whence ) );
-
- oldpos = KFpos;
- switch( whence ) {
- case SEEK_SET:
- KFpos = where;
- break;
- case SEEK_CUR:
- KFpos += where;
- break;
- case SEEK_END:
- KFpos = KFileSize + where;
- break;
- default:
- return( -1 );
- }
- if (KFpos < 0) {
- KFpos = 0;
- return( -1 );
- }
- else if (KFpos > KFileSize) {
- KFpos = KFileSize;
- return( -1 );
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> KFILE_CHUNK_BITS;
- newchunk = KFpos >> KFILE_CHUNK_BITS;
- while( oldchunk < newchunk ) {
- if (KFile[oldchunk]) {
- free( KFile[oldchunk] );
- KFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
-
- return( KFpos );
-}
-
-
-int ll_close( int fd )
-
-{
- if (!KFileSize)
- return( close( fd ) );
-
- free_kfile();
- return( 0 );
-}
-
-
-static void free_kfile( void )
-
-{ int i;
-
- for( i = 0; i < KFILE_N_CHUNKS; ++i )
- if (KFile[i]) free( KFile[i] );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/* BOOTP Procedure */
-
-
-static int bootp( char *image_name )
-
-{ BOOTP req;
- Packet _reply;
- BOOTP *reply = (BOOTP *)_reply;
- static unsigned char mincookie[] = { 99, 130, 83, 99, 255 };
- unsigned long starttime, rancopy;
- int err, len, retry;
-
- memset( (char *)&req, 0, sizeof(req) );
- /* Now fill in the packet... */
- req.bootp.op = BOOTREQUEST;
- req.bootp.htype = 1; /* 10Mb/s Ethernet */
- req.bootp.hlen = 6;
- memcpy( req.bootp.chaddr, &MyHwaddr, ETHADDRLEN );
-
- /* Put in the minimal RFC1497 Magic cookie */
- memcpy( req.bootp.vend, mincookie, sizeof(mincookie) );
- /* Put the user precified bootfile name in place */
- memcpy( req.bootp.file, image_name, strlen(image_name)+1);
-
- starttime = _hz_200;
- for( retry = 0; retry < BOOTP_RETRYS; ++retry ) {
-
- /* Initialize server addresses and own IP to defaults */
- ServerIPaddr = IP_Broadcast_Addr; /* 255.255.255.255 */
- MyIPaddr = IP_Unknown_Addr; /* 0.0.0.0 */
- memcpy( ServerHwaddr, Eth_Broadcast_Addr, ETHADDRLEN );
-
- if (retry)
- sleep( 3 );
-
- req.bootp.xid = rancopy = _hz_200;
- req.bootp.secs = (_hz_200 - starttime) / HZ;
-
- if ((err = udp_send( (UDP *)&req, sizeof(req.bootp),
- UDP_BOOTPC, UDP_BOOTPS )) < 0) {
- printf( "bootp send: %s\n", ErrStr[-err-1] );
- continue;
- }
-
- if ((err = udp_rcv( (UDP *)reply, &len,
- UDP_BOOTPS, UDP_BOOTPC )) < 0) {
- printf( "bootp rcv: %s\n", ErrStr[-err-1] );
- continue;
- }
- if (len < sizeof(struct bootp)) {
- printf( "received short BOOTP packet (%d bytes)\n", len );
- continue;
- }
-
- if (reply->bootp.xid == rancopy)
- /* Ok, got the answer */
- break;
- printf( "bootp: xid mismatch\n" );
- }
- if (retry >= BOOTP_RETRYS) {
- printf( "No response from a bootp server\n" );
- return( -2 );
- }
-
- ServerIPaddr = reply->bootp.siaddr;
- memcpy( ServerHwaddr, reply->ether.src_addr, ETHADDRLEN );
- printf( "\nBoot server is " );
- if (strlen(reply->bootp.sname) > 0)
- printf( "%s, IP ", reply->bootp.sname );
- print_ip( ServerIPaddr );
- printf( ", HW address " );
- print_hw( ServerHwaddr );
- printf( "\n" );
-
- MyIPaddr = reply->bootp.yiaddr;
- printf( "My IP address is " );
- print_ip( MyIPaddr );
- printf( "\n" );
-
- strcpy( image_name, reply->bootp.file );
- return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* TFTP Procedure */
-
-
-static int tftp( char *image_name )
-
-{ TFTP spkt;
- Packet _rpkt;
- TFTP *rpkt = (TFTP *)&_rpkt;
- unsigned short mytid, rtid = 0;
- int blk, retries, i, wpos, err, len, datalen;
- static char rotchar[4] = { '|', '/', '-', '\\' };
-
- retries = 5;
- /* Construct and send a read request */
- repeat_req:
- spkt.tftp.req.opcode = TFTP_RRQ;
- strcpy( spkt.tftp.req.name, image_name );
- strcpy( spkt.tftp.req.name + strlen(spkt.tftp.req.name) + 1, "octet" );
- mytid = _hz_200 & 0xffff;
-
- if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.req.opcode) +
- strlen(image_name) + 1 +
- strlen( "octect" ) +1,
- mytid, UDP_TFTP )) < 0) {
- printf( "TFTP RREQ: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_req;
- return( err == ETIMEO ? -2 : -1 );
- }
-
- retries = 5;
- for( i = 0; i < KFILE_N_CHUNKS; ++i )
- KFile[i] = NULL;
- wpos = 0;
- printf( "Receiving kernel image %s:\n", image_name );
-
- for( blk = 1; ; ++blk ) {
-
- repeat_data:
- if ((err = udp_rcv( (UDP *)rpkt, &len, rtid, mytid )) < 0) {
- printf( "TFTP rcv: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_data;
- goto err;
- }
- if (rtid == 0)
- /* Store the remote port at the first packet received */
- rtid = rpkt->udp.src_port;
-
- if (rpkt->tftp.opcode == TFTP_ERROR) {
- if (strlen(rpkt->tftp.error.str) > 0)
- printf( "TFTP error: %s\n", rpkt->tftp.error.str );
- else
- printf( "TFTP error #%d (no description)\n",
- rpkt->tftp.error.errcode );
- goto err;
- }
- else if (rpkt->tftp.opcode != TFTP_DATA) {
- printf( "Bad TFTP packet type: %d\n", rpkt->tftp.opcode );
- if (--retries > 0)
- goto repeat_data;
- goto err;
- }
-
- if (rpkt->tftp.data.nr != blk) {
- /* doubled data packet; ignore it */
- goto repeat_data;
- }
- datalen = len - sizeof(rpkt->tftp.data.opcode) -
- sizeof(rpkt->tftp.data.nr);
-
- /* store data */
- if (datalen > 0) {
- int chunk = wpos >> KFILE_CHUNK_BITS;
- if (chunk >= KFILE_N_CHUNKS) {
- printf( "TFTP: file too large! Aborting.\n" );
- out_of_mem:
- spkt.tftp.error.opcode = TFTP_ERROR;
- spkt.tftp.error.errcode = 3;
- strcpy( spkt.tftp.error.str, "Out of memory" );
- udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack), mytid, rtid );
- goto err;
- }
- if (!KFile[chunk]) {
- if (!(KFile[chunk] = malloc( KFILE_CHUNK_SIZE ))) {
- printf( "TFTP: Out of memory for kernel image\n" );
- goto out_of_mem;
- }
- }
- memcpy( KFile[chunk] + (wpos & KFILE_CHUNK_MASK),
- rpkt->tftp.data.data, datalen );
- wpos += datalen;
-
-#define DISPLAY_BITS 13
- if ((wpos & ((1 << DISPLAY_BITS)-1)) == 0) {
- printf( "\r %c %7d Bytes ",
- rotchar[(wpos>>DISPLAY_BITS)&3], wpos );
- fflush( stdout );
- }
- }
-
- /* Send ACK packet */
- repeat_ack:
- spkt.tftp.ack.opcode = TFTP_ACK;
- spkt.tftp.ack.nr = blk;
- if ((err = udp_send( (UDP *)&spkt, sizeof(spkt.tftp.ack),
- mytid, rtid )) < 0) {
- printf( "TFTP ACK: %s\n", ErrStr[-err-1] );
- if (--retries > 0)
- goto repeat_ack;
- goto err;
- }
-
- if (datalen < 512) {
- /* This was the last packet */
- printf( "\r %7d Bytes done\n\n", wpos );
- break;
- }
-
- retries = 5;
- }
-
- KFileSize = wpos;
- return( 0 );
-
- err:
- free_kfile();
- return( -1 );
-}
-
-
-
-/* --------------------------------------------------------------------- */
-/* UDP/IP Protocol Quick Hack Implementation */
-
-
-static int udp_send( UDP *pkt, int len, int fromport, int toport )
-
-{
- /* UDP layer */
- pkt->udp.src_port = fromport;
- pkt->udp.dst_port = toport;
- pkt->udp.len = (len += sizeof(struct udphdr));
- pkt->udp.chksum = 0; /* Too lazy to calculate :-) */
-
- /* IP layer */
- pkt->ip.version = 4;
- pkt->ip.ihl = 5;
- pkt->ip.tos = 0;
- pkt->ip.tot_len = (len += sizeof(struct iphdr));
- pkt->ip.id = 0;
- pkt->ip.frag_off = 0;
- pkt->ip.ttl = 255;
- pkt->ip.protocol = 17; /* UDP */
- pkt->ip.src_addr = MyIPaddr;
- pkt->ip.dst_addr = ServerIPaddr;
- pkt->ip.chksum = 0;
- pkt->ip.chksum = ip_checksum( &pkt->ip );
-
- /* Ethernet layer */
- memcpy( &pkt->ether.dst_addr, ServerHwaddr, ETHADDRLEN );
- memcpy( &pkt->ether.src_addr, MyHwaddr, ETHADDRLEN );
- pkt->ether.type = 0x0800;
- len += sizeof(struct etherhdr);
-
- return( eth_send( (Packet *)pkt, len ) );
-}
-
-
-static unsigned short ip_checksum( struct iphdr *buf )
-
-{ unsigned long sum = 0, wlen = 5;
-
- __asm__ ("subqw #1,%2\n"
- "1:\t"
- "movel %1@+,%/d0\n\t"
- "addxl %/d0,%0\n\t"
- "dbra %2,1b\n\t"
- "movel %0,%/d0\n\t"
- "swap %/d0\n\t"
- "addxw %/d0,%0\n\t"
- "clrw %/d0\n\t"
- "addxw %/d0,%0"
- : "=d" (sum), "=a" (buf), "=d" (wlen)
- : "0" (sum), "1" (buf), "2" (wlen)
- : "d0");
- return( (~sum) & 0xffff );
-}
-
-
-static int udp_rcv( UDP *pkt, int *len, int fromport, int atport )
-
-{ int err;
-
- repeat:
- if ((err = eth_rcv( (Packet *)pkt, len )))
- return( err );
-
- /* Ethernet layer */
- if (pkt->ether.type == 0x0806) {
- /* ARP */
- ARP *pk = (ARP *)pkt;
- unsigned char *shw, *sip, *thw, *tip;
-
- if (pk->arp.hrd != 1 || pk->arp.pro != 0x0800 ||
- pk->arp.op != 1 || MyIPaddr == IP_Unknown_Addr)
- /* Wrong hardware type or protocol; or reply -> ignore */
- goto repeat;
- shw = pk->arp.addr;
- sip = shw + pk->arp.hln;
- thw = sip + pk->arp.pln;
- tip = thw + pk->arp.hln;
-
- if (memcmp( tip, &MyIPaddr, pk->arp.pln ) == 0) {
- memcpy( thw, shw, pk->arp.hln );
- memcpy( tip, sip, pk->arp.pln );
- memcpy( shw, &MyHwaddr, pk->arp.hln );
- memcpy( sip, &MyIPaddr, pk->arp.pln );
-
- memcpy( &pk->ether.dst_addr, thw, ETHADDRLEN );
- memcpy( &pk->ether.src_addr, &MyHwaddr, ETHADDRLEN );
- eth_send( (Packet *)pk, *len );
- }
- goto repeat;
- }
- else if (pkt->ether.type != 0x0800) {
- printf( "Unknown Ethernet packet type %04x received\n",
- pkt->ether.type );
- goto repeat;
- }
-
- /* IP layer */
- if (MyIPaddr != IP_Unknown_Addr && pkt->ip.dst_addr != MyIPaddr) {
- printf( "Received packet for wrong IP address\n" );
- goto repeat;
- }
- if (ServerIPaddr != IP_Unknown_Addr &&
- ServerIPaddr != IP_Broadcast_Addr &&
- pkt->ip.src_addr != ServerIPaddr) {
- printf( "Received packet from wrong server\n" );
- goto repeat;
- }
- /* If IP header is longer than 5 longs, delete the options */
- if (pkt->ip.ihl > 5) {
- char *udpstart = (char *)((long *)&pkt->ip + pkt->ip.ihl);
- memmove( &pkt->udp, udpstart, *len - (udpstart-(char *)pkt) );
- }
-
- /* UDP layer */
- if (fromport != 0 && pkt->udp.src_port != fromport) {
- printf( "Received packet from wrong port %d\n", pkt->udp.src_port );
- goto repeat;
- }
- if (pkt->udp.dst_port != atport) {
- printf( "Received packet at wrong port %d\n", pkt->udp.dst_port );
- goto repeat;
- }
-
- *len = pkt->udp.len - sizeof(struct udphdr);
- return( 0 );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Address Printing */
-
-
-static void print_ip( IPADDR addr )
-
-{
- printf( "%ld.%ld.%ld.%ld",
- (addr >> 24) & 0xff,
- (addr >> 16) & 0xff,
- (addr >> 8) & 0xff,
- addr & 0xff );
-}
-
-
-static void print_hw( HWADDR addr )
-
-{
- printf( "%02x:%02x:%02x:%02x:%02x:%02x",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] );
-}
-
-
-/* --------------------------------------------------------------------- */
-/* Ethernet Interface Abstraction Layer */
-
-
-#ifdef ETHLL_LANCE
-#include "ethlance.h"
-#endif
-
-static ETHIF_SWITCH *PossibleInterfaces[] = {
-#ifdef ETHLL_LANCE
- &LanceSwitch,
-#endif
-};
-
-#define N_PossibleInterfaces (sizeof(PossibleInterfaces)/sizeof(*PossibleInterfaces))
-
-/* Detected interface */
-static ETHIF_SWITCH *Ethif = NULL;
-
-
-static int check_ethif( void )
-
-{ int i;
-
- /* Check for configured interfaces */
- Ethif = NULL;
- for( i = 0; i < N_PossibleInterfaces; ++i ) {
- if (PossibleInterfaces[i]->probe() >= 0) {
- Ethif = PossibleInterfaces[i];
- break;
- }
- }
- if (!Ethif)
- return( -1 );
-
- if (Ethif->init() < 0) {
- printf( "Ethernet interface initialization failed\n" );
- return( -1 );
- }
- Ethif->get_hwaddr( &MyHwaddr );
- return( 0 );
-}
-
-
-static int eth_send( Packet *pkt, int len )
-
-{
- return( Ethif->snd( pkt, len ));
-}
-
-
-static int eth_rcv( Packet *pkt, int *len )
-
-{
- return( Ethif->rcv( pkt, len ));
-}
-
-
-#if 0
-static void dump_packet( UDP *pkt )
-
-{ int i, l;
- unsigned char *p;
-
- printf( "Packet dump:\n" );
-
- printf( "Ethernet header:\n" );
- printf( " dst addr: " ); print_hw( pkt->ether.dst_addr ); printf( "\n" );
- printf( " src addr: " ); print_hw( pkt->ether.src_addr ); printf( "\n" );
- printf( " type: %04x\n", pkt->ether.type );
-
- printf( "IP header:\n" );
- printf( " version: %d\n", pkt->ip.version );
- printf( " hdr len: %d\n", pkt->ip.ihl );
- printf( " tos: %d\n", pkt->ip.tos );
- printf( " tot_len: %d\n", pkt->ip.tot_len );
- printf( " id: %d\n", pkt->ip.id );
- printf( " frag_off: %d\n", pkt->ip.frag_off );
- printf( " ttl: %d\n", pkt->ip.ttl );
- printf( " prot: %d\n", pkt->ip.protocol );
- printf( " src addr: " ); print_ip( pkt->ip.src_addr ); printf( "\n" );
- printf( " dst addr: " ); print_ip( pkt->ip.dst_addr ); printf( "\n" );
-
- printf( "UDP header:\n" );
- printf( " src port: %d\n", pkt->udp.src_port );
- printf( " dst port: %d\n", pkt->udp.dst_port );
- printf( " len: %d\n", pkt->udp.len );
-
- printf( "Data:" );
- l = pkt->udp.len - sizeof(pkt->udp);
- p = (unsigned char *)&pkt->udp + sizeof(pkt->udp);
- for( i = 0; i < l; ++i ) {
- if ((i % 32) == 0)
- printf( "\n %04x ", i );
- printf( "%02x ", *p );
- }
- printf( "\n" );
-}
-#endif
diff --git a/arch/m68k/boot/atari/bootp.h b/arch/m68k/boot/atari/bootp.h
index 0ee96cdcc..e69de29bb 100644
--- a/arch/m68k/boot/atari/bootp.h
+++ b/arch/m68k/boot/atari/bootp.h
@@ -1,44 +0,0 @@
-#ifndef _bootp_h
-#define _bootp_h
-
-/* --------------------------------------------------------------------- */
-/* Ethernet Definitions */
-
-#define PKTLEN 1544
-typedef unsigned char Packet[PKTLEN];
-
-#define ETHADDRLEN 6
-typedef unsigned char HWADDR[ETHADDRLEN];
-
-typedef struct {
- int (*probe)( void );
- int (*init)( void );
- void (*get_hwaddr)( HWADDR *addr );
- int (*snd)( Packet *pkt, int len );
- int (*rcv)( Packet *pkt, int *len );
-} ETHIF_SWITCH;
-
-
-/* error codes */
-#define ETIMEO -1 /* Timeout */
-#define ESEND -2 /* General send error (carrier, abort, ...) */
-#define ERCV -3 /* General receive error */
-#define EFRAM -4 /* Framing error */
-#define EOVERFL -5 /* Overflow (too long packet) */
-#define ECRC -6 /* CRC error */
-
-
-typedef unsigned long IPADDR;
-
-
-/***************************** Prototypes *****************************/
-
-int get_remote_kernel( const char *kname );
-int ll_read( int fd, void *buf, unsigned cnt );
-int ll_lseek( int fd, int where, int whence );
-int ll_close( int fd );
-
-/************************* End of Prototypes **************************/
-
-#endif /* _bootp_h */
-
diff --git a/arch/m68k/boot/atari/bootstrap.c b/arch/m68k/boot/atari/bootstrap.c
index 84c6a6e4b..e69de29bb 100644
--- a/arch/m68k/boot/atari/bootstrap.c
+++ b/arch/m68k/boot/atari/bootstrap.c
@@ -1,1602 +0,0 @@
-/*
-** bootstrap.c -- Load and launch the Atari Linux kernel
-**
-** Copyright 1993 by Arjan Knor
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-** History:
-** 01 Feb 1997 Implemented kernel decompression (Roman)
-** 28 Nov 1996 Fixed and tested previous change (James)
-** 27 Nov 1996 Compatibility with bootinfo interface version 1.0 (Geert)
-** 12 Nov 1996 Fixed and tested previous change (Andreas)
-** 18 Aug 1996 Updated for the new boot information structure (untested!)
-** (Geert)
-** 10 Dec 1995 BOOTP/TFTP support (Roman)
-** 03 Oct 1995 Allow kernel to be loaded to TT ram again (Andreas)
-** 11 Jul 1995 Add support for ELF format kernel (Andreas)
-** 16 Jun 1995 Adapted to Linux 1.2: kernel always loaded into ST ram
-** (Andreas)
-** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
-** start address is KSTART_ADDR + PAGE_SIZE, this
-** does not need the ugly kludge with
-** -fwritable-strings (++andreas)
-** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
-** mentions all ST-Ram and the mover is located somewhere
-** in the middle of memory (roman)
-** Added the default arguments file known from the other
-** bootstrap version
-** 19 Feb 1994 Changed everything so that it works? (rdv)
-** 14 Mar 1994 New mini-copy routine used (rdv)
-*/
-
-
-#define BOOTINFO_COMPAT_1_0 /* bootinfo interface version 1.0 compatible */
-/* support compressed kernels? */
-#define ZKERNEL
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stddef.h>
-#include <string.h>
-#include <ctype.h>
-#include "sysvars.h"
-#include <osbind.h>
-#include <sys/types.h>
-#include <sys/file.h>
-
-/* linux specific include files */
-#include <linux/a.out.h>
-#include <linux/elf.h>
-#include <asm/page.h>
-
-#define _LINUX_TYPES_H /* Hack to prevent including <linux/types.h> */
-#include <asm/bootinfo.h>
-#include <asm/setup.h>
-
-/* Atari bootstrap include file */
-#include "bootstrap.h"
-
-#define MIN_RAMSIZE (3) /* 3 MB */
-#define TEMP_STACKSIZE 256
-
-extern char *optarg;
-extern int optind;
-static void get_default_args( int *argc, char ***argv );
-static int create_bootinfo(void);
-#ifdef BOOTINFO_COMPAT_1_0
-static int create_compat_bootinfo(void);
-#endif /* BOOTINFO_COMPAT_1_0 */
-static int add_bi_record(u_short tag, u_short size, const void *data);
-static int add_bi_string(u_short tag, const u_char *s);
-/* This is missing in <unistd.h> */
-extern int sync (void);
-
-/* Bootinfo */
-static struct atari_bootinfo bi;
-
-#ifdef BOOTINFO_COMPAT_1_0
-static struct compat_bootinfo compat_bootinfo;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-#define MAX_BI_SIZE (4096)
-static u_long bi_size;
-static union {
-struct bi_record record;
- u_char fake[MAX_BI_SIZE];
-} bi_union;
-
-u_long *cookiejar;
-u_long userstk;
-
-/* getcookie -- function to get the value of the given cookie. */
-static int getcookie(char *cookie, u_long *value)
-{
- int i = 0;
-
- while(cookiejar[i] != 0L) {
- if(cookiejar[i] == *(u_long *)cookie) {
- *value = cookiejar[i + 1];
- return 1;
- }
- i += 2;
- }
- return -1;
-}
-
-static void usage(void)
-{
- fprintf(stderr, "Usage:\n"
- "\tbootstrap [-dst] [-k kernel_executable] [-r ramdisk_file]"
- " [option...]\n");
- exit(EXIT_FAILURE);
-}
-
-/*
- * Copy the kernel and the ramdisk to their final resting places.
- *
- * I assume that the kernel data and the ramdisk reside somewhere
- * in the middle of the memory.
- *
- * This program itself should be somewhere in the first 4096 bytes of memory
- * where the kernel never will be. In this way it can never be overwritten
- * by itself.
- *
- * At this point the registers have:
- * a0: the start of the final kernel
- * a1: the start of the current kernel
- * a2: the end of the final ramdisk
- * a3: the end of the current ramdisk
- * d0: the kernel size
- * d1: the ramdisk size
- */
-asm ("
-.text
-.globl _copyall, _copyallend
-_copyall:
-
- movel a0,a4 /* save the start of the kernel for booting */
-
-1: movel a1@+,a0@+ /* copy the kernel starting at the beginning */
- subql #4,d0
- jcc 1b
-
- tstl d1
- beq 3f
-
-2: movel a3@-,a2@- /* copy the ramdisk starting at the end */
- subql #4,d1
- jcc 2b
-
-3: jmp a4@ /* jump to the start of the kernel */
-_copyallend:
-");
-
-extern char copyall, copyallend;
-
-
-/* Test for a Medusa: This is the only machine on which address 0 is
- * writeable!
- * ...err! On the Afterburner040 (for the Falcon) it's the same... So we do
- * another test with 0x00ff82fe, that gives a bus error on the Falcon, but is
- * in the range where the Medusa always asserts DTACK.
- * On the Hades address 0 is writeable as well and it asserts DTACK on
- * address 0x00ff82fe. To test if the machine is a Hades, address 0xb0000000
- * is tested. On the Medusa this gives a bus error.
- */
-
-int test_medusa( void )
-
-{ int rv = 0;
-
- __asm__ __volatile__
- ( "movel 0x8,a0\n\t"
- "movel sp,a1\n\t"
- "moveb 0x0,d1\n\t"
- "movel #Lberr,0x8\n\t"
- "moveq #0,%0\n\t"
- "clrb 0x0\n\t"
- "nop \n\t"
- "moveb d1,0x0\n\t"
- "nop \n\t"
- "tstb 0x00ff82fe\n\t"
- "nop \n\t"
- "moveq #1,%0\n\t"
- "tstb 0xb0000000\n\t"
- "nop \n\t"
- "moveq #0,%0\n"
- "Lberr:\t"
- "movel a1,sp\n\t"
- "movel a0,0x8"
- : "=d" (rv)
- : /* no inputs */
- : "d1", "a0", "a1", "memory" );
-
- return( rv );
-}
-
-
-/* Test if FPU instructions are executed in hardware, or if they're
- emulated in software. For this, the F-line vector is temporarily
- replaced. */
-
-int test_software_fpu(void)
-{
- int rv = 0;
-
- __asm__ __volatile__
- ( "movel 0x2c,a0\n\t"
- "movel sp,a1\n\t"
- "movel #Lfline,0x2c\n\t"
- "moveq #1,%0\n\t"
- "fnop \n\t"
- "nop \n\t"
- "moveq #0,%0\n"
- "Lfline:\t"
- "movel a1,sp\n\t"
- "movel a0,0x2c"
- : "=d" (rv)
- : /* no inputs */
- : "a0", "a1" );
-
- return rv;
-}
-
-
-void get_medusa_bank_sizes( u_long *bank1, u_long *bank2 )
-
-{ static u_long save_addr;
- u_long test_base, saved_contents[16];
-#define TESTADDR(i) (*((u_long *)((char *)test_base + i*8*MB)))
-#define TESTPAT 0x12345678
- unsigned short oldflags;
- int i;
-
- /* This ensures at least that none of the test addresses conflicts
- * with the test code itself */
- test_base = ((unsigned long)&save_addr & 0x007fffff) | 0x20000000;
- *bank1 = *bank2 = 0;
-
- /* Interrupts must be disabled because arbitrary addresses may be
- * temporarily overwritten, even code of an interrupt handler */
- __asm__ __volatile__ ( "movew sr,%0; oriw #0x700,sr" : "=g" (oldflags) : );
- disable_cache();
-
- /* save contents of the test addresses */
- for( i = 0; i < 16; ++i )
- saved_contents[i] = TESTADDR(i);
-
- /* write 0s into all test addresses */
- for( i = 0; i < 16; ++i )
- TESTADDR(i) = 0;
-
- /* test for bank 1 */
-#if 0
- /* This is Freddi's original test, but it didn't work. */
- TESTADDR(0) = TESTADDR(1) = TESTPAT;
- if (TESTADDR(1) == TESTPAT) {
- if (TESTADDR(2) == TESTPAT)
- *bank1 = 8*MB;
- else if (TESTADDR(3) == TESTPAT)
- *bank1 = 16*MB;
- else
- *bank1 = 32*MB;
- }
- else {
- if (TESTADDR(2) == TESTPAT)
- *bank1 = 0;
- else
- *bank1 = 16*MB;
- }
-#else
- TESTADDR(0) = TESTPAT;
- if (TESTADDR(1) == TESTPAT)
- *bank1 = 8*MB;
- else if (TESTADDR(2) == TESTPAT)
- *bank1 = 16*MB;
- else if (TESTADDR(4) == TESTPAT)
- *bank1 = 32*MB;
- else
- *bank1 = 64*MB;
-#endif
-
- /* test for bank2 */
- if (TESTADDR(8) != 0)
- *bank2 = 0;
- else {
- TESTADDR(8) = TESTPAT;
- if (TESTADDR(9) != 0) {
- if (TESTADDR(10) == TESTPAT)
- *bank2 = 8*MB;
- else
- *bank2 = 32*MB;
- }
- else {
- TESTADDR(9) = TESTPAT;
- if (TESTADDR(10) == TESTPAT)
- *bank2 = 16*MB;
- else
- *bank2 = 64*MB;
- }
- }
-
- /* restore contents of the test addresses and restore interrupt mask */
- for( i = 0; i < 16; ++i )
- TESTADDR(i) = saved_contents[i];
- __asm__ __volatile__ ( "movew %0,sr" : : "g" (oldflags) );
-}
-
-#undef TESTADDR
-#undef TESTPAT
-
-
-static int check_bootinfo_version(char *memptr)
-{
- struct bootversion *bv = (struct bootversion *)memptr;
- unsigned long version = 0;
- int i, kernel_major, kernel_minor, boots_major, boots_minor;
-
- printf( "\n" );
- if (bv->magic == BOOTINFOV_MAGIC) {
- for( i = 0; bv->machversions[i].machtype != 0; ++i ) {
- if (bv->machversions[i].machtype == MACH_ATARI) {
- version = bv->machversions[i].version;
- break;
- }
- }
- }
- if (!version)
- printf("Kernel has no bootinfo version info, assuming 0.0\n");
-
- kernel_major = BI_VERSION_MAJOR(version);
- kernel_minor = BI_VERSION_MINOR(version);
- boots_major = BI_VERSION_MAJOR(ATARI_BOOTI_VERSION);
- boots_minor = BI_VERSION_MINOR(ATARI_BOOTI_VERSION);
- printf("Bootstrap's bootinfo version: %d.%d\n",
- boots_major, boots_minor);
- printf("Kernel's bootinfo version : %d.%d\n",
- kernel_major, kernel_minor);
-
- switch (kernel_major) {
- case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
- if (kernel_minor > boots_minor) {
- printf("Warning: Bootinfo version of bootstrap and kernel "
- "differ!\n");
- printf(" Certain features may not work.\n");
- }
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
- printf("(using backwards compatibility mode)\n");
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- printf("\nThis bootstrap is too %s for this kernel!\n",
- boots_major < kernel_major ? "old" : "new");
- return 0;
- }
- return kernel_major;
-}
-
-
-#ifdef USE_BOOTP
-# include "bootp.h"
-#else
-# define ll_read read
-# define ll_lseek lseek
-# define ll_close close
-#endif
-
-#ifdef ZKERNEL
-static int load_zkernel( int fd );
-static int kread( int fd, void *buf, unsigned cnt );
-static int klseek( int fd, int where, int whence );
-static int kclose( int fd );
-#else
-# define kread read
-# define klseek lseek
-# define kclose close
-#endif
-
-/* ++andreas: this must be inline due to Super */
-static inline void boot_exit (int) __attribute__ ((noreturn));
-static inline void boot_exit(int status)
-{
- /* first go back to user mode */
- (void)Super(userstk);
- getchar();
- exit(status);
-}
-
-int main(int argc, char *argv[])
-{
- int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
- int load_to_stram = 0;
- char *ramdisk_name, *kernel_name, *memptr;
- u_long ST_ramsize, TT_ramsize, memreq;
- u_long cpu_type, fpu_type, mch_type, mint;
- struct exec kexec;
- int elf_kernel = 0;
- Elf32_Ehdr kexec_elf;
- Elf32_Phdr *kernel_phdrs = NULL;
- u_long start_mem, mem_size, rd_size, text_offset = 0, kernel_size;
- int prefer_bootp = 1, kname_set = 0, n_knames;
-#ifdef USE_BOOTP
- int err;
-#endif
- char kname_list[5][64];
- void *bi_ptr;
-
- ramdisk_name = NULL;
- kernel_name = "vmlinux";
-
- /* print the startup message */
- puts("\fLinux/68k Atari Bootstrap version 2.2"
-#ifdef USE_BOOTP
- " (with BOOTP)"
-#endif
- );
- puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
-
- /* ++roman: If no arguments on the command line, read them from
- * file */
- if (argc == 1)
- get_default_args( &argc, &argv );
-
- /* machine is Atari */
- bi.machtype = MACH_ATARI;
-
- /* check arguments */
- while ((ch = getopt(argc, argv, "bdtsk:r:")) != EOF)
- switch (ch) {
- case 'd':
- debugflag = 1;
- break;
- case 't':
- ignore_ttram = 1;
- break;
- case 's':
- load_to_stram = 1;
- break;
- case 'k':
- kernel_name = optarg;
- kname_set = 1;
- break;
- case 'r':
- ramdisk_name = optarg;
- break;
- case 'b':
- prefer_bootp = 0;
- break;
- case '?':
- default:
- usage();
- }
-
- argc -= optind;
- argv += optind;
-
- /* We have to access some system variables to get
- * the information we need, so we must switch to
- * supervisor mode first.
- */
- userstk = Super(0L);
-
- /* get the info we need from the cookie-jar */
- cookiejar = *_p_cookies;
- if(cookiejar == 0L) {
- /* if we find no cookies, it's probably an ST */
- fprintf(stderr, "Error: No cookiejar found. Is this an ST?\n");
- boot_exit(EXIT_FAILURE);
- }
-
- /* Exit if MiNT/MultiTOS is running. */
- if(getcookie("MiNT", &mint) != -1)
- {
- puts("Warning: MiNT is running\n");
-#if 0
- puts("Linux cannot be started when MiNT is running. Aborting...\n");
- boot_exit(EXIT_FAILURE);
-#endif
- }
-
- /* get _CPU, _FPU and _MCH */
- getcookie("_CPU", &cpu_type);
- getcookie("_FPU", &fpu_type);
- getcookie("_MCH", &mch_type);
-
- /* check if we are on a 68030/40 with FPU */
- if ((cpu_type != 30 && cpu_type != 40 && cpu_type != 60))
- {
- puts("Machine type currently not supported. Aborting...");
- boot_exit(EXIT_FAILURE);
- }
-
- switch(cpu_type) {
- case 0:
- case 10: break;
- case 20: bi.cputype = CPU_68020; bi.mmutype = MMU_68851; break;
- case 30: bi.cputype = CPU_68030; bi.mmutype = MMU_68030; break;
- case 40: bi.cputype = CPU_68040; bi.mmutype = MMU_68040; break;
- case 60: bi.cputype = CPU_68060; bi.mmutype = MMU_68060; break;
- default:
- fprintf(stderr, "Error: Unknown CPU type. Aborting...\n");
- boot_exit(EXIT_FAILURE);
- break;
- }
-
- printf("CPU: %ld; ", cpu_type + 68000);
- printf("FPU: ");
-
- /* check for FPU; in case of a '040 or '060, don't look at _FPU itself,
- * some software may set it to wrong values (68882 or the like) */
- if (cpu_type == 40) {
- bi.fputype = FPU_68040;
- puts( "68040\n" );
- }
- else if (cpu_type == 60) {
- bi.fputype = FPU_68060;
- puts( "68060\n" );
- }
- else {
- switch ((fpu_type >> 16) & 7) {
- case 0:
- puts("not present\n");
- break;
- case 1:
- puts("SFP004 not supported. Assuming no FPU.");
- break;
- case 2:
- /* try to determine real type */
- if (fpu_idle_frame_size () != 0x18)
- goto m68882;
- /* fall through */
- case 4:
- bi.fputype = FPU_68881;
- puts("68881\n");
- break;
- case 6:
- m68882:
- bi.fputype = FPU_68882;
- puts("68882\n");
- break;
- default:
- puts("Unknown FPU type. Assuming no FPU.");
- break;
- }
- }
- /* ++roman: If an FPU was announced in the cookie, test
- whether it is a real hardware FPU or a software emulator! */
- if (bi.fputype) {
- if (test_software_fpu()) {
- bi.fputype = 0;
- puts("FPU: software emulated. Assuming no FPU.");
- }
- }
-
- /* Get the amounts of ST- and TT-RAM. */
- /* The size must be a multiple of 1MB. */
- i = 0;
-
- if (!test_medusa()) {
- struct {
- unsigned short version; /* version - currently 1 */
- unsigned long fr_start; /* start addr FastRAM */
- unsigned long fr_len; /* length FastRAM */
- } *magn_cookie;
- struct {
- unsigned long version;
- unsigned long fr_start; /* start addr */
- unsigned long fr_len; /* length */
- } *fx_cookie;
-
- TT_ramsize = 0;
- if (!ignore_ttram) {
- /* "Original" or properly emulated TT-Ram */
- if (*ramtop) {
- /* the 'ramtop' variable at 0x05a4 is not
- * officially documented. We use it anyway
- * because it is the only way to get the TTram size.
- * (It is zero if there is no TTram.)
- */
- bi.memory[i].addr = TT_RAM_BASE;
- bi.memory[i].size = (*ramtop - TT_RAM_BASE) & ~(MB - 1);
- TT_ramsize = bi.memory[i].size / MB;
- i++;
- printf("TT-RAM: %ld Mb; ", TT_ramsize);
- }
-
- /* test for MAGNUM alternate RAM
- * added 26.9.1995 M. Schwingen, rincewind@discworld.oche.de
- */
- if (getcookie("MAGN", (u_long *)&magn_cookie) != -1) {
- bi.memory[i].addr = magn_cookie->fr_start;
- bi.memory[i].size = magn_cookie->fr_len & ~(MB - 1);
- TT_ramsize += bi.memory[i].size / MB;
- printf("MAGNUM alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
- i++;
- }
-
- /* BlowUps FX */
- if (getcookie("BPFX", (u_long *)&fx_cookie) != -1 && fx_cookie) {
- /* if fx is set (cookie call above),
- * we assume that BlowUps FX-card
- * is installed. (Nat!)
- */
- bi.memory[i].addr = fx_cookie->fr_start;
- bi.memory[i].size = fx_cookie->fr_len & ~(MB - 1);
- printf("FX alternate RAM: %ld Mb; ", bi.memory[i].size/MB);
- i++;
- }
- }
-
- bi.memory[i].addr = 0;
- bi.memory[i].size = *phystop & ~(MB - 1);
- ST_ramsize = bi.memory[i].size / MB;
- i++;
- printf("ST-RAM: %ld Mb\n", ST_ramsize );
-
- bi.num_memory = i;
-
- if (load_to_stram && i > 1) {
- /* Put ST-RAM first in the list of mem blocks */
- struct mem_info temp = bi.memory[i - 1];
- bi.memory[i - 1] = bi.memory[0];
- bi.memory[0] = temp;
- }
- }
- else {
- u_long bank1, bank2, medusa_st_ram;
-
- get_medusa_bank_sizes( &bank1, &bank2 );
- medusa_st_ram = *phystop & ~(MB - 1);
- bank1 -= medusa_st_ram;
- TT_ramsize = 0;
-
- bi.memory[i].addr = 0;
- bi.memory[i].size = medusa_st_ram;
- ST_ramsize = bi.memory[i].size / MB;
- i++;
- printf("Medusa pseudo ST-RAM from bank 1: %ld Mb; ", ST_ramsize );
-
- if (!ignore_ttram && bank1 > 0) {
- bi.memory[i].addr = 0x20000000 + medusa_st_ram;
- bi.memory[i].size = bank1;
- TT_ramsize += bank1;
- i++;
- printf("TT-RAM bank 1: %ld Mb; ", bank1/MB );
- }
-
- if (!ignore_ttram && bank2 > 0) {
- bi.memory[i].addr = 0x24000000;
- bi.memory[i].size = bank2;
- TT_ramsize += bank2;
- i++;
- printf("TT-RAM bank 2: %ld Mb; ", bank2/MB );
- }
-
- bi.num_memory = i;
- printf("\n");
- }
-
- /* verify that there is enough RAM; ST- and TT-RAM combined */
- if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
- puts("Not enough RAM. Aborting...");
- boot_exit(10);
- }
-
-#if 0
- /* Get language/keyboard info */
- /* TODO: do we need this ? */
- /* Could be used to auto-select keyboard map later on. (rdv) */
- if (getcookie("_AKP",&language) == -1)
- {
- /* Get the language info from the OS-header */
- os_header = *_sysbase;
- os_header = os_header->os_beg;
- lang = (os_header->os_conf) >> 1;
- printf("Language: ");
- switch(lang) {
- case HOL: puts("Dutch"); break; /* Own country first :-) */
- case USA: puts("American"); break;
- case SWG: puts("Switzerland (German)"); break;
- case FRG: puts("German"); break;
- case FRA: puts("French"); break;
- case SWF: puts("Switzerland (French)"); break;
- case UK: puts("English"); break;
- case SPA: puts("Spanish"); break;
- case ITA: puts("Italian"); break;
- case SWE: puts("Swedish"); break;
- case TUR: puts("Turkey"); break;
- case FIN: puts("Finnish"); break;
- case NOR: puts("Norwegian"); break;
- case DEN: puts("Danish"); break;
- case SAU: puts("Saudi-Arabian"); break;
- default: puts("Unknown"); break;
- }
- }
- else
- {
- printf("Language: ");
- switch(language & 0x0F)
- {
- case 1: printf("German "); break;
- case 2: printf("French "); break;
- case 4: printf("Spanish "); break;
- case 5: printf("Italian "); break;
- case 7: printf("Swiss French "); break;
- case 8: printf("Swiss German "); break;
- default: printf("English ");
- }
- printf("Keyboard type :");
- switch(language >> 8)
- {
- case 1: printf("German "); break;
- case 2: printf("French "); break;
- case 4: printf("Spanish "); break;
- case 5: printf("Italian "); break;
- case 7: printf("Swiss French "); break;
- case 8: printf("Swiss German "); break;
- default: printf("English ");
- }
- printf("\n");
- }
-#endif
-
- /* Pass contents of the _MCH cookie to the kernel */
- bi.mch_cookie = mch_type;
-
- /*
- * Copy command line options into the kernel command line.
- */
- i = 0;
- while (argc--) {
- if ((i+strlen(*argv)+1) < CL_SIZE) {
- i += strlen(*argv) + 1;
- if (bi.command_line[0])
- strcat (bi.command_line, " ");
- strcat (bi.command_line, *argv++);
- }
- }
- printf ("Command line is '%s'\n", bi.command_line);
-
- start_mem = bi.memory[0].addr;
- mem_size = bi.memory[0].size;
-
- /* tell us where the kernel will go */
- printf("\nThe kernel will be located at 0x%08lx\n", start_mem);
-
-#ifdef TEST
- /*
- ** Temporary exit point for testing
- */
- boot_exit(-1);
-#endif /* TEST */
-
- i = 0;
-#ifdef USE_BOOTP
- if (!kname_set)
- kname_list[i++][0] = '\0'; /* default kernel which BOOTP server says */
-#endif
-#ifdef ZKERNEL
- strcpy( kname_list[i], kernel_name );
- strcat( kname_list[i], ".gz" );
- ++i;
-#endif
- strcpy( kname_list[i++], kernel_name );
-#ifdef ZKERNEL
- if (!kname_set)
- strcpy( kname_list[i++], "vmlinuz" );
-#endif
- n_knames = i;
-
- kfd = -1;
-#ifdef USE_BOOTP
- if (prefer_bootp) {
- for( i = 0; i < n_knames; ++i ) {
- if ((err = get_remote_kernel( kname_list[i] )) >= 0)
- goto kernel_open;
- if (err < -1) /* fatal error; retries don't help... */
- break;
- }
- printf( "\nremote boot failed; trying local kernel\n" );
- }
-#endif
- for( i = 0; i < n_knames; ++i ) {
- if ((kfd = open( kname_list[i], O_RDONLY )) != -1)
- goto kernel_open;
- }
-#ifdef USE_BOOTP
- if (!prefer_bootp) {
- printf( "\nlocal kernel failed; trying remote boot\n" );
- for( i = 0; i < n_knames; ++i ) {
- if ((err = get_remote_kernel( kname_list[i] )) >= 0)
- goto kernel_open;
- if (err < -1) /* fatal error; retries don't help... */
- break;
- }
- }
-#endif
- fprintf( stderr, "Unable to open any kernel file\n(Tried " );
- for( i = 0; i < n_knames; ++i ) {
- fprintf( stderr, "%s%s", kname_list[i],
- i < n_knames-2 ? ", " :
- i == n_knames-2 ? ", and " :
- ")\n" );
- }
- boot_exit( EXIT_FAILURE );
-
- kernel_open:
-
- if (kread (kfd, (void *)&kexec, sizeof(kexec)) != sizeof(kexec))
- {
- fprintf (stderr, "Unable to read exec header from %s\n", kernel_name);
- boot_exit (EXIT_FAILURE);
- }
-
-#ifdef ZKERNEL
- if (((unsigned char *)&kexec)[0] == 037 &&
- (((unsigned char *)&kexec)[1] == 0213 ||
- ((unsigned char *)&kexec)[1] == 0236)) {
- /* That's a compressed kernel */
- printf( "Kernel is compressed\n" );
- if (load_zkernel( kfd )) {
- printf( "Decompression error -- aborting\n" );
- boot_exit( EXIT_FAILURE );
- }
- }
-#endif
-
- switch (N_MAGIC(kexec)) {
- case ZMAGIC:
- text_offset = N_TXTOFF(kexec);
- break;
- case QMAGIC:
- text_offset = sizeof(kexec);
- /* the text size includes the exec header; remove this */
- kexec.a_text -= sizeof(kexec);
- break;
- default:
- /* Try to parse it as an ELF header */
- klseek (kfd, 0, SEEK_SET);
- if (kread (kfd, (void *)&kexec_elf, sizeof (kexec_elf)) == sizeof (kexec_elf)
- && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0)
- {
- elf_kernel = 1;
- /* A few plausibility checks */
- if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K
- || kexec_elf.e_version != EV_CURRENT)
- {
- fprintf (stderr, "Invalid ELF header contents in kernel\n");
- boot_exit (EXIT_FAILURE);
- }
- /* Load the program headers */
- kernel_phdrs = (Elf32_Phdr *) Malloc (kexec_elf.e_phnum * sizeof (Elf32_Phdr));
- if (kernel_phdrs == NULL)
- {
- fprintf (stderr, "Unable to allocate memory for program headers\n");
- boot_exit (EXIT_FAILURE);
- }
- klseek (kfd, kexec_elf.e_phoff, SEEK_SET);
- if (kread (kfd, (void *) kernel_phdrs,
- kexec_elf.e_phnum * sizeof (*kernel_phdrs))
- != kexec_elf.e_phnum * sizeof (*kernel_phdrs))
- {
- fprintf (stderr, "Unable to read program headers from %s\n",
- kernel_name);
- boot_exit (EXIT_FAILURE);
- }
- break;
- }
- fprintf (stderr, "Wrong magic number %lo in kernel header\n",
- N_MAGIC(kexec));
- boot_exit (EXIT_FAILURE);
- }
-
- /* Load the kernel one page after start of mem */
- start_mem += PAGE_SIZE;
- mem_size -= PAGE_SIZE;
- /* Align bss size to multiple of four */
- if (!elf_kernel)
- kexec.a_bss = (kexec.a_bss + 3) & ~3;
-
- /* init ramdisk */
- if(ramdisk_name) {
- if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
- fprintf(stderr, "Unable to open ramdisk file %s\n",
- ramdisk_name);
- boot_exit(EXIT_FAILURE);
- }
- bi.ramdisk.size = lseek(rfd, 0, SEEK_END);
- }
- else
- bi.ramdisk.size = 0;
-
- /* calculate the total required amount of memory */
- if (elf_kernel)
- {
- u_long min_addr = 0xffffffff, max_addr = 0;
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- if (min_addr > kernel_phdrs[i].p_vaddr)
- min_addr = kernel_phdrs[i].p_vaddr;
- if (max_addr < kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz)
- max_addr = kernel_phdrs[i].p_vaddr + kernel_phdrs[i].p_memsz;
- }
- /* This is needed for newer linkers that include the header in
- the first segment. */
- if (min_addr == 0)
- {
- min_addr = PAGE_SIZE;
- kernel_phdrs[0].p_vaddr += PAGE_SIZE;
- kernel_phdrs[0].p_offset += PAGE_SIZE;
- kernel_phdrs[0].p_filesz -= PAGE_SIZE;
- kernel_phdrs[0].p_memsz -= PAGE_SIZE;
- }
- kernel_size = max_addr - min_addr;
- }
- else
- kernel_size = kexec.a_text + kexec.a_data + kexec.a_bss;
-
- rd_size = bi.ramdisk.size;
- if (rd_size + kernel_size > mem_size - MB/2 && bi.num_memory > 1)
- /* If running low on ST ram load ramdisk into alternate ram. */
- bi.ramdisk.addr = (u_long) bi.memory[1].addr + bi.memory[1].size - rd_size;
- else
- /* Else hopefully there is enough ST ram. */
- bi.ramdisk.addr = (u_long)start_mem + mem_size - rd_size;
-
- /* create the bootinfo structure */
- if (!create_bootinfo())
- boot_exit (EXIT_FAILURE);
-
- memreq = kernel_size + bi_size;
-#ifdef BOOTINFO_COMPAT_1_0
- if (sizeof(compat_bootinfo) > bi_size)
- memreq = kernel_size+sizeof(compat_bootinfo);
-#endif /* BOOTINFO_COMPAT_1_0 */
- /* align load address of ramdisk image, read() is sloooow on odd addr. */
- memreq = ((memreq + 3) & ~3) + rd_size;
-
- /* allocate RAM for the kernel */
- if (!(memptr = (char *)Malloc (memreq)))
- {
- fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
- boot_exit (EXIT_FAILURE);
- }
- else
- fprintf(stderr, "kernel at address %lx\n", (u_long) memptr);
-
- (void)memset(memptr, 0, memreq);
-
- /* read the text and data segments from the kernel image */
- if (elf_kernel)
- {
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- if (klseek (kfd, kernel_phdrs[i].p_offset, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to segment %d\n", i);
- boot_exit (EXIT_FAILURE);
- }
- if (kread (kfd, memptr + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
- kernel_phdrs[i].p_filesz)
- != kernel_phdrs[i].p_filesz)
- {
- fprintf (stderr, "Failed to read segment %d\n", i);
- boot_exit (EXIT_FAILURE);
- }
- }
- }
- else
- {
- if (klseek (kfd, text_offset, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to text\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- if (kread (kfd, memptr, kexec.a_text) != kexec.a_text)
- {
- fprintf (stderr, "Failed to read text\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- /* data follows immediately after text */
- if (kread (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
- {
- fprintf (stderr, "Failed to read data\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- }
- kclose (kfd);
-
- /* Check kernel's bootinfo version */
- switch (check_bootinfo_version(memptr)) {
- case BI_VERSION_MAJOR(ATARI_BOOTI_VERSION):
- bi_ptr = &bi_union.record;
- break;
-
-#ifdef BOOTINFO_COMPAT_1_0
- case BI_VERSION_MAJOR(COMPAT_ATARI_BOOTI_VERSION):
- if (!create_compat_bootinfo()) {
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- bi_ptr = &compat_bootinfo;
- bi_size = sizeof(compat_bootinfo);
- break;
-#endif /* BOOTINFO_COMPAT_1_0 */
-
- default:
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
-
- /* copy the boot_info struct to the end of the kernel image */
- memcpy ((void *)(memptr + kernel_size), bi_ptr, bi_size);
-
- /* read the ramdisk image */
- if (rfd != -1)
- {
- if (lseek (rfd, 0, SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to beginning of ramdisk file\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- if (read (rfd, memptr + memreq - rd_size,
- rd_size) != rd_size)
- {
- fprintf (stderr, "Failed to read ramdisk file\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
- close (rfd);
- }
-
- /* for those who want to debug */
- if (debugflag)
- {
- if (bi.ramdisk.size)
- printf ("RAM disk at %#lx, size is %ld\n",
- (u_long)(memptr + memreq - rd_size),
- bi.ramdisk.size);
-
- if (elf_kernel)
- {
- for (i = 0; i < kexec_elf.e_phnum; i++)
- {
- printf ("Kernel segment %d at %#lx, size %ld\n", i,
- start_mem + kernel_phdrs[i].p_vaddr - PAGE_SIZE,
- kernel_phdrs[i].p_memsz);
- }
- }
- else
- {
- printf ("\nKernel text at %#lx, code size %d\n",
- start_mem, kexec.a_text);
- printf ("Kernel data at %#lx, data size %d\n",
- start_mem + kexec.a_text, kexec.a_data );
- printf ("Kernel bss at %#lx, bss size %d\n",
- start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
- }
- printf ("\nboot_info is at %#lx\n",
- start_mem + kernel_size);
- printf ("\nKernel entry is %#lx\n",
- elf_kernel ? kexec_elf.e_entry : kexec.a_entry);
- printf ("ramdisk dest top is %#lx\n", bi.ramdisk.addr + rd_size);
- printf ("ramdisk lower limit is %#lx\n",
- (u_long)(memptr + memreq - rd_size));
- printf ("ramdisk src top is %#lx\n", (u_long)(memptr + memreq));
-
- printf ("Type a key to continue the Linux boot...");
- fflush (stdout);
- getchar();
- }
-
- printf("Booting Linux...\n");
-
- sync ();
-
- /* turn off interrupts... */
- disable_interrupts();
-
- /* turn off caches... */
- disable_cache();
-
- /* ..and any MMU translation */
- disable_mmu();
-
- /* ++guenther: allow reset if launched with MiNT */
- *(long*)0x426 = 0;
-
- /* copy mover code to a safe place if needed */
- memcpy ((void *) 0x400, &copyall, &copyallend - &copyall);
-
- /* setup stack */
- change_stack ((void *) PAGE_SIZE);
-
- /*
- * On the Atari you can have two situations:
- * 1. One piece of contiguous RAM (Falcon)
- * 2. Two pieces of contiguous RAM (TT)
- * In case 2 you can load your program into ST-ram and load your data in
- * any old RAM you have left.
- * In case 1 you could overwrite your own program when copying the
- * kernel and ramdisk to their final positions.
- * To solve this the mover code is copied to a safe place first.
- * Then this program jumps to the mover code. After the mover code
- * has finished it jumps to the start of the kernel in its new position.
- * I thought the memory just after the interrupt vector table was a safe
- * place because it is used by TOS to store some system variables.
- * This range goes from 0x400 to approx. 0x5B0.
- * This is more than enough for the miniscule mover routine (16 bytes).
- */
-
- jump_to_mover((char *) start_mem, memptr,
- (char *) bi.ramdisk.addr + rd_size, memptr + memreq,
- kernel_size + bi_size, rd_size,
- (void *) 0x400);
-
- for (;;);
- /* NOTREACHED */
-}
-
-
-
-#define MAXARGS 30
-
-static void get_default_args( int *argc, char ***argv )
-
-{ FILE *f;
- static char *nargv[MAXARGS];
- char arg[256], *p;
- int c, quote, state;
-
- if (!(f = fopen( "bootargs", "r" )))
- return;
-
- *argc = 1;
- if (***argv)
- nargv[0] = **argv;
- else
- nargv[0] = "bootstrap";
- *argv = nargv;
-
- quote = state = 0;
- p = arg;
- while( (c = fgetc(f)) != EOF ) {
-
- if (state == 0) {
- /* outside args, skip whitespace */
- if (!isspace(c)) {
- state = 1;
- p = arg;
- }
- }
-
- if (state) {
- /* inside an arg: copy it into 'arg', obeying quoting */
- if (!quote && (c == '\'' || c == '"'))
- quote = c;
- else if (quote && c == quote)
- quote = 0;
- else if (!quote && isspace(c)) {
- /* end of this arg */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- state = 0;
- }
- else
- *p++ = c;
- }
- }
- if (state) {
- /* last arg finished by EOF! */
- *p = 0;
- nargv[(*argc)++] = strdup(arg);
- }
- fclose( f );
-
- nargv[*argc] = 0;
-}
-
-
- /*
- * Create the Bootinfo Structure
- */
-
-static int create_bootinfo(void)
-{
- int i;
- struct bi_record *record;
-
- /* Initialization */
- bi_size = 0;
-
- /* Generic tags */
- if (!add_bi_record(BI_MACHTYPE, sizeof(bi.machtype), &bi.machtype))
- return(0);
- if (!add_bi_record(BI_CPUTYPE, sizeof(bi.cputype), &bi.cputype))
- return(0);
- if (!add_bi_record(BI_FPUTYPE, sizeof(bi.fputype), &bi.fputype))
- return(0);
- if (!add_bi_record(BI_MMUTYPE, sizeof(bi.mmutype), &bi.mmutype))
- return(0);
- for (i = 0; i < bi.num_memory; i++)
- if (!add_bi_record(BI_MEMCHUNK, sizeof(bi.memory[i]), &bi.memory[i]))
- return(0);
- if (bi.ramdisk.size)
- if (!add_bi_record(BI_RAMDISK, sizeof(bi.ramdisk), &bi.ramdisk))
- return(0);
- if (!add_bi_string(BI_COMMAND_LINE, bi.command_line))
- return(0);
-
- /* Atari tags */
- if (!add_bi_record(BI_ATARI_MCH_COOKIE, sizeof(bi.mch_cookie),
- &bi.mch_cookie))
- return(0);
-
- /* Trailer */
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = BI_LAST;
- bi_size += sizeof(bi_union.record.tag);
-
- return(1);
-}
-
-
- /*
- * Add a Record to the Bootinfo Structure
- */
-
-static int add_bi_record(u_short tag, u_short size, const void *data)
-{
- struct bi_record *record;
- u_short size2;
-
- size2 = (sizeof(struct bi_record)+size+3)&-4;
- if (bi_size+size2+sizeof(bi_union.record.tag) > MAX_BI_SIZE) {
- fprintf (stderr, "Can't add bootinfo record. Ask a wizard to enlarge me.\n");
- return(0);
- }
- record = (struct bi_record *)((u_long)&bi_union.record+bi_size);
- record->tag = tag;
- record->size = size2;
- memcpy(record->data, data, size);
- bi_size += size2;
- return(1);
-}
-
-
- /*
- * Add a String Record to the Bootinfo Structure
- */
-
-static int add_bi_string(u_short tag, const u_char *s)
-{
- return add_bi_record(tag, strlen(s)+1, (void *)s);
-}
-
-
-#ifdef BOOTINFO_COMPAT_1_0
-
- /*
- * Create the Bootinfo structure for backwards compatibility mode
- */
-
-static int create_compat_bootinfo(void)
-{
- u_int i;
-
- compat_bootinfo.machtype = bi.machtype;
- if (bi.cputype & CPU_68020)
- compat_bootinfo.cputype = COMPAT_CPU_68020;
- else if (bi.cputype & CPU_68030)
- compat_bootinfo.cputype = COMPAT_CPU_68030;
- else if (bi.cputype & CPU_68040)
- compat_bootinfo.cputype = COMPAT_CPU_68040;
- else if (bi.cputype & CPU_68060)
- compat_bootinfo.cputype = COMPAT_CPU_68060;
- else {
- printf("CPU type 0x%08lx not supported by kernel\n", bi.cputype);
- return(0);
- }
- if (bi.fputype & FPU_68881)
- compat_bootinfo.cputype |= COMPAT_FPU_68881;
- else if (bi.fputype & FPU_68882)
- compat_bootinfo.cputype |= COMPAT_FPU_68882;
- else if (bi.fputype & FPU_68040)
- compat_bootinfo.cputype |= COMPAT_FPU_68040;
- else if (bi.fputype & FPU_68060)
- compat_bootinfo.cputype |= COMPAT_FPU_68060;
- else {
- printf("FPU type 0x%08lx not supported by kernel\n", bi.fputype);
- return(0);
- }
- compat_bootinfo.num_memory = bi.num_memory;
- if (compat_bootinfo.num_memory > COMPAT_NUM_MEMINFO) {
- printf("Warning: using only %d blocks of memory\n",
- COMPAT_NUM_MEMINFO);
- compat_bootinfo.num_memory = COMPAT_NUM_MEMINFO;
- }
- for (i = 0; i < compat_bootinfo.num_memory; i++) {
- compat_bootinfo.memory[i].addr = bi.memory[i].addr;
- compat_bootinfo.memory[i].size = bi.memory[i].size;
- }
- if (bi.ramdisk.size) {
- compat_bootinfo.ramdisk_size = (bi.ramdisk.size+1023)/1024;
- compat_bootinfo.ramdisk_addr = bi.ramdisk.addr;
- } else {
- compat_bootinfo.ramdisk_size = 0;
- compat_bootinfo.ramdisk_addr = 0;
- }
- strncpy(compat_bootinfo.command_line, bi.command_line, COMPAT_CL_SIZE);
- compat_bootinfo.command_line[COMPAT_CL_SIZE-1] = '\0';
-
- compat_bootinfo.bi_atari.hw_present = 0;
- compat_bootinfo.bi_atari.mch_cookie = bi.mch_cookie;
- return(1);
-}
-#endif /* BOOTINFO_COMPAT_1_0 */
-
-
-#ifdef ZKERNEL
-
-#define ZFILE_CHUNK_BITS 16 /* chunk is 64 KB */
-#define ZFILE_CHUNK_SIZE (1 << ZFILE_CHUNK_BITS)
-#define ZFILE_CHUNK_MASK (ZFILE_CHUNK_SIZE-1)
-#define ZFILE_N_CHUNKS (2*1024*1024/ZFILE_CHUNK_SIZE)
-
-/* variables for storing the uncompressed data */
-static char *ZFile[ZFILE_N_CHUNKS];
-static int ZFileSize = 0;
-static int ZFpos = 0;
-static int Zwpos = 0;
-
-static int Zinfd = 0; /* fd of compressed file */
-
-/*
- * gzip declarations
- */
-
-#define OF(args) args
-
-#define memzero(s, n) memset ((s), 0, (n))
-
-typedef unsigned char uch;
-typedef unsigned short ush;
-typedef unsigned long ulg;
-
-#define INBUFSIZ 4096
-#define WSIZE 0x8000 /* window size--must be a power of two, and */
- /* at least 32K for zip's deflate method */
-
-static uch *inbuf;
-static uch *window;
-
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
-static int exit_code = 0;
-static long bytes_out = 0;
-
-#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* Diagnostic functions (stubbed out) */
-#define Assert(cond,msg)
-#define Trace(x)
-#define Tracev(x)
-#define Tracevv(x)
-#define Tracec(c,x)
-#define Tracecv(c,x)
-
-#define STATIC static
-
-static int fill_inbuf(void);
-static void flush_window(void);
-static void error(char *m);
-static void gzip_mark(void **);
-static void gzip_release(void **);
-
-#include "../../../../lib/inflate.c"
-
-static void gzip_mark( void **ptr )
-{
-}
-
-static void gzip_release( void **ptr )
-{
-}
-
-
-/*
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-static int fill_inbuf( void )
-{
- if (exit_code)
- return -1;
-
- insize = ll_read( Zinfd, inbuf, INBUFSIZ );
- if (insize <= 0)
- return -1;
-
- inptr = 1;
- return( inbuf[0] );
-}
-
-/*
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-static void flush_window( void )
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
- int chunk = Zwpos >> ZFILE_CHUNK_BITS;
-
- if (chunk >= ZFILE_N_CHUNKS) {
- fprintf( stderr, "compressed image too large! Aborting.\n" );
- boot_exit( EXIT_FAILURE );
- }
- if (!ZFile[chunk]) {
- if (!(ZFile[chunk] = (char *)Malloc( ZFILE_CHUNK_SIZE ))) {
- fprintf( stderr, "Out of memory for decompresing kernel image\n" );
- boot_exit( EXIT_FAILURE );
- }
- }
- memcpy( ZFile[chunk] + (Zwpos & ZFILE_CHUNK_MASK), window, outcnt );
- Zwpos += outcnt;
-
-#define DISPLAY_BITS 13
- if ((Zwpos & ((1 << DISPLAY_BITS)-1)) == 0) {
- printf( "." );
- fflush( stdout );
- }
-
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void error( char *x )
-{
- fprintf( stderr, "\n%s", x);
- exit_code = 1;
-}
-
-static int load_zkernel( int fd )
-{
- int i, err;
-
- for( i = 0; i < ZFILE_N_CHUNKS; ++i )
- ZFile[i] = NULL;
- Zinfd = fd;
- ll_lseek( fd, 0, SEEK_SET );
-
- if (!(inbuf = (uch *)Malloc( INBUFSIZ ))) {
- fprintf( stderr, "Couldn't allocate gunzip buffer\n" );
- boot_exit( EXIT_FAILURE );
- }
- if (!(window = (uch *)Malloc( WSIZE ))) {
- fprintf( stderr, "Couldn't allocate gunzip window\n" );
- boot_exit( EXIT_FAILURE );
- }
-
- printf( "Uncompressing kernel image " );
- fflush( stdout );
- makecrc();
- if (!(err = gunzip()))
- printf( "done\n" );
- ZFileSize = Zwpos;
- ll_close( Zinfd ); /* input file not needed anymore */
-
- Mfree( inbuf );
- Mfree( window );
- return( err );
-}
-
-/* Note about the read/lseek wrapper and its memory management: It assumes
- * that all seeks are only forward, and thus data already read or skipped can
- * be freed. This is true for current organization of bootstrap and kernels.
- * Little exception: The struct kexec at the start of the file. After reading
- * it, there may be a seek back to the end of the file. But this currently
- * doesn't hurt. Same considerations apply to the TFTP file buffers. (Roman)
- */
-
-static int kread( int fd, void *buf, unsigned cnt )
-{
- unsigned done = 0;
-
- if (!ZFileSize)
- return( ll_read( fd, buf, cnt ) );
-
- if (ZFpos + cnt > ZFileSize)
- cnt = ZFileSize - ZFpos;
-
- while( cnt > 0 ) {
- unsigned chunk = ZFpos >> ZFILE_CHUNK_BITS;
- unsigned endchunk = (chunk+1) << ZFILE_CHUNK_BITS;
- unsigned n = cnt;
-
- if (ZFpos + n > endchunk)
- n = endchunk - ZFpos;
- memcpy( buf, ZFile[chunk] + (ZFpos & ZFILE_CHUNK_MASK), n );
- cnt -= n;
- buf += n;
- done += n;
- ZFpos += n;
-
- if (ZFpos == endchunk) {
- Mfree( ZFile[chunk] );
- ZFile[chunk] = NULL;
- }
- }
-
- return( done );
-}
-
-
-static int klseek( int fd, int where, int whence )
-{
- unsigned oldpos, oldchunk, newchunk;
-
- if (!ZFileSize)
- return( ll_lseek( fd, where, whence ) );
-
- oldpos = ZFpos;
- switch( whence ) {
- case SEEK_SET:
- ZFpos = where;
- break;
- case SEEK_CUR:
- ZFpos += where;
- break;
- case SEEK_END:
- ZFpos = ZFileSize + where;
- break;
- default:
- return( -1 );
- }
- if (ZFpos < 0) {
- ZFpos = 0;
- return( -1 );
- }
- else if (ZFpos > ZFileSize) {
- ZFpos = ZFileSize;
- return( -1 );
- }
-
- /* free memory of skipped-over data */
- oldchunk = oldpos >> ZFILE_CHUNK_BITS;
- newchunk = ZFpos >> ZFILE_CHUNK_BITS;
- while( oldchunk < newchunk ) {
- if (ZFile[oldchunk]) {
- Mfree( ZFile[oldchunk] );
- ZFile[oldchunk] = NULL;
- }
- ++oldchunk;
- }
-
- return( ZFpos );
-}
-
-
-static void free_zfile( void )
-{
- int i;
-
- for( i = 0; i < ZFILE_N_CHUNKS; ++i )
- if (ZFile[i]) Mfree( ZFile[i] );
-}
-
-static int kclose( int fd )
-{
- if (ZFileSize) {
- free_zfile();
- return( 0 );
- }
- else
- return( ll_close( fd ) );
-}
-
-
-
-#endif /* ZKERNEL */
diff --git a/arch/m68k/boot/atari/bootstrap.h b/arch/m68k/boot/atari/bootstrap.h
index 594916dfe..e69de29bb 100644
--- a/arch/m68k/boot/atari/bootstrap.h
+++ b/arch/m68k/boot/atari/bootstrap.h
@@ -1,171 +0,0 @@
-/*
-** bootstrap.h -- This file is a part of the Atari bootloader.
-**
-** Copyright 1993 by Arjan Knor
-**
-** Modified by Andreas Schwab
-** - clear transparent translation registers
-** Modified 18-Aug-96 by Geert Uytterhoeven
-** - Updated for the new boot information structure (untested!)
-** Modified 1996-11-12 by Andreas Schwab
-** - Fixed and tested previous change
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file COPYING in the main directory of this archive
-** for more details.
-**
-*/
-
-#ifndef BOOTSTRAP_H
-#define BOOTSTRAP_H
-
- /*
- * Atari Bootinfo Definitions
- *
- * All limits herein are `soft' limits, i.e. they don't put constraints
- * on the actual parameters in the kernel.
- */
-
-struct atari_bootinfo {
- unsigned long machtype; /* machine type */
- unsigned long cputype; /* system CPU */
- unsigned long fputype; /* system FPU */
- unsigned long mmutype; /* system MMU */
- int num_memory; /* # of memory blocks found */
- struct mem_info memory[NUM_MEMINFO]; /* memory description */
- struct mem_info ramdisk; /* ramdisk description */
- char command_line[CL_SIZE]; /* kernel command line parameters */
- unsigned long mch_cookie; /* _MCH cookie from TOS */
-};
-
-
-/* _MCH cookie values */
-#define MACH_ST 0
-#define MACH_STE 1
-#define MACH_TT 2
-#define MACH_FALCON 3
-
-/* some constants for memory handling */
-#define ST_RAM 0
-#define TT_RAM 1
-#define TT_RAM_BASE (u_long)(0x01000000)
-#define MB (1024 * 1024)
-#define START_MEM (bi.memory[0].addr)
-#define MEM_SIZE (bi.memory[0].size)
-
-/* the various CPU- and FPU-types */
-#define AFF_68000 (1)
-#define AFF_68020 (2)
-#define AFF_68030 (4)
-#define AFF_68040 (8)
-#define AFF_68881 (16)
-#define AFF_68882 (32)
-
-/* the possible OS-languages */
-#define USA 0
-#define FRG 1
-#define FRA 2
-#define UK 3
-#define SPA 4
-#define ITA 5
-#define SWE 6
-#define SWF 7
-#define SWG 8
-#define TUR 9
-#define FIN 10
-#define NOR 11
-#define DEN 12
-#define SAU 13
-#define HOL 14
-
-/* some inline functions */
-
-static __inline int fpu_idle_frame_size (void)
-{
- char fpu_frame[216];
- __asm__ __volatile__ ("fnop"::);
- __asm__ __volatile__ ("fsave %0@" : : "a" (fpu_frame));
- return fpu_frame[1];
-}
-
-static __inline void change_stack (u_long *stackp)
-{
- __asm__ volatile ("movel %0,sp\n\t" :: "g" (stackp) : "sp");
-}
-
-static __inline void disable_interrupts (void)
-{
- __asm__ volatile ("orw #0x700,sr":);
-}
-
-extern struct atari_bootinfo bi;
-static __inline void disable_cache (void)
-{
- __asm__ volatile ("movec %0,cacr" :: "d" (0));
- if (bi.cputype & CPU_68060) {
- /* '060: clear branch cache after disabling it;
- * disable superscalar operation (and enable FPU) */
- __asm__ volatile ("movec %0,cacr" :: "d" (0x00400000));
- __asm__ volatile ("moveq #0,d0;"
- ".long 0x4e7b0808" /* movec d0,pcr */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- }
-}
-
-static __inline void disable_mmu (void)
-{
- if (bi.cputype & (CPU_68040|CPU_68060)) {
- __asm__ volatile ("moveq #0,d0;"
- ".long 0x4e7b0003;" /* movec d0,tc */
- ".long 0x4e7b0004;" /* movec d0,itt0 */
- ".long 0x4e7b0005;" /* movec d0,itt1 */
- ".long 0x4e7b0006;" /* movec d0,dtt0 */
- ".long 0x4e7b0007" /* movec d0,dtt1 */
- : /* no outputs */
- : /* no inputs */
- : "d0");
- }
- else {
- __asm__ volatile ("subl #4,sp\n\t"
- "pmove tc,sp@\n\t"
- "bclr #7,sp@\n\t"
- "pmove sp@,tc\n\t"
- "addl #4,sp");
- if (bi.cputype & CPU_68030) {
- __asm__ volatile ("clrl sp@-\n\t"
- ".long 0xf0170800\n\t" /* pmove sp@,tt0 */
- ".long 0xf0170c00\n\t" /* pmove sp@,tt1 */
- "addl #4,sp\n");
- }
- }
-}
-
-static __inline void jump_to_mover (void *, void *, void *, void *, int, int,
- void *) __attribute__ ((noreturn));
-static __inline void jump_to_mover (void *kernel_start, void *mem_start,
- void *ramdisk_end, void *mem_end,
- int kernel_size, int ramdisk_size,
- void *mover_addr)
-{
- asm volatile ("movel %0,a0\n\t"
- "movel %1,a1\n\t"
- "movel %2,a2\n\t"
- "movel %3,a3\n\t"
- "movel %4,d0\n\t"
- "movel %5,d1\n\t"
- "jmp %6@\n"
- : /* no outputs */
- : "g" (kernel_start), "g" (mem_start),
- "g" (ramdisk_end), "g" (mem_end),
- "g" (kernel_size), "g" (ramdisk_size),
- "a" (mover_addr)
- : "a0", "a1", "a2", "a3", "d0", "d1");
-
- /* Avoid warning that function may return */
- for (;;) ;
-}
-
-#endif /* BOOTSTRAP_H */
-
diff --git a/arch/m68k/boot/atari/ethlance.c b/arch/m68k/boot/atari/ethlance.c
index 3b248c4af..e69de29bb 100644
--- a/arch/m68k/boot/atari/ethlance.c
+++ b/arch/m68k/boot/atari/ethlance.c
@@ -1,435 +0,0 @@
-
-#include <stdio.h>
-#include <string.h>
-
-#include "bootp.h"
-#include "ethlance.h"
-
-
-struct {
- volatile unsigned short *memaddr;
- volatile unsigned short *ioaddr;
-} lance_addr_list[] = {
- { (void *)0xfe010000, (void *)0xfe00fff0 }, /* RieblCard VME in TT */
- { (void *)0xfec10000, (void *)0xfec0fff0 }, /* RieblCard VME in MegaSTE
- (highest byte stripped) */
- { (void *)0xfee00000, (void *)0xfeff7000 }, /* RieblCard in ST
- (highest byte stripped) */
- { (void *)0xfecf0000, (void *)0xfecffff0 }, /* PAMCard VME in TT and MSTE
- (highest byte stripped) */
-};
-
-#define N_LANCE_ADDR (sizeof(lance_addr_list)/sizeof(*lance_addr_list))
-
-#define TX_RING_SIZE 1
-#define TX_RING_LEN_BITS 0
-
-#define RX_RING_SIZE 16
-#define RX_RING_LEN_BITS (4 << 5)
-
-#define offsetof(type,elt) ((unsigned long)(&(((type *)0)->elt)))
-
-/* The LANCE Rx and Tx ring descriptors. */
-struct lance_rx_head {
- unsigned short base; /* Low word of base addr */
- volatile unsigned char flag;
- unsigned char base_hi; /* High word of base addr (unused) */
- short buf_length; /* This length is 2s complement! */
- short msg_length; /* This length is "normal". */
-};
-
-struct lance_tx_head {
- unsigned short base; /* Low word of base addr */
- volatile unsigned char flag;
- unsigned char base_hi; /* High word of base addr (unused) */
- short length; /* Length is 2s complement! */
- volatile short misc;
-};
-
-struct ringdesc {
- unsigned short adr_lo; /* Low 16 bits of address */
- unsigned char len; /* Length bits */
- unsigned char adr_hi; /* High 8 bits of address (unused) */
-};
-
-struct lance_packet {
- volatile unsigned char data[PKTLEN];
-};
-
-/* The LANCE initialization block, described in databook. */
-struct lance_init_block {
- unsigned short mode; /* Pre-set mode */
- unsigned char hwaddr[6]; /* Physical ethernet address */
- unsigned filter[2]; /* Multicast filter (unused). */
- /* Receive and transmit ring base, along with length bits. */
- struct ringdesc rx_ring;
- struct ringdesc tx_ring;
-};
-
-/* The whole layout of the Lance shared memory */
-struct lance_memory {
- struct lance_init_block init;
- struct lance_tx_head tx_head[TX_RING_SIZE];
- struct lance_rx_head rx_head[RX_RING_SIZE];
- struct lance_packet tx_packet[TX_RING_SIZE];
- struct lance_packet rx_packet[TX_RING_SIZE];
-};
-
-#define RIEBL_MAGIC 0x09051990
-#define RIEBL_MAGIC_ADDR ((unsigned long *)(((char *)MEM) + 0xee8a))
-#define RIEBL_HWADDR_ADDR ((unsigned char *)(((char *)MEM) + 0xee8e))
-#define RIEBL_IVEC_ADDR ((unsigned short *)(((char *)MEM) + 0xfffe))
-
-struct lance_ioreg {
-/* base+0x0 */ volatile unsigned short data;
-/* base+0x2 */ volatile unsigned short addr;
- unsigned char _dummy1[3];
-/* base+0x7 */ volatile unsigned char ivec;
- unsigned char _dummy2[5];
-/* base+0xd */ volatile unsigned char eeprom;
- unsigned char _dummy3;
-/* base+0xf */ volatile unsigned char mem;
-};
-
-enum lance_type {
- OLD_RIEBL, /* old Riebl card without battery */
- NEW_RIEBL, /* new Riebl card with battery */
- PAM_CARD /* PAM card with EEPROM */
-} CardType;
-
-HWADDR dev_addr;
-
-/* This is a default address for the old RieblCards without a battery
- * that have no ethernet address at boot time. 00:00:36:04 is the
- * prefix for Riebl cards, the 00:00 at the end is arbitrary.
- */
-
-HWADDR OldRieblDefHwaddr = {
- 0x00, 0x00, 0x36, 0x04, 0x00, 0x00
-};
-
-struct lance_ioreg *IO;
-struct lance_memory *MEM;
-
-#define DREG IO->data
-#define AREG IO->addr
-#define REGA(a) ( AREG = (a), DREG )
-
-int CurRx;
-
-
-/* Definitions for the Lance */
-
-/* tx_head flags */
-#define TMD1_ENP 0x01
-#define TMD1_STP 0x02
-#define TMD1_DEF 0x04
-#define TMD1_ONE 0x08
-#define TMD1_MORE 0x10
-#define TMD1_ERR 0x40
-#define TMD1_OWN 0x80
-
-#define TMD1_OWN_CHIP TMD1_OWN
-#define TMD1_OWN_HOST 0
-
-/* tx_head misc field */
-#define TMD3_TDR 0x03FF
-#define TMD3_RTRY 0x0400
-#define TMD3_LCAR 0x0800
-#define TMD3_LCOL 0x1000
-#define TMD3_UFLO 0x4000
-#define TMD3_BUFF3 0x8000
-
-/* rx_head flags */
-#define RMD1_ENP 0x01
-#define RMD1_STP 0x02
-#define RMD1_BUFF 0x04
-#define RMD1_CRC 0x08
-#define RMD1_OFLO 0x10
-#define RMD1_FRAM 0x20
-#define RMD1_ERR 0x40
-#define RMD1_OWN 0x80
-
-#define RMD1_OWN_CHIP RMD1_OWN
-#define RMD1_OWN_HOST 0
-
-/* register names */
-#define CSR0 0
-#define CSR1 1
-#define CSR2 2
-#define CSR3 3
-
-/* CSR0 */
-#define CSR0_INIT 0x0001 /* initialize */
-#define CSR0_STRT 0x0002 /* start */
-#define CSR0_STOP 0x0004 /* stop */
-#define CSR0_TDMD 0x0008 /* transmit demand */
-#define CSR0_TXON 0x0010 /* transmitter on */
-#define CSR0_RXON 0x0020 /* receiver on */
-#define CSR0_INEA 0x0040 /* interrupt enable */
-#define CSR0_INTR 0x0080 /* interrupt active */
-#define CSR0_IDON 0x0100 /* initialization done */
-#define CSR0_TINT 0x0200 /* transmitter interrupt */
-#define CSR0_RINT 0x0400 /* receiver interrupt */
-#define CSR0_MERR 0x0800 /* memory error */
-#define CSR0_MISS 0x1000 /* missed frame */
-#define CSR0_CERR 0x2000 /* carrier error (no heartbeat :-) */
-#define CSR0_BABL 0x4000 /* babble: tx-ed too many bits */
-#define CSR0_ERR 0x8000 /* error */
-
-/* CSR3 */
-#define CSR3_BCON 0x0001
-#define CSR3_ACON 0x0002
-#define CSR3_BSWP 0x0004
-
-
-#define HZ 200
-#define _hz_200 (*(volatile unsigned long *)0x4ba)
-
-
-
-
-/***************************** Prototypes *****************************/
-
-static int lance_probe( void );
-static int addr_readable( volatile void *regp, int wordflag );
-static int lance_init( void );
-static void lance_get_hwaddr( HWADDR *addr );
-static int lance_snd( Packet *pkt, int len );
-static int lance_rcv( Packet *pkt, int *len );
-
-/************************* End of Prototypes **************************/
-
-
-
-ETHIF_SWITCH LanceSwitch = {
- lance_probe, lance_init, lance_get_hwaddr,
- lance_snd, lance_rcv
-};
-
-
-static int lance_probe( void )
-
-{ int i;
-
- for( i = 0; i < N_LANCE_ADDR; ++i ) {
- if (addr_readable( lance_addr_list[i].memaddr, 1 ) &&
- (lance_addr_list[i].memaddr[0] = 1,
- lance_addr_list[i].memaddr[0] == 1) &&
- (lance_addr_list[i].memaddr[0] = 0,
- lance_addr_list[i].memaddr[0] == 0) &&
- addr_readable( lance_addr_list[i].ioaddr, 1 )) {
- break;
- }
- }
- if (i == N_LANCE_ADDR) return( -1 );
-
- IO = (struct lance_ioreg *)lance_addr_list[i].ioaddr;
- MEM = (struct lance_memory *)lance_addr_list[i].memaddr;
- REGA( CSR0 ) = CSR0_STOP;
-
- return( 0 );
-}
-
-
-static int addr_readable( volatile void *regp, int wordflag )
-
-{ int ret;
- long *vbr, save_berr;
-
- __asm__ __volatile__ ( "movec %/vbr,%0" : "=r" (vbr) : );
- save_berr = vbr[2];
-
- __asm__ __volatile__
- ( "movel %/sp,%/d1\n\t"
- "movel #Lberr,%2@\n\t"
- "moveq #0,%0\n\t"
- "tstl %3\n\t"
- "bne 1f\n\t"
- "tstb %1@\n\t"
- "bra 2f\n"
-"1: tstw %1@\n"
-"2: moveq #1,%0\n"
-"Lberr: movel %/d1,%/sp"
- : "=&d" (ret)
- : "a" (regp), "a" (&vbr[2]), "rm" (wordflag)
- : "d1", "memory"
- );
-
- vbr[2] = save_berr;
-
- return( ret );
-}
-
-
-static int lance_init( void )
-
-{ int i;
-
- /* Now test for type: If the eeprom I/O port is readable, it is a
- * PAM card */
- if (addr_readable( &(IO->eeprom), 0 )) {
- /* Switch back to Ram */
- i = IO->mem;
- CardType = PAM_CARD;
- }
- else if (*RIEBL_MAGIC_ADDR == RIEBL_MAGIC) {
- CardType = NEW_RIEBL;
- }
- else
- CardType = OLD_RIEBL;
-
- /* Get the ethernet address */
- switch( CardType ) {
- case OLD_RIEBL:
- /* No ethernet address! (Set some default address) */
- memcpy( dev_addr, OldRieblDefHwaddr, ETHADDRLEN );
- break;
- case NEW_RIEBL:
- memcpy( dev_addr, RIEBL_HWADDR_ADDR, ETHADDRLEN );
- break;
- case PAM_CARD:
- i = IO->eeprom;
- for( i = 0; i < ETHADDRLEN; ++i )
- dev_addr[i] =
- ((((unsigned short *)MEM)[i*2] & 0x0f) << 4) |
- ((((unsigned short *)MEM)[i*2+1] & 0x0f));
- i = IO->mem;
- break;
- }
-
- MEM->init.mode = 0x0000; /* Disable Rx and Tx. */
- for( i = 0; i < ETHADDRLEN; i++ )
- MEM->init.hwaddr[i] = dev_addr[i^1]; /* <- 16 bit swap! */
- MEM->init.filter[0] = 0x00000000;
- MEM->init.filter[1] = 0x00000000;
- MEM->init.rx_ring.adr_lo = offsetof( struct lance_memory, rx_head );
- MEM->init.rx_ring.adr_hi = 0;
- MEM->init.rx_ring.len = RX_RING_LEN_BITS;
- MEM->init.tx_ring.adr_lo = offsetof( struct lance_memory, tx_head );
- MEM->init.tx_ring.adr_hi = 0;
- MEM->init.tx_ring.len = TX_RING_LEN_BITS;
-
- REGA( CSR3 ) = CSR3_BSWP | (CardType == PAM_CARD ? CSR3_ACON : 0);
- REGA( CSR2 ) = 0;
- REGA( CSR1 ) = 0;
- REGA( CSR0 ) = CSR0_INIT | CSR0_STRT;
-
- i = 1000000;
- while( i-- > 0 )
- if (DREG & CSR0_IDON)
- break;
- if (i < 0 || (DREG & CSR0_ERR)) {
- DREG = CSR0_STOP;
- return( -1 );
- }
- DREG = CSR0_IDON;
-
- for (i = 0; i < TX_RING_SIZE; i++) {
- MEM->tx_head[i].base = offsetof( struct lance_memory, tx_packet[i] );
- MEM->tx_head[i].flag = TMD1_OWN_HOST;
- MEM->tx_head[i].base_hi = 0;
- MEM->tx_head[i].length = 0;
- MEM->tx_head[i].misc = 0;
- }
-
- for (i = 0; i < RX_RING_SIZE; i++) {
- MEM->rx_head[i].base = offsetof( struct lance_memory, rx_packet[i] );
- MEM->rx_head[i].flag = TMD1_OWN_CHIP;
- MEM->rx_head[i].base_hi = 0;
- MEM->rx_head[i].buf_length = -PKTLEN;
- MEM->rx_head[i].msg_length = 0;
- }
- CurRx = 0;
-
- return( 0 );
-}
-
-
-static void lance_get_hwaddr( HWADDR *addr )
-
-{
- memcpy( addr, dev_addr, ETHADDRLEN );
-}
-
-
-static int lance_snd( Packet *pkt, int len )
-
-{ unsigned long timeout;
-
- /* The old LANCE chips doesn't automatically pad buffers to min. size. */
- len = (len < 60) ? 60 : len;
- /* PAM-Card has a bug: Can only send packets with even number of bytes! */
- if (CardType == PAM_CARD && (len & 1))
- ++len;
-
- MEM->tx_head[0].length = -len;
- MEM->tx_head[0].misc = 0;
- memcpy( (void *)&MEM->tx_packet[0].data, pkt, len );
- MEM->tx_head[0].base = offsetof(struct lance_memory, tx_packet[0]);
- MEM->tx_head[0].base_hi = 0;
- MEM->tx_head[0].flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-
- /* Trigger an immediate send poll. */
- REGA( CSR0 ) = CSR0_TDMD;
-
- /* Wait for packet being sent */
- timeout = _hz_200 + 3*HZ;
- while( (MEM->tx_head[0].flag & TMD1_OWN_CHIP) &&
- !MEM->tx_head[0].misc &&
- _hz_200 < timeout )
- ;
-
- if ((MEM->tx_head[0].flag & TMD1_OWN) == TMD1_OWN_HOST &&
- !(MEM->tx_head[0].misc & TMD1_ERR))
- /* sent ok */
- return( 0 );
-
- /* failure */
- if (_hz_200 >= timeout)
- return( ETIMEO );
- if (MEM->tx_head[0].misc & TMD3_UFLO) {
- /* On FIFO errors, must re-turn on TX! */
- DREG = CSR0_STRT;
- }
-
- return( ESEND );
-}
-
-
-static int lance_rcv( Packet *pkt, int *len )
-
-{ unsigned long timeout;
- int stat;
-
- /* Wait for a packet */
- timeout = _hz_200 + 4*HZ;
- while( (MEM->rx_head[CurRx].flag & TMD1_OWN_CHIP) &&
- _hz_200 < timeout )
- ;
- /* Not ours -> was a timeout */
- if (((stat = MEM->rx_head[CurRx].flag) & TMD1_OWN) == TMD1_OWN_CHIP)
- return( ETIMEO );
-
- /* Check for errors */
- if (stat != (RMD1_ENP|RMD1_STP)) {
- MEM->rx_head[CurRx].flag &= (RMD1_ENP|RMD1_STP);
- if (stat & RMD1_FRAM) return( EFRAM );
- if (stat & RMD1_OFLO) return( EOVERFL );
- if (stat & RMD1_CRC) return( ECRC );
- return( ERCV );
- }
-
- /* Get the packet */
- *len = MEM->rx_head[CurRx].msg_length & 0xfff;
- memcpy( pkt, (void *)&MEM->rx_packet[CurRx].data, *len );
-
- /* Give the buffer back to the chip */
- MEM->rx_head[CurRx].buf_length = -PKTLEN;
- MEM->rx_head[CurRx].flag |= RMD1_OWN_CHIP;
- CurRx = (CurRx + 1) % RX_RING_SIZE;
-
- return( 0 );
-}
-
-
diff --git a/arch/m68k/boot/atari/ethlance.h b/arch/m68k/boot/atari/ethlance.h
index 4f9c90241..e69de29bb 100644
--- a/arch/m68k/boot/atari/ethlance.h
+++ b/arch/m68k/boot/atari/ethlance.h
@@ -1,7 +0,0 @@
-
-#ifndef _ethlance_h
-#define _ethlance_h
-
-extern ETHIF_SWITCH LanceSwitch;
-
-#endif /* _ethlance_h */
diff --git a/arch/m68k/boot/atari/sysvars.h b/arch/m68k/boot/atari/sysvars.h
index 087d9f695..e69de29bb 100644
--- a/arch/m68k/boot/atari/sysvars.h
+++ b/arch/m68k/boot/atari/sysvars.h
@@ -1,22 +0,0 @@
-typedef struct _osheader
-{
- unsigned short os_entry;
- unsigned short os_version;
- void *reseth;
- struct _osheader *os_beg;
- void *os_end;
- long os_rsv1;
- void *os_magic;
- long os_date;
- unsigned short os_conf;
- unsigned short os_dosdate;
- char **p_root;
- unsigned char **pkbshift;
- void **p_run;
- char *p_rsv2;
-} OSHEADER;
-
-#define phystop ((unsigned long *)0x42e)
-#define _sysbase ((OSHEADER **)0x4f2)
-#define _p_cookies ((unsigned long **)0x5a0)
-#define ramtop ((unsigned long *)0x5a4)
diff --git a/arch/m68k/config.in b/arch/m68k/config.in
index b963687ae..2390fb6fc 100644
--- a/arch/m68k/config.in
+++ b/arch/m68k/config.in
@@ -218,6 +218,10 @@ define_bool CONFIG_VT y
define_bool CONFIG_VT_CONSOLE y
define_bool CONFIG_FB_CONSOLE y
+if [ "$CONFIG_ATARI" = "y" ]; then
+ define_bool CONFIG_NVRAM y
+fi
+
tristate 'Parallel printer support' CONFIG_PRINTER
if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate 'Multiface Card III parallel support' CONFIG_MULTIFACE_III_LP $CONFIG_PRINTER
@@ -243,6 +247,7 @@ if [ "$CONFIG_AMIGA" = "y" ]; then
dep_tristate 'GVP IO-Extender parallel printer support' CONFIG_GVPIOEXT_LP $CONFIG_GVPIOEXT
dep_tristate 'GVP IO-Extender PLIP support' CONFIG_GVPIOEXT_PLIP $CONFIG_GVPIOEXT
tristate 'Multiface Card III serial support' CONFIG_MULTIFACE_III_TTY
+ bool 'Hisoft Whippet PCMCIA serial support' CONFIG_WHIPPET
fi
if [ "$CONFIG_ATARI_MFPSER" = "y" -o "$CONFIG_ATARI_SCC" = "y" -o \
"$CONFIG_ATARI_MIDI" = "y" -o "$CONFIG_AMIGA_BUILTIN_SERIAL" = "y" -o \
diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig
index 18763c58b..65f71d5a9 100644
--- a/arch/m68k/defconfig
+++ b/arch/m68k/defconfig
@@ -152,9 +152,6 @@ CONFIG_NETDEVICES=y
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=y
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=y
diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S
index 35542d4f1..d068d5a16 100644
--- a/arch/m68k/ifpsp060/iskeleton.S
+++ b/arch/m68k/ifpsp060/iskeleton.S
@@ -37,6 +37,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
+
|################################
| (1) EXAMPLE CALL-OUTS #
| #
diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c
index 204f4d3cc..5e7b29717 100644
--- a/arch/m68k/kernel/console.c
+++ b/arch/m68k/kernel/console.c
@@ -420,7 +420,10 @@ int vc_resize(unsigned long lines, unsigned long columns)
set_scrmem(fg_console, 0);
set_origin(fg_console);
#endif /* XXX */
- update_screen(fg_console);
+ /* don't update in graphics mode */
+ if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
+
set_cursor(fg_console);
return 0;
@@ -512,8 +515,9 @@ void vc_resize_con(unsigned long lines, unsigned long columns,
console_table[currcons]->winsize = ws;
}
- if (currcons == fg_console)
- update_screen(fg_console);
+ /* don't update in graphics mode */
+ if (currcons == fg_console && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ update_screen(fg_console);
}
void vc_disallocate(unsigned int currcons)
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 33542ca96..459e9e93a 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -190,7 +190,7 @@ SYMBOL_NAME_LABEL(ret_from_interrupt)
andw #ALLOWINT,%sr
/* check if we need to do software interrupts */
-
+
movel SYMBOL_NAME(bh_active),%d0
andl SYMBOL_NAME(bh_mask),%d0
jeq SYMBOL_NAME(ret_from_exception)
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 36a4072ac..116c3cb27 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -273,6 +273,9 @@ Ltest_berr:
movel %d2,%a0@
lea %pc@(SYMBOL_NAME(is_medusa)),%a0
movel %d3,%a0@
+ lea %pc@(Liobase),%a0
+ movel %d2,%a0@ /* On a Hades the iobase must be set
+ before opening the serial port. */
Lnotypetest:
#endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index ad0662f22..27883a86e 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -283,8 +283,9 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp)
struct pt_regs *regs = (struct pt_regs *) &name;
lock_kernel();
- error = getname(name, &filename);
- if (error)
+ filename = getname(name);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index e29509cac..9c56fed37 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -205,11 +205,10 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
return -ENOSYS;
}
-/* Convert virtual address VADDR to physical address PADDR, recording
- in VALID whether the virtual address is actually mapped. */
-#define virt_to_phys_040(vaddr, paddr, valid) \
-{ \
- unsigned long _mmusr; \
+/* Convert virtual address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr) \
+({ \
+ unsigned long _mmusr, _paddr; \
\
__asm__ __volatile__ (".chip 68040\n\t" \
"ptestr (%1)\n\t" \
@@ -217,20 +216,14 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
".chip 68k" \
: "=r" (_mmusr) \
: "a" (vaddr)); \
- if (!(_mmusr & MMU_R_040)) \
- (valid) = 0; \
- else \
- { \
- (valid) = 1; \
- (paddr) = _mmusr & PAGE_MASK; \
- } \
-}
+ _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \
+ _paddr; \
+})
static inline int
cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
{
- unsigned long paddr;
- int valid;
+ unsigned long paddr, i;
switch (scope)
{
@@ -261,19 +254,31 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
break;
case FLUSH_SCOPE_LINE:
- len >>= 4;
/* Find the physical address of the first mapped page in the
address range. */
- for (;;)
- {
- virt_to_phys_040 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ if ((paddr = virt_to_phys_040(addr))) {
+ paddr += addr & ~(PAGE_MASK | 15);
+ len = (len + (addr & 15) + 15) >> 4;
+ } else {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ len = (len + 15) >> 4;
+ }
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
while (len--)
{
switch (cache)
@@ -301,36 +306,33 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
: : "a" (paddr));
break;
}
- addr += 16;
- if (len)
+ if (!--i && len)
{
- if ((addr & (PAGE_SIZE-1)) < 16)
+ addr += PAGE_SIZE;
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
{
- /* Recompute physical address when crossing a page
- boundary. */
- for (;;)
- {
- virt_to_phys_040 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
}
- else
- paddr += 16;
}
+ else
+ paddr += 16;
}
break;
default:
case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
{
- virt_to_phys_040 (addr, paddr, valid);
- if (!valid)
+ if (!(paddr = virt_to_phys_040(addr)))
continue;
switch (cache)
{
@@ -363,21 +365,21 @@ cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
return 0;
}
-#define virt_to_phys_060(vaddr, paddr, valid) \
-{ \
+#define virt_to_phys_060(vaddr) \
+({ \
+ unsigned long paddr; \
__asm__ __volatile__ (".chip 68060\n\t" \
"plpar (%0)\n\t" \
".chip 68k" \
: "=a" (paddr) \
: "0" (vaddr)); \
- (valid) = 1; /* XXX */ \
-}
+ (paddr); /* XXX */ \
+})
static inline int
cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
{
- unsigned long paddr;
- int valid;
+ unsigned long paddr, i;
switch (scope)
{
@@ -407,19 +409,30 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
break;
case FLUSH_SCOPE_LINE:
- len >>= 4;
/* Find the physical address of the first mapped page in the
address range. */
- for (;;)
- {
- virt_to_phys_060 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
+ len += addr & 15;
+ addr &= -16;
+ if (!(paddr = virt_to_phys_060(addr))) {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ }
+ len = (len + 15) >> 4;
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
while (len--)
{
switch (cache)
@@ -447,36 +460,35 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
: : "a" (paddr));
break;
}
- addr += 16;
- if (len)
+ if (!--i && len)
{
- if ((addr & (PAGE_SIZE-1)) < 16)
- {
- /* Recompute the physical address when crossing a
- page boundary. */
- for (;;)
- {
- virt_to_phys_060 (addr, paddr, valid);
- if (valid)
- break;
- if (len <= PAGE_SIZE / 16)
- return 0;
- len -= (PAGE_SIZE - (addr & PAGE_MASK)) / 16;
- addr = (addr + PAGE_SIZE) & PAGE_MASK;
- }
- }
- else
- paddr += 16;
+ addr += PAGE_SIZE;
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
+ }
}
+ else
+ paddr += 16;
}
break;
default:
case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+ addr &= PAGE_MASK; /* Workaround for bug in some
+ revisions of the 68060 */
for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
{
- virt_to_phys_060 (addr, paddr, valid);
- if (!valid)
+ if (!(paddr = virt_to_phys_060(addr)))
continue;
switch (cache)
{
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index dd834efd9..f632508f0 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -41,7 +41,6 @@ zdisk: zImage
fi
dep:
- $(CPP) -M *.[cS] > .depend
clean:
rm -f zImage zImage.tmp mkboot
diff --git a/arch/mips/config.in b/arch/mips/config.in
index 22aff787f..35903797a 100644
--- a/arch/mips/config.in
+++ b/arch/mips/config.in
@@ -84,7 +84,7 @@ bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
if [ "$CONFIG_SGI" != "y" ]; then
- tristate 'Parallel port support' CONFIG_PARPORT
+ tristate 'Parallel port support' CONFIG_PNP_PARPORT
fi
endmenu
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 082dc7520..a40178f36 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -1,4 +1,4 @@
-/* $Id: irixsig.c,v 1.3 1997/07/24 11:28:49 ralf Exp $
+/* $Id: irixsig.c,v 1.3 1997/07/29 03:04:27 ralf Exp $
* irixsig.c: WHEEE, IRIX signals! YOW, am I compatable or what?!?!
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -142,7 +142,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -180,7 +180,7 @@ asmlinkage int do_irix_signal(unsigned long oldmask, struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
@@ -679,7 +679,7 @@ repeat:
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
- notify_parent(p);
+ notify_parent(p, SIGCHLD);
} else
release(p);
goto end_waitsys;
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index e61911549..97a11abc4 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -488,7 +488,7 @@ asmlinkage void syscall_trace(void)
return;
current->exit_code = SIGTRAP;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
/*
* this isn't the same as continuing with a signal, but it will do
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 1c18ce912..34ed87fb6 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -4,7 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996 Ralf Baechle
*
- * $Id: signal.c,v 1.3 1997/06/25 14:48:36 ralf Exp $
+ * $Id: signal.c,v 1.3 1997/06/25 20:08:49 ralf Exp $
*/
#include <linux/config.h>
#include <linux/sched.h>
@@ -292,7 +292,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
current->exit_code = signr;
current->state = TASK_STOPPED;
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
if (!(signr = current->exit_code))
continue;
@@ -332,7 +332,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
SA_NOCLDSTOP))
- notify_parent(current);
+ notify_parent(current, SIGCHLD);
schedule();
continue;
diff --git a/arch/mips/kernel/syscalls.h b/arch/mips/kernel/syscalls.h
index 66d66ce5b..fd1b39bca 100644
--- a/arch/mips/kernel/syscalls.h
+++ b/arch/mips/kernel/syscalls.h
@@ -7,7 +7,7 @@
*
* Copyright (C) 1995, 1996, 1997 by Ralf Baechle
*
- * $Id: syscalls.h,v 1.4 1997/06/25 20:07:40 ralf Exp $
+ * $Id: syscalls.h,v 1.5 1997/07/20 14:57:27 ralf Exp $
*/
/*
@@ -210,3 +210,5 @@ SYS(sys_poll, 3)
SYS(sys_nfsservctl, 3)
SYS(sys_setresgid, 3) /* 4190 */
SYS(sys_getresgid, 3)
+SYS(sys_setresgid, 3) /* 4190 */
+SYS(sys_getresgid, 3)
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index e87e5084b..c1b672e76 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.4 1997/07/19 19:03:18 root Exp $
+/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
* sysirix.c: IRIX system call emulation.
*
* Copyright (C) 1996 David S. Miller
@@ -751,6 +751,8 @@ asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
}
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -1514,6 +1516,8 @@ asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
@@ -1877,6 +1881,8 @@ asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
error = 0;
+dput_and_out:
+ dput(dentry);
out:
unlock_kernel();
return error;
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index cdbcacb43..b7ceea080 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -196,6 +196,8 @@ static void default_be_board_handler(struct pt_regs *regs)
/*
* Assume it would be too dangerous to continue ...
*/
+ printk ("BE HANDLER\n");
+ show_regs (regs);
force_sig(SIGBUS, current);
}
diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c
index 553508056..0c7f81877 100644
--- a/arch/mips/lib/dump_tlb.c
+++ b/arch/mips/lib/dump_tlb.c
@@ -16,12 +16,27 @@
#include <asm/page.h>
#include <asm/pgtable.h>
+static char *region_map [] = {
+ "u", "s", "k", "!"
+};
+
+static char *cache_map [] = {
+ "c/nc/wt/nwa,",
+ "c/nc/wt/wa, ",
+ "uncached, ",
+ "c/nc/wb, "
+ "unknown, ",
+ "unknown, ",
+ "unknown, ",
+ "unknown, "
+};
+
void
dump_tlb(int first, int last)
{
int i;
int wired;
- unsigned int pagemask;
+ unsigned int pagemask, c0, c1, r;
unsigned long long entryhi, entrylo0, entrylo1;
wired = read_32bit_cp0_register(CP0_WIRED);
@@ -48,14 +63,25 @@ dump_tlb(int first, int last)
/*
* Only print entries in use
*/
- printk("\nIndex: %2d %08x", i, pagemask);
-
- printk(" %08x %08x", (unsigned int)(entryhi >> 32),
- (unsigned int) entryhi);
- printk(" %08x %08x", (unsigned int)(entrylo0 >> 32),
- (unsigned int) entrylo0);
- printk(" %08x %08x", (unsigned int)(entrylo1 >> 32),
- (unsigned int) entrylo1);
+ printk("\nIndex: %2d pgmask=%08x ", i, pagemask);
+
+ r = entryhi >> 62;
+ c0 = (entrylo0 >> 3) & 7;
+ c1 = (entrylo1 >> 3) & 7;
+
+ printk("%s vpn2=%08x "
+ "[pfn=%06x c=%d d=%d v=%d g=%d]"
+ "[pfn=%06x c=%d d=%d v=%d g=%d]",
+ region_map [r], (entryhi >> 13) & 0xffffffff,
+ (entrylo0 >> 6) & 0xffffff, c0,
+ (entrylo0 & 4) ? 1 : 0,
+ (entrylo0 & 2) ? 1 : 0,
+ (entrylo0 & 1),
+ (entrylo1 >> 6) & 0xffffff, c1,
+ (entrylo1 & 4) ? 1 : 0,
+ (entrylo1 & 2) ? 1 : 0,
+ (entrylo1 & 1));
+
}
}
printk("\n");
diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c
index c00d63bc8..2b32ca455 100644
--- a/arch/mips/mm/r4xx0.c
+++ b/arch/mips/mm/r4xx0.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r4xx0.c,v 1.4 1997/07/01 09:00:50 ralf Exp $
+ * $Id: r4xx0.c,v 1.5 1997/07/29 22:54:52 tsbogend Exp $
*/
#include <linux/config.h>
@@ -1943,7 +1943,7 @@ static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
int oldpid, newpid, idx;
#ifdef DEBUG_TLB
- printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+ printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
#endif
newpid = (vma->vm_mm->context & 0xff);
page &= (PAGE_MASK << 1);
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index af577c5ae..ac2719977 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -25,61 +25,62 @@ HOSTCC = gcc
CC = gcc$(SUFFIX)
CFLAGSINC = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
CFLAGS = $(CFLAGSINC) \
- -Wstrict-prototypes \
- -fomit-frame-pointer \
+ -Wstrict-prototypes -fomit-frame-pointer \
-fno-builtin \
- -finhibit-size-directive -fno-strength-reduce\
- -O2 -fsigned-char -pipe -mstring -mmultiple
+ -finhibit-size-directive \
+ -O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
+# -fverbose-asm
CPP = $(CC) -E $(CFLAGS)
AR = ar$(SUFFIX)
RANLIB = ranlib$(SUFFIX)
STRIP = strip$(SUFFIX)
NM = nm$(SUFFIX)
-ifdef CONFIG_603
-CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
+ifdef CONFIG_601
+CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
endif
-ifdef CONFIG_603e
-CFLAGS := $(CFLAGS) -mcpu=603e -DCPU=603e
+ifdef CONFIG_603
+CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
endif
ifdef CONFIG_604
CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
endif
-#
-# NFS_ROOT_NAME specifies the default name of the directory to mount
-# as root via NFS, if the kernel does not get the "root=" option from
-# the boot loader. The "%s" will be replaced by the IP-number of the
-# local system.
-#
-NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root\""
-
HEAD := arch/ppc/kernel/head.o
ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib
SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS)
ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
-
+CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
-netboot: vmlinux
+checks:
+ @$(MAKE) -C arch/$(ARCH)/kernel checks
+
+netboot: checks vmlinux
@$(MAKEBOOT) netboot
-znetboot: vmlinux
+znetboot: checks vmlinux
@$(MAKEBOOT) znetboot
-zImage: vmlinux
+#rcpboot: checks vmlinux
+# @$(MAKEBOOT) rcpboot
+
+zImage: checks vmlinux
@$(MAKEBOOT) zImage
-floppy: vmlinux
+floppy: checks vmlinux
@$(MAKEBOOT) floppy
-install: vmlinux
+install: checks vmlinux
@$(MAKEBOOT) install
+vmlinux.coff : checks vmlinux
+ $(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
+
arch/ppc/kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
@@ -89,12 +90,24 @@ arch/ppc/mm: dummy
arch/ppc/lib: dummy
$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
+diffs:
+ arch/ppc/mkdiff
+
+tar:
+ arch/ppc/mktar
archclean:
- rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h TAGS
+ rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
+ rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+ rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
@$(MAKEBOOT) clean
archdep:
+ $(MAKE) -C arch/ppc/boot fastdep
+ $(MAKE) -C arch/ppc/kernel fastdep
+ $(MAKE) -C arch/ppc/mm fastdep
+ $(MAKE) -C arch/ppc/lib fastdep
+
+tags :
+ etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c
-corttags :
- etags arch/ppc/*/*.c include/asm/* */*.c drivers/*/*.c net/*.c
diff --git a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
index 7b4ed71f6..5dcac750e 100644
--- a/arch/ppc/boot/Makefile
+++ b/arch/ppc/boot/Makefile
@@ -7,6 +7,7 @@
#
# Copyright (C) 1994 by Linus Torvalds
# Adapted for PowerPC by Gary Thomas
+# modified by Cort (cort@cs.nmt.edu)
#
.c.s:
@@ -22,7 +23,7 @@
ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
-GZIP_FLAGS = -9
+GZIP_FLAGS = -v9
SYSTEM = $(TOPDIR)/vmlinux
@@ -32,49 +33,51 @@ CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
all: $(TOPDIR)/zImage
-mkboot : cortstrip.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mkboot cortstrip.c
+mkprep : mkprep.c
+ $(HOSTCC) $(CFLAGSINC) -o mkprep mkprep.c
+
+find_name : find_name.c
+ $(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
mk_type41: mk_type41.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static -o mk_type41 mk_type41.c
+ $(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
+
+piggyback: piggyback.c
+ $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-floppy: zImage $(TOPDIR)/vmlinux
+floppy: $(TOPDIR)/vmlinux zImage
dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
-netboot : $(TOPDIR)/vmlinux mkboot
- mkboot $(TOPDIR)/vmlinux $(TOPDIR)/netboot
-# rcp $(TOPDIR)/netboot charon:/usr/tftpboot/vmlinux
+netboot : $(TOPDIR)/vmlinux mkprep
+ mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+
+znetboot : zvmlinux mkprep
+ mkprep zvmlinux $(TOPDIR)/znetboot
+ cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
-znetboot : mkboot zvmlinux
- mkboot zvmlinux $(TOPDIR)/znetboot
+rcpboot : znetboot
rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
-zImage: mk_type41 zvmlinux
-# make znetboot ourselves since using the normal dep
-# will rcp it -- Cort
- mkboot zvmlinux $(TOPDIR)/znetboot
- mk_type41 $(TOPDIR)/znetboot $(TOPDIR)/zImage
+zImage: zvmlinux mkprep
+ mkprep -pbp zvmlinux $(TOPDIR)/zImage
install: zImage
dd if=$(TOPDIR)/zImage of=/dev/sda4
ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
cp $(TOPDIR)/System.map $(INSTALL_PATH)/
-zvmlinux: $(OBJECTS) $(SYSTEM) piggyback netboot $(TOPDIR)/vmlinux
- gzip ${GZIP_FLAGS} <$(TOPDIR)/netboot | ./piggyback | $(AS) -o piggy.o
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep find_name
+ mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
$(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
- rm -f piggy.o xx_boot
-
-head.o: head.s
-
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional head.S -o head.s
-
-piggyback: piggyback.c
- $(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+ rm -f piggy.o
clean:
- rm -f piggyback zvmlinux mk_type41 mkprep mkboot
+ rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
dep:
+ $(CPP) -M *.S *.c > .depend
+
diff --git a/arch/ppc/boot/cortstrip.c b/arch/ppc/boot/cortstrip.c
index 78856d2bb..e69de29bb 100644
--- a/arch/ppc/boot/cortstrip.c
+++ b/arch/ppc/boot/cortstrip.c
@@ -1,73 +0,0 @@
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* amount to skip */
-#define PLACE 65536
-
-/* size of read buffer */
-#define SIZE 0x100000
-
-/* crude program to strip the elf header to make a bootable
- image via tftp
- */
-
-
-int main(int argc, char **argv )
-{
- int fd, fdo;
- unsigned char data[SIZE];
- int i, n, skip;
-
-#if 0
- if ( argc != 3 )
- {
- fprintf(stderr,"%s infile outfile\n", argv[0]);
- exit(-1);
- }
-#endif
-
-
- fd = open(argv[1], O_RDONLY);
- if ( fd == -1 )
- {
- fprintf(stderr,"Couldn't open %s\n", argv[1]);
- perror("open()");
- exit(-1);
- }
-
- fdo = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,0755);
- if ( fdo == -1 )
- {
- fprintf(stderr,"Couldn't open %s\n", argv[2]);
- perror("open()");
- exit(-1);
- }
-
-#if 0
- skip = atoi(argv[3]);
-#else
- skip = PLACE;
-#endif
- i = lseek(fd, skip, SEEK_SET);
- /*printf("lseek'd %d bytes\n", i);*/
- if ( i == -1 )
- {
- perror("lseek()");
- }
-
- while ( (n = read(fd, data, SIZE)) > 0 )
- {
- /*printf("Read %d bytes\n", n);*/
- i = write(fdo, data, n);
- /*printf("Wrote %d bytes\n", i); */
- }
-
-
- close(fdo);
- close(fd);
- return(0);
-}
-
-
diff --git a/arch/ppc/boot/gzip.h b/arch/ppc/boot/gzip.h
index 2f738b945..9d8e54a4b 100644
--- a/arch/ppc/boot/gzip.h
+++ b/arch/ppc/boot/gzip.h
@@ -271,7 +271,7 @@ extern int fill_inbuf OF((void));
extern void flush_outbuf OF((void));
extern void flush_window OF((void));
extern char *strlwr OF((char *s));
-extern char *basename OF((char *fname));
+/*extern char *basename OF((char *fname));*/
extern char *add_envopt OF((int *argcp, char ***argvp, char *env));
extern void error OF((char *m));
extern void warn OF((char *a, char *b));
diff --git a/arch/ppc/boot/head.S b/arch/ppc/boot/head.S
index 35dacd514..6b25cb157 100644
--- a/arch/ppc/boot/head.S
+++ b/arch/ppc/boot/head.S
@@ -1,5 +1,6 @@
#include "../kernel/ppc_defs.h"
#include "../kernel/ppc_asm.tmpl"
+#include <asm/processor.h>
.text
diff --git a/arch/ppc/boot/inflate.c b/arch/ppc/boot/inflate.c
index 848fef6ae..1beecacdb 100644
--- a/arch/ppc/boot/inflate.c
+++ b/arch/ppc/boot/inflate.c
@@ -9,7 +9,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+static char rcsid[] = "$Id: inflate.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
#endif
#include "gzip.h"
diff --git a/arch/ppc/boot/misc.c b/arch/ppc/boot/misc.c
index 0b1638562..a983ea106 100644
--- a/arch/ppc/boot/misc.c
+++ b/arch/ppc/boot/misc.c
@@ -327,7 +327,7 @@ decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, R
_put_MSR(_get_MSR() & ~0x0030);
vga_init(0xC0000000);
- clear_screen();
+ /*clear_screen();*/
output_ptr = 0;
@@ -373,93 +373,6 @@ show_residual_data(RESIDUAL *res)
#endif
}
-#if 0
-verify_ram()
-{
- unsigned long loc;
- puts("Clearing memory:");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0x0;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0x0)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("0");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0xFFFFFFFF;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0xFFFFFFFF)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("1");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = loc;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != loc)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("?");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0xDEADB00B;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0xDEADB00B)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts(">");
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- *(unsigned long *)loc = 0x0;
- }
- for (loc = 0; loc <= 0x400000; loc += 4);
- {
- if (*(unsigned long *)loc != 0x0)
- {
- puts(" - failed at ");
- puthex(loc);
- puts(": ");
- puthex(*(unsigned long *)loc);
- while (1);
- }
- }
- puts("\n");
-}
-
do_cksum(unsigned long loc)
{
unsigned int ptr, cksum;
@@ -582,7 +495,6 @@ test_data(unsigned long load_addr)
}
return (errors == 0);
}
-#endif
void puthex(unsigned long val)
{
diff --git a/arch/ppc/boot/mk_type41.c b/arch/ppc/boot/mk_type41.c
index 4e2a7b3aa..e69de29bb 100644
--- a/arch/ppc/boot/mk_type41.c
+++ b/arch/ppc/boot/mk_type41.c
@@ -1,208 +0,0 @@
-/*
- * This program will make a type 0x41 load image from an
- * executable file. Note: assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
- */
-
-#include <stdio.h>
-#include <errno.h>
-#ifdef linux
-#include <asm/stat.h>
-#else
-#include <sys/stat.h>
-#endif
-
-_LE(long val, unsigned char *le)
-{
- le[0] = val;
- le[1] = val >> 8;
- le[2] = val >> 16;
- le[3] = val >> 24;
-}
-
-main(int argc, char *argv[])
-{
- int in_fd, out_fd, len, size;
- struct stat info;
- char buf[8192];
- struct hdr
- {
- unsigned long entry_point;
- unsigned long image_length;
- } hdr;
- if (argc != 3)
- {
- fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
- exit(1);
- }
- if ((in_fd = open(argv[1], 0)) < 0)
- {
- fprintf(stderr, "Can't open input file: '%s': %s\n", argv[1], strerror(errno));
- exit(2);
- }
- if ((out_fd = creat(argv[2], 0666)) < 0)
- {
- fprintf(stderr, "Can't create output file: '%s': %s\n", argv[2], strerror(errno));
- exit(2);
- }
- if (fstat(in_fd, &info) < 0)
- {
- fprintf(stderr, "Can't get info on input file: %s\n", strerror(errno));
- exit(4);
- }
- write_prep_boot_partition(out_fd);
- _LE(0x400, &hdr.entry_point);
- _LE(info.st_size+0x400, &hdr.image_length);
- lseek(out_fd, 0x200, 0);
- if (write(out_fd, &hdr, sizeof(hdr)) != sizeof(hdr))
- {
- fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
- exit(5);
- }
- lseek(out_fd, 0x400, 0);
- while ((len = read(in_fd, buf, sizeof(buf))) > 0)
- {
- if (write(out_fd, buf, len) != len)
- {
- fprintf(stderr, "Can't write output file: %s\n", strerror(errno));
- exit(5);
- }
- }
- if (len < 0)
- {
- fprintf(stderr, "Can't read input file: %s\n", strerror(errno));
- exit(6);
- }
- close(in_fd);
- close(out_fd);
-}
-
-/* Adapted from IBM Naked Application Package (NAP) */
-
-#define Align(value,boundary) \
- (((value) + (boundary) - 1) & ~((boundary) - 1))
-
-#define HiByte(word) ((word_t)(word) >> 8)
-#define LoByte(word) ((word_t)(word) & 0xFF)
-
-#define HiWord(dword) ((dword_t)(dword) >> 16)
-#define LoWord(dword) ((dword_t)(dword) & 0xFFFF)
-
-/*
- * Little-endian stuff
- */
-#define LeWord(word) \
- (((word_t)(word) >> 8) | ((word_t)(word) << 8))
-
-#define LeDword(dword) \
- (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-#define PcDword(dword) \
- (LeWord(LoWord(dword)) << 16) | LeWord(HiWord(dword))
-
-
-typedef unsigned long dword_t;
-typedef unsigned short word_t;
-typedef unsigned char byte_t;
-typedef byte_t block_t[512];
-typedef byte_t page_t[4096];
-
-/*
- * Partition table entry
- * - from the PReP spec
- */
-typedef struct partition_entry {
- byte_t boot_indicator;
- byte_t starting_head;
- byte_t starting_sector;
- byte_t starting_cylinder;
-
- byte_t system_indicator;
- byte_t ending_head;
- byte_t ending_sector;
- byte_t ending_cylinder;
-
- dword_t beginning_sector;
- dword_t number_of_sectors;
-} partition_entry_t;
-
-#define BootActive 0x80
-#define SystemPrep 0x41
-
-
-/*
- * Writes the "boot record", which contains the partition table, to the
- * diskette, followed by the dummy PC boot block and load image descriptor
- * block. It returns the number of bytes it has written to the load
- * image.
- *
- * The boot record is the first block of the diskette and identifies the
- * "PReP" partition. The "PReP" partition contains the "load image" starting
- * at offset zero within the partition. The first block of the load image is
- * a dummy PC boot block. The second block is the "load image descriptor"
- * which contains the size of the load image and the entry point into the
- * image. The actual boot image starts at offset 1024 bytes (third sector)
- * in the partition.
- */
-void
-write_prep_boot_partition(int out_fd)
-{
- block_t block;
- partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
- dword_t *entry = (dword_t *)&block[0];
- dword_t *length = (dword_t *)&block[4];
-
- bzero( &block, sizeof block );
-
- /*
- * Magic marker
- */
- block[510] = 0x55;
- block[511] = 0xAA;
-
- /*
- * Build a "PReP" partition table entry in the boot record
- * - "PReP" may only look at the system_indicator
- */
- pe->boot_indicator = BootActive;
- pe->system_indicator = SystemPrep;
-
- /*
- * The first block of the diskette is used by this "boot record" which
- * actually contains the partition table. (The first block of the
- * partition contains the boot image, but I digress...) We'll set up
- * one partition on the diskette and it shall contain the rest of the
- * diskette.
- */
- pe->starting_head = 0; /* zero-based */
- pe->starting_sector = 2; /* one-based */
- pe->starting_cylinder = 0; /* zero-based */
-
- pe->ending_head = 1; /* assumes two heads */
- pe->ending_sector = 18; /* assumes 18 sectors/track */
- pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
-
- /*
- * The "PReP" software ignores the above fields and just looks at
- * the next two.
- * - size of the diskette is (assumed to be)
- * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
- * - unlike the above sector numbers, the beginning sector is zero-based!
- */
-#if 0
- pe->beginning_sector = LeDword(1);
-#else
- /* This has to be 0 on the PowerStack? */
- pe->beginning_sector = LeDword(0);
-#endif
- pe->number_of_sectors = LeDword(2*18*80-1);
-
- /*
- * Write the partition table
- */
- lseek( out_fd, 0, 0 );
- write( out_fd, block, sizeof block );
-}
-
diff --git a/arch/ppc/boot/mkprep.c b/arch/ppc/boot/mkprep.c
index a79ad98f2..417334670 100644
--- a/arch/ppc/boot/mkprep.c
+++ b/arch/ppc/boot/mkprep.c
@@ -1,19 +1,54 @@
/*
- * This program will make a type 0x41 load image from an
- * executable file. Note: assumes that the executable has
- * already been "flattened" by 'mkboot'.
- *
- * usage: mk_type41 flat-file image
+ * Makes a prep bootable image which can be dd'd onto
+ * a disk device to make a bootdisk. Will take
+ * as input a elf executable, strip off the header
+ * and write out a boot image as:
+ * 1) default - strips elf header
+ * suitable as a network boot image
+ * 2) -pbp - strips elf header and writes out prep boot partition image
+ * cat or dd onto disk for booting
+ * 3) -asm - strips elf header and writes out as asm data
+ * useful for generating data for a compressed image
+ * -- Cort
*/
-#include <stdio.h>
-#include <errno.h>
#ifdef linux
+#include <linux/types.h>
#include <asm/stat.h>
+/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
#else
+#include <unistd.h>
#include <sys/stat.h>
#endif
-#include <asm/byteorder.h> /* use same as kernel -- Cort */
+
+#include <stdio.h>
+#include <errno.h>
+
+#define cpu_to_le32(x) le32_to_cpu((x))
+unsigned long le32_to_cpu(unsigned long x)
+{
+ return (((x & 0x000000ffU) << 24) |
+ ((x & 0x0000ff00U) << 8) |
+ ((x & 0x00ff0000U) >> 8) |
+ ((x & 0xff000000U) >> 24));
+}
+
+
+#define cpu_to_le16(x) le16_to_cpu((x))
+unsigned short le16_to_cpu(unsigned short x)
+{
+ return (((x & 0x00ff) << 8) |
+ ((x & 0xff00) >> 8));
+}
+
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+
+/* size of read buffer */
+#define SIZE 0x1000
+
typedef unsigned long dword_t;
typedef unsigned short word_t;
@@ -21,119 +56,239 @@ typedef unsigned char byte_t;
typedef byte_t block_t[512];
typedef byte_t page_t[4096];
-_LE(long val, unsigned char *le)
-{
- le[0] = val;
- le[1] = val >> 8;
- le[2] = val >> 16;
- le[3] = val >> 24;
-}
/*
* Partition table entry
* - from the PReP spec
*/
typedef struct partition_entry {
- byte_t boot_indicator;
- byte_t starting_head;
- byte_t starting_sector;
- byte_t starting_cylinder;
-
- byte_t system_indicator;
- byte_t ending_head;
- byte_t ending_sector;
- byte_t ending_cylinder;
-
- dword_t beginning_sector;
- dword_t number_of_sectors;
+ byte_t boot_indicator;
+ byte_t starting_head;
+ byte_t starting_sector;
+ byte_t starting_cylinder;
+
+ byte_t system_indicator;
+ byte_t ending_head;
+ byte_t ending_sector;
+ byte_t ending_cylinder;
+
+ dword_t beginning_sector;
+ dword_t number_of_sectors;
} partition_entry_t;
#define BootActive 0x80
#define SystemPrep 0x41
+void copy_image(int , int);
+void write_prep_partition(int , int );
+void write_asm_data( int in, int out );
+
+unsigned int elfhdr_size = 65536;
int main(int argc, char *argv[])
{
- struct stat info;
- char buf[8192];
- int in_fd, out_fd,len;
+ int in_fd, out_fd;
+ int argptr = 1;
+ unsigned int prep = 0;
+ unsigned int asmoutput = 0;
+
+ if ( (argc < 3) || (argc > 4) )
+ {
+ fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
+ exit(-1);
+ }
+
+ /* needs to handle args more elegantly -- but this is a small/simple program */
+
+ /* check for -pbp */
+ if ( !strcmp( argv[argptr], "-pbp" ) )
+ {
+ prep = 1;
+ argptr++;
+ }
+
+ /* check for -asm */
+ if ( !strcmp( argv[argptr], "-asm" ) )
+ {
+ asmoutput = 1;
+ argptr++;
+ }
+
+ /* input file */
+ if ( !strcmp( argv[argptr], "-" ) )
+ in_fd = 0; /* stdin */
+ else
+ if ((in_fd = open( argv[argptr] , 0)) < 0)
+ exit(-1);
+ argptr++;
+
+ /* output file */
+ if ( !strcmp( argv[argptr], "-" ) )
+ out_fd = 1; /* stdout */
+ else
+ if ((out_fd = creat( argv[argptr] , 0755)) < 0)
+ exit(-1);
+ argptr++;
+
+ /* skip elf header in input file */
+ lseek(in_fd, elfhdr_size, SEEK_SET);
+
+ /* write prep partition if necessary */
+ if ( prep )
+ write_prep_partition( in_fd, out_fd );
+
+ /* write input image to bootimage */
+ if ( asmoutput )
+ write_asm_data( in_fd, out_fd );
+ else
+ copy_image(in_fd, out_fd);
+
+ return 0;
+}
+
+void write_prep_partition(int in, int out)
+{
unsigned char block[512];
partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
- dword_t *entry = (dword_t *)&block[0x50];
- dword_t *length = (dword_t *)&block[0x51];
+ dword_t *entry = (dword_t *)&block[0];
+ dword_t *length = (dword_t *)&block[sizeof(long)];
+ struct stat info;
- if (argc != 3)
- {
- fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
- exit(1);
- }
- if ((in_fd = open(argv[1], 0)) < 0)
- {
- exit(2);
- }
- if ((out_fd = creat(argv[2], 0755)) < 0)
- {
- exit(2);
- }
+ if (fstat(in, &info) < 0)
+ {
+ fprintf(stderr,"info failed\n");
+ exit(-1);
+ }
+
+ bzero( block, sizeof block );
- bzero( &block, sizeof block );
-
+
+ /* set entry point and boot image size */
+ *entry = cpu_to_le32(0x400);
+ /* need use size - elfheader? */
+ *length = cpu_to_le32(info.st_size+0x400);
/*
- * Magic marker
+ * Writes the "boot record", which contains the partition table, to the
+ * diskette, followed by the dummy PC boot block and load image descriptor
+ * block. It returns the number of bytes it has written to the load
+ * image.
+ *
+ * The boot record is the first block of the diskette and identifies the
+ * "PReP" partition. The "PReP" partition contains the "load image" starting
+ * at offset zero within the partition. The first block of the load image is
+ * a dummy PC boot block. The second block is the "load image descriptor"
+ * which contains the size of the load image and the entry point into the
+ * image. The actual boot image starts at offset 1024 bytes (third sector)
+ * in the partition.
*/
+
+ /* sets magic number for msdos partition (used by linux) */
block[510] = 0x55;
block[511] = 0xAA;
+ /*
+ * Build a "PReP" partition table entry in the boot record
+ * - "PReP" may only look at the system_indicator
+ */
pe->boot_indicator = BootActive;
pe->system_indicator = SystemPrep;
- pe->starting_head = 0; /* zero-based */
- pe->starting_sector = 2; /* one-based */
- pe->starting_cylinder = 0; /* zero-based */
-
- pe->ending_head = 1; /* assumes two heads */
- pe->ending_sector = 18; /* assumes 18 sectors/track */
- pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+ /*
+ * The first block of the diskette is used by this "boot record" which
+ * actually contains the partition table. (The first block of the
+ * partition contains the boot image, but I digress...) We'll set up
+ * one partition on the diskette and it shall contain the rest of the
+ * diskette.
+ */
+ pe->starting_head = 0; /* zero-based */
+ pe->starting_sector = 2; /* one-based */
+ pe->starting_cylinder = 0; /* zero-based */
+ pe->ending_head = 1; /* assumes two heads */
+ pe->ending_sector = 18; /* assumes 18 sectors/track */
+ pe->ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+ /*
+ * The "PReP" software ignores the above fields and just looks at
+ * the next two.
+ * - size of the diskette is (assumed to be)
+ * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+ * - unlike the above sector numbers, the beginning sector is zero-based!
+ */
#if 0
-#if 0
- pe->beginning_sector = LeDword(1);
+ pe->beginning_sector = cpu_to_le32(1);
#else
- /* This has to be 0 on the PowerStack? */
- pe->beginning_sector = LeDword(0);
-#endif
- pe->number_of_sectors = LeDword(2*18*80-1);
-#endif
+ /* This has to be 0 on the PowerStack? */
+ pe->beginning_sector = cpu_to_le32(0);
+#endif
+/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+
+ write( out, block, sizeof(block) );
+ write( out, entry, sizeof(*entry) );
+ write( out, length, sizeof(*length) );
+ /* set file position to 2nd sector where image will be written */
+ lseek( out, 0x400, SEEK_SET );
+}
+
+
+
+void
+copy_image(int in, int out)
+{
+ char buf[SIZE];
+ int n;
+
+ while ( (n = read(in, buf, SIZE)) > 0 )
+ write(out, buf, n);
+}
+
+
+void
+write_asm_data( int in, int out )
+{
+ int i, cnt, pos, len;
+ unsigned int cksum, val;
+ unsigned char *lp;
+ unsigned char buf[SIZE];
+ unsigned char str[256];
- if (fstat(in_fd, &info) < 0)
+ write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
+ strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
+ pos = 0;
+ cksum = 0;
+ while ((len = read(in, buf, sizeof(buf))) > 0)
+ {
+ cnt = 0;
+ lp = (unsigned char *)buf;
+ len = (len + 3) & ~3; /* Round up to longwords */
+ for (i = 0; i < len; i += 4)
{
- exit(4);
+ if (cnt == 0)
+ {
+ write( out, "\t.long\t", strlen( "\t.long\t" ) );
+ }
+ sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+ write( out, str, strlen(str) );
+ val = *(unsigned long *)lp;
+ cksum ^= val;
+ lp += 4;
+ if (++cnt == 4)
+ {
+ cnt = 0;
+ sprintf( str, " # %x \n", pos+i-12);
+ write( out, str, strlen(str) );
+ } else
+ {
+ write( out, ",", 1 );
+ }
}
- /* begin execution at 0x400 */
- _LE(0x400,(unsigned char *)entry);
- _LE(info.st_size+0x400,length);
-
- lseek( out_fd, 0, 0 );
- /* write out 1st block */
- write( out_fd, block, sizeof block );
-
- /* copy image */
-#if 1
- lseek(out_fd, 0x400, 0);
- while ((len = read(in_fd, buf, sizeof(buf))) > 0)
- {
- if (write(out_fd, buf, len) != len)
- {
- exit(5);
- }
- }
- if (len < 0)
- {
- exit(6);
- }
- close(in_fd);
- close(out_fd);
-#endif
- return 0;
-}
+ if (cnt)
+ {
+ write( out, "0\n", 2 );
+ }
+ pos += len;
+ }
+ sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+ write( out, str, strlen(str) );
+ fprintf(stderr, "cksum = %x\n", cksum);
+}
diff --git a/arch/ppc/boot/piggyback.c b/arch/ppc/boot/piggyback.c
index ca9fc2957..e69de29bb 100644
--- a/arch/ppc/boot/piggyback.c
+++ b/arch/ppc/boot/piggyback.c
@@ -1,64 +0,0 @@
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[8192];
- if (argc != 1)
- {
- fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
- exit(1);
- }
- fprintf(stdout, "#\n");
- fprintf(stdout, "# Miscellaneous data structures:\n");
- fprintf(stdout, "# WARNING - this file is automatically generated!\n");
- fprintf(stdout, "#\n");
- fprintf(stdout, "\n");
- fprintf(stdout, "\t.data\n");
- fprintf(stdout, "\t.globl input_data\n");
- fprintf(stdout, "input_data:\n");
- pos = 0;
- cksum = 0;
- while ((len = read(0, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- fprintf(stdout, "\t.long\t");
- }
- fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- fprintf(stdout, " # %x \n", pos+i-12);
- fflush(stdout);
- } else
- {
- fprintf(stdout, ",");
- }
- }
- if (cnt)
- {
- fprintf(stdout, "0\n");
- }
- pos += len;
- }
- fprintf(stdout, "\t.globl input_len\n");
- fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
- fflush(stdout);
- fclose(stdout);
- fprintf(stderr, "cksum = %x\n", cksum);
- exit(0);
-}
-
diff --git a/arch/ppc/boot/unzip.c b/arch/ppc/boot/unzip.c
index 0c660adcf..fcebd9dd8 100644
--- a/arch/ppc/boot/unzip.c
+++ b/arch/ppc/boot/unzip.c
@@ -17,7 +17,7 @@
*/
#ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+static char rcsid[] = "$Id: unzip.c,v 1.1.1.1 1997/02/25 05:18:11 cort Exp $";
#endif
#include "gzip.h"
diff --git a/arch/ppc/boot/vreset.c b/arch/ppc/boot/vreset.c
index 7da3670c8..3bc3936c6 100644
--- a/arch/ppc/boot/vreset.c
+++ b/arch/ppc/boot/vreset.c
@@ -7,6 +7,864 @@
* Steve Sellgren
* San Francisco Indigo Company
* sfindigo!sellgren@uunet.uu.net
+ *
+ * Original concept by:
+ * Gary Thomas <gdt@linuxppc.org>
+ * Adapted for Moto boxes by:
+ * Pat Kane & Mark Scott, 1996
+ * Adapted for IBM portables by:
+ * Takeshi Ishimoto
+ * Multi-console support:
+ * Terje Malmedal <terje.malmedal@usit.uio.no>
+ */
+
+#include "iso_font.h"
+#include <linux/delay.h>
+
+extern char *vidmem;
+extern int lines, cols;
+/* estimate for delay */
+unsigned long loops_per_sec = 50000000;;
+/*
+ * VGA Register
+ */
+struct VgaRegs
+{
+ unsigned short io_port;
+ unsigned char io_index;
+ unsigned char io_value;
+};
+
+/*
+ * Default console text mode registers used to reset
+ * graphics adapter.
+ */
+#define NREGS 54
+#define ENDMK 0xFFFF /* End marker */
+
+#define S3Vendor 0x5333
+#define CirrusVendor 0x1013
+#define DiamondVendor 0x100E
+#define MatroxVendor 0x102B
+#define ParadiseVendor 0x101C
+
+struct VgaRegs GenVgaTextRegs[NREGS+1] = {
+/* port index value */
+ /* SR Regs */
+ 0x3c4, 0x1, 0x0,
+ 0x3c4, 0x2, 0x3,
+ 0x3c4, 0x3, 0x0,
+ 0x3c4, 0x4, 0x2,
+ /* CR Regs */
+ 0x3d4, 0x0, 0x5f,
+ 0x3d4, 0x1, 0x4f,
+ 0x3d4, 0x2, 0x50,
+ 0x3d4, 0x3, 0x82,
+ 0x3d4, 0x4, 0x55,
+ 0x3d4, 0x5, 0x81,
+ 0x3d4, 0x6, 0xbf,
+ 0x3d4, 0x7, 0x1f,
+ 0x3d4, 0x8, 0x00,
+ 0x3d4, 0x9, 0x4f,
+ 0x3d4, 0xa, 0x0d,
+ 0x3d4, 0xb, 0x0e,
+ 0x3d4, 0xc, 0x00,
+ 0x3d4, 0xd, 0x00,
+ 0x3d4, 0xe, 0x00,
+ 0x3d4, 0xf, 0x00,
+ 0x3d4, 0x10, 0x9c,
+ 0x3d4, 0x11, 0x8e,
+ 0x3d4, 0x12, 0x8f,
+ 0x3d4, 0x13, 0x28,
+ 0x3d4, 0x14, 0x1f,
+ 0x3d4, 0x15, 0x96,
+ 0x3d4, 0x16, 0xb9,
+ 0x3d4, 0x17, 0xa3,
+ /* GR Regs */
+ 0x3ce, 0x0, 0x0,
+ 0x3ce, 0x1, 0x0,
+ 0x3ce, 0x2, 0x0,
+ 0x3ce, 0x3, 0x0,
+ 0x3ce, 0x4, 0x0,
+ 0x3ce, 0x5, 0x10,
+ 0x3ce, 0x6, 0xe,
+ 0x3ce, 0x7, 0x0,
+ 0x3ce, 0x8, 0xff,
+ ENDMK
+};
+
+struct VgaRegs S3TextRegs[NREGS+1] = {
+/* port index value */
+ /* SR Regs */
+ 0x3c4, 0x1, 0x0,
+ 0x3c4, 0x2, 0x3,
+ 0x3c4, 0x3, 0x0,
+ 0x3c4, 0x4, 0x2,
+ /* CR Regs */
+ 0x3d4, 0x0, 0x5f,
+ 0x3d4, 0x1, 0x4f,
+ 0x3d4, 0x2, 0x50,
+ 0x3d4, 0x3, 0x82,
+ 0x3d4, 0x4, 0x55,
+ 0x3d4, 0x5, 0x81,
+ 0x3d4, 0x6, 0xbf,
+ 0x3d4, 0x7, 0x1f,
+ 0x3d4, 0x8, 0x00,
+ 0x3d4, 0x9, 0x4f,
+ 0x3d4, 0xa, 0x0d,
+ 0x3d4, 0xb, 0x0e,
+ 0x3d4, 0xc, 0x00,
+ 0x3d4, 0xd, 0x00,
+ 0x3d4, 0xe, 0x00,
+ 0x3d4, 0xf, 0x00,
+ 0x3d4, 0x10, 0x9c,
+ 0x3d4, 0x11, 0x8e,
+ 0x3d4, 0x12, 0x8f,
+ 0x3d4, 0x13, 0x28,
+ 0x3d4, 0x14, 0x1f,
+ 0x3d4, 0x15, 0x96,
+ 0x3d4, 0x16, 0xb9,
+ 0x3d4, 0x17, 0xa3,
+ /* GR Regs */
+ 0x3ce, 0x0, 0x0,
+ 0x3ce, 0x1, 0x0,
+ 0x3ce, 0x2, 0x0,
+ 0x3ce, 0x3, 0x0,
+ 0x3ce, 0x4, 0x0,
+ 0x3ce, 0x5, 0x10,
+ 0x3ce, 0x6, 0xe,
+ 0x3ce, 0x7, 0x0,
+ 0x3ce, 0x8, 0xff,
+ ENDMK
+};
+
+struct RGBColors
+{
+ unsigned char r, g, b;
+};
+
+/*
+ * Default console text mode color table.
+ * These values were obtained by booting Linux with
+ * text mode firmware & then dumping the registers.
+ */
+struct RGBColors TextCLUT[256] =
+{
+ /* red green blue */
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x2a,
+ 0x0, 0x2a, 0x0,
+ 0x0, 0x2a, 0x2a,
+ 0x2a, 0x0, 0x0,
+ 0x2a, 0x0, 0x2a,
+ 0x2a, 0x2a, 0x0,
+ 0x2a, 0x2a, 0x2a,
+ 0x0, 0x0, 0x15,
+ 0x0, 0x0, 0x3f,
+ 0x0, 0x2a, 0x15,
+ 0x0, 0x2a, 0x3f,
+ 0x2a, 0x0, 0x15,
+ 0x2a, 0x0, 0x3f,
+ 0x2a, 0x2a, 0x15,
+ 0x2a, 0x2a, 0x3f,
+ 0x0, 0x15, 0x0,
+ 0x0, 0x15, 0x2a,
+ 0x0, 0x3f, 0x0,
+ 0x0, 0x3f, 0x2a,
+ 0x2a, 0x15, 0x0,
+ 0x2a, 0x15, 0x2a,
+ 0x2a, 0x3f, 0x0,
+ 0x2a, 0x3f, 0x2a,
+ 0x0, 0x15, 0x15,
+ 0x0, 0x15, 0x3f,
+ 0x0, 0x3f, 0x15,
+ 0x0, 0x3f, 0x3f,
+ 0x2a, 0x15, 0x15,
+ 0x2a, 0x15, 0x3f,
+ 0x2a, 0x3f, 0x15,
+ 0x2a, 0x3f, 0x3f,
+ 0x15, 0x0, 0x0,
+ 0x15, 0x0, 0x2a,
+ 0x15, 0x2a, 0x0,
+ 0x15, 0x2a, 0x2a,
+ 0x3f, 0x0, 0x0,
+ 0x3f, 0x0, 0x2a,
+ 0x3f, 0x2a, 0x0,
+ 0x3f, 0x2a, 0x2a,
+ 0x15, 0x0, 0x15,
+ 0x15, 0x0, 0x3f,
+ 0x15, 0x2a, 0x15,
+ 0x15, 0x2a, 0x3f,
+ 0x3f, 0x0, 0x15,
+ 0x3f, 0x0, 0x3f,
+ 0x3f, 0x2a, 0x15,
+ 0x3f, 0x2a, 0x3f,
+ 0x15, 0x15, 0x0,
+ 0x15, 0x15, 0x2a,
+ 0x15, 0x3f, 0x0,
+ 0x15, 0x3f, 0x2a,
+ 0x3f, 0x15, 0x0,
+ 0x3f, 0x15, 0x2a,
+ 0x3f, 0x3f, 0x0,
+ 0x3f, 0x3f, 0x2a,
+ 0x15, 0x15, 0x15,
+ 0x15, 0x15, 0x3f,
+ 0x15, 0x3f, 0x15,
+ 0x15, 0x3f, 0x3f,
+ 0x3f, 0x15, 0x15,
+ 0x3f, 0x15, 0x3f,
+ 0x3f, 0x3f, 0x15,
+ 0x3f, 0x3f, 0x3f,
+ 0x39, 0xc, 0x5,
+ 0x15, 0x2c, 0xf,
+ 0x26, 0x10, 0x3d,
+ 0x29, 0x29, 0x38,
+ 0x4, 0x1a, 0xe,
+ 0x2, 0x1e, 0x3a,
+ 0x3c, 0x25, 0x33,
+ 0x3c, 0xc, 0x2c,
+ 0x3f, 0x3, 0x2b,
+ 0x1c, 0x9, 0x13,
+ 0x25, 0x2a, 0x35,
+ 0x1e, 0xa, 0x38,
+ 0x24, 0x8, 0x3,
+ 0x3, 0xe, 0x36,
+ 0xc, 0x6, 0x2a,
+ 0x26, 0x3, 0x32,
+ 0x5, 0x2f, 0x33,
+ 0x3c, 0x35, 0x2f,
+ 0x2d, 0x26, 0x3e,
+ 0xd, 0xa, 0x10,
+ 0x25, 0x3c, 0x11,
+ 0xd, 0x4, 0x2e,
+ 0x5, 0x19, 0x3e,
+ 0xc, 0x13, 0x34,
+ 0x2b, 0x6, 0x24,
+ 0x4, 0x3, 0xd,
+ 0x2f, 0x3c, 0xc,
+ 0x2a, 0x37, 0x1f,
+ 0xf, 0x12, 0x38,
+ 0x38, 0xe, 0x2a,
+ 0x12, 0x2f, 0x19,
+ 0x29, 0x2e, 0x31,
+ 0x25, 0x13, 0x3e,
+ 0x33, 0x3e, 0x33,
+ 0x1d, 0x2c, 0x25,
+ 0x15, 0x15, 0x5,
+ 0x32, 0x25, 0x39,
+ 0x1a, 0x7, 0x1f,
+ 0x13, 0xe, 0x1d,
+ 0x36, 0x17, 0x34,
+ 0xf, 0x15, 0x23,
+ 0x2, 0x35, 0xd,
+ 0x15, 0x3f, 0xc,
+ 0x14, 0x2f, 0xf,
+ 0x19, 0x21, 0x3e,
+ 0x27, 0x11, 0x2f,
+ 0x38, 0x3f, 0x3c,
+ 0x36, 0x2d, 0x15,
+ 0x16, 0x17, 0x2,
+ 0x1, 0xa, 0x3d,
+ 0x1b, 0x11, 0x3f,
+ 0x21, 0x3c, 0xd,
+ 0x1a, 0x39, 0x3d,
+ 0x8, 0xe, 0xe,
+ 0x22, 0x21, 0x23,
+ 0x1e, 0x30, 0x5,
+ 0x1f, 0x22, 0x3d,
+ 0x1e, 0x2f, 0xa,
+ 0x0, 0x1c, 0xe,
+ 0x0, 0x1c, 0x15,
+ 0x0, 0x1c, 0x1c,
+ 0x0, 0x15, 0x1c,
+ 0x0, 0xe, 0x1c,
+ 0x0, 0x7, 0x1c,
+ 0xe, 0xe, 0x1c,
+ 0x11, 0xe, 0x1c,
+ 0x15, 0xe, 0x1c,
+ 0x18, 0xe, 0x1c,
+ 0x1c, 0xe, 0x1c,
+ 0x1c, 0xe, 0x18,
+ 0x1c, 0xe, 0x15,
+ 0x1c, 0xe, 0x11,
+ 0x1c, 0xe, 0xe,
+ 0x1c, 0x11, 0xe,
+ 0x1c, 0x15, 0xe,
+ 0x1c, 0x18, 0xe,
+ 0x1c, 0x1c, 0xe,
+ 0x18, 0x1c, 0xe,
+ 0x15, 0x1c, 0xe,
+ 0x11, 0x1c, 0xe,
+ 0xe, 0x1c, 0xe,
+ 0xe, 0x1c, 0x11,
+ 0xe, 0x1c, 0x15,
+ 0xe, 0x1c, 0x18,
+ 0xe, 0x1c, 0x1c,
+ 0xe, 0x18, 0x1c,
+ 0xe, 0x15, 0x1c,
+ 0xe, 0x11, 0x1c,
+ 0x14, 0x14, 0x1c,
+ 0x16, 0x14, 0x1c,
+ 0x18, 0x14, 0x1c,
+ 0x1a, 0x14, 0x1c,
+ 0x1c, 0x14, 0x1c,
+ 0x1c, 0x14, 0x1a,
+ 0x1c, 0x14, 0x18,
+ 0x1c, 0x14, 0x16,
+ 0x1c, 0x14, 0x14,
+ 0x1c, 0x16, 0x14,
+ 0x1c, 0x18, 0x14,
+ 0x1c, 0x1a, 0x14,
+ 0x1c, 0x1c, 0x14,
+ 0x1a, 0x1c, 0x14,
+ 0x18, 0x1c, 0x14,
+ 0x16, 0x1c, 0x14,
+ 0x14, 0x1c, 0x14,
+ 0x14, 0x1c, 0x16,
+ 0x14, 0x1c, 0x18,
+ 0x14, 0x1c, 0x1a,
+ 0x14, 0x1c, 0x1c,
+ 0x14, 0x1a, 0x1c,
+ 0x14, 0x18, 0x1c,
+ 0x14, 0x16, 0x1c,
+ 0x0, 0x0, 0x10,
+ 0x4, 0x0, 0x10,
+ 0x8, 0x0, 0x10,
+ 0xc, 0x0, 0x10,
+ 0x10, 0x0, 0x10,
+ 0x10, 0x0, 0xc,
+ 0x10, 0x0, 0x8,
+ 0x10, 0x0, 0x4,
+ 0x10, 0x0, 0x0,
+ 0x10, 0x4, 0x0,
+ 0x10, 0x8, 0x0,
+ 0x10, 0xc, 0x0,
+ 0x10, 0x10, 0x0,
+ 0xc, 0x10, 0x0,
+ 0x8, 0x10, 0x0,
+ 0x4, 0x10, 0x0,
+ 0x0, 0x10, 0x0,
+ 0x0, 0x10, 0x4,
+ 0x0, 0x10, 0x8,
+ 0x0, 0x10, 0xc,
+ 0x0, 0x10, 0x10,
+ 0x0, 0xc, 0x10,
+ 0x0, 0x8, 0x10,
+ 0x0, 0x4, 0x10,
+ 0x8, 0x8, 0x10,
+ 0xa, 0x8, 0x10,
+ 0xc, 0x8, 0x10,
+ 0xe, 0x8, 0x10,
+ 0x10, 0x8, 0x10,
+ 0x10, 0x8, 0xe,
+ 0x10, 0x8, 0xc,
+ 0x10, 0x8, 0xa,
+ 0x10, 0x8, 0x8,
+ 0x10, 0xa, 0x8,
+ 0x10, 0xc, 0x8,
+ 0x10, 0xe, 0x8,
+ 0x10, 0x10, 0x8,
+ 0xe, 0x10, 0x8,
+ 0xc, 0x10, 0x8,
+ 0xa, 0x10, 0x8,
+ 0x8, 0x10, 0x8,
+ 0x8, 0x10, 0xa,
+ 0x8, 0x10, 0xc,
+ 0x8, 0x10, 0xe,
+ 0x8, 0x10, 0x10,
+ 0x8, 0xe, 0x10,
+ 0x8, 0xc, 0x10,
+ 0x8, 0xa, 0x10,
+ 0xb, 0xb, 0x10,
+ 0xc, 0xb, 0x10,
+ 0xd, 0xb, 0x10,
+ 0xf, 0xb, 0x10,
+ 0x10, 0xb, 0x10,
+ 0x10, 0xb, 0xf,
+ 0x10, 0xb, 0xd,
+ 0x10, 0xb, 0xc,
+ 0x10, 0xb, 0xb,
+ 0x10, 0xc, 0xb,
+ 0x10, 0xd, 0xb,
+ 0x10, 0xf, 0xb,
+ 0x10, 0x10, 0xb,
+ 0xf, 0x10, 0xb,
+ 0xd, 0x10, 0xb,
+ 0xc, 0x10, 0xb,
+ 0xb, 0x10, 0xb,
+ 0xb, 0x10, 0xc,
+ 0xb, 0x10, 0xd,
+ 0xb, 0x10, 0xf,
+ 0xb, 0x10, 0x10,
+ 0xb, 0xf, 0x10,
+ 0xb, 0xd, 0x10,
+ 0xb, 0xc, 0x10,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0
+};
+
+unsigned char AC[21] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+ 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
+ 0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+static int scanPCI(int start_slt);
+static int PCIVendor(int);
+static void printslots(void);
+int delayLoop(int);
+extern void puthex(unsigned long);
+extern void puts(const char *);
+static void unlockS3(void);
+
+static inline
+outw(int port, unsigned short val)
+{
+ outb(port, val >> 8);
+ outb(port+1, val);
+}
+
+#define PPC_601 1
+
+vga_init(unsigned char *ISA_mem)
+{
+ int slot;
+ struct VgaRegs *VgaTextRegs;
+
+ if ((_get_PVR()>>16) == PPC_601) {
+ return(old_vga_init(ISA_mem));
+ }
+
+#if 1
+ /* See if VGA already in TEXT mode - exit if so! */
+ outb(0x3CE, 0x06);
+ if ((inb(0x3CF) & 0x01) == 0){puts("VGA already in text mode\n"); return;}
+#endif
+
+ /* If no VGA responding in text mode, then we have some work to do...
+ */
+ slot = -1;
+ while((slot = scanPCI(slot)) > -1) { /* find video card in use */
+ unlockVideo(slot); /* enable I/O to card */
+ VgaTextRegs = GenVgaTextRegs;
+
+ switch (PCIVendor(slot)) {
+ default:
+ break;
+ case(S3Vendor):
+ unlockS3();
+ VgaTextRegs = S3TextRegs;
+ break;
+
+ case(CirrusVendor):
+ outw(0x3C4, 0x0612); /* unlock ext regs */
+ outw(0x3C4, 0x0700); /* reset ext sequence mode */
+ break;
+
+ case(ParadiseVendor): /* IBM Portable 850 */
+ outw(0x3ce, 0x0f05); /* unlock pardise registers */
+ outw(0x3c4, 0x0648);
+ outw(0x3d4, 0x2985);
+ outw(0x3d4, 0x34a6);
+ outb(0x3ce, 0x0b); /* disable linear addressing */
+ outb(0x3cf, inb(0x3cf) & ~0x30);
+ outw(0x3c4, 0x1400);
+ outb(0x3ce, 0x0e); /* disable 256 color mode */
+ outb(0x3cf, inb(0x3cf) & ~0x01);
+ outb(0xd00, 0xff); /* enable auto-centering */
+ if (!(inb(0xd01) & 0x03)) {
+ outb(0x3d4, 0x33);
+ outb(0x3d5, inb(0x3d5) & ~0x90);
+ outb(0x3d4, 0x32);
+ outb(0x3d5, inb(0x3d5) | 0x04);
+ outw(0x3d4, 0x0250);
+ outw(0x3d4, 0x07ba);
+ outw(0x3d4, 0x0900);
+ outw(0x3d4, 0x15e7);
+ outw(0x3d4, 0x2a95);
+ }
+ outw(0x3d4, 0x34a0);
+ break;
+
+ #if 0 /* Untested - probably doesn't work */
+ case(MatroxVendor):
+ case(DiamondVendor):
+ puts("VGA Chip Vendor ID: ");
+ puthex(PCIVendor(slot));
+ puts("\n");
+ delayLoop(1);
+ #endif
+ };
+
+ outw(0x3C4, 0x0120); /* disable video */
+ setTextRegs(VgaTextRegs); /* initial register setup */
+ setTextCLUT(0); /* load color lookup table */
+ loadFont(ISA_mem); /* load font */
+ setTextRegs(VgaTextRegs); /* reload registers */
+ outw(0x3C4, 0x0100); /* re-enable video */
+ clearVideoMemory();
+
+ if (PCIVendor(slot) == S3Vendor) {
+ outb(0x3c2, 0x63); /* MISC */
+ } /* endif */
+
+ #ifdef DEBUG
+ printslots();
+ delayLoop(5);
+ #endif
+
+ delayLoop(1); /* give time for the video monitor to come up */
+ }
+ return (1); /* 'CRT' I/O supported */
+}
+
+static int
+NOP(int x)
+{
+}
+
+/*
+ * Write to VGA Attribute registers.
+ */
+writeAttr(index, data, videoOn)
+ unsigned char index;
+ unsigned char data;
+ unsigned char videoOn; /* video on flag */
+{
+ unsigned char v;
+ v = inb(0x3da); /* reset attr. address toggle */
+ if (videoOn)
+ outb(0x3c0, (index & 0x1F) | 0x20);
+ else
+ outb(0x3c0, (index & 0x1F));
+ outb(0x3c0, data);
+}
+
+setTextRegs(struct VgaRegs *svp)
+{
+ int i;
+
+ /*
+ * saved settings
+ */
+ while( svp->io_port != ENDMK ) {
+ outb(svp->io_port, svp->io_index);
+ outb(svp->io_port+1, svp->io_value);
+ svp++;
+ }
+
+ outb(0x3c2, 0x67); /* MISC */
+ outb(0x3c6, 0xff); /* MASK */
+
+ for ( i = 0; i < 0x10; i++)
+ writeAttr(i, AC[i], 0); /* pallete */
+ writeAttr(0x10, 0x0c, 0); /* text mode */
+ writeAttr(0x11, 0x00, 0); /* overscan color (border) */
+ writeAttr(0x12, 0x0f, 0); /* plane enable */
+ writeAttr(0x13, 0x08, 0); /* pixel panning */
+ writeAttr(0x14, 0x00, 1); /* color select; video on */
+}
+
+setTextCLUT(int shift)
+{
+ int i;
+
+ outb(0x3C6, 0xFF);
+ i = inb(0x3C7);
+ outb(0x3C8, 0);
+ i = inb(0x3C7);
+
+ for ( i = 0; i < 256; i++) {
+ outb(0x3C9, TextCLUT[i].r << shift);
+ outb(0x3C9, TextCLUT[i].g << shift);
+ outb(0x3C9, TextCLUT[i].b << shift);
+ }
+}
+
+
+loadFont(unsigned char *ISA_mem)
+{
+ int i, j;
+ unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+
+ outb(0x3C2, 0x67);
+ /*
+ * Load font
+ */
+ i = inb(0x3DA); /* Reset Attr toggle */
+
+ outb(0x3C0,0x30);
+ outb(0x3C0, 0x01); /* graphics mode */
+
+ outw(0x3C4, 0x0001); /* reset sequencer */
+ outw(0x3C4, 0x0204); /* write to plane 2 */
+ outw(0x3C4, 0x0406); /* enable plane graphics */
+ outw(0x3C4, 0x0003); /* reset sequencer */
+ outw(0x3CE, 0x0402); /* read plane 2 */
+ outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
+ outw(0x3CE, 0x0605); /* set graphics mode */
+
+ for (i = 0; i < sizeof(font); i += 16) {
+ for (j = 0; j < 16; j++) {
+ __asm__ volatile("eieio");
+ font_page[(2*i)+j] = font[i+j];
+ }
+ }
+}
+
+static void
+unlockS3(void)
+{
+ int s3_device_id;
+ outw(0x3d4, 0x3848);
+ outw(0x3d4, 0x39a5);
+ outb(0x3d4, 0x2d);
+ s3_device_id = inb(0x3d5) << 8;
+ outb(0x3d4, 0x2e);
+ s3_device_id |= inb(0x3d5);
+
+ if (s3_device_id != 0x8812) {
+ /* From the S3 manual */
+ outb(0x46E8, 0x10); /* Put into setup mode */
+ outb(0x3C3, 0x10);
+ outb(0x102, 0x01); /* Enable registers */
+ outb(0x46E8, 0x08); /* Enable video */
+ outb(0x3C3, 0x08);
+ outb(0x4AE8, 0x00);
+
+#if 0
+ outb(0x42E8, 0x80); /* Reset graphics engine? */
+#endif
+
+ outb(0x3D4, 0x38); /* Unlock all registers */
+ outb(0x3D5, 0x48);
+ outb(0x3D4, 0x39);
+ outb(0x3D5, 0xA5);
+ outb(0x3D4, 0x40);
+ outb(0x3D5, inb(0x3D5)|0x01);
+ outb(0x3D4, 0x33);
+ outb(0x3D5, inb(0x3D5)&~0x52);
+ outb(0x3D4, 0x35);
+ outb(0x3D5, inb(0x3D5)&~0x30);
+ outb(0x3D4, 0x3A);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x53);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x31);
+ outb(0x3D5, inb(0x3D5)&~0x4B);
+ outb(0x3D4, 0x58);
+
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x54);
+ outb(0x3D5, 0x38);
+ outb(0x3D4, 0x60);
+ outb(0x3D5, 0x07);
+ outb(0x3D4, 0x61);
+ outb(0x3D5, 0x80);
+ outb(0x3D4, 0x62);
+ outb(0x3D5, 0xA1);
+ outb(0x3D4, 0x69); /* High order bits for cursor address */
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x32);
+ outb(0x3D5, inb(0x3D5)&~0x10);
+ } else {
+ outw(0x3c4, 0x0806); /* IBM Portable 860 */
+ outw(0x3c4, 0x1041);
+ outw(0x3c4, 0x1128);
+ outw(0x3d4, 0x4000);
+ outw(0x3d4, 0x3100);
+ outw(0x3d4, 0x3a05);
+ outw(0x3d4, 0x6688);
+ outw(0x3d4, 0x5800); /* disable linear addressing */
+ outw(0x3d4, 0x4500); /* disable H/W cursor */
+ outw(0x3c4, 0x5410); /* enable auto-centering */
+ outw(0x3c4, 0x561f);
+ outw(0x3c4, 0x1b80); /* lock DCLK selection */
+ outw(0x3d4, 0x3900); /* lock S3 registers */
+ outw(0x3d4, 0x3800);
+ } /* endif */
+}
+
+/*
+ * cursor() sets an offset (0-1999) into the 80x25 text area
+ */
+void
+cursor(int x, int y)
+{
+ int pos = (y*cols)+x;
+ outb(0x3D4, 14);
+ outb(0x3D5, pos >> 8);
+ outb(0x3D4, 15);
+ outb(0x3D5, pos);
+}
+
+clearVideoMemory()
+{
+ int i, j;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < cols; j++) {
+ vidmem[((i*cols)+j)*2] = 0x20; /* fill with space character */
+ vidmem[((i*cols)+j)*2+1] = 0x07; /* set bg & fg attributes */
+ }
+ }
+}
+
+/* ============ */
+
+
+#define NSLOTS 8
+#define NPCIREGS 5
+
+
+/*
+ should use devfunc number/indirect method to be totally safe on
+ all machines, this works for now on 3 slot Moto boxes
+*/
+
+struct PCI_ConfigInfo {
+ unsigned long * config_addr;
+ unsigned long regs[NPCIREGS];
+} PCI_slots [NSLOTS] = {
+
+ { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */
+ { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */
+ { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */
+ { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */
+};
+
+
+
+/*
+ * The following code modifies the PCI Command register
+ * to enable memory and I/O accesses.
+ */
+unlockVideo(slot)
+{
+ volatile unsigned char * ppci;
+
+ ppci = (unsigned char * )PCI_slots[slot].config_addr;
+ ppci[4] = 0x0003; /* enable memory and I/O accesses */
+ ppci[0x10] = 0x00000; /* turn off memory mapping */
+ ppci[0x11] = 0x00000; /* mem_base = 0 */
+ ppci[0x12] = 0x00000;
+ ppci[0x13] = 0x00000;
+ __asm__ volatile("eieio");
+
+ outb(0x3d4, 0x11);
+ outb(0x3d5, 0x0e); /* unlock CR0-CR7 */
+}
+
+long
+SwapBytes(long lv) /* turn little endian into big indian long */
+{
+ long t;
+ t = (lv&0x000000FF) << 24;
+ t |= (lv&0x0000FF00) << 8;
+ t |= (lv&0x00FF0000) >> 8;
+ t |= (lv&0xFF000000) >> 24;
+ return(t);
+}
+
+
+#define DEVID 0
+#define CMD 1
+#define CLASS 2
+#define MEMBASE 4
+
+int
+scanPCI(int start_slt)
+{
+ int slt, r;
+ struct PCI_ConfigInfo *pslot;
+ int theSlot = -1;
+ int highVgaSlot = 0;
+
+ for ( slt = start_slt + 1; slt < NSLOTS; slt++) {
+ pslot = &PCI_slots[slt];
+ for ( r = 0; r < NPCIREGS; r++) {
+ pslot->regs[r] = SwapBytes ( pslot->config_addr[r] );
+ }
+ /* card in slot ? */
+ if ( pslot->regs[DEVID] != 0xFFFFFFFF ) {
+ /* VGA ? */
+ if ( ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x03000000) ||
+ ((pslot->regs[CLASS] & 0xFFFFFF00) == 0x00010000)) {
+ highVgaSlot = slt;
+ /* did firmware enable it ? */
+ if ( (pslot->regs[CMD] & 0x03) ) {
+ theSlot = slt;
+ break;
+ }
+ }
+ }
+ }
+
+ return ( theSlot );
+}
+
+/* Delay for a certain number of seconds */
+/* Note: They loop is used since 'udelay' can't handle really long counts! */
+
+int
+delayLoop(int k)
+{
+ int i;
+ while (k-- > 0) {
+ for (i = 0; i < 1000; i++) {
+ udelay(1000);
+ }
+ }
+}
+
+
+/* return Vendor ID of card in the slot */
+static
+int PCIVendor(int slotnum) {
+ struct PCI_ConfigInfo *pslot;
+
+ pslot = &PCI_slots[slotnum];
+
+return (pslot->regs[DEVID] & 0xFFFF);
+}
+
+static
+void printslots(void)
+{
+ int i;
+ struct PCI_ConfigInfo *pslot;
+ for(i=0; i < NSLOTS; i++) {
+#if 0
+ pslot = &PCI_slots[i];
+ printf("Slot: %d, Addr: %x, Vendor: %08x, Class: %08x\n",
+ i, pslot->config_addr, pslot->regs[0], pslot->regs[2]);
+#else
+ puts("PCI Slot number: "); puthex(i);
+ puts(" Vendor ID: ");
+ puthex(PCIVendor(i)); puts("\n");
+#endif
+
+ }
+}
+
+/*
+ * OLD vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ * Steve Sellgren
+ * San Francisco Indigo Company
+ * sfindigo!sellgren@uunet.uu.net
*/
unsigned char CRTC[24] = {
@@ -15,13 +873,8 @@ unsigned char CRTC[24] = {
0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
-unsigned char AC[21] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x0C, 0x00, 0x0F, 0x08, 0x00};
-
-#include "iso_font.h"
+#if 0
static const unsigned char color_LUT[] =
{
0x00, 0x00, 0x00, /* 0 - black */
@@ -41,124 +894,124 @@ static const unsigned char color_LUT[] =
0x2A, 0x2A, 0x15, /* 14 - yellow */
0x2A, 0x2A, 0x3F, /* 15 - bright white */
};
-
-static inline
-outw(int port, unsigned short val)
-{
- outb(port, val >> 8);
- outb(port+1, val);
-}
+#endif
-vga_init(unsigned char *ISA_mem)
+old_vga_init(unsigned char *ISA_mem)
{
- int i, j;
- int value;
- unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+ int i, j;
+ int value;
+ unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
- /* See if VGA already in TEXT mode - exit if so! */
- outb(0x3CE, 0x06);
- if ((inb(0x3CF) & 0x01) == 0) return;
+ /* See if VGA already in TEXT mode - exit if so! */
+ outb(0x3CE, 0x06);
+ if ((inb(0x3CF) & 0x01) == 0) return;
- /* From the S3 manual */
- outb(0x46E8, 0x10); /* Put into setup mode */
- outb(0x3C3, 0x10);
- outb(0x102, 0x01); /* Enable registers */
- outb(0x46E8, 0x08); /* Enable video */
- outb(0x3C3, 0x08);
- outb(0x4AE8, 0x00);
-
- outb(0x42E8, 0x80); /* Reset graphics engine? */
-
- outb(0x3D4, 0x38); /* Unlock all registers */
- outb(0x3D5, 0x48);
- outb(0x3D4, 0x39);
- outb(0x3D5, 0xA5);
- outb(0x3D4, 0x40);
- outb(0x3D5, inb(0x3D5)|0x01);
- outb(0x3D4, 0x33);
- outb(0x3D5, inb(0x3D5)&~0x52);
- outb(0x3D4, 0x35);
- outb(0x3D5, inb(0x3D5)&~0x30);
- outb(0x3D4, 0x3A);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x53);
- outb(0x3D5, 0x00);
- outb(0x3D4, 0x31);
- outb(0x3D5, inb(0x3D5)&~0x4B);
- outb(0x3D4, 0x58);
- outb(0x3D5, 0);
-
- outb(0x3D4, 0x54);
- outb(0x3D5, 0x38);
- outb(0x3D4, 0x60);
- outb(0x3D5, 0x07);
- outb(0x3D4, 0x61);
- outb(0x3D5, 0x80);
- outb(0x3D4, 0x62);
- outb(0x3D5, 0xA1);
- outb(0x3D4, 0x69); /* High order bits for cursor address */
- outb(0x3D5, 0);
+ /* From the S3 manual */
+ outb(0x46E8, 0x10); /* Put into setup mode */
+ outb(0x3C3, 0x10);
+ outb(0x102, 0x01); /* Enable registers */
+ outb(0x46E8, 0x08); /* Enable video */
+ outb(0x3C3, 0x08);
+ outb(0x4AE8, 0x00);
+
+#if 0
+ outb(0x42E8, 0x80); /* Reset graphics engine? */
+#endif
+
+ outb(0x3D4, 0x38); /* Unlock all registers */
+ outb(0x3D5, 0x48);
+ outb(0x3D4, 0x39);
+ outb(0x3D5, 0xA5);
+ outb(0x3D4, 0x40);
+ outb(0x3D5, inb(0x3D5)|0x01);
+ outb(0x3D4, 0x33);
+ outb(0x3D5, inb(0x3D5)&~0x52);
+ outb(0x3D4, 0x35);
+ outb(0x3D5, inb(0x3D5)&~0x30);
+ outb(0x3D4, 0x3A);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x53);
+ outb(0x3D5, 0x00);
+ outb(0x3D4, 0x31);
+ outb(0x3D5, inb(0x3D5)&~0x4B);
+ outb(0x3D4, 0x58);
+ outb(0x3D5, 0);
+
+ outb(0x3D4, 0x54);
+ outb(0x3D5, 0x38);
+ outb(0x3D4, 0x60);
+ outb(0x3D5, 0x07);
+ outb(0x3D4, 0x61);
+ outb(0x3D5, 0x80);
+ outb(0x3D4, 0x62);
+ outb(0x3D5, 0xA1);
+ outb(0x3D4, 0x69); /* High order bits for cursor address */
+ outb(0x3D5, 0);
- outb(0x3D4, 0x32);
- outb(0x3D5, inb(0x3D5)&~0x10);
-
- outb(0x3C2, 0x67);
-
- /* Initialize DAC */
- outb(0x3C6,0xFF);
- inb(0x3C7);
- outb(0x3C8,0x00);
- inb(0x3C7);
- for (i=0; i<sizeof(color_LUT); i++) {
- outb(0x3C9, color_LUT[i]);
- }
- for (i; i<768; i += 3) {
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- outb(0x3C9, 0x3F); /* White? */
- }
-
- /* Load font */
- NOP(inb(0x3DA)); /* Reset Address/Data FlipFlop for Attribute ctlr */
- outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
- outw(0x3C4, 0x0001); /* reset sequencer */
- outw(0x3C4, 0x0204); /* write to plane 2 */
- outw(0x3C4, 0x0407); /* enable plane graphics */
- outw(0x3C4, 0x0003); /* reset sequencer */
- outw(0x3CE, 0x0402); /* read plane 2 */
- outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
- outw(0x3CE, 0x0600); /* set graphics */
- for (i = 0; i < sizeof(font); i += 16) {
- for (j = 0; j < 16; j++) {
- font_page[(2*i)+j] = font[i+j];
- }
- }
-
- for (i = 0; i < 24; i++) {
- outb(0x3D4, i);
- outb(0x3D5, CRTC[i]);
- }
- for (i = 0; i < 5; i++) {
- outb(0x3C4, i);
- outb(0x3C5, SEQ[i]);
- }
- for (i = 0; i < 9; i++) {
- outb(0x3CE, i);
- outb(0x3CF, GC[i]);
- }
- value = inb(0x3DA); /* reset flip-flop */
- for (i = 0; i < 16; i++) {
- outb(0x3C0, i);
- outb(0x3C0, AC[i]);
- }
- for (i = 16; i < 21; i++) {
- outb(0x3C0, i | 0x20);
- outb(0x3C0, AC[i]);
- }
- outb(0x3C2, 0x23);
-}
+ outb(0x3D4, 0x32);
+ outb(0x3D5, inb(0x3D5)&~0x10);
-static int
-NOP(int x)
-{
+ outb(0x3C2, 0x67);
+
+#if 0
+ /* Initialize DAC */
+ outb(0x3C6,0xFF);
+ inb(0x3C7);
+ outb(0x3C8,0x00);
+ inb(0x3C7);
+ for (i=0; i<sizeof(color_LUT); i++) {
+ outb(0x3C9, color_LUT[i]);
+ }
+ for (i; i<768; i += 3) {
+ outb(0x3C9, 0x3F); /* White? */
+ outb(0x3C9, 0x3F); /* White? */
+ outb(0x3C9, 0x3F); /* White? */
+ }
+
+ /* Load font */
+ NOP(inb(0x3DA)); /* Reset Address/Data FlipFlop for Attribute ctlr */
+ outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
+ outw(0x3C4, 0x0001); /* reset sequencer */
+ outw(0x3C4, 0x0204); /* write to plane 2 */
+ outw(0x3C4, 0x0407); /* enable plane graphics */
+ outw(0x3C4, 0x0003); /* reset sequencer */
+ outw(0x3CE, 0x0402); /* read plane 2 */
+ outw(0x3CE, 0x0500); /* write mode 0, read mode 0 */
+ outw(0x3CE, 0x0600); /* set graphics */
+ for (i = 0; i < sizeof(font); i += 16) {
+ for (j = 0; j < 16; j++) {
+ font_page[(2*i)+j] = font[i+j];
+ }
+ }
+#else
+ outw(0x3C4, 0x0120); /* disable video */
+ setTextCLUT(2); /* load color lookup table */
+ loadFont(ISA_mem); /* load font */
+#endif
+
+ for (i = 0; i < 24; i++) {
+ outb(0x3D4, i);
+ outb(0x3D5, CRTC[i]);
+ }
+ for (i = 0; i < 5; i++) {
+ outb(0x3C4, i);
+ outb(0x3C5, SEQ[i]);
+ }
+ for (i = 0; i < 9; i++) {
+ outb(0x3CE, i);
+ outb(0x3CF, GC[i]);
+ }
+ value = inb(0x3DA); /* reset flip-flop */
+ for (i = 0; i < 16; i++) {
+ outb(0x3C0, i);
+ outb(0x3C0, AC[i]);
+ }
+ for (i = 16; i < 21; i++) {
+ outb(0x3C0, i | 0x20);
+ outb(0x3C0, AC[i]);
+ }
+ clearVideoMemory();
+ outw(0x3C4, 0x0100); /* re-enable video */
+ outb(0x3C2, 0x23);
+ return (1); /* Keyboard should work */
}
diff --git a/arch/ppc/config.in b/arch/ppc/config.in
index 4211b6b00..9df35fa24 100644
--- a/arch/ppc/config.in
+++ b/arch/ppc/config.in
@@ -2,62 +2,62 @@
# For a description of the syntax of this configuration file,
# see the Configure script.
#
-mainmenu_name "Linux Kernel Configuration"
+mainmenu_name "Linux/PowerPC Kernel Configuration"
-mainmenu_option next_comment
-comment 'Code maturity level options'
+if [ "`uname`" != "Linux" ]; then
+ define_bool CONFIG_CROSSCOMPILE y
+else
+ define_bool CONFIG_NATIVE y
+fi
+
+bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
+bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-endmenu
+bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
+bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+choice 'Processor type' \
+ "Common CONFIG_MCOMMON \
+ 601 CONFIG_M601 \
+ 603 CONFIG_M603 \
+ 604 CONFIG_M604" Common
-mainmenu_option next_comment
-comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
if [ "$CONFIG_MODULES" = "y" ]; then
bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
fi
-endmenu
-mainmenu_option next_comment
-comment 'General setup'
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION
+mainmenu_option next_comment
+define_bool CONFIG_PCI y
+bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
-if [ "$CONFIG_PCI" = "y" ]; then
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
- fi
-fi
-bool 'System V IPC' CONFIG_SYSVIPC
bool 'Sysctl support' CONFIG_SYSCTL
-tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
+bool 'System V IPC' CONFIG_SYSVIPC
+
+# only elf supported, a.out is not -- Cort
+define_bool CONFIG_BINFMT_ELF y
+define_bool CONFIG_KERNEL_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
-tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-if [ "$CONFIG_BINFMT_ELF" = "y" ]; then
- bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF
-fi
-source drivers/block/Config.in
-if [ "$CONFIG_NET" = "y" ]; then
- source net/Config.in
-fi
+source drivers/pnp/Config.in
+source drivers/block/Config.in
mainmenu_option next_comment
comment 'SCSI support'
-
tristate 'SCSI support' CONFIG_SCSI
-
if [ "$CONFIG_SCSI" != "n" ]; then
source drivers/scsi/Config.in
fi
endmenu
+
if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
comment 'Network device support'
-
+ source net/Config.in
bool 'Network device support' CONFIG_NETDEVICES
if [ "$CONFIG_NETDEVICES" = "y" ]; then
source drivers/net/Config.in
@@ -65,9 +65,9 @@ if [ "$CONFIG_NET" = "y" ]; then
endmenu
fi
+
mainmenu_option next_comment
comment 'ISDN subsystem'
-
tristate 'ISDN support' CONFIG_ISDN
if [ "$CONFIG_ISDN" != "n" ]; then
source drivers/isdn/Config.in
@@ -76,7 +76,6 @@ endmenu
mainmenu_option next_comment
comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
-
bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
source drivers/cdrom/Config.in
@@ -84,12 +83,10 @@ fi
endmenu
source fs/Config.in
-
source drivers/char/Config.in
mainmenu_option next_comment
comment 'Sound'
-
tristate 'Sound card support' CONFIG_SOUND
if [ "$CONFIG_SOUND" != "n" ]; then
source drivers/sound/Config.in
@@ -97,11 +94,11 @@ fi
endmenu
mainmenu_option next_comment
-comment 'Kernel hacking'
-
+#comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Kernel profiling support' CONFIG_PROFILE
-if [ "$CONFIG_PROFILE" = "y" ]; then
- int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
-fi
+#bool 'Kernel profiling support' CONFIG_PROFILE
+#if [ "$CONFIG_PROFILE" = "y" ]; then
+# int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
+#fi
endmenu
+
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index 0bfb26c01..941cd9e38 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -22,32 +22,49 @@
HOST_CC = gcc
-OBJS = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
- signal.o ksyms.o time.o syscalls.o usercpy.o\
- support.o ptrace.o
+OBJS = misc.o port_io.o pci.o traps.o process.o \
+ signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
all: head.o kernel.o
+head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
-head.o: head.s
-head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
+ifeq ($(CONFIG_PREP),y)
+OBJS += prep_setup.o prep_time.o
+endif
+
+ifeq ($(CONFIG_PMAC),y)
+OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+endif
+
+ifeq ($(CONFIG_MODULES),y)
+OBJS = ksyms.o
+endif
-ppc_defs.h: mk_defs
- mk_defs $@
-mk_defs: mk_defs.c
- $(HOSTCC) $(CFLAGSINC) -Wl,-static ${CFLAGS} -o mk_defs mk_defs.c
+ppc_defs.h: mk_defs.c ppc_defs.head \
+ $(TOPDIR)/include/asm/mmu.h \
+ $(TOPDIR)/include/asm/processor.h \
+ $(TOPDIR)/include/asm/pgtable.h \
+ $(TOPDIR)/include/asm/ptrace.h
+ $(CC) ${CFLAGS} -S mk_defs.c
+ cp ppc_defs.head ppc_defs.h
+ grep '^#define' mk_defs.s >>ppc_defs.h
+ rm mk_defs.s
+checks: checks.c
+ $(HOSTCC) ${CFLAGS} -o checks checks.c
+ checks
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
- sync
-
-dep:
- $(CPP) -M *.c > .depend
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+ $(CPP) -M *.S *.c > .depend
-modules:
+modules:
dummy:
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 648c7bccf..25f2dd8a0 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,1077 +1,422 @@
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <asm/ppc_machine.h>
-
-#define NEWMM 1
-#define SYNC() \
- isync; \
- sync
-
-#define STATS
/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
+ * arch/ppc/kernel/head.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This file contains the low-level support and setup for the
+ * PowerPC platform, including trap and interrupt dispatch.
+ * Also included here is low-level thread/task switch support.
+ *
+ * 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.
+ *
*/
-#define BUMP(ctr) \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- stw r3,0(r2)
-
-/* The same as 'BUMP' but running unmapped (TLB code) */
-#define BUMP_UNMAPPED(ctr) \
- mfspr r0,XER; \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lis r3,0xF000; \
- andc r2,r2,r3; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- mtspr XER,r0; \
- stw r3,0(r2)
-
-#define DO_RFI_TRACE_UNMAPPED(mark)
-#define DO_RFI_TRACE_MAPPED(mark)
-
-#define DEFAULT_TRAP(offset) \
- li r13,0; \
- ori r13,r13,HID0_ICE; \
- mtspr HID0,r13; \
- lis r13,0xFFF00000>>16; \
- ori r13,r13,offset; \
- mtlr r13; \
- blr
-#define TRACE_TRAP(offset)
-#define DATA_CACHE_OFF() \
- mfspr r2,HID0; \
- li r3,0; \
- ori r3,r3,HID0_DCE; \
- andc r2,r2,r3; \
- mtspr HID0,r2;
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/config.h>
-#define DATA_CACHE_ON() \
- mfspr r2,HID0; \
- ori r2,r2,HID0_DCE; \
- mtspr HID0,r2;
+#define SYNC() \
+ sync; \
+ isync
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
- li r4,64; \
- mtspr CTR,r4; \
- lis r4,0x9000; \
+ li r4,128; \
+ mtctr r4; \
+ lis r4,0xC000; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-/* Validate kernel stack - check for overflow */
-/* all regs are considered scratch since the C function will stomp them */
-#define CHECK_STACK() \
- /*lis r3,current_set@ha; \
- lwz r3,current_set@l(r3); \
- bl _EXTERN(check_stack)*/
-#if 0
-#define _CHECK_STACK() \
- mtspr SPR0,r3; \
- mtspr SPR1,r4; /* use r3,4 as scratch */ \
- lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- lwz r2,KERNEL_STACK_PAGE(r2); \
- /* if kernel stack is sys_stack skip check */ \
- /*lis r3,sys_stack@h; \
- ori r3,r3,sys_stack@l; \
- cmpl 0,r1,r3;*/ \
- /* check for STACK_MAGIC on kernel stack page */ \
- lis r3, 0xdead; /* STACK_MAGIC */ \
- ori r3,r3,0xbeef; \
- lwz r4,0(r2); /* get *kernel_stack_page */ \
- cmpl 0,r4,r3; \
- bne 01f; \
- /* check that ksp is > kernel page */ \
- /*li r3,0x0FFF; \
- andc r2,r2,r3; \
- andc r3,r1,r3; \
- cmp 0,r3,r2; \
- beq 02f;*/ \
- /* check that ksp and kernel stack page are on same page */ \
- cmp 0,r1,r2; \
- bge 02f; \
-01: mr r6,r1; /* setup info for call to bad_stack() */ \
- mr r5,r2; \
- bl _EXTERN(bad_stack); \
-02: mfspr r4,SPR1; \
- mfspr r3,SPR0
-#endif
-
-/* save fp regs if fp is used */
-/* assumes that r1 contains ptr to regs of task and r2 is scratch
- -- Cort */
-#define SAVE_FP_REGS() \
- /* check if fp has been used by checking msr_fp bit */ \
- lwz r2,_MSR(r1); \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- save fp regs */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/ \
- stfd fr0,TSS_FPR0(r2); \
- stfd fr1,TSS_FPR1(r2); \
- stfd fr2,TSS_FPR2(r2); \
- stfd fr3,TSS_FPR3(r2); \
- stfd fr4,TSS_FPR4(r2); \
- stfd fr5,TSS_FPR5(r2); \
- stfd fr6,TSS_FPR6(r2); \
- stfd fr7,TSS_FPR7(r2); \
- stfd fr8,TSS_FPR8(r2); \
- stfd fr9,TSS_FPR9(r2); \
- stfd fr10,TSS_FPR10(r2); \
- stfd fr11,TSS_FPR11(r2); \
- stfd fr12,TSS_FPR12(r2); \
- stfd fr13,TSS_FPR13(r2); \
- stfd fr14,TSS_FPR14(r2); \
- stfd fr15,TSS_FPR15(r2); \
- stfd fr16,TSS_FPR16(r2); \
- stfd fr17,TSS_FPR17(r2); \
- stfd fr18,TSS_FPR18(r2); \
- stfd fr19,TSS_FPR19(r2); \
- stfd fr20,TSS_FPR20(r2); \
- stfd fr21,TSS_FPR21(r2); \
- stfd fr22,TSS_FPR22(r2); \
- stfd fr23,TSS_FPR23(r2); \
- stfd fr24,TSS_FPR24(r2); \
- stfd fr25,TSS_FPR25(r2); \
- stfd fr26,TSS_FPR26(r2); \
- stfd fr27,TSS_FPR27(r2); \
- stfd fr28,TSS_FPR28(r2); \
- stfd fr29,TSS_FPR29(r2); \
- stfd fr30,TSS_FPR30(r2); \
- stfd fr31,TSS_FPR31(r2); \
-00:
-
-
-/* restores fp regs if fp has been used -- always restores fpscr */
-/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
- what will become the msr when this process executes -- Cort*/
-#define RESTORE_FP_REGS(mark) \
- /* check if restoring from _switch() */ \
- li r2, mark; \
- cmpi 0,r2,0x0f0f; \
- bne 00f; /* only need to save if called from _switch() with 0x0f0f */\
- /* check if fp has been used by checking msr_fp bit */ \
- /* srr1 contains msr */ \
- mfspr r2,SRR1; \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- restore fp regs */ \
- /* Hey, Rocky! Watch me pull fp regs from my stack! */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/\
- lfd fr0,TSS_FPR0(r2); \
- lfd fr1,TSS_FPR1(r2); \
- lfd fr2,TSS_FPR2(r2); \
- lfd fr3,TSS_FPR3(r2); \
- lfd fr4,TSS_FPR4(r2); \
- lfd fr5,TSS_FPR5(r2); \
- lfd fr6,TSS_FPR6(r2); \
- lfd fr7,TSS_FPR7(r2); \
- lfd fr8,TSS_FPR8(r2); \
- lfd fr9,TSS_FPR9(r2); \
- lfd fr10,TSS_FPR10(r2); \
- lfd fr11,TSS_FPR11(r2); \
- lfd fr12,TSS_FPR12(r2); \
- lfd fr13,TSS_FPR13(r2); \
- lfd fr14,TSS_FPR14(r2); \
- lfd fr15,TSS_FPR15(r2); \
- lfd fr16,TSS_FPR16(r2); \
- lfd fr17,TSS_FPR17(r2); \
- lfd fr18,TSS_FPR18(r2); \
- lfd fr19,TSS_FPR19(r2); \
- lfd fr20,TSS_FPR20(r2); \
- lfd fr21,TSS_FPR21(r2); \
- lfd fr22,TSS_FPR22(r2); \
- lfd fr23,TSS_FPR23(r2); \
- lfd fr24,TSS_FPR24(r2); \
- lfd fr25,TSS_FPR25(r2); \
- lfd fr26,TSS_FPR26(r2); \
- lfd fr27,TSS_FPR27(r2); \
- lfd fr28,TSS_FPR28(r2); \
- lfd fr29,TSS_FPR29(r2); \
- lfd fr30,TSS_FPR30(r2); \
- lfd fr31,TSS_FPR31(r2); \
-00:
-
-/* save all registers */
-#define SAVE_ALL_REGS(mark) \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stmw r3,GPR3(r1); /* Save R3..R31 */ \
- stw r3,ORIG_GPR3(r1); \
- stw r0,GPR0(r1); \
- mfspr r2,SPR0; \
- stw r2,GPR1(r1); \
- mfspr r2,SPR1; \
- stw r2,GPR2(r1); \
- mfspr r2,SPR2; \
- stw r2,_NIP(r1); \
- mfspr r2,SPR3; \
- stw r2,_MSR(r1); \
- mfctr r2; \
- stw r2,_CTR(r1); \
- mflr r2; \
- stw r2,_LINK(r1); \
- mfcr r2; \
- stw r2,_CCR(r1); \
- mfspr r2,XER; \
- stw r2,_XER(r1); \
- mffs fr0; \
- stfd fr0,FPCSR(r1); \
- lis r2,_break_lwarx@h; \
- ori r2,r2,_break_lwarx@l; \
- stwcx. r2,0,r2; \
- li r2,mark; \
- stw r2,TRAP(r1); \
- lis r2,0xDEAD; \
- ori r2,r2,0xDEAD; \
- stw r2,MARKER(r1); \
- li r2,0; \
- stw r2,RESULT(r1)
-
-
-/* save registers clobbered by a page fault handler */
-#define SAVE_PAGE_FAULT_REGS(offset) \
- mfspr r2,DAR; \
- stw r2,_DAR(r1); \
- mfspr r2,DSISR; \
- stw r2,_DSISR(r1); \
- mfspr r2,PVR; /* Check for 603/603e */ \
- srwi r2,r2,16; \
- cmpi 0,r2,3; /* 603 */ \
- beq 22f; \
- cmpi 0,r2,6; /* 603e */ \
- bne 24f; \
-22: mfspr r2,HASH1; /* Note: these registers exist only on 603 */ \
- stw r2,_HASH1(r1); \
- mfspr r2,HASH2; \
- stw r2,_HASH2(r1); \
- mfspr r2,IMISS; \
- stw r2,_IMISS(r1); \
- mfspr r2,DMISS; \
- stw r2,_DMISS(r1); \
- mfspr r2,ICMP; \
- stw r2,_ICMP(r1); \
- mfspr r2,DCMP; \
- stw r2,_DCMP(r1); \
-24:
-
-#define SAVE_INT_REGS(mark) \
- mtspr SPR0,r1; /* Save current stack pointer */ \
- mtspr SPR1,r2; /* Scratch */ \
- mfcr r2; \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; /* Interrupt from user/system mode */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* Jump if system - already have stack */ \
- mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,05f@h; \
- ori r2,r2,05f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- rfi; \
-05: lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- mfspr r1,SPR2; \
- stw r1,TSS+LAST_PC(r2); \
- mfspr r1,SPR0; \
- stw r1,TSS+USER_STACK(r2); \
- lwz r1,TSS+KSP(r2); \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stw r1,TSS+PT_REGS(r2); /* Save regs pointer for 'ptrace' */ \
- lwz r1,TSS+KSP(r2); \
- b 20f; \
-10: mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,20f@h; \
- ori r2,r2,20f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- SYNC(); \
- rfi; \
-20: SAVE_ALL_REGS(mark); \
- CHECK_STACK()
-
-#define RETURN_FROM_INT(mark) \
-90: mfmsr r0; /* Disable interrupts */ \
- li r4,0; \
- ori r4,r4,MSR_EE; \
- andc r0,r0,r4; \
- sync; /* Some chip revs need this... */ \
- mtmsr r0; \
- lis r2,intr_count@ha; /* Need to run 'bottom half' */ \
- lwz r3,intr_count@l(r2); \
- cmpi 0,r3,0; \
- bne 00f; \
- lis r4,bh_mask@ha; \
- lwz r4,bh_mask@l(r4); \
- lis r5,bh_active@ha; \
- lwz r5,bh_active@l(r5); \
- and. r4,r4,r5; \
- beq 00f; \
- addi r3,r3,1; \
- stw r3,intr_count@l(r2); \
- bl _EXTERN(_do_bottom_half); \
- lis r2,intr_count@ha; \
- lwz r3,intr_count@l(r2); \
- subi r3,r3,1; \
- stw r3,intr_count@l(r2); \
-00: lwz r2,_MSR(r1); /* Returning to user mode? */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* no - no need to mess with stack */ \
-/* lis r2,kernel_pages_are_copyback@ha; \
- lwz r2,kernel_pages_are_copyback@l(r2); \
- cmpi 0,r2,0; \
- beq 05f; \
- bl _EXTERN(flush_instruction_cache); */ \
-05: lis r3,current_set@ha; /* need to save kernel stack pointer */ \
- lwz r3,current_set@l(r3); \
- /*addi r4,r1,INT_FRAME_SIZE*/; /* size of frame */ \
- lwz r4, KERNEL_STACK_PAGE(r3); \
- addi r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
- /* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
- stw r4,TSS+KSP(r3); \
- lwz r4,STATE(r3); /* If state != 0, can't run */ \
- cmpi 0,r4,0; \
- beq 06f; \
- bl _EXTERN(schedule); \
- b 90b; \
-06: lwz r4,COUNTER(r3); /* Time quantum expired? */ \
- cmpi 0,r4,0; \
- bne 07f; \
- bl _EXTERN(schedule); \
- b 90b; \
-07: lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
- lwz r5,SIGNAL(r3); \
- andc. r0,r5,r4; /* Lets thru any unblocked */ \
- beq 10f; \
- mr r3,r4; \
- mr r4,r1; \
- bl _EXTERN(do_signal); \
-10: lwz r2,_NIP(r1); /* Restore environment */ \
- mtspr SRR0,r2; \
- lwz r2,_MSR(r1); \
- mtspr SRR1,r2; \
- lmw r3,GPR3(r1); \
- lwz r2,_CTR(r1); \
- mtctr r2; \
- lwz r2,_LINK(r1); \
- mtlr r2; \
- lwz r2,_XER(r1); \
- mtspr XER,r2; \
- lfd fr0,FPCSR(r1); \
- mtfsf 0xFF,fr0; \
- RESTORE_FP_REGS(mark) ; \
- lwz r2,_CCR(r1); \
- mtcrf 0xFF,r2; \
- lwz r0,GPR0(r1); \
- lwz r2,GPR2(r1); \
- lwz r1,GPR1(r1); \
- SYNC(); \
- rfi
-
-
-_TEXT()
-/*
- * This code may be executed by a bootstrap process. If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- * R30: 'BeBx' if this is a BeBox
- *
- */
- .globl _start
- .globl _stext
-_stext:
-_start:
- addi r4,r4,0x400 /* Point at start of image */
- li r5,0 /* Load address */
- subi r4,r4,4 /* Adjust for auto-increment */
- subi r5,r5,4
- subi r3,r3,4
-00: lwzu r0,4(r4) /* Fast move */
- stwu r0,4(r5)
- cmp 0,r3,r4
- bne 00b
- li r5,0x100 /* Actual code starts here */
- mtlr r5
- blr
+#define TOPHYS(x) (x - KERNELBASE)
-hang:
- ori r0,r0,0
- b hang
-/*
- * BeBox CPU #1 vector & code
+/* this is a very kludgey way of loading up the BATs on the
+ prep system. I'll kill this horrible macro and write
+ something clean when I have a chance -- Cort
*/
-_ORG(0x0080)
- .globl BeBox_CPU1_vector
-BeBox_CPU1_vector:
- .long 0
-BeBox_CPU1_reset:
- li r1,BeBox_CPU1_vector@l
- li r2,0
- stw r2,0(r1)
-00: lwz r2,0(r1)
- cmpi 0,r2,0
- bne 10f
- li r2,10000
- mtctr r2
-02: nop
- bdnz 02b
- b 00b
-10: mtlr r1
- blr
+#define LOAD_BATS(RA,RB) \
+ mfspr RA,PVR ; \
+ srwi r5,r5,16 ; \
+ cmpi 0,RA,1 ; \
+ beq 199f ; \
+ /* load bats for 60x */ ; \
+ lis RA,BAT0@h ; \
+ ori RA,RA,BAT0@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1@h ; \
+ ori RA,RA,BAT1@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2@h ; \
+ ori RA,RA,BAT2@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3@h ; \
+ ori RA,RA,BAT3@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+ b 200f ; \
+199: /*load bats for 601 */ ; \
+ lis RA,BAT0_601@h ; \
+ ori RA,RA,BAT0_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1_601@h ; \
+ ori RA,RA,BAT1_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2_601@h ; \
+ ori RA,RA,BAT2_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3_601@h ; \
+ ori RA,RA,BAT3_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+200:
-_ORG(0x0100)
-/* Hard Reset */
- .globl HardReset
-HardReset:
- b Reset
-_ORG(0x0200)
- b MachineCheck
-
-_ORG(0x0300)
- b DataAccess
-
-_ORG(0x0400)
- b InstructionAccess
-
-_ORG(0x0500)
- b HardwareInterrupt
-
-_ORG(0x0600)
- b Alignment
-
-_ORG(0x0700)
- b ProgramCheck
-
-_ORG(0x0800)
- b FloatingPointCheck
-
-/* Decrementer register - ignored for now... */
-_ORG(0x0900)
-/* TRACE_TRAP(0x900) */
- mtspr SPR0,r1
- lis r1,0x7FFF
- ori r1,r1,0xFFFF
- mtspr DEC,r1
- mfspr r1,SPR0
-#if 0
- SYNC
-#endif
- rfi
-_ORG(0x0A00)
-DEFAULT_TRAP(0x0A00)
-_ORG(0x0B00)
-DEFAULT_TRAP(0x0B00)
-
-/*
- * System call
- */
-_ORG(0x0C00)
- b SystemCall
+ .text
+ .globl _stext
+_stext:
-_ORG(0x0D00)
- b SingleStep
+#ifdef CONFIG_PREP
+ . = 0x100
+_GLOBAL(HardReset)
+ b _start
-_ORG(0x0E00)
-DEFAULT_TRAP(0x0E00)
-_ORG(0x0F00)
-DEFAULT_TRAP(0x0F00)
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
/*
- * Handle TLB Miss on an instruction load
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
*/
-_ORG(0x1000)
-/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
-/* could be a 'trace' in progress when the TLB miss occurs. */
-/* TRACE_TRAP(0x1000) */
- b InstructionTLBMiss
+ .text
+ .globl _start
+_start:
+ .long TOPHYS(__start),0,0
/*
- * Handle TLB Miss on a data item load
+ * Enter here with the kernel text, data and bss loaded starting at
+ * 0, running with virtual == physical mapping.
+ * r5 points to the prom entry point (the client interface handler
+ * address). Address translation is turned on, with the prom
+ * managing the hash table. Interrupts are disabled. The stack
+ * pointer (r1) points to just below the end of the half-meg region
+ * from 0x380000 - 0x400000, which is mapped in already.
*/
-_ORG(0x1100)
-/* TRACE_TRAP(0x1100) */
- b DataLoadTLBMiss
+ .globl __start
+__start:
/*
- * Handle TLB Miss on a store operation
+ * Use the first pair of BAT registers to map the 1st 8MB
+ * of RAM to KERNELBASE.
*/
-_ORG(0x1200)
-/* TRACE_TRAP(0x1200) */
- b DataStoreTLBMiss
-
-_ORG(0x1300)
-InstructionAddressBreakpoint:
- DEFAULT_TRAP(0x1300)
-
-_ORG(0x1400)
-SystemManagementInterrupt:
- DEFAULT_TRAP(0x1400)
-
-_ORG(0x1500)
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r7,KERNELBASE@h
+ bne 4f
+ ori r7,r7,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ b 5f
+4: ori r7,r7,0xff /* set up BAT registers for 604 */
+ li r8,2
+ mtspr DBAT0U,r7
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r7
+ mtspr IBAT0L,r8
+ isync
/*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode. This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream. Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
+ * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
+ * refer to addresses of data items, procedures, etc. normally.
*/
-#define NUM_CACHE_LINES 128*4
-#define CACHE_LINE_SIZE 32
-cache_flush_buffer:
- .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
-
-#if NUM_CACHE_LINES < 512
-_ORG(0x4000)
-#endif
+ lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PMAC */
-/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
-/*
- * Hardware reset [actually from bootstrap]
- * Initialize memory management & call secondary init
- * Registers initialized by bootstrap:
- * R11: Start of command line string
- * R12: End of command line string
- * R28: Residual data
- * R29: Total Memory Size
- * R30: 'BeBx' if this is a BeBox
- */
-Reset:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* set pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- andc r1,r1,r7
-/* changed to use r3 as residual pointer (as firmware does) -- Cort */
-/* this is only a ptr, the actual data is copied in mmu_init */
- stw r3,0(r1)
-
-/* Copy argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- andc r1,r1,r7 /* No MMU yet - need unmapped address */
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r1,isBeBox@h
- ori r1,r1,isBeBox@l
- andc r1,r1,r7
-/* See if this is a CPU other than CPU#1 */
-/* This [currently] happens on the BeBox */
- lwz r2,0(r1)
- cmpi 0,r2,0
- bne Reset_BeBox_CPU1
-/* Save machine type indicator */
- li r2,0
- lis r3,IS_BE_BOX>>16
- ori r3,r3,IS_BE_BOX&0xFFFF
- cmp 0,r30,r3
- bne 00f
- li r2,1
- mr r11,r28
- mr r12,r29
- lis r5,BeBox_CPU1_vector@h
- ori r5,r5,BeBox_CPU1_vector@l
- andc r5,r5,r7 /* Tell CPU #1 where to go */
-00: stw r2,0(r1)
- stw r30,4(r1)
-
-#if 0
- lis r1,sys_stack@h
- ori r1,r1,sys_stack@l
-#else
- lis r1,init_kernel_stack@h
- ori r1,r1,init_kernel_stack@l
-#endif
- addi r1,r1,0x1000 /* top of stack */
-#if 0
- li r2,0x0FFF /* Mask stack address down to page boundary */
-#endif
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
- mtmsr r0
- lis r3,_edata@h /* Clear BSS */
- ori r3,r3,_edata@l
- andc r3,r3,r7 /* make unmapped address */
- lis r4,_end@h
- ori r4,r4,_end@l
- andc r4,r4,r7 /* make unmapped address */
- subi r3,r3,4
- li r0,0
-00: stwu r0,4(r3)
- cmp 0,r3,r4
- blt 00b
-#if 0
-/* Save total memory size (passed from bootstrap) */
- lis r3,_TotalMemory@h
- ori r3,r3,_TotalMemory@l
- andc r3,r3,r7 /* make unmapped address */
- stw r29,0(r3)
-#endif
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
- mtspr IBAT0L,r0
- mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
- mtspr IBAT1L,r0
- mtspr DBAT1L,r0
-/* this BAT mapping will cover all of kernel space */
-#ifdef NEWMM
- lis r3,BAT2@h
- ori r3,r3,BAT2@l
-#else
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
-#endif
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-#if 1
- lis r3,BAT3@h
- ori r3,r3,BAT3@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT3U,r0
- mtspr DBAT3U,r0
- lwz r0,4(r3)
- mtspr IBAT3L,r0
- mtspr DBAT3L,r0
-#endif
-/* Now we can turn on the MMU */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0000)
- SYNC
- rfi /* enables MMU */
-10: bl _EXTERN(MMU_init) /* initialize MMU environment */
-DO_RFI_TRACE_MAPPED(0xDEAD0100)
-/* Withdraw BAT2->RAM mapping */
- lis r7,0xF000 /* To mask upper 4 bits */
- lis r3,20f@h
- ori r3,r3,20f@l
- andc r3,r3,r7 /* make unmapped address */
- mtspr SRR0,r3
- mfmsr r3
- li r4,MSR_DR|MSR_IR
- andc r3,r3,r4
- mtspr SRR1,r3
- SYNC
-DO_RFI_TRACE_MAPPED(0xDEAD0200)
- SYNC
- rfi
-20:
-
-DO_RFI_TRACE_UNMAPPED(0xDEAD0400)
-20: lis r3,BAT2@h
- ori r3,r3,BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Load up the kernel context */
- lis r2,init_task@h
- ori r2,r2,init_task@l
- addi r2,r2,TSS
- andc r2,r2,r7 /* make unmapped address */
- SYNC /* Force all PTE updates to finish */
- tlbia /* Clear all TLB entries */
- lis r3,_SDR1@h
- ori r3,r3,_SDR1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r3,0(r3)
- mtspr SDR1,r3
- lwz r0,MMU_SEG0(r2)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r2)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r2)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r2)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r2)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r2)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r2)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r2)
- mtsr SR7,r0
- lwz r0,MMU_SEG8(r2)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r2)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r2)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r2)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r2)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r2)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r2)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r2)
- mtsr SR15,r0
-/* Now turn on the MMU for real! */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,30f@h
- ori r3,r3,30f@l
- mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0500)
- SYNC
- rfi /* enables MMU */
-30:
-/* Turn on L1 Data Cache */
- mfspr r3,HID0 /* Caches are controlled by this register */
- ori r4,r3,(HID0_ICE|HID0_ICFI)
- ori r3,r3,(HID0_ICE)
- ori r4,r4,(HID0_DCE|HID0_DCI)
- ori r3,r3,(HID0_DCE)
- sync
- mtspr HID0,r4
- mtspr HID0,r3
-/* L1 cache enable */
- mfspr r2,PVR /* Check for 603/603e */
- srwi r2,r2,16
- cmpi 0,r2,4 /* 604 */
- bne 40f
- mfspr r3,HID0 /* Turn on 604 specific features */
- ori r3,r3,(HID0_SIED|HID0_BHTE)
- mtspr HID0,r3
-40: b _EXTERN(start_kernel) /* call main code */
- .long 0 # Illegal!
-
/*
- * BeBox CPU #2 runs here
+ * Macros for storing registers into and loading registers from
+ * exception frames.
*/
-Reset_BeBox_CPU1:
- lis r1,CPU1_stack@h
- ori r1,r1,CPU1_stack@l
- li r2,0x0FFF /* Mask stack address down to page boundary */
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- andc r30,r30,r7
- li r5,1
- stw r5,0(r30)
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
- mtmsr r0
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
- mtspr IBAT0L,r0
- mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
- mtspr IBAT1L,r0
- mtspr DBAT1L,r0
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Now we can turn on the MMU */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
- li r5,2
- stw r5,0(r30)
- SYNC
- rfi /* enables MMU */
-10:
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- li r5,3
- stw r5,0(r30)
- bl _EXTERN(BeBox_CPU1)
-
-/*
- * Machine Check (Bus Errors, etc)
- */
-MachineCheck:
- TRACE_TRAP(0x0200)
- SAVE_INT_REGS(0x0200)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(MachineCheckException)
- RETURN_FROM_INT(0x0200)
-
-/*
- * Data Access exception
- */
-DataAccess:
- SAVE_INT_REGS(0x0300)
-#if 1
- mfspr r3, DAR
- mfspr r4, DSISR
- li r5, 0 /* not a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(DataAccessException)
-#endif
- RETURN_FROM_INT(0x0300)
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
/*
- * Instruction Access Exception
+ * Exception entry code. This code runs with address translation
+ * turned off, i.e. using physical addresses.
+ * We assume sprg3 has the physical address of the current
+ * task's thread_struct.
*/
-InstructionAccess:
- SAVE_INT_REGS(0x0400)
-#if 1
- mfspr r3, SPR2 /* srr0 was saved here */
- mfspr r4, SPR3 /* srr1 was saved here */
- li r5, 1 /* a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(InstructionAccessException)
-#endif
- RETURN_FROM_INT(0x0400)
-
+#define EXCEPTION_PROLOG \
+0: mtspr SPRG0,r20; \
+ mtspr SPRG1,r21; \
+ mfcr r20; \
+ mfspr r21,SRR1; /* test whether from user or kernel */\
+ andi. r21,r21,MSR_PR; \
+ mr r21,r1; /* from kernel - use current sp */\
+ beq 1f; \
+ mfspr r21,SPRG3; /* from user - load kernel sp */\
+ lwz r21,KSP(r21); \
+1: addis r21,r21,-KERNELBASE@h; /* convert sp to physical */ \
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+ stw r1,GPR1(r21); \
+ stw r1,0(r21); \
+ addis r1,r21,KERNELBASE@h; /* set new kernel sp */ \
+ stw r20,_CCR(r21); /* save registers */ \
+ stw r22,GPR22(r21); \
+ stw r23,GPR23(r21); \
+ mfspr r20,SPRG0; \
+ stw r20,GPR20(r21); \
+ mfspr r22,SPRG1; \
+ stw r22,GPR21(r21); \
+ mflr r20; \
+ stw r20,_LINK(r21); \
+ mfctr r22; \
+ stw r22,_CTR(r21); \
+ mfspr r20,XER; \
+ stw r20,_XER(r21); \
+ mfspr r22,SRR0; \
+ mfspr r23,SRR1; /* we can now take exceptions */\
+ stw r0,GPR0(r21); \
+ stw r2,GPR2(r21); \
+ SAVE_4GPRS(3, r21);
/*
- * Hardware Interrupt
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
*/
-HardwareInterrupt:
- SAVE_INT_REGS(0x0500)
- BUMP(__Hardware_Interrupts)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(handle_IRQ)
- RETURN_FROM_INT(0x0500)
/*
- * Alignment
- */
-Alignment:
- TRACE_TRAP(0x0600)
- SAVE_INT_REGS(0x0600)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(AlignmentException)
- RETURN_FROM_INT(0x0600)
-
-/*
- * Illegal instruction
+ * Exception vectors.
*/
+#define STD_EXCEPTION(n, label, hdlr) \
+ . = n; \
+label: \
+ EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r20,MSR_KERNEL; \
+ bl transfer_to_handler; \
+ .long hdlr; \
+ .long int_return
+
+#ifndef CONFIG_PREP
+/* System reset */
+ STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif /* ndef CONFIG_PREP */
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data access exception */
+ . = 0x300
+DataAccess:
+ EXCEPTION_PROLOG
+ mfspr r20,DSISR
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 1f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: stw r20,_DSISR(r21)
+ mr r5,r20
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* Instruction access exception */
+ . = 0x400
+InstructionAccess:
+ EXCEPTION_PROLOG
+ andis. r0,r23,0x4000 /* no pte found? */
+ beq 1f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r22
+ mr r5,r23
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* External interrupt */
+ STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+
+/* Alignment exception */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long AlignmentException
+ .long int_return
+
+/* Program check exception */
+ . = 0x700
ProgramCheck:
- TRACE_TRAP(0x0700)
- SAVE_INT_REGS(0x0700)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(ProgramCheckException)
- RETURN_FROM_INT(0x0700)
-
-/*
- * Single Step Exception
- */
-SingleStep:
- SAVE_INT_REGS(0x0D00)
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(SingleStepException)
-#if 0
- bl _EXTERN(flush_instruction_cache)
-#endif
- RETURN_FROM_INT(0x0D00)
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long ProgramCheckException
+ .long int_return
+
+/* Floating-point unavailable */
+ . = 0x800
+FPUnavailable:
+ EXCEPTION_PROLOG
+ bne load_up_fpu /* if from user, just load it up */
+ li r20,MSR_KERNEL
+ bl transfer_to_handler /* if from kernel, take a trap */
+ .long KernelFP
+ .long int_return
+
+/* Decrementer */
+#ifdef CONFIG_PREP
+/* - ignored for now... */
+_ORG(0x0900)
+ mtspr SPRG0,r1
+ lis r1,0x7FFF
+ ori r1,r1,0xFFFF
+ mtspr DEC,r1
+ mfspr r1,SPRG0
+ rfi
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+#endif /* CONFIG_PMAC */
-/*
- * Floating point [not available, etc]
- */
-FloatingPointCheck:
- SAVE_INT_REGS(0x0800)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(FloatingPointCheckException)
- cmpi 0,r3,MSR_FP /* check if fp was turned on by handler */
- bne 00f
- RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
-00: RETURN_FROM_INT(0x0200)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
-/*
- * System Call exception
- */
+/* System call */
+ . = 0xc00
SystemCall:
- SAVE_INT_REGS(0x0C00)
- lwz r2,_CCR(r1) /* Clear SO bit in CR */
- lis r9,0x1000
- andc r2,r2,r9
- stw r2,_CCR(r1)
- cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
- bne+ 10f
- mr r3,r1
- bl _EXTERN(sys_sigreturn)
- cmpi 0,r3,0 /* Check for restarted system call */
- bge 99f
- b 20f
-10: lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- lwz r2,TASK_FLAGS(r2)
- andi. r2,r2,PF_TRACESYS
- bne 50f
-
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
- slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
-#if 1
- cmpi 0,r2,0 /* make sure syscall handler not 0 */
- beq 99f
- cmpi 0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
- bgt 99f
-#endif
- mtlr r2
- mr r9,r1
- blrl /* Call handler */
-
-20: stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 30f
- neg r3,r3
- cmpi 0,r3,ERESTARTNOHAND
- bne 22f
- li r3,EINTR
-22: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
-30: stw r3,GPR3(r1) /* Update return value */
- b 99f
-/* Traced system call support */
-50: bl _EXTERN(syscall_trace)
- lwz r0,GPR0(r1) /* Restore original registers */
- lwz r3,GPR3(r1)
- lwz r4,GPR4(r1)
- lwz r5,GPR5(r1)
- lwz r6,GPR6(r1)
- lwz r7,GPR7(r1)
- lwz r8,GPR8(r1)
- lwz r9,GPR9(r1)
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
- slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
- mtlr r2
- mr r9,r1
- blrl /* Call handler */
- stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 60f
- neg r3,r3
- cmpi 0,r3,ERESTARTNOHAND
- bne 52f
- li r3,EINTR
-52: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
-60: stw r3,GPR3(r1) /* Update return value */
- bl _EXTERN(syscall_trace)
-99:
- RETURN_FROM_INT(0x0C00)
+ EXCEPTION_PROLOG
+ stw r3,ORIG_GPR3(r21)
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long DoSyscall
+ .long int_return
+
+/* Single step - not used on 601 */
+ STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
/*
- * Handle TLB miss for instruction
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
*/
+ . = 0x1000
InstructionTLBMiss:
- BUMP_UNMAPPED(__Instruction_TLB_Misses)
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,ICMP /* Partial item compare value */
@@ -1080,37 +425,47 @@ InstructionTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
-#if 0
- andi. r3,r1,0x08 /* Check guard bit - invalid access if set */
- bne InstructionFetchError
-#endif
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- bne 20f /* If set, all done */
- ori r1,r1,0x100 /* Set bit */
- stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,IMISS /* Set to update TLB */
mtspr RPA,r1
tlbli r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne InstructionAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
+ b 00b /* Try lookup again */
+InstructionAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ or r2,r2,r1
+ mtspr SRR1,r2
+ mfspr r1,IMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b InstructionAccess
/*
- * Handle TLB miss for DATA Load operation
- */
+ * Handle TLB miss for DATA Load operation on 603/603e
+ */
+ . = 0x1100
DataLoadTLBMiss:
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
@@ -1120,36 +475,47 @@ DataLoadTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- ori r1,r1,0x100 /* Set bit */
- bne 20f /* If set, all done */
- stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
-/* SYNC() */
tlbld r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne DataAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
+ b 00b /* Try lookup again */
+DataAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ mtspr SRR1,r2
+ mfspr r1,DMISS /* Get failing address */
+ rlwinm. r2,r2,0,31,31 /* Check for little endian access */
+ beq 20f /* Jump if big endian */
+ xori r1,r1,3
+20: mtspr DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b DataAccess
/*
- * Handle TLB miss for DATA STORE
+ * Handle TLB miss for DATA Store on 603/603e
*/
+ . = 0x1200
DataStoreTLBMiss:
- BUMP_UNMAPPED(__DataStore_TLB_Misses)
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,DCMP /* Partial item compare value */
@@ -1158,26 +524,15 @@ DataStoreTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x80 /* Check C bit (changed) */
-#if 0 /* Note: no validation */
- beq 40f /* If not set (first time) validate access */
-#else
- ori r1,r1,0x180 /* Set changed, accessed */
- bne 20f
- stw r1,4(r2)
-#endif
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
tlbld r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
@@ -1185,229 +540,980 @@ DataStoreTLBMiss:
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
-/* PTE found - validate access */
-40: rlwinm. r3,r1,30,0,1 /* Extract PP bits */
- bge- 50f /* Jump if PP=0,1 */
- andi. r3,r1,1
- beq+ 70f /* Access OK */
- b WriteProtectError /* Not OK - fail! */
-50: mfspr r3,SRR1 /* Check privilege */
- andi. r3,r3,MSR_PR
- beq+ 60f /* Jump if supervisor mode */
- mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x2000 /* If Kp==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-60: mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x4000 /* If Ks==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-70: ori r1,r1,0x180 /* Set changed, accessed */
- stw r1,4(r2) /* Update PTE in memory */
- b 20b
-
+
+/* Instruction address breakpoint exception (on 603/604) */
+ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+
+/* System management exception (603?) */
+ STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+
+/* Run mode exception */
+ STD_EXCEPTION(0x2000, RunMode, RunModeException)
+
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+ . = 0x3000
+
/*
- * These routines are error paths/continuations of the exception
- * handlers above. They are placed here to avoid the problems
- * of only 0x100 bytes per exception handler.
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
*/
-
-/* Invalid address */
-InstructionAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss */
+ beq 2f
+#ifdef CONFIG_PMAC
+ lwz r24,GPR1(r21)
+ stw r22,LAST_PC(r23)
+ stw r24,USER_STACK(r23)
+#endif /* CONFIG_PMAC */
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ addis r2,r2,KERNELBASE@h
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
-/* Fetch from guarded or no-access page */
-InstructionFetchError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,IMISS /* Get failing address */
- rlwinm. r2,r2,0,31,31 /* Check for little endian access */
- beq 20f /* Jump if big endian */
- xori r1,r1,3
-20: mtspr DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b InstructionAccess
+/*
+ * Continuation of the floating-point unavailable handler.
+ */
+load_up_fpu:
+ bl giveup_fpu_unmapped
+ ori r23,r23,MSR_FP /* enable use of FP after return */
+ mfspr r5,SPRG3 /* current task's TSS (phys) */
+ lfd fr0,TSS_FPSCR-4(r5)
+ mtfsf 0xff,fr0
+ REST_32FPRS(0, r5)
+
+/* use last_task_used_math instead of fpu_tss */
+ lis r3,last_task_used_math@h/*a*/
+ addis r3,r3,-KERNELBASE@h
+ subi r4,r5,TSS
+ addis r4,r4,KERNELBASE@h
+ stw r4,last_task_used_math@l(r3)
+#if 0
+ lis r3,fpu_tss@ha
+ addis r4,r5,KERNELBASE@h
+ addis r3,r3,-KERNELBASE@h
+ stw r4,fpu_tss@l(r3)
+#endif
+ /* restore registers and return */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ REST_GPR(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used ctr or xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
-/* Invalid address */
-DataAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r3, and r4 contains access flags:
+ * _PAGE_USER (4) if a user-mode access, ored with
+ * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1,
+ * so bit 1 (0x40000000) is set if the exception was due
+ * to no matching PTE being found in the hash table.
+ * r5 contains the physical address of the current task's tss.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address. Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r2 - r6, ctr, lr.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known. These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0x180000
+Hash_bits = 12 /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+ .globl hash_page
+hash_page:
+ /* Get PTE (linux-style) and check access */
+ lwz r5,PG_TABLES(r5) /* task's page tables */
+ lis r2,-KERNELBASE@h
+ add r5,r5,r2 /* convert to phys addr */
+ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
+ lwz r5,0(r5) /* get pmd entry */
+ rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+ beqlr- /* return if no mapping */
+ add r2,r5,r2
+ rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
+ lwz r6,0(r2) /* get linux-style pte */
+ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
+ andc. r0,r4,r6 /* check access & ~permission */
+ bnelr- /* return if access not permitted */
+ ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
+ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
+ rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */
+ or r6,r6,r5
+ stw r6,0(r2) /* update PTE (accessed/dirty bits) */
+
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r4,r4,0xe04 /* clear out reserved bits */
+ andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */
+
+ /* 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 */
+ oris r5,r5,0x8000 /* set V (valid) bit */
+ 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
+hash_page_patch_A:
+ lis r4,Hash_base@h /* base address of hash table */
+ rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */
+ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */
+ xor r4,r4,r0 /* make primary hash */
+
+ /* See whether it was a PTE not found exception or a
+ protection violation. */
+ andis. r0,r20,0x4000
+ li r2,8 /* PTEs/group */
+ bne 10f /* no PTE: go look for an empty slot */
+ tlbie r3 /* invalidate TLB entry */
+
+ /* Search the primary PTEG for a PTE whose 1st word matches r5 */
+ mtctr r2
+ addi r3,r4,-8
+1: lwzu r0,8(r3) /* get next PTE */
+ cmp 0,r0,r5
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_slot
+
+ /* Search the secondary PTEG for a matching PTE */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_B
+hash_page_patch_B:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmp 0,r0,r5
+ bdnzf 2,2b
+ beq+ found_slot
+ xori r5,r5,0x40 /* clear H bit again */
+
+ /* Search the primary PTEG for an empty slot */
+10: mtctr r2
+ addi r3,r4,-8 /* search primary PTEG */
+1: lwzu r0,8(r3) /* get next PTE */
+ cmpi 0,r0,0 /* empty? */
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_empty
+
+ /* Search the secondary PTEG for an empty slot */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_C
+hash_page_patch_C:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmpi 0,r0,0
+ bdnzf 2,2b
+ beq+ found_empty
+
+ /* Choose an arbitrary slot in the primary PTEG to overwrite */
+ xori r5,r5,0x40 /* clear H bit again */
+ lwz r2,next_slot@l(0)
+ addi r2,r2,8
+ andi. r2,r2,0x38
+ stw r2,next_slot@l(0)
+ add r3,r4,r2
+
+ /* Store PTE in PTEG */
+found_empty:
+ stw r5,0(r3)
+found_slot:
+ stw r6,4(r3)
+ SYNC
+ /* Return from the exception */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ lwz r5,_CTR(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ mtctr r5
+ REST_GPR(0, r21)
+ REST_2GPRS(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
-/* Write to read-only space */
-WriteProtectError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,DMISS /* Get failing address */
- rlwinm. r2,r2,0,31,31 /* Check for little endian access */
- beq 20f /* Jump if big endian */
- xori r1,r1,3
-20: mtspr DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b DataAccess
+next_slot:
+ .long 0
/*
- * Flush instruction cache
- * *** I'm really paranoid here!
+ * This is where the main kernel code starts.
*/
-_GLOBAL(flush_instruction_cache)
- mflr r5
- bl _EXTERN(flush_data_cache)
- mfspr r3,HID0 /* Caches are controlled by this register */
+
+start_here:
+ /*
+ * Enable caches and 604-specific features if necessary.
+ */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31
+ cmpi 0,r9,1
+ beq 4f /* not needed for 601 */
+ mfspr r7,HID0
+ andi. r0,r7,HID0_DCE
+ ori r7,r7,HID0_ICE|HID0_DCE
+ ori r8,r7,HID0_ICFI
+ bne 3f /* don't invalidate the D-cache */
+ ori r8,r8,HID0_DCI /* unless it wasn't enabled */
+3: sync
+ mtspr HID0,r8 /* enable and invalidate caches */
+ sync
+ mtspr HID0,r7 /* enable caches */
+ sync
+ isync
+ cmpi 0,r9,4 /* check for 604 */
+ cmpi 1,r9,9 /* or 604e */
+ cror 2,2,6
+ bne 4f
+ ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r7 /* superscalar exec & br history tbl */
+4:
+ /* ptr to current */
+ lis r2,init_task_union@h
+ ori r2,r2,init_task_union@l
+ /* ptr to phys current tss */
+ addis r3,r2,-KERNELBASE@h
+ addi r3,r3,TSS /* init task's TSS */
+ mtspr SPRG3,r3
+ /* stack */
+ addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ stwu r0,-STACK_FRAME_OVERHEAD(r1)
+
+ /* Clear out the BSS */
+ lis r7,_end@ha
+ addi r7,r7,_end@l
+ lis r8,__bss_start@ha
+ addi r8,r8,__bss_start@l
+ subf r7,r8,r7
+ addi r7,r7,3
+ rlwinm. r7,r7,30,2,31
+ beq 2f
+ addi r8,r8,-4
+ mtctr r7
+ li r0,0
+3: stwu r0,4(r8)
+ bdnz 3b
+2:
+/*
+ * Initialize the prom stuff (powermacs only) and the MMU.
+ */
+#ifdef CONFIG_PMAC
+ bl prom_init
+#endif /* CONFIG_PMAC */
+ bl MMU_init
+
+/*
+ * Go back to running unmapped so we can load up new values
+ * for SDR1 (hash table pointer) and the segment registers
+ * and change to using our exception vectors.
+ */
+ lis r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ rfi
+/* Load up the kernel context */
+2:
+#ifdef CONFIG_PREP
+ /* reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r0)
+#endif
+
+ SYNC /* Force all PTE updates to finish */
+ tlbia /* Clear all TLB entries */
+ mtspr SDR1,r6
+ li r0,16 /* load up segment register values */
+ mtctr r0 /* for context 0 */
+ lis r3,0x2000 /* Ku = 1, VSID = 0 */
li r4,0
- ori r4,r4,(HID0_ICE|HID0_ICFI)
- or r3,r3,r4 /* Need to enable+invalidate to clear */
- mtspr HID0,r3
- andc r3,r3,r4
- ori r3,r3,HID0_ICE /* Enable cache */
- mtspr HID0,r3
- mtlr r5
- blr
+3: mtsrin r3,r4
+ addi r3,r3,1 /* increment VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+#ifdef CONFIG_PMAC
+ li r0,0 /* zot the BATs */
+#if 1
+ mtspr IBAT0U,r0
+ mtspr IBAT0L,r0
+ mtspr DBAT0U,r0
+ mtspr DBAT0L,r0
+#endif
+ mtspr IBAT1U,r0
+ mtspr IBAT1L,r0
+ mtspr DBAT1U,r0
+ mtspr DBAT1L,r0
+ mtspr IBAT2U,r0
+ mtspr IBAT2L,r0
+ mtspr DBAT2U,r0
+ mtspr DBAT2L,r0
+ mtspr IBAT3U,r0
+ mtspr IBAT3L,r0
+ mtspr DBAT3U,r0
+ mtspr DBAT3L,r0
+#endif
+/* Now turn on the MMU for real! */
+ li r4,MSR_KERNEL
+ lis r3,start_kernel@h
+ ori r3,r3,start_kernel@l
+ mtspr SRR0,r3
+ mtspr SRR1,r4
+ rfi /* enable MMU and jump to start_kernel */
+#ifdef CONFIG_PREP
/*
- * Flush data cache
- * *** I'm really paranoid here!
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader. The expected layout
+ * of the regs is:
+ * R3: End of image
+ * R4: Start of image - 0x400
+ * R11: Start of command line string
+ * R12: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort
*/
-_GLOBAL(flush_data_cache)
- BUMP(__Cache_Flushes)
- lis r3,cache_is_copyback@ha
- lwz r3,cache_is_copyback@l(r3)
- cmpi 0,r3,0
- beq 10f
-/* When DATA CACHE is copy-back */
- lis r3,cache_flush_buffer@h
- ori r3,r3,cache_flush_buffer@l
- li r4,NUM_CACHE_LINES
- mtctr r4
-00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
- addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
- bdnz 00b
-10: blr
+ .globl __start
+__start:
+ .globl _start
+_start:
+ lis r7,0xF000 /* To mask upper 4 bits */
+/* save pointer to residual data */
+ lis r1,resptr@h
+ ori r1,r1,resptr@l
+ addis r1,r1,-KERNELBASE@h
+ stw r3,0(r1)
+/* save argument string */
+ li r0,0 /* Null terminate string */
+ stb r0,0(r12)
+ lis r1,cmd_line@h
+ ori r1,r1,cmd_line@l
+ addis r1,r1,-KERNELBASE@h
+ subi r1,r1,1
+ subi r11,r11,1
+00: lbzu r0,1(r11)
+ cmpi 0,r0,0
+ stbu r0,1(r1)
+ bne 00b
+/* setup the msr with sane values */
+ li r0,MSR_
+ mtmsr r0
+/* turn on the mmu with bats covering kernel enough to get started */
+ LOAD_BATS(r3,r0)
+ mfmsr r3
+ ori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR1,r3
+ lis r3,10f@h
+ ori r3,r3,10f@l
+ mtspr SRR0,r3
+ SYNC
+ rfi /* enables MMU */
+10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PREP */
+
+/*
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
+ */
+KernelFP:
+ lwz r3,_MSR(r1)
+ ori r3,r3,MSR_FP
+ stw r3,_MSR(r1) /* enable use of FP after return */
+ lis r3,86f@h
+ ori r3,r3,86f@l
+ mr r4,r2 /* current */
+ lwz r5,_NIP(r1)
+ bl printk
+ b int_return
+86: .string "floating point used in kernel (task=%p, pc=%x)\n"
+ .align 4
/*
- * Flush a particular page from the DATA cache
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * void flush_page(void *page)
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * (If giveup_fpu_unmapped uses any integer registers other than
+ * r3 - r6, the return code at load_up_fpu above will have
+ * to be adjusted.)
*/
-_GLOBAL(flush_page)
- li r4,0x0FFF
- andc r3,r3,r4 /* Get page base address */
- li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
- mtctr r4
-00: dcbf 0,r3 /* Clear line */
- icbi 0,r3
- addi r3,r3,CACHE_LINE_SIZE
- bdnz 00b
+giveup_fpu_unmapped:
+ lis r6,-KERNELBASE@h
+ b 1f
+
+ .globl giveup_fpu
+giveup_fpu:
+ li r6,0
+1:
+ addis r3,r6,last_task_used_math@h/*a*/
+ lwz r4,last_task_used_math@l(r3)
+#if 0
+ addis r3,r6,fpu_tss@ha
+ lwz r4,fpu_tss@l(r3)
+#endif
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+ cmpi 0,r4,0
+ add r4,r4,r6
+ beqlr /* if no previous owner, done */
+ addi r4,r4,TSS /* want TSS of last_task_used_math */
+ li r5,0
+ stw r5,last_task_used_math@l(r3)
+#if 0
+ stw r5,fpu_tss@l(r3)
+#endif
+ SAVE_32FPRS(0, r4)
+ mffs fr0
+ stfd fr0,TSS_FPSCR-4(r4)
+ lwz r5,PT_REGS(r4)
+ lwz r5,PT_REGS(r4)
+ add r5,r5,r6
+ lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r4,MSR_FP
+ andc r3,r3,r4 /* disable FP for previous task */
+ stw r3,_MSR-STACK_FRAME_OVERHEAD(r5)
blr
/*
+ * Handle a system call.
+ */
+DoSyscall:
+ stw r0,TSS+LAST_SYSCALL(r2)
+ lwz r11,_CCR(r1) /* Clear SO bit in CR */
+ lis r10,0x1000
+ andc r11,r11,r10
+ stw r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ lis r31,show_syscalls_task@ha
+ lwz r31,show_syscalls_task@l(r31)
+ cmp 0,r2,r31
+ bne 1f
+#endif
+ lis r3,7f@ha
+ addi r3,r3,7f@l
+ lwz r4,GPR0(r1)
+ lwz r5,GPR3(r1)
+ lwz r6,GPR4(r1)
+ lwz r7,GPR5(r1)
+ lwz r8,GPR6(r1)
+ mr r9,r2
+ bl printk
+ lwz r0,GPR0(r1)
+ lwz r3,GPR3(r1)
+ lwz r4,GPR4(r1)
+ lwz r5,GPR5(r1)
+ lwz r6,GPR6(r1)
+ lwz r7,GPR7(r1)
+ lwz r8,GPR8(r1)
+1:
+#endif /* SHOW_SYSCALLS */
+ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
+ beq- 10f
+ lwz r10,TASK_FLAGS(r2)
+ andi. r10,r10,PF_TRACESYS
+ bne- 50f
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+ .globl syscall_ret_1
+syscall_ret_1:
+20: stw r3,RESULT(r1) /* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ cmp 0,r2,r31
+ bne 91f
+#endif
+ mr r4,r3
+ lis r3,79f@ha
+ addi r3,r3,79f@l
+ bl printk
+ lwz r3,RESULT(r1)
+91:
+#endif
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 30f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 22f
+ li r3,EINTR
+22: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
+30: stw r3,GPR3(r1) /* Update return value */
+ b int_return
+66: li r3,ENOSYS
+ b 22b
+/* sys_sigreturn */
+10: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(sys_sigreturn)
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge int_return
+ b 20b
+/* Traced system call support */
+50: bl _EXTERN(syscall_trace)
+ lwz r0,GPR0(r1) /* Restore original registers */
+ lwz r3,GPR3(r1)
+ lwz r4,GPR4(r1)
+ lwz r5,GPR5(r1)
+ lwz r6,GPR6(r1)
+ lwz r7,GPR7(r1)
+ lwz r8,GPR8(r1)
+ lwz r9,GPR9(r1)
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+ .globl syscall_ret_2
+syscall_ret_2:
+ stw r3,RESULT(r1) /* Save result */
+ stw r3,GPR0(r1) /* temporary gross hack to make strace work */
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 60f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 52f
+ li r3,EINTR
+52: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
+60: stw r3,GPR3(r1) /* Update return value */
+ bl _EXTERN(syscall_trace)
+ b int_return
+66: li r3,ENOSYS
+ b 52b
+#ifdef SHOW_SYSCALLS
+7: .string "syscall %d(%x, %x, %x, %x), current=%p\n"
+79: .string " -> %x\n"
+ .align 2
+#endif
+
+/*
* This routine switches between two different tasks. The process
* state of one is saved on its kernel stack. Then the state
* of the other is restored from its kernel stack. The memory
* management hardware is updated to the second process's state.
- * Finally, we can return to the second process, via the 'return'.
+ * Finally, we can return to the second process, via int_return.
+ * On entry, r3 points to the TSS for the current task, r4
+ * points to the TSS for the new task, and r5 contains the
+ * MMU context number for the new task.
*
* Note: there are two ways to get to the "going out" portion
* of this code; either by coming in via the entry (_switch)
* or via "fork" which must set up an environment equivalent
* to the "_switch" path. If you change this (or in particular, the
- * SAVE_ALL_REGS macro), you'll have to change the fork code also.
+ * SAVE_REGS macro), you'll have to change the fork code also.
*
* The code which creates the new task context is in 'copy_thread'
* in arch/ppc/kernel/process.c
*/
_GLOBAL(_switch)
- mtspr SPR0,r1 /* SAVE_ALL_REGS prologue */
- mtspr SPR1,r2
- mflr r2 /* Return to switch caller */
- mtspr SPR2,r2
- mfmsr r2
- mtspr SPR3,r2
- SAVE_ALL_REGS(0x0FF0)
- SAVE_FP_REGS()
- CHECK_STACK()
- SYNC()
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,GPR0(r1)
+ lwz r0,0(r1)
+ stw r0,GPR1(r1)
+ SAVE_10GPRS(2, r1)
+ SAVE_10GPRS(12, r1)
+ SAVE_10GPRS(22, r1)
+ mflr r20 /* Return to switch caller */
+ mfmsr r22
+ li r0,MSR_FP /* Disable floating-point */
+ andc r22,r22,r0
+ stw r20,_NIP(r1)
+ stw r22,_MSR(r1)
+ stw r20,_LINK(r1)
+ mfcr r20
+ mfctr r22
+ mfspr r23,XER
+ stw r20,_CCR(r1)
+ stw r22,_CTR(r1)
+ stw r23,_XER(r1)
+ li r0,0x0ff0
+ stw r0,TRAP(r1)
stw r1,KSP(r3) /* Set old stack pointer */
- BUMP(__Context_Switches)
+ sync
+ addis r0,r4,-KERNELBASE@h
+ mtspr SPRG3,r0 /* Update current TSS phys addr */
+ SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
- lwz r0,MMU_SEG0(r4)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r4)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r4)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r4)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r4)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r4)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r4)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r4)
- mtsr SR7,r0
-#if 0
- /* segs 8-15 are shared by everyone -- don't need to be changed */
- lwz r0,MMU_SEG8(r4)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r4)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r4)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r4)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r4)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r4)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r4)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r4)
- mtsr SR15,r0
-#endif
- /* no need to invalidate tlb since each process has a distinct
- set of vsid's. -- Cort */
-#if 0
- tlbia /* Invalidate entire TLB */
- BUMP(__TLBIAs)
-#endif
- /* p5.2 603 users manual - with addr transl. enabled,
- the memory access is performed under the control of
- the page table entry. I interpret this to mean that
- it is tagged with the vsid -- so no need to flush here
- since each process has a distinct set of vsid's.
- Of course, my intepretation may be wrong.
- -- Cort */
- /*bl _EXTERN(flush_instruction_cache)*/
- RETURN_FROM_INT(0x0f0f)
-
+ addi r2,r4,-TSS /* Update current */
+ /* Set up segment registers for new task */
+ rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
+ addis r5,r5,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r3,0
+3: mtsrin r5,r3
+ addi r5,r5,1 /* next VSID */
+ addis r3,r3,0x1000 /* address of next segment */
+ bdnz 3b
+ SYNC
+
+/* FALL THROUGH into int_return */
+
+/*
+ * Trap exit.
+ */
+ .globl int_return
+int_return:
+0: mfmsr r30 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r30,r30,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r30
+ SYNC
+ lwz r5,_MSR(r1)
+ and. r5,r5,r4
+ beq 2f
+3: lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ beq+ 1f
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ b 3b
+1: lis r4,bh_mask@ha
+ lwz r4,bh_mask@l(r4)
+ lis r5,bh_active@ha
+ lwz r5,bh_active@l(r5)
+ and. r4,r4,r5
+ beq+ 2f
+ ori r31,r30,MSR_EE /* re-enable interrupts */
+ SYNC
+ mtmsr r31
+ SYNC
+ bl _EXTERN(do_bottom_half)
+ SYNC
+ mtmsr r30 /* disable interrupts again */
+ SYNC
+2: lwz r3,_MSR(r1) /* Returning to user mode? */
+ andi. r3,r3,MSR_PR
+ beq+ 10f /* no - no need to mess with stack */
+ lis r3,need_resched@ha
+ lwz r3,need_resched@l(r3)
+ cmpi 0,r3,0 /* check need_resched flag */
+ beq+ 7f
+ bl _EXTERN(schedule)
+ b 0b
+7: lwz r3,BLOCKED(r2) /* Check for pending unblocked signals */
+ lwz r5,SIGNAL(r2)
+ andc. r0,r5,r3 /* Lets thru any unblocked */
+ beq+ 8f
+ addi r4,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(do_signal)
+ b 0b
+8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
+ stw r4,TSS+KSP(r2) /* save kernel stack pointer */
+10:
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/*
+ * Fake an interrupt from kernel mode.
+ * This is used when enable_irq loses an interrupt.
+ * We only fill in the stack frame minimally.
+ */
+_GLOBAL(fake_interrupt)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,_NIP(r1)
+ stw r0,_LINK(r1)
+ mfmsr r3
+ stw r3,_MSR(r1)
+ li r0,0x0fac
+ stw r0,TRAP(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ lwz r0,4(r1)
+ mtlr r0
+ blr
+
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+ rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
+ addis r3,r3,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,1 /* next VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+ SYNC
+ blr
+
+/*
+ * Flush instruction cache.
+ * This is a no-op on the 601.
+ */
+_GLOBAL(flush_instruction_cache)
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmpi 0,r3,1
+ beqlr /* for 601, do nothing */
+ /* 603/604 processor - use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
+ mtspr HID0,r3
+ SYNC
+ blr
+
+/*
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
+ * This is a no-op on the 601.
+ *
+ * store_cache_range(unsigned long start, unsigned long stop)
+ */
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+_GLOBAL(store_cache_range)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync
+ isync
+ blr
+
+/*
+ * Flush a particular page from the DATA cache
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ * This is a no-op on the 601 which has a unified cache.
+ *
+ * void flush_page_to_ram(void *page)
+ */
+_GLOBAL(flush_page_to_ram)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r4,0x0FFF
+ andc r3,r3,r4 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Flush entries from the hash table with VSIDs in the range
+ * given.
+ */
+_GLOBAL(flush_hash_segments)
+ rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
+ oris r3,r3,0x8000 /* set V bit */
+ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
+ oris r4,r4,0x8000
+ ori r4,r4,0x7f
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
+ lis r6,Hash_size@ha
+ lwz r6,Hash_size@l(r6) /* size in bytes */
+ srwi r6,r6,3 /* # PTEs */
+ mtctr r6
+ addi r5,r5,-8
+ li r0,0
+1: lwzu r6,8(r5) /* get next tag word */
+ cmplw 0,r6,r3
+ cmplw 1,r6,r4
+ cror 0,0,5 /* set cr0.lt if out of range */
+ blt 2f /* branch if out of range */
+ stw r0,0(r5) /* invalidate entry */
+2: bdnz 1b /* continue with loop */
+ sync
+ tlbia
+ isync
+ blr
+
+/*
+ * Flush the entry for a particular page from the hash table.
+ *
+ * flush_hash_page(unsigned context, unsigned long va)
+ */
+_GLOBAL(flush_hash_page)
+ rlwinm r3,r3,11,1,20 /* put context into vsid */
+ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
+ oris r3,r3,0x8000 /* set V (valid) bit */
+ rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */
+ rlwinm r7,r4,32-6,10,25 /* get page index << 6 */
+ rlwinm r5,r3,32-1,7,25 /* vsid << 6 */
+ xor r7,r7,r5 /* primary hash << 6 */
+ lis r5,Hash_mask@ha
+ lwz r5,Hash_mask@l(r5) /* hash mask */
+ slwi r5,r5,6 /* << 6 */
+ and r7,r7,r5
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
+ add r6,r6,r7 /* address of primary PTEG */
+ li r8,8
+ mtctr r8
+ addi r7,r6,-8
+1: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */
+ beq 3f /* if we found it */
+ ori r3,r3,0x40 /* set H (alt. hash) bit */
+ xor r6,r6,r5 /* address of secondary PTEG */
+ mtctr r8
+ addi r7,r6,-8
+2: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */
+ bne 4f /* if we didn't find it */
+3: li r0,0
+ stw r0,0(r7) /* invalidate entry */
+4: sync
+ tlbie r4 /* in hw tlb too */
+ isync
+ blr
/*
* This routine is just here to keep GCC happy - sigh...
@@ -1415,18 +1521,212 @@ _GLOBAL(_switch)
_GLOBAL(__main)
blr
+#ifdef CONFIG_PMAC
+/*
+ * These exception handlers are used when we have called a prom
+ * routine after we have taken over the exception vectors and MMU.
+ */
+ .globl prom_exc_table
+prom_exc_table:
+ .long TOPHYS(prom_exception) /* 0 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+
+/*
+ * When we come in to these prom exceptions, r1 and lr have been
+ * saved in sprg1 and sprg2, and lr points to a word containing
+ * the vector offset.
+ */
+prom_exception:
+ mr r1,r21 /* save r21 */
+ lis r21,prom_sp@ha /* get a stack to use */
+ addis r21,r21,-KERNELBASE@h
+ lwz r21,prom_sp@l(r21)
+ addis r21,r21,-KERNELBASE@h /* convert to physical addr */
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r0,GPR0(r21)
+ stw r2,GPR2(r21)
+ stw r3,GPR3(r21)
+ stw r4,GPR4(r21)
+ stw r5,GPR5(r21)
+ stw r6,GPR6(r21)
+ stw r20,GPR20(r21)
+ stw r1,GPR21(r21)
+ stw r22,GPR22(r21)
+ stw r23,GPR23(r21)
+ mfspr r1,SPRG1
+ stw r1,GPR1(r21)
+ mfcr r3
+ mfspr r4,SPRG2
+ stw r3,_CCR(r21)
+ stw r4,_LINK(r21)
+ mfctr r3
+ mfspr r4,XER
+ stw r3,_CTR(r21)
+ stw r4,_XER(r21)
+ mfspr r22,SRR0
+ mfspr r23,SRR1
+
+ /* at this point we have set things up pretty much exactly
+ how EXCEPTION_PROLOG does */
+ mflr r3
+ lwz r3,0(r3) /* get exception vector */
+ stw r3,TRAP(r21)
+ cmpi 0,r3,0x300 /* was it a dsi? */
+ bne 1f
+
+ mfspr r20,DSISR /* here on data access exc. */
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 3f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ b 2f
+
+1: cmpi 0,r3,0x400 /* was it an isi? */
+ bne 3f
+ andis. r0,r23,0x4000 /* if so, check if no pte found */
+ beq 3f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+2: lis r5,prom_tss@ha /* phys addr of TSS */
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ bl hash_page
+
+3: addis r1,r21,KERNELBASE@h /* restore kernel stack ptr */
+ addi r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r3,0(r21) /* set stack chain pointer */
+ lis r5,prom_tss@ha
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ mtspr SPRG3,r5 /* reset phys TSS pointer */
+ lwz r4,TRAP(r21) /* the real exception vector */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ bl transfer_to_handler
+ .long PromException
+ .long prom_int_return
+
+ .comm prom_sp,4
+ .comm prom_tss,4
+
+ .globl prom_int_return
+prom_int_return:
+ lis r3,prom_exc_table@ha /* restore sprg3 for prom vectors */
+ addi r3,r3,prom_exc_table@l
+ addis r3,r3,-KERNELBASE@h
+ mtspr SPRG3,r3
+ b int_return
+
+/*
+ * When entering the prom, we have to change to using a different
+ * set of exception vectors.
+ */
+ .globl enter_prom
+enter_prom:
+ stwu r1,-32(r1)
+ mflr r0
+ stw r0,36(r1)
+ stw r29,20(r1)
+ stw r30,24(r1)
+ stw r31,28(r1)
+ lis r8,prom_entry@ha
+ lwz r8,prom_entry@l(r8)
+ mfmsr r31
+ andi. r0,r31,MSR_IP /* using our own vectors yet? */
+ beq 1f /* if so, have to switch */
+ mtlr r8
+ blrl /* if not, can just charge ahead */
+ b 2f
+1: lis r9,prom_sp@ha /* save sp for exception handler */
+ stw r1,prom_sp@l(r9)
+ mfspr r29,SPRG3 /* save physical tss pointer */
+ lis r9,prom_tss@ha
+ stw r29,prom_tss@l(r9)
+ li r9,0
+ ori r9,r9,MSR_EE
+ andc r30,r31,r9
+ lis r9,prom_exc_table@ha /* set pointer to exception table */
+ addi r9,r9,prom_exc_table@l
+ addis r9,r9,-KERNELBASE@h
+ ori r0,r31,MSR_IP
+ sync
+ mtmsr r30 /* disable interrupts */
+ mtspr SPRG3,r9 /* while we update MSR_IP and sprg3 */
+ sync
+ mtmsr r0 /* start using exc. vectors in prom */
+ mtlr r8
+ blrl /* call prom */
+ sync
+ mtmsr r30 /* disable interrupts again */
+ mtspr SPRG3,r29 /* while we restore MSR_IP and sprg3 */
+ sync
+ mtmsr r31 /* reenable interrupts */
+2: lwz r0,36(r1)
+ mtlr r0
+ lwz r29,20(r1)
+ lwz r30,24(r1)
+ lwz r31,28(r1)
+ lwz r1,0(r1)
+ 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:
.space 2*4096
-
-#if 0
-_GLOBAL(sys_stack)
-sys_stack:
- .space 4096
-#endif
-CPU1_stack:
-
.globl empty_zero_page
empty_zero_page:
.space 4096
@@ -1435,6 +1735,7 @@ empty_zero_page:
swapper_pg_dir:
.space 4096
+#ifdef CONFIG_PREP
/*
* 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.
@@ -1442,54 +1743,5 @@ swapper_pg_dir:
.globl cmd_line
cmd_line:
.space 512
-
-#ifdef STATS
-/*
- * Miscellaneous statistics - gathered just for performance info
- */
- .globl _INTR_stats
-_INTR_stats:
- .globl __Instruction_TLB_Misses
-__Instruction_TLB_Misses:
- .long 0,0 /* Instruction TLB misses */
- .globl __DataLoad_TLB_Misses
-__DataLoad_TLB_Misses:
- .long 0,0 /* Data [load] TLB misses */
- .globl __DataStore_TLB_Misses
-__DataStore_TLB_Misses:
- .long 0,0 /* Data [store] TLB misses */
- .globl __Instruction_Page_Faults
-__Instruction_Page_Faults:
- .long 0,0 /* Instruction page faults */
- .globl __Data_Page_Faults
-__Data_Page_Faults:
- .long 0,0 /* Data page faults */
- .globl __Cache_Flushes
-__Cache_Flushes:
- .long 0,0 /* Explicit cache flushes */
- .globl __Context_Switches
-__Context_Switches:
- .long 0,0 /* Context switches */
- .globl __Hardware_Interrupts
-__Hardware_Interrupts:
- .long 0,0 /* I/O interrupts (disk, timer, etc) */
- .globl __TLBIAs
- .globl __TLBIAs
-__TLBIAs:
- .long 0,0 /* TLB cache forceably flushed */
- .globl __TLBIEs
-__TLBIEs:
- .long 0,0 /* Specific TLB entry flushed */
-#endif
-
- .globl _TotalMemory
-_TotalMemory:
- .long 0,0
-
-/*
- * This location is used to break any outstanding "lock"s when
- * changing contexts.
- */
-_break_lwarx: .long 0
-
+#endif /* CONFIG_PREP */
diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
index 41d453186..171bfaa5c 100644
--- a/arch/ppc/kernel/irq.c
+++ b/arch/ppc/kernel/irq.c
@@ -1,9 +1,13 @@
/*
- * linux/arch/ppc/kernel/irq.c
+ * arch/ppc/kernel/irq.c
*
- * Copyright (C) 1992 Linus Torvalds
- * Adapted from arch/i386 by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Power Macintosh version
+ * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * Derived from arch/i386/kernel/irq.c
+ * Copyright (C) 1992 Linus Torvalds
+ * Adapted from arch/i386 by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*
* This file contains the code used by various IRQ handling routines:
* asking for different IRQ's should be done through these routines
@@ -11,7 +15,7 @@
* shouldn't result in any weird surprises, and installing new handlers
* should be easier.
*/
-
+
/*
* IRQ's are in fact implemented a bit like signal handlers for the kernel.
* Naturally it's not a 1:1 relation, but there are similarities.
@@ -25,323 +29,300 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
+#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
-inline int get_irq_list(char *);
-void check_irq(void);
-void BeBox_CPU1(void);
-void BeBox_state(void);
-int BeBox_irq(void);
-void show_BeBox_state(void);
-void BeBox_enable_irq(int );
-void BeBox_disable_irq(int );
-void BeBox_init_IRQ(void);
-void _do_bottom_half(void);
-static _NOP(void);
-static _delay(void);
-void hard_disk_LED(int state);
+#define IRQ_FLAG ((unsigned *)0xf3000020)
+#define IRQ_ENABLE ((unsigned *)0xf3000024)
+#define IRQ_ACK ((unsigned *)0xf3000028)
+#define IRQ_LEVEL ((unsigned *)0xf300002c)
+
+#define KEYBOARD_IRQ 20 /* irq number for command-power interrupt */
+#undef SHOW_IRQ 1
-#define SHOW_IRQ
-#undef SHOW_IRQ
+unsigned lost_interrupts = 0;
+
+unsigned int local_irq_count[NR_CPUS];
+static struct irqaction irq_action[32];
/*
- * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
- * and 16..31 for other BeBox motherboard type interrupts.
+ * This contains the irq mask for both irq controllers
*/
-
-unsigned long isBeBox[];
-unsigned char *BeBox_IO_page;
+static unsigned int cached_irq_mask = 0xffff;
+
+#define cached_21 (((char *)(&cached_irq_mask))[0])
+#define cached_A1 (((char *)(&cached_irq_mask))[1])
+
-static unsigned char cache_21 = 0xff;
-static unsigned char cache_A1 = 0xff;
+int __ppc_bh_counter;
-void disable_irq(unsigned int irq_nr)
+void *null_handler(int,void *,struct pt_regs *);
+
+/*
+ * disable and enable intrs in software. This is used
+ * from the non-realtime parts of Linux to disable interrupts.
+ * The realtime part disables/enables intrs in the hardware.
+ * -- Cort
+ */
+unsigned long soft_intr_enable = 1;
+void _soft_cli(void)
{
- unsigned char mask;
- int s = _disable_interrupts();
+ soft_intr_enable = 0;
+}
- if (isBeBox[0] && (irq_nr >= 16))
- {
- BeBox_disable_irq(irq_nr);
- } else
+void _soft_sti(void)
+{
+ soft_intr_enable = 1;
+ if ( lost_interrupts )
{
- mask = 1 << (irq_nr & 7);
- if (irq_nr < 8)
- {
- cache_21 |= mask;
- outb(cache_21,0x21);
- } else
- {
- cache_A1 |= mask;
- outb(cache_A1,0xA1);
- }
+ printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
+ fake_interrupt();
}
- _enable_interrupts(s);
}
-void enable_irq(unsigned int irq_nr)
+void *
+null_handler(int a, void *b, struct pt_regs *regs)
+{
+ /*printk("irq.c: null_handler() called. Should not have happened.\n");*/
+}
+
+void
+disable_irq(unsigned int irq_nr)
{
- unsigned char mask;
int s = _disable_interrupts();
+ unsigned char mask;
- if (isBeBox[0] && (irq_nr >= 16))
+#ifdef CONFIG_PMAC
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+#else /* CONFIG_PMAC */
+ mask = 1 << (irq_nr & 7);
+ if (irq_nr < 8)
{
- BeBox_enable_irq(irq_nr);
- _enable_interrupts(s);
- return;
+ cached_21 |= mask;
+ outb(cached_21,0x21);
} else
{
- mask = ~(1 << (irq_nr & 7));
- if (irq_nr < 8) {
- cache_21 &= mask;
- outb(cache_21,0x21);
- } else
- {
- cache_A1 &= mask;
- outb(cache_A1,0xA1);
- }
- }
+ cached_A1 |= mask;
+ outb(cached_A1,0xA1);
+ }
+#endif /* CONFIG_PMAC */
_enable_interrupts(s);
}
-/*
- * Irq handlers.
- */
-struct irq_action {
- void (*handler)(int, void *dev, struct pt_regs *);
- unsigned long flags;
- unsigned long mask;
- const char *name;
- int notified;
- void *dev_id;
-};
-
-static struct irq_action irq_action[32] = {
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL },
- { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
-};
-
-
-inline int get_irq_list(char *buf)
+void
+enable_irq(unsigned int irq_nr)
{
- int i, len = 0;
- struct irq_action * action = irq_action;
-
- for (i = 0; i < 32; i++, action++) {
- if (!action->handler)
- continue;
- len += sprintf(buf+len, "%2d: %8d %c %s\n",
- i, kstat.interrupts[i],
- (action->flags & SA_INTERRUPT) ? '+' : ' ',
- action->name);
- }
- return len;
-}
+ int s = _disable_interrupts();
+#ifdef CONFIG_PMAC
+ unsigned bit = 1U << irq_nr;
+
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+ out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
+
+ /*
+ * Unfortunately, setting the bit in the enable register
+ * when the device interrupt is already on *doesn't* set
+ * the bit in the flag register or request another interrupt.
+ */
+ if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
+ lost_interrupts |= bit;
+#else /* CONFIG_PMAC */
+ if (irq_nr < 8) {
+ cached_21 &= ~(1 << (irq_nr & 7));
+ outb(cached_21,0x21);
+ } else
+ {
+ cached_A1 &= ~(1 << (irq_nr-8 & 7));
+ outb(cached_A1,0xA1);
+ }
+#endif /* CONFIG_PMAC */
-inline void
-process_IRQ(int irq, int _irq, struct pt_regs *regs)
-{
- struct irq_action *action;
- atomic_inc(&intr_count);
- if (irq < 16)
- {
- /* Mask interrupt */
- if (irq > 7)
- {
- cache_A1 |= (1<<(irq-8));
- outb(cache_A1, 0xA1);
- } else
- {
- cache_21 |= (1<<irq);
- outb(cache_21, 0x21);
- }
- }
- action = irq + irq_action;
- kstat.interrupts[irq]++;
- /* TEMP */
- /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
- if (irq == 0)
- {
- static int count;
- if (++count == 500)
- {
- if (inb(0x64) & 0x01)
- {
- struct irq_action *action;
- action = irq_action + 1; /* Keyboard */
- printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
- inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
- action->handler(1, action->dev_id, regs);
- }
- count = 0;
- }
- }
- if (action->handler)
- {
- action->handler(irq, action->dev_id, regs);
- } else
- {
- printk("Bogus interrupt %d/%x, pc %x regs %x\n",
- irq, _irq,regs->nip,regs);
-#if 0
- printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
- show_BeBox_state();
- cnpause();
-#endif
- }
- if (_disable_interrupts() && !action->notified)
- {
- action->notified = 1;
- printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
- action->name, irq);
- }
- if (irq < 16)
- {
- /* Issue EOI to interrupt controller */
- if (irq > 7)
- {
- outb(0xE0|(irq-8), 0xA0);
- outb(0xE2, 0x20);
- } else
- {
- outb(0xE0|irq, 0x20);
- }
- if (!(action->flags & SA_ONESHOT))
- {
- /* Re-enable interrupt */
- if (irq > 7)
- {
- cache_A1 &= ~(1<<(irq-8));
- outb(cache_A1, 0xA1);
- } else
- {
- cache_21 &= ~(1<<irq);
- outb(cache_21, 0x21);
- }
- }
- } else
- {
- BeBox_enable_irq(irq);
- }
- atomic_dec(&intr_count);
+ _enable_interrupts(s);
}
-asmlinkage inline void handle_IRQ(struct pt_regs *regs)
+
+int get_irq_list(char *buf)
{
- int irq, _irq, s;
- struct irq_action *action;
- static int _ints;
-
- if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
- {
- /* Figure out IRQ#, etc. */
- outb(0x0C, 0x20); /* Poll interrupt controller */
- irq = _irq = inb(0x20);
- irq &= 0x07; /* Caution! */
- if (irq == 2)
- { /* Cascaded interrupt -> IRQ8..IRQ15 */
- outb(0x0C, 0xA0);
- irq = (_irq = inb(0xA0)) & 0x07;
- irq += 8;
- }
- }
- process_IRQ(irq, _irq, regs);
-
- /* Sometimes, the cascaded IRQ controller get's "stuck" */
- if ((irq == 0) && (_ints++ == 100))
- {
- _ints = 0;
- outb(0x0A, 0xA0); _irq = inb(0xA0);
- if (_irq & ~cache_A1)
- { /* Figure out which IRQs are present */
- _irq &= ~cache_A1;
- for (irq = 0; irq < 7; irq++)
- {
- if (_irq & (1<<irq))
- {
-#if 0
- printk("Dropped IRQ #%d\n", irq+8);
-#endif
- process_IRQ(irq+8, _irq, regs);
+ int i, len = 0;
+ struct irqaction * action;
+
+ for (i = 0 ; i < NR_IRQS ; i++) {
+ action = irq_action + i;
+ if (!action || !action->handler)
+ continue;
+ len += sprintf(buf+len, "%2d: %10u %s",
+ i, kstat.interrupts[i], action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ", %s", action->name);
+ }
+ len += sprintf(buf+len, "\n");
}
- }
- }
- }
-}
-
/*
- * Display current IRQ state
+ * Linus - should you add NMI counts here ?????
*/
-
-void
-show_irq_state(void)
-{
- unsigned char state_21, state_A1;
- outb(0x0A, 0x20); state_21 = inb(0x20);
- outb(0x0A, 0xA0); state_A1 = inb(0xA0);
- printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
+#ifdef __SMP_PROF__
+ len+=sprintf(buf+len, "IPI: %8lu received\n",
+ ipi_count);
+#endif
+ return len;
}
-/*
- * Initialize interrupt controllers to a well-known state.
- */
-
-static void
-reset_int_controllers(void)
+asmlinkage void handle_IRQ(struct pt_regs *regs)
{
- /* Initialize interrupt controllers */
- outb(0x11, 0x20); /* Start init sequence */
- outb(0x40, 0x21); /* Vector base */
- outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
- outb(0x01, 0x21); /* Select 8086 mode */
- outb(0xFF, 0x21); /* Mask all */
- outb(0x11, 0xA0); /* Start init sequence */
- outb(0x48, 0xA1); /* Vector base */
- outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
- outb(0x01, 0xA1); /* Select 8086 mode */
- outb(0xFF, 0xA1); /* Mask all */
-#if 0
- outb(0x00, 0x4D0); /* All edge triggered */
- outb(0xCF, 0x4D1); /* Trigger mode */
+ int irq;
+ unsigned bits;
+ struct irqaction *action;
+ int cpu = smp_processor_id();
+
+ hardirq_enter(cpu);
+
+#ifdef CONFIG_PMAC
+ bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+ lost_interrupts = 0;
+
+ for (irq = NR_IRQS; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
+#else /* CONFIG_PMAC */
+#if 1
+ if ( lost_interrupts )
+ {
+ irq = ffz(~lost_interrupts);
+ lost_interrupts &= ~irq;
+ goto retry;
+ }
+ outb(0x0C, 0x20);
+ irq = inb(0x20) & 7;
+ if (irq == 2)
+ {
+retry_cascade:
+ outb(0x0C, 0xA0);
+ irq = inb(0xA0);
+ /* if no intr left */
+ if ( !(irq & 128 ) )
+ goto out;
+ irq = (irq&7) + 8;
+ }
+retry:
+#else
+ /* get the irr from the intr controller */
+ outb(0x0A, 0x20);
+ bits = inb(0x20);
+ /* handle cascade */
+ if ( bits )
+ {
+ bits &= 4;
+ outb(0x0A, 0xA0);
+ bits = inb(0xA0)<<8;
+ }
+ /* get lost interrupts */
+ bits |= lost_interrupts;
+ /* save intrs that are masked out */
+ lost_interrupts = bits & cached_irq_mask;
+ /* get rid of intrs being masked */
+ bits &= ~cached_irq_mask;
+ /* non-specifc eoi */
+ outb(0x20,0x20);
+ if ( bits & 0xff00 )
+ outb(0x20,0xA0);
+
+ printk("bits %04X lost %04X mask %04x\n",
+ bits, lost_interrupts,cached_irq_mask);
+
+ for (irq = NR_IRQS; irq >= 0; --irq)
+ if (bits & (1U << irq))
+ break;
#endif
- outb(cache_A1, 0xA1);
- outb(cache_21, 0x21);
- enable_irq(2); /* Enable cascade interrupt */
+#endif /* CONFIG_PMAC */
+
+ if (irq < 0) {
+ printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+ goto out;
+ }
+
+#ifdef CONFIG_PMAC
+ out_le32(IRQ_ACK, 1U << irq);
+#else /* CONFIG_PMAC */
+ /* mask out the irq while handling it */
+ disable_irq(irq);
+ /*
+ * send eoi to interrupt controller right away or lower
+ * priority intrs would be ignored even if with intrs enabled
+ */
+ if (irq > 7)
+ {
+ outb(0xE0|(irq-8), 0xA0);
+ outb(0xE2, 0x20);
+ } else
+ {
+ outb(0xE0|irq, 0x20);
+ }
+#endif /* !CONFIG_PMAC */
+
+ /*
+ * now that we've acked the irq, if intrs are disabled in software
+ * we're in the real-time system and non-rt linux has disabled them
+ * so we just queue it up and return -- Cort
+ */
+ if ( ! soft_intr_enable )
+ {
+ lost_interrupts |= 1UL << irq;
+ /* can't printk - kernel expects intrs off! */
+ /*printk("irq %d while intrs soft disabled\n", irq);*/
+ goto out;
+ }
+
+ action = irq + irq_action;
+ kstat.interrupts[irq]++;
+ if (action->handler) {
+ action->handler(irq, action->dev_id, regs);
+ _disable_interrupts(); /* in case the handler turned them on */
+ } else {
+ disable_irq( irq );
+ }
+#ifdef CONFIG_PREP
+ /* re-enable if the interrupt was good and isn't one-shot */
+ if ( action->handler && !(action->flags & SA_ONESHOT) )
+ enable_irq(irq);
+ /* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
+ if ( irq > 7 )
+ goto retry_cascade;
+#endif
+
+ hardirq_exit(cpu);
+ /*
+ * This should be conditional: we should really get
+ * a return code from the irq handler to tell us
+ * whether the handler wants us to do software bottom
+ * half handling or not..
+ */
+ if (1)
+ if (bh_active & bh_mask)
+ do_bottom_half();
+ return;
+out:
+ hardirq_exit(cpu);
+
}
int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char * devname, void *dev_id)
+ unsigned long irqflags, const char * devname, void *dev_id)
{
- struct irq_action * action;
+ struct irqaction * action;
unsigned long flags;
-
-#ifdef SHOW_IRQ
-if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
-#endif
- if (irq > 15)
- {
- if (!isBeBox[0] || (irq > 31))
- return -EINVAL;
- }
+
+#ifdef SHOW_IRQ
+ printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
+ irq,handler,devname,dev_id);
+#endif /* SHOW_IRQ */
+
+ if (irq > NR_IRQS)
+ return -EINVAL;
action = irq + irq_action;
if (action->handler)
return -EBUSY;
@@ -361,10 +342,14 @@ if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
void free_irq(unsigned int irq, void *dev_id)
{
- struct irq_action * action = irq + irq_action;
+ struct irqaction * action = irq + irq_action;
unsigned long flags;
- if (irq > 31) {
+#ifdef SHOW_IRQ
+ printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
+#endif /* SHOW_IRQ */
+
+ if (irq > NR_IRQS) {
printk("Trying to free IRQ%d\n",irq);
return;
}
@@ -383,15 +368,6 @@ void free_irq(unsigned int irq, void *dev_id)
restore_flags(flags);
}
-#define SA_PROBE SA_ONESHOT
-
-static void no_action(int irq, void *dev, struct pt_regs * regs)
-{
-#ifdef DEBUG
- printk("Probe got IRQ: %d\n", irq);
-#endif
-}
-
unsigned long probe_irq_on (void)
{
unsigned int i, irqs = 0, irqmask;
@@ -399,7 +375,7 @@ unsigned long probe_irq_on (void)
/* first, snaffle up any unassigned irqs */
for (i = 15; i > 0; i--) {
- if (!request_irq(i, no_action, SA_PROBE, "probe", NULL)) {
+ if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
enable_irq(i);
irqs |= (1 << i);
}
@@ -409,7 +385,7 @@ unsigned long probe_irq_on (void)
for (delay = jiffies + 2; delay > jiffies; ); /* min 10ms delay */
/* now filter out any obviously spurious interrupts */
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
for (i = 15; i > 0; i--) {
if (irqs & (1 << i) & irqmask) {
irqs ^= (1 << i);
@@ -426,13 +402,13 @@ int probe_irq_off (unsigned long irqs)
{
unsigned int i, irqmask;
- irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21;
+ irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
for (i = 15; i > 0; i--) {
if (irqs & (1 << i)) {
free_irq(i, NULL);
}
}
-#ifdef DEBUG
+#ifdef SHOW_IRQ
printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
#endif
irqs &= irqmask;
@@ -443,209 +419,65 @@ int probe_irq_off (unsigned long irqs)
i = -i;
return i;
}
-
-void init_IRQ(void)
-{
- int i;
-
- if ((_get_PVR()>>16) == 1) /* PPC 601 */
- { /* Nobis? */
- reset_int_controllers();
- }
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
- /* set the clock to 100 Hz */
- outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
- outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
- if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
- printk("Unable to get IRQ2 for cascade\n");
- request_region(0x20,0x20,"pic1");
- request_region(0xa0,0x20,"pic2");
-
- /* Make sure IRQ2 (cascade) interrupt is "level" based */
- outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
-
- /* Set up PCI interrupts */
- route_PCI_interrupts();
-
- if (isBeBox[0])
- {
- BeBox_init_IRQ();
- }
-}
-/*
- * Wrapper for "bottom 1/2" of interrupt processing. This routine
- * is called whenever an interrupt needs non-interrupt-time service.
- */
-
-void _do_bottom_half(void)
-{
- _enable_interrupts(1);
- do_bottom_half();
- _disable_interrupts();
-}
-
-void hard_disk_LED(int state)
-{
- if (_Processor == _PROC_IBM) {
- outb(state, IBM_HDD_LED);
- }
-}
-
-
-/*
- * Support for interrupts on the BeBox
- */
-
-#define CPU0_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x0F0)
-#define CPU1_INT_MASK (volatile unsigned long *)(BeBox_IO_page+0x1F0)
-#define INT_SOURCE (volatile unsigned long *)(BeBox_IO_page+0x2F0)
-#define CPU_RESET (volatile unsigned long *)(BeBox_IO_page+0x4F0)
-
-#define _CPU0_INT_MASK (volatile unsigned long *)(0xA0000000+0x0F0)
-#define _CPU1_INT_MASK (volatile unsigned long *)(0xA0000000+0x1F0)
-#define _INT_SOURCE (volatile unsigned long *)(0xA0000000+0x2F0)
-#define _CPU_RESET (volatile unsigned long *)(0xA0000000+0x4F0)
-
-#define CPU_HRESET 0x20000000
-#define CPU_SRESET 0x40000000
-
-#define SCSI_IRQ 16
-
-#define INT_SCSI (1<<21)
-#define INT_8259 (1<<5)
-
-/*
- * Map of pseudo IRQs to actual bits
- * Note: We give out IRQ #16..31 for all interrupt sources which are
- * not found in the 8259 PIC.
- */
-
-unsigned long BeBox_IRQ_map[] =
- {
- INT_SCSI, /* 16 - SCSI */
- 0x00000000, /* 17 - Unused */
- 0x00000000, /* 18 - Unused */
- 0x00000000, /* 19 - Unused */
- 0x00000000, /* 20 - Unused */
- 0x00000000, /* 21 - Unused */
- 0x00000000, /* 22 - Unused */
- 0x00000000, /* 23 - Unused */
- 0x00000000, /* 24 - Unused */
- 0x00000000, /* 25 - Unused */
- 0x00000000, /* 26 - Unused */
- 0x00000000, /* 27 - Unused */
- 0x00000000, /* 28 - Unused */
- 0x00000000, /* 29 - Unused */
- 0x00000000, /* 30 - Unused */
- 0x00000000, /* 31 - Unused */
- };
-
-volatile int CPU1_alive;
-volatile int CPU1_trace;
-
-static
-_NOP(void)
-{
-}
-
-static
-_delay(void)
+void init_IRQ(void)
{
- int i;
- for (i = 0; i < 100; i++) _NOP();
-}
+#ifdef CONFIG_PMAC
+ extern void xmon_irq(int, void *, struct pt_regs *);
-void
-BeBox_init_IRQ(void)
-{
- int tmr;
- volatile extern long BeBox_CPU1_vector;
- *CPU0_INT_MASK = 0x0FFFFFFC; /* Clear all bits? */
- *CPU0_INT_MASK = 0x80000003 | INT_8259;
- *CPU1_INT_MASK = 0x0FFFFFFC;
-printk("Start CPU #1 - CPU Status: %x\n", *CPU_RESET);
- BeBox_CPU1_vector = 0x0100; /* Reset */
- tmr = 0;
- while (CPU1_alive == 0)
- {
- if (++tmr == 1000)
- {
-printk("CPU #1 not there? - CPU Status: %x, Trace: %x\n", *CPU_RESET, CPU1_trace);
- break;
- }
- _delay();
- }
-printk("CPU #1 running!\n");
-}
+ *IRQ_ENABLE = 0;
+ request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#else /* CONFIG_PMAC */
+ /* Initialize interrupt controllers */
+ outb(0x11, 0x20); /* Start init sequence */
+ outb(0x40, 0x21); /* Vector base */
+#if 1
+ outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+#else
+ outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+
+ outb(0x01, 0x21); /* Select 8086 mode */
+ outb(0xFF, 0x21); /* Mask all */
-void
-BeBox_disable_irq(int irq)
-{
- /* Note: this clears the particular bit */
- *CPU0_INT_MASK = BeBox_IRQ_map[irq-16];
-}
+ outb(0x11, 0xA0); /* Start init sequence */
+ outb(0x48, 0xA1); /* Vector base */
+#if 1
+ outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+#else
+ outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+#endif
+ outb(0x01, 0xA1); /* Select 8086 mode */
+ outb(0xFF, 0xA1); /* Mask all */
-void
-BeBox_enable_irq(int irq)
-{
- int s = _disable_interrupts();
- /* Sets a single bit */
+ /*
+ * Program level mode for irq's that 'can' be level triggered.
+ * This does not effect irq's 0,1,2 and 8 since they must be
+ * edge triggered. This is not the PIC controller. The default
+ * here is for edge trigger mode. -- Cort
+ */
#if 0
-printk("BeBox IRQ Mask = %x", *CPU0_INT_MASK);
+ outb(0xf8, 0x4d0); /* level triggered */
+ outb(0xff, 0x4d1);
#endif
- *CPU0_INT_MASK = 0x80000000 | BeBox_IRQ_map[irq-16];
-#if 0
-printk("/%x\n", *CPU0_INT_MASK);
-#endif
- _enable_interrupts(s);
-}
-
-void
-show_BeBox_state(void)
-{
- unsigned long cpu0_int_mask;
- unsigned long int_state;
- cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
- int_state = cpu0_int_mask & *INT_SOURCE;
- printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-}
-
-int
-BeBox_irq(void)
-{
- int i;
- unsigned long cpu0_int_mask;
- unsigned long int_state;
- cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
- int_state = cpu0_int_mask & *INT_SOURCE;
- if (int_state)
- { /* Determine the pseudo-interrupt # */
#if 0
- printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-#endif
- for (i = 0; i < 16; i++)
- {
- if (BeBox_IRQ_map[i] & int_state)
- {
- return (i+16);
- }
- }
-printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
-printk("Can't find BeBox IRQ!\n");
- }
- return (0);
-}
-
-void BeBox_state(void)
-{
- printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
-}
-
-void BeBox_CPU1(void)
-{
- CPU1_alive++;
- while (1) ;
+ outb(0x00, 0x4D0); /* All edge triggered */
+ outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
+ outb(cached_A1, 0xA1);
+ outb(cached_21, 0x21);
+ if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
+ printk("Unable to get IRQ2 for cascade\n");
+ enable_irq(2); /* Enable cascade interrupt */
+
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+ /* set timer to periodic mode */
+ outb_p(0x34,TIMER_CONTROL); /* binary, mode 2, LSB/MSB, ch 0 */
+ /* set the clock to ~100 Hz */
+ outb_p(LATCH & 0xff , TIMER0_COUNT); /* LSB */
+ outb(LATCH >> 8 , TIMER0_COUNT); /* MSB */
+
+ route_pci_interrupts();
+#endif /* CONFIG_PMAC */
}
diff --git a/arch/ppc/kernel/ksyms.c b/arch/ppc/kernel/ksyms.c
index b59b8964e..b246fa6df 100644
--- a/arch/ppc/kernel/ksyms.c
+++ b/arch/ppc/kernel/ksyms.c
@@ -1,4 +1,40 @@
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void handle_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+unsigned long sys_call_table[];
+
+extern struct task_struct *current_set[1];
/* platform dependent support */
+EXPORT_SYMBOL(current_set);
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(handle_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(FloatingPointCheckException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(sys_call_table);
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index c2a2989ec..430cd7a5d 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -1,234 +1,40 @@
/*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * 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.
+ *
*/
-#include "ppc_asm.tmpl"
+#include <linux/config.h>
#include <linux/sys.h>
+#include <asm/unistd.h>
#include <asm/errno.h>
-#include "ppc_defs.h"
#include <asm/processor.h>
-
-/* Keep track of low-level exceptions - rather crude, but informative */
-#define STATS
-
-/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
- */
-#define BUMP(ctr) \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- stw r3,0(r2)
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
-/*#ifdef CONFIG_603*/
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 601 or 603 */
#define tlbia \
- li r4,64; \
+ li r4,128; \
mtspr CTR,r4; \
li r4,0; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-/*#endif*/ /* CONFIG_603*/
_TEXT()
-#define CPU_CTL 0x80000092
-_GLOBAL(hard_reset_now)
- mfmsr r3 /* Disable interrupts */
- li r4,0
- ori r4,r4,MSR_EE
- andc r3,r3,r4
- ori r3,r3,MSR_IP /* Set FLASH/ROM interrupt handlers */
- sync
- mtmsr r3
- lis r3,CPU_CTL>>16
- ori r3,r3,(CPU_CTL&0xFFFF)
- lbz r4,0(r3) /* Turn on SRESET */
- li r5,1
- andc r4,r4,r5 /* Make sure we go from 0->1 */
- stb r4,0(r3)
- ori r4,r4,1
- stb r4,0(r3) /* This should do it! */
-99: nop
- b 99b
-
-#if 0
-/*
- unsigned short
- le16_to_cpu(unsigned short val)
-*/
-_GLOBAL(le16_to_cpu)
- lis r4,_le_scratch@h
- ori r4,r4,_le_scratch@l
- sth r3,0(r4)
- li r5,0
- lhbrx r3,r4,r5
- blr
-
-_GLOBAL(le32_to_cpu)
- lis r4,_le_scratch@h
- ori r4,r4,_le_scratch@l
- stw r3,0(r4)
- li r5,0
- lwbrx r3,r4,r5
- blr
-_GLOBAL(_le_scratch)
- .space 4
-#endif
-#if 1
-/*
-extern int __put_user_8(char, char *);
-extern int __put_user_16(short, short *);
-extern int __put_user_32(long, long *);
-*/
-_GLOBAL(__put_user_8)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- stb r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__put_user_16)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- sth r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-_GLOBAL(__put_user_32)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- stw r3,0(r4)
- li r3,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r3,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_8)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- lbz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_16)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
-
- lhz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-
-_GLOBAL(__get_user_32)
- /* setup exception stuff */
- lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- /* increment excount */
- lwz r6,TSS+TSS_EXCOUNT(r2)
- addi r6,r6,1
- stw r6,TSS+TSS_EXCOUNT(r2)
- /* set expc */
- lis r6,1f@h
- ori r6,r6,1f@l
- stw r6,TSS+TSS_EXPC(r2)
- lwz r3,0(r4)
- li r4,0 /* successful return */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-1: li r4,-EFAULT /* bad access */
- li r6,0
- stw r6,TSS+TSS_EXCOUNT(r2)
- blr
-#endif
/*
* Disable interrupts
* rc = _disable_interrupts()
*/
_GLOBAL(_disable_interrupts)
+_GLOBAL(__cli)
+_GLOBAL(_hard_cli)
mfmsr r0 /* Get current interrupt state */
rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
li r4,0 /* Need [unsigned] value of MSR_EE */
@@ -244,20 +50,18 @@ _GLOBAL(_disable_interrupts)
* turns on interrupts if state = 1.
*/
_GLOBAL(_enable_interrupts)
- mfmsr r0 /* Get current state */
- rlwimi r0,r3,16-1,32-16,32-16 /* Insert bit */
+ cmpi 0,r3,0 /* turning them on? */
+ beqlr /* nothing to do if state == 0 */
+_GLOBAL(__sti)
+_GLOBAL(_hard_sti)
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ mfmsr r3 /* Get current state */
+ ori r3,r3,MSR_EE /* Turn on 'EE' bit */
+ cmpi 0,r4,0 /* lost interrupts to process first? */
+ bne- do_lost_interrupts
sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
- blr
-
-/*
- * Get 'flags' (aka machine status register)
- * __save_flags(long *ptr)
- */
-_GLOBAL(__save_flags)
- mfmsr r0 /* Get current state */
- stw r0,0(r3)
- mr r3,r0
+ mtmsr r3 /* Update machine state */
blr
/*
@@ -265,34 +69,37 @@ _GLOBAL(__save_flags)
* __restore_flags(long val)
*/
_GLOBAL(__restore_flags)
- sync /* Some chip revs have problems here... */
+ andi. r0,r3,MSR_EE /* enabling interrupts? */
+ beq 2f
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ bne do_lost_interrupts
+2: sync /* Some chip revs have problems here... */
mtmsr r3
isync
blr
/*
- * Disable interrupts - like an 80x86
- * cli()
- */
-_GLOBAL(cli)
- mfmsr r0 /* Get current interrupt state */
- rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */
- li r4,0 /* Need [unsigned] value of MSR_EE */
- ori r4,r4,MSR_EE /* Set to turn off bit */
- andc r0,r0,r4 /* Clears bit in (r4) */
- sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
- blr /* Done */
-
-/*
- * Enable interrupts - like an 80x86
- * sti()
+ * We were about to enable interrupts but we have to simulate
+ * some interrupts that were lost by enable_irq first.
*/
-_GLOBAL(sti)
- mfmsr r0 /* Get current state */
- ori r0,r0,MSR_EE /* Turn on 'EE' bit */
- sync /* Some chip revs have problems here... */
- mtmsr r0 /* Update machine state */
+do_lost_interrupts:
+ stwu r1,-16(r1)
+ mflr r0
+ stw r0,20(r1)
+ stw r3,8(r1)
+1: bl fake_interrupt
+ lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ bne- 1b
+ lwz r3,8(r1)
+ sync
+ mtmsr r3
+ lwz r0,20(r1)
+ mtlr r0
+ addi r1,r1,16
blr
/*
@@ -300,7 +107,6 @@ _GLOBAL(sti)
*/
_GLOBAL(_tlbia)
tlbia
- BUMP(__TLBIAs)
blr
/*
@@ -308,17 +114,7 @@ _GLOBAL(_tlbia)
*/
_GLOBAL(_tlbie)
tlbie r3
- BUMP(__TLBIEs)
blr
-
-/*
- * Fetch the current SR register
- * get_SR(int index)
- */
-_GLOBAL(get_SR)
- mfsrin r3,r3
- blr
-
/*
* Atomic [test&set] exchange
*
@@ -340,7 +136,11 @@ _GLOBAL(xchg_u32)
* void atomic_sub(int c, int *v)
* void atomic_inc(int *v)
* void atomic_dec(int *v)
- * void atomic_dec_and_test(int *v)
+ * int atomic_dec_and_test(int *v)
+ * int atomic_inc_return(int *v)
+ * int atomic_dec_return(int *v)
+ * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
+ * void atomic_set_mask(atomic_t mask, atomic_t *addr);
*/
_GLOBAL(atomic_add)
10: lwarx r5,0,r4 /* Fetch old value & reserve */
@@ -360,69 +160,46 @@ _GLOBAL(atomic_inc)
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
blr
+_GLOBAL(atomic_inc_return)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ addi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ mr r3,r5 /* Return new value */
+ blr
_GLOBAL(atomic_dec)
10: lwarx r5,0,r3 /* Fetch old value & reserve */
subi r5,r5,1 /* Perform 'add' operation */
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
blr
+_GLOBAL(atomic_dec_return)
+10: lwarx r5,0,r3 /* Fetch old value & reserve */
+ subi r5,r5,1 /* Perform 'add' operation */
+ stwcx. r5,0,r3 /* Update with new value */
+ bne- 10b /* Retry if "reservation" (i.e. lock) lost */
+ mr r3,r5 /* Return new value */
+ blr
_GLOBAL(atomic_dec_and_test)
10: lwarx r5,0,r3 /* Fetch old value & reserve */
subi r5,r5,1 /* Perform 'add' operation */
stwcx. r5,0,r3 /* Update with new value */
bne- 10b /* Retry if "reservation" (i.e. lock) lost */
cmpi 0,r5,0 /* Return 'true' IFF 0 */
- bne 15f
li r3,1
+ beqlr
+ li r3,0
blr
-15: li r3,0
- blr
-
-
-/*
- * Delay for a specific # of "loops"
- * __delay(int loops)
- */
-_GLOBAL(__delay)
- mtctr r3
-00: addi r3,r3,0 /* NOP */
- bdnz 00b
- blr
-
-/*
- * Delay for a number of microseconds
- * udelay(int usecs)
- */
-_GLOBAL(udelay)
-00: li r0,86 /* Instructions / microsecond? */
- mtctr r0
-10: addi r0,r0,0 /* NOP */
- bdnz 10b
- subic. r3,r3,1
- bne 00b
- blr
-
-/*
- * Atomically increment [intr_count]
- */
-_GLOBAL(start_bh_atomic)
- lis r3,intr_count@h
- ori r3,r3,intr_count@l
-10: lwarx r4,0,r3
- addi r4,r4,1
- stwcx. r4,0,r3
+_GLOBAL(atomic_clear_mask)
+10: lwarx r5,0,r4
+ andc r5,r5,r3
+ stwcx. r5,0,r4
bne- 10b
blr
-
-/*
- * Atomically decrement [intr_count]
- */
-_GLOBAL(end_bh_atomic)
- lis r3,intr_count@h
- ori r3,r3,intr_count@l
-10: lwarx r4,0,r3
- subic r4,r4,1
- stwcx. r4,0,r3
+_GLOBAL(atomic_set_mask)
+10: lwarx r5,0,r4
+ or r5,r5,r3
+ stwcx. r5,0,r4
bne- 10b
blr
@@ -431,6 +208,8 @@ _GLOBAL(end_bh_atomic)
*
* insw(port, buf, len)
* outsw(port, buf, len)
+ * insl(port, buf, len)
+ * outsl(port, buf, len)
*/
_GLOBAL(_insw)
mtctr r5
@@ -448,135 +227,39 @@ _GLOBAL(_outsw)
bdnz 00b
blr
-#if 0
-/*
- *extern inline int find_first_zero_bit(void * vaddr, unsigned size)
- *{
- * unsigned long res;
- * unsigned long *p;
- * unsigned long *addr = vaddr;
- *
- * if (!size)
- * return 0;
- * __asm__ __volatile__ (" moveq #-1,d0\n\t"
- * "1:"
- * " cmpl %1@+,d0\n\t"
- * " bne 2f\n\t"
- * " subql #1,%0\n\t"
- * " bne 1b\n\t"
- * " bra 5f\n\t"
- * "2:"
- * " movel %1@-,d0\n\t"
- * " notl d0\n\t"
- * " bfffo d0{#0,#0},%0\n\t"
- * "5:"
- * : "=d" (res), "=a" (p)
- * : "0" ((size + 31) >> 5), "1" (addr)
- * : "d0");
- * return ((p - addr) << 5) + res;
- *}
- */
-_GLOBAL(find_first_zero_bit)
- li r5,0 /* bit # */
- subi r3,r3,4 /* Adjust pointer for auto-increment */
-00: lwzu r0,4(r3) /* Get next word */
- not. r7,r0 /* Complement to find ones */
- beq 10f /* Jump if all ones */
-02: andi. r7,r0,1 /* Check low-order bit */
- beq 20f /* All done when zero found */
- srawi r0,r0,1
- addi r5,r5,1
- b 02b
-10: addi r5,r5,32 /* Update bit # */
- subic. r4,r4,32 /* Any more? */
- bgt 00b
-20: mr r3,r5 /* Compute result */
+_GLOBAL(_insl)
+ mtctr r5
+ subi r4,r4,4
+00: lwbrx r5,0,r3
+ stwu r5,4(r4)
+ bdnz 00b
blr
-
-/*
- *static inline int find_next_zero_bit (void *vaddr, int size,
- * int offset)
- *{
- * unsigned long *addr = vaddr;
- * unsigned long *p = addr + (offset >> 5);
- * int set = 0, bit = offset & 31, res;
- *
- * if (bit) {
- * // Look for zero in first longword
- * __asm__("bfffo %1{#0,#0},%0"
- * : "=d" (set)
- * : "d" (~*p << bit));
- * if (set < (32 - bit))
- * return set + offset;
- * set = 32 - bit;
- * p++;
- * }
- * // No zero yet, search remaining full bytes for a zero
- * res = find_first_zero_bit (p, size - 32 * (p - addr));
- * return (offset + set + res);
- *}
- */
-_GLOBAL(find_next_zero_bit)
- addi r5,r5,1 /* bump offset to start */
- srawi r6,r5,5 /* word offset */
- add r6,r6,r6 /* byte offset */
- add r6,r6,r6 /* byte offset */
- add r3,r3,r6 /* compute byte position */
- sub r4,r4,r5 /* adjust size by starting index */
- andi. r0,r5,0x1F /* offset in current word? */
- beq 10f /* at start of word */
- lwz r0,0(r3) /* get word */
- sraw r0,r0,r5 /* shift right */
- not. r7,r0
- beq 07f /* jump if only ones remain */
-05: andi. r7,r0,1 /* found zero? */
- beq 90f /* yes - all done */
- srawi r0,r0,1
- addi r5,r5,1
- b 05b
-07: andi. r6,r5,0x1F
- subfic r0,r6,32
- add r5,r5,r0
- sub r4,r4,r0
- b 20f
-10: subi r3,r3,4 /* Adjust pointer for auto-increment */
-20: lwzu r0,4(r3) /* Get next word */
- not. r7,r0 /* Complement to find ones */
- beq 40f /* Jump if all ones */
-30: andi. r7,r0,1 /* Check low-order bit */
- beq 90f /* All done when zero found */
- srawi r0,r0,1
- addi r5,r5,1
- b 30b
-40: addi r5,r5,32 /* Update bit # */
- subic. r4,r4,32 /* Any more? */
- bgt 20b
-90: mr r3,r5 /* Compute result */
+
+_GLOBAL(_outsl)
+ mtctr r5
+ subi r4,r4,4
+00: lwzu r5,4(r4)
+ stwbrx r5,0,r3
+ bdnz 00b
+ blr
+
+#ifdef CONFIG_PMAC
+_GLOBAL(ide_insw)
+ mtctr r5
+ subi r4,r4,2
+00: lhzx r5,0,r3
+ sthu r5,2(r4)
+ bdnz 00b
blr
+
+_GLOBAL(ide_outsw)
+ mtctr r5
+ subi r4,r4,2
+00: lhzu r5,2(r4)
+ sthx r5,0,r3
+ bdnz 00b
+ blr
#endif
-
-/*
- *
- * ffz = Find First Zero in word. Undefined if no zero exists,
- * so code should check against ~0UL first..
- *
- *extern inline unsigned long ffz(unsigned long word)
- *{
- * __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
- * : "=d" (word)
- * : "d" (~(word)));
- * return word;
- *}
- */
-_GLOBAL(ffz)
- mr r4,r3
- li r3,0
-10: andi. r0,r4,1 /* Find the zero we know is there */
- srawi r4,r4,1
- beq 90f
- addi r3,r3,1
- b 10b
-90: blr
/*
* Extended precision shifts
@@ -605,43 +288,7 @@ _GLOBAL(__ashldi3)
slw r3,r3,r5 /* YYY--- */
or r3,r3,r7 /* YYYZZZ */
blr
-
-_GLOBAL(abort)
- .long 0
-
-/* in include/asm/string.h now -- Cort */
-#if 0
-_GLOBAL(bzero)
-#define bufp r3
-#define len r4
-#define pat r5
-/* R3 has buffer */
-/* R4 has length */
-/* R5 has pattern */
- cmpi 0,len,0 /* Exit if len <= 0 */
- ble 99f
- andi. r0,bufp,3 /* Must be on longword boundary */
- bne 10f /* Use byte loop if not aligned */
- andi. r0,len,3 /* Check for overrage */
- subi bufp,bufp,4 /* Adjust pointer */
- srawi len,len,2 /* Divide by 4 */
- blt 99f /* If negative - bug out! */
- mtspr CTR,len /* Set up counter */
- li pat,0
-00: stwu pat,4(bufp) /* Store value */
- bdnz 00b /* Loop [based on counter] */
- mr len,r0 /* Get remainder (bytes) */
-10: cmpi 0,len,0 /* Any bytes left */
- ble 99f /* No - all done */
- mtspr CTR,len /* Set up counter */
- subi bufp,bufp,1 /* Adjust pointer */
- li pat,0
-20: stbu pat,1(bufp) /* Store value */
- bdnz 20b /* Loop [based on counter] */
-99: blr
-#endif
-
_GLOBAL(abs)
cmpi 0,r3,0
bge 10f
@@ -651,39 +298,72 @@ _GLOBAL(abs)
_GLOBAL(_get_SP)
mr r3,r1 /* Close enough */
blr
-
-_GLOBAL(_get_SDR1)
- mfspr r3,SDR1
+
+_GLOBAL(_get_PVR)
+ mfspr r3,PVR
blr
-_GLOBAL(_get_SRx)
- mfsrin r3,r3
+_GLOBAL(cvt_fd)
+cvt_fd:
+ lfs 0,0(r3)
+ stfd 0,0(r4)
+ blr
+/*
+ * Fetch the current SR register
+ * get_SR(int index)
+ */
+_GLOBAL(get_SR)
+ mfsrin r4,r3
+ mr r3,r4
blr
-_GLOBAL(_get_PVR)
- mfspr r3,PVR
+
+_GLOBAL(cvt_df)
+cvt_df:
+ lfd 0,0(r3)
+ stfs 0,0(r4)
blr
/*
* Create a kernel thread
* __kernel_thread(flags, fn, arg)
*/
-#if 1
-#define SYS_CLONE 120
_GLOBAL(__kernel_thread)
-__kernel_thread:
- li r0,SYS_CLONE
+ li r0,__NR_clone
sc
cmpi 0,r3,0 /* parent or child? */
bnelr /* return if parent */
mtlr r4 /* fn addr in lr */
mr r3,r5 /* load arg and call fn */
- blr
- li 0, 1 /* exit after child exits */
- li 3, 0
+ blrl
+ li r0,__NR_exit /* exit after child exits */
+ li r3,0
sc
-#endif
-
+
+#define SYSCALL(name) \
+_GLOBAL(name) \
+ li r0,__NR_##name; \
+ sc; \
+ bnslr; \
+ lis r4,errno@ha; \
+ stw r3,errno@l(r4); \
+ li r3,-1; \
+ blr
+
+#define __NR__exit __NR_exit
+
+SYSCALL(idle)
+SYSCALL(setup)
+SYSCALL(sync)
+SYSCALL(setsid)
+SYSCALL(write)
+SYSCALL(dup)
+SYSCALL(execve)
+SYSCALL(open)
+SYSCALL(close)
+SYSCALL(waitpid)
+
+
/* Why isn't this a) automatic, b) written in 'C'? */
.data
.align 4
@@ -694,12 +374,12 @@ sys_call_table:
.long sys_fork
.long sys_read
.long sys_write
- .long sys_open /* 5 */
+ .long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
- .long sys_unlink /* 10 */
+ .long sys_unlink /* 10 */
.long sys_execve
.long sys_chdir
.long sys_time
@@ -709,7 +389,7 @@ sys_call_table:
.long sys_break
.long sys_stat
.long sys_lseek
- .long sys_getpid /* 20 */
+ .long sys_getpid /* 20 */
.long sys_mount
.long sys_umount
.long sys_setuid
@@ -734,12 +414,12 @@ sys_call_table:
.long sys_pipe
.long sys_times
.long sys_prof
- .long sys_brk /* 45 */
+ .long sys_brk /* 45 */
.long sys_setgid
.long sys_getgid
.long sys_signal
.long sys_geteuid
- .long sys_getegid /* 50 */
+ .long sys_getegid /* 50 */
.long sys_acct
.long sys_phys
.long sys_lock
@@ -754,57 +434,57 @@ sys_call_table:
.long sys_ustat
.long sys_dup2
.long sys_getppid
- .long sys_getpgrp /* 65 */
+ .long sys_getpgrp /* 65 */
.long sys_setsid
.long sys_sigaction
.long sys_sgetmask
.long sys_ssetmask
- .long sys_setreuid /* 70 */
+ .long sys_setreuid /* 70 */
.long sys_setregid
.long sys_sigsuspend
.long sys_sigpending
.long sys_sethostname
- .long sys_setrlimit /* 75 */
+ .long sys_setrlimit /* 75 */
.long sys_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
- .long sys_getgroups /* 80 */
+ .long sys_getgroups /* 80 */
.long sys_setgroups
- .long sys_select
+ .long ppc_select
.long sys_symlink
.long sys_lstat
- .long sys_readlink /* 85 */
+ .long sys_readlink /* 85 */
.long sys_uselib
.long sys_swapon
.long sys_reboot
.long old_readdir /* was sys_readdir */
- .long sys_mmap /* 90 */
+ .long sys_mmap /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
.long sys_fchmod
- .long sys_fchown /* 95 */
+ .long sys_fchown /* 95 */
.long sys_getpriority
.long sys_setpriority
.long sys_profil
.long sys_statfs
- .long sys_fstatfs /* 100 */
+ .long sys_fstatfs /* 100 */
.long sys_ioperm
.long sys_socketcall
.long sys_syslog
.long sys_setitimer
- .long sys_getitimer /* 105 */
+ .long sys_getitimer /* 105 */
.long sys_newstat
.long sys_newlstat
.long sys_newfstat
.long sys_uname
- .long sys_iopl /* 110 */
+ .long sys_iopl /* 110 */
.long sys_vhangup
.long sys_idle
.long sys_vm86
.long sys_wait4
- .long sys_swapoff /* 115 */
+ .long sys_swapoff /* 115 */
.long sys_sysinfo
.long sys_ipc
.long sys_fsync
@@ -814,7 +494,7 @@ sys_call_table:
.long sys_newuname
.long sys_modify_ldt
.long sys_adjtimex
- .long sys_mprotect /* 125 */
+ .long sys_mprotect /* 125 */
.long sys_sigprocmask
.long sys_create_module
.long sys_init_module
@@ -829,9 +509,9 @@ sys_call_table:
.long 0 /* for afs_syscall */
.long sys_setfsuid
.long sys_setfsgid
- .long sys_llseek /* 140 */
+ .long sys_llseek /* 140 */
.long sys_getdents
- .long sys_newselect
+ .long ppc_select
.long sys_flock
.long sys_msync
.long sys_readv /* 145 */
@@ -844,7 +524,7 @@ sys_call_table:
.long sys_mlockall
.long sys_munlockall
.long sys_sched_setparam
- .long sys_sched_getparam /* 155 */
+ .long sys_sched_getparam /* 155 */
.long sys_sched_setscheduler
.long sys_sched_getscheduler
.long sys_sched_yield
@@ -853,8 +533,11 @@ sys_call_table:
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_mremap
- .long SYMBOL_NAME(sys_setresuid)
- .long SYMBOL_NAME(sys_getresuid)
- .long SYMBOL_NAME(sys_nfsservctl)
- .space (NR_syscalls-166)*4
+ .long sys_setresuid
+ .long sys_getresuid /* 165 */
+ .long sys_query_module
+ .long sys_poll
+ .long sys_nfsservctl
+ .long sys_debug
+ .space (NR_syscalls-170)*4
diff --git a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
index 5e6789a1d..3f404a37a 100644
--- a/arch/ppc/kernel/mk_defs.c
+++ b/arch/ppc/kernel/mk_defs.c
@@ -1,11 +1,14 @@
/*
* This program is used to generate definitions needed by
* assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
*/
-#define MK_DEFS
-#include <stdio.h>
-#include <linux/config.h>
+#include <stddef.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/head.h>
@@ -16,156 +19,114 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/processor.h>
-extern int errno;
+#define DEFINE(sym, val) \
+ asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
-main(int argc, char *argv[])
+void
+main(void)
{
- FILE *out;
- struct task_struct task;
- struct thread_struct tss;
- int i;
- char s[256];
- struct pt_regs regs;
- if (!(out = fopen(argv[1], "w")))
- {
- fprintf(stderr, "Can't create output file: %s\n", strerror(errno));
- exit(1);
- }
- fprintf(out, "/*\n");
- fprintf(out, " * WARNING! This file is automatically generated - DO NOT EDIT!\n");
- fprintf(out, " */\n");
- put_line(out, "STATE", (int)&task.state-(int)&task);
- put_line(out, "COUNTER", (int)&task.counter-(int)&task);
- put_line(out, "BLOCKED", (int)&task.blocked-(int)&task);
- put_line(out, "SIGNAL", (int)&task.signal-(int)&task);
- put_line(out, "KERNEL_STACK_PAGE", (int)&task.kernel_stack_page-(int)&task);
- put_line(out, "TSS", (int)&task.tss-(int)&task);
- put_line(out, "KSP", (int)&tss.ksp-(int)&tss);
- put_line(out, "LAST_PC", (int)&tss.last_pc-(int)&tss);
- put_line(out, "USER_STACK", (int)&tss.user_stack-(int)&tss);
- put_line(out, "PT_REGS", (int)&tss.regs-(int)&tss);
- put_line(out, "PF_TRACESYS", PF_TRACESYS);
- put_line(out, "TASK_FLAGS", (int)&task.flags-(int)&task);
- put_line(out, "MMU_SEG0", (int)&tss.segs[0]-(int)&tss);
- put_line(out, "MMU_SEG1", (int)&tss.segs[1]-(int)&tss);
- put_line(out, "MMU_SEG2", (int)&tss.segs[2]-(int)&tss);
- put_line(out, "MMU_SEG3", (int)&tss.segs[3]-(int)&tss);
- put_line(out, "MMU_SEG4", (int)&tss.segs[4]-(int)&tss);
- put_line(out, "MMU_SEG5", (int)&tss.segs[5]-(int)&tss);
- put_line(out, "MMU_SEG6", (int)&tss.segs[6]-(int)&tss);
- put_line(out, "MMU_SEG7", (int)&tss.segs[7]-(int)&tss);
- put_line(out, "MMU_SEG8", (int)&tss.segs[8]-(int)&tss);
- put_line(out, "MMU_SEG9", (int)&tss.segs[9]-(int)&tss);
- put_line(out, "MMU_SEG10", (int)&tss.segs[10]-(int)&tss);
- put_line(out, "MMU_SEG11", (int)&tss.segs[11]-(int)&tss);
- put_line(out, "MMU_SEG12", (int)&tss.segs[12]-(int)&tss);
- put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
- put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
- put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
- put_line(out, "TSS_EXPC", (int)&tss.expc-(int)&tss);
- put_line(out, "TSS_EXCOUNT", (int)&tss.excount-(int)&tss);
- put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
- put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
- put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
- put_line(out, "TSS_FPR3", (int)&tss.fpr[3]-(int)&tss);
- put_line(out, "TSS_FPR4", (int)&tss.fpr[4]-(int)&tss);
- put_line(out, "TSS_FPR5", (int)&tss.fpr[5]-(int)&tss);
- put_line(out, "TSS_FPR6", (int)&tss.fpr[6]-(int)&tss);
- put_line(out, "TSS_FPR7", (int)&tss.fpr[7]-(int)&tss);
- put_line(out, "TSS_FPR8", (int)&tss.fpr[8]-(int)&tss);
- put_line(out, "TSS_FPR9", (int)&tss.fpr[9]-(int)&tss);
- put_line(out, "TSS_FPR10", (int)&tss.fpr[10]-(int)&tss);
- put_line(out, "TSS_FPR11", (int)&tss.fpr[11]-(int)&tss);
- put_line(out, "TSS_FPR12", (int)&tss.fpr[12]-(int)&tss);
- put_line(out, "TSS_FPR13", (int)&tss.fpr[13]-(int)&tss);
- put_line(out, "TSS_FPR14", (int)&tss.fpr[14]-(int)&tss);
- put_line(out, "TSS_FPR15", (int)&tss.fpr[15]-(int)&tss);
- put_line(out, "TSS_FPR16", (int)&tss.fpr[16]-(int)&tss);
- put_line(out, "TSS_FPR17", (int)&tss.fpr[17]-(int)&tss);
- put_line(out, "TSS_FPR18", (int)&tss.fpr[18]-(int)&tss);
- put_line(out, "TSS_FPR19", (int)&tss.fpr[19]-(int)&tss);
- put_line(out, "TSS_FPR20", (int)&tss.fpr[20]-(int)&tss);
- put_line(out, "TSS_FPR21", (int)&tss.fpr[21]-(int)&tss);
- put_line(out, "TSS_FPR22", (int)&tss.fpr[22]-(int)&tss);
- put_line(out, "TSS_FPR23", (int)&tss.fpr[23]-(int)&tss);
- put_line(out, "TSS_FPR24", (int)&tss.fpr[24]-(int)&tss);
- put_line(out, "TSS_FPR25", (int)&tss.fpr[25]-(int)&tss);
- put_line(out, "TSS_FPR26", (int)&tss.fpr[26]-(int)&tss);
- put_line(out, "TSS_FPR27", (int)&tss.fpr[27]-(int)&tss);
- put_line(out, "TSS_FPR28", (int)&tss.fpr[28]-(int)&tss);
- put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
- put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
- put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
- put_line(out, "TSS_FP_USED", (int)&tss.fp_used-(int)&tss);
- /* Interrupt register frame */
- put_line(out, "INT_FRAME_SIZE", sizeof(regs));
- put_line(out, "GPR0", (int)&regs.gpr[0]-(int)&regs);
- put_line(out, "GPR1", (int)&regs.gpr[1]-(int)&regs);
- put_line(out, "GPR2", (int)&regs.gpr[2]-(int)&regs);
- put_line(out, "GPR3", (int)&regs.gpr[3]-(int)&regs);
- put_line(out, "GPR4", (int)&regs.gpr[4]-(int)&regs);
- put_line(out, "GPR5", (int)&regs.gpr[5]-(int)&regs);
- put_line(out, "GPR6", (int)&regs.gpr[6]-(int)&regs);
- put_line(out, "GPR7", (int)&regs.gpr[7]-(int)&regs);
- put_line(out, "GPR8", (int)&regs.gpr[8]-(int)&regs);
- put_line(out, "GPR9", (int)&regs.gpr[9]-(int)&regs);
- put_line(out, "GPR10", (int)&regs.gpr[10]-(int)&regs);
- put_line(out, "GPR11", (int)&regs.gpr[11]-(int)&regs);
- put_line(out, "GPR12", (int)&regs.gpr[12]-(int)&regs);
- put_line(out, "GPR13", (int)&regs.gpr[13]-(int)&regs);
- put_line(out, "GPR14", (int)&regs.gpr[14]-(int)&regs);
- put_line(out, "GPR15", (int)&regs.gpr[15]-(int)&regs);
- put_line(out, "GPR16", (int)&regs.gpr[16]-(int)&regs);
- put_line(out, "GPR17", (int)&regs.gpr[17]-(int)&regs);
- put_line(out, "GPR18", (int)&regs.gpr[18]-(int)&regs);
- put_line(out, "GPR19", (int)&regs.gpr[19]-(int)&regs);
- put_line(out, "GPR20", (int)&regs.gpr[20]-(int)&regs);
- put_line(out, "GPR21", (int)&regs.gpr[21]-(int)&regs);
- put_line(out, "GPR22", (int)&regs.gpr[22]-(int)&regs);
- put_line(out, "GPR23", (int)&regs.gpr[23]-(int)&regs);
- put_line(out, "GPR24", (int)&regs.gpr[24]-(int)&regs);
- put_line(out, "GPR25", (int)&regs.gpr[25]-(int)&regs);
- put_line(out, "GPR26", (int)&regs.gpr[26]-(int)&regs);
- put_line(out, "GPR27", (int)&regs.gpr[27]-(int)&regs);
- put_line(out, "GPR28", (int)&regs.gpr[28]-(int)&regs);
- put_line(out, "GPR29", (int)&regs.gpr[29]-(int)&regs);
- put_line(out, "GPR30", (int)&regs.gpr[30]-(int)&regs);
- put_line(out, "GPR31", (int)&regs.gpr[31]-(int)&regs);
-#if 0
- for ( i = 0 ; i <= 31 ; i++)
- {
- sprintf(s,"FPR%d",i);
- put_line(out, s, (int)&regs.fpr[i]-(int)&regs);
- }
+ /*DEFINE(KERNELBASE, KERNELBASE);*/
+ DEFINE(STATE, offsetof(struct task_struct, state));
+ DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
+ DEFINE(COUNTER, offsetof(struct task_struct, counter));
+ DEFINE(BLOCKED, offsetof(struct task_struct, blocked));
+ DEFINE(SIGNAL, offsetof(struct task_struct, signal));
+ DEFINE(TSS, offsetof(struct task_struct, tss));
+ DEFINE(KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
+#ifdef CONFIG_PMAC
+ DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
+ DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
+#endif
+ DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
+ DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+ DEFINE(PF_TRACESYS, PF_TRACESYS);
+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
+#if 0
+ DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
+ DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
+ DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
+ DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
+ DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
+ DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
+ DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
+ DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
+ DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
+ DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
+ DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
+ DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
+ DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
+ DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
+ DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
+ DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
+ DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
+ DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
+ DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
+ DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
+ DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
+ DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
+ DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
+ DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
+ DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
+ DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
+ DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
+ DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
+ DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
+ DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
+ DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
#endif
- put_line(out, "FPCSR", (int)&regs.fpcsr-(int)&regs);
- /* Note: these symbols include "_" because they overlap with special register names */
- put_line(out, "_NIP", (int)&regs.nip-(int)&regs);
- put_line(out, "_MSR", (int)&regs.msr-(int)&regs);
- /* put_line(out, "_SRR1", (int)&regs.srr1-(int)&regs);
- put_line(out, "_SRR0", (int)&regs.srr0-(int)&regs); */
- put_line(out, "_CTR", (int)&regs.ctr-(int)&regs);
- put_line(out, "_LINK", (int)&regs.link-(int)&regs);
- put_line(out, "_CCR", (int)&regs.ccr-(int)&regs);
- put_line(out, "_XER", (int)&regs.xer-(int)&regs);
- put_line(out, "_DAR", (int)&regs.dar-(int)&regs);
- put_line(out, "_DSISR", (int)&regs.dsisr-(int)&regs);
- put_line(out, "_HASH1", (int)&regs.hash1-(int)&regs);
- put_line(out, "_HASH2", (int)&regs.hash2-(int)&regs);
- put_line(out, "_IMISS", (int)&regs.imiss-(int)&regs);
- put_line(out, "_DMISS", (int)&regs.dmiss-(int)&regs);
- put_line(out, "_ICMP", (int)&regs.icmp-(int)&regs);
- put_line(out, "_DCMP", (int)&regs.dcmp-(int)&regs);
- put_line(out, "ORIG_GPR3", (int)&regs.orig_gpr3-(int)&regs);
- put_line(out, "RESULT", (int)&regs.result-(int)&regs);
- put_line(out, "TRAP", (int)&regs.trap-(int)&regs);
- put_line(out, "MARKER", (int)&regs.marker-(int)&regs);
- exit(0);
-}
-
-put_line(FILE *out, char *name, int offset)
-{
- fprintf(out, "#define %s %d\n", name, offset);
+ DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
+ /* Interrupt register frame */
+ DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
+ DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+ DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+ DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+ DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+ DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+ DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+ DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+ DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+ DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+ DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+ DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+ DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+ DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10]));
+ DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11]));
+ DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12]));
+ DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13]));
+ DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14]));
+ DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15]));
+ DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16]));
+ DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17]));
+ DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18]));
+ DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19]));
+ DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+ DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+ DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+ DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+ DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24]));
+ DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25]));
+ DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26]));
+ DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27]));
+ DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28]));
+ DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29]));
+ DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30]));
+ DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31]));
+ /* Note: these symbols include _ because they overlap with special register names */
+ DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+ DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+ DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+ DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+ DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+ DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+ DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+ DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+ DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+ DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+ DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
}
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 74f796792..612a24bff 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -11,14 +11,18 @@
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+
/*
* PCI interrupt configuration. This is motherboard specific.
*/
-
-
/* Which PCI interrupt line does a given device [slot] use? */
/* Note: This really should be two dimensional based in slot/pin used */
unsigned char *Motherboard_map;
+unsigned char *Motherboard_map_name;
/* How is the 82378 PIRQ mapping setup? */
unsigned char *Motherboard_routes;
@@ -27,7 +31,7 @@ unsigned char *Motherboard_routes;
/* Motorola PowerStack */
static char Blackhawk_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
@@ -44,20 +48,20 @@ static char Blackhawk_pci_IRQ_map[16] =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Blackhawk_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* Motorola MVME16xx */
static char Genesis_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
@@ -74,20 +78,20 @@ static char Genesis_pci_IRQ_map[16] =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Genesis_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
10, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* Motorola Series-E */
static char Comet_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
@@ -104,20 +108,20 @@ static char Comet_pci_IRQ_map[16] =
0, /* Slot 13 - unused */
1, /* Slot 14 - Ethernet */
0, /* Slot 15 - unused */
- };
+};
static char Comet_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
10, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* BeBox */
static char BeBox_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
@@ -134,20 +138,20 @@ static char BeBox_pci_IRQ_map[16] =
0, /* Slot 13 - unused */
0, /* Slot 14 - unused */
0, /* Slot 15 - unused */
- };
+};
static char BeBox_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
9, /* Line 1 */
11, /* Line 2 */
14, /* Line 3 */
15 /* Line 4 */
- };
+};
/* IBM Nobis */
static char Nobis_pci_IRQ_map[16] =
- {
+{
0, /* Slot 0 - unused */
0, /* Slot 1 - unused */
0, /* Slot 2 - unused */
@@ -164,54 +168,83 @@ static char Nobis_pci_IRQ_map[16] =
0, /* Slot 13 - unused */
0, /* Slot 14 - unused */
0, /* Slot 15 - unused */
- };
+};
static char Nobis_pci_IRQ_routes[] =
- {
+{
0, /* Line 0 - Unused */
13, /* Line 1 */
13, /* Line 2 */
13, /* Line 3 */
13 /* Line 4 */
- };
+};
+
+
+/*
+ * ibm 830 (and 850?).
+ * This is actually based on the Carolina motherboard
+ * -- Cort
+ */
+static char ibm8xx_pci_IRQ_map[23] = {
+ 0, /* Slot 0 - unused */
+ 0, /* Slot 1 - unused */
+ 0, /* Slot 2 - unused */
+ 0, /* Slot 3 - unused */
+ 0, /* Slot 4 - unused */
+ 0, /* Slot 5 - unused */
+ 0, /* Slot 6 - unused */
+ 0, /* Slot 7 - unused */
+ 0, /* Slot 8 - unused */
+ 0, /* Slot 9 - unused */
+ 0, /* Slot 10 - unused */
+ 0, /* Slot 11 - FireCoral */
+ 4, /* Slot 12 - Ethernet PCIINTD# */
+ 2, /* Slot 13 - PCI Slot #2 */
+ 2, /* Slot 14 - S3 Video PCIINTD# */
+ 0, /* Slot 15 - onboard SCSI (INDI) [1] */
+ 3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
+ 0, /* Slot 17 - unused */
+ 2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+ 0, /* Slot 19 - unused */
+ 0, /* Slot 20 - unused */
+ 0, /* Slot 21 - unused */
+ 2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+static char ibm8xx_pci_IRQ_routes[] = {
+ 0, /* Line 0 - unused */
+ 13, /* Line 1 */
+ 10, /* Line 2 */
+ 15, /* Line 3 */
+ 15, /* Line 4 */
+};
+/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
+ * it really needs some logic to set them to unique IRQ's, or even
+ * add some logic to the drivers to ask an irq.c routine to re-map
+ * the IRQ if it needs one to itself...
+ */
+static char Carolina_PIRQ_routes[] = {
+ 0xad, /* INTB# = 10, INTA# = 13 */
+ 0xff /* INTD# = 15, INTC# = 15 */
+};
+/* We have to turn on LEVEL mode for changed IRQ's */
+/* All PCI IRQ's need to be level mode, so this should be something
+ * other than hard-coded as well... IRQ's are individually mappable
+ * to either edge or level.
+ */
+#define CAROLINA_IRQ_EDGE_MASK_LO 0x00 /* IRQ's 0-7 */
+#define CAROLINA_IRQ_EDGE_MASK_HI 0xA4 /* IRQ's 8-15 [10,13,15] */
+#define PCI_DEVICE_ID_IBM_CORAL 0x000a
-#define PCI_DEBUG
#undef PCI_DEBUG
#ifdef PCI_STATS
int PCI_conversions[2];
#endif
-unsigned long pcibios_init(unsigned long mem_start,
- unsigned long mem_end)
-{
- return mem_start;
-}
unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
{
- return mem_start;
-}
-
-
-unsigned long
-_LE_to_BE_long(unsigned long val)
-{
- unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
- PCI_conversions[0]++;
-#endif
- return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | (p[0] << 0));
-}
-
-unsigned short
-_LE_to_BE_short(unsigned long val)
-{
- unsigned char *p = (unsigned char *)&val;
-#ifdef PCI_STATS
- PCI_conversions[1]++;
-#endif
- return ((p[3] << 8) | (p[2] << 0));
+ return mem_start;
}
int
@@ -225,7 +258,7 @@ pcibios_present (void)
int
pcibios_read_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int *val)
+ unsigned char dev, unsigned char offset, unsigned int *val)
{
unsigned long _val;
unsigned long *ptr;
@@ -243,7 +276,7 @@ pcibios_read_config_dword (unsigned char bus,
#ifdef PCI_DEBUG
printk("[%x] ", ptr);
#endif
- _val = _LE_to_BE_long(*ptr);
+ _val = le32_to_cpu(*ptr);
}
#ifdef PCI_DEBUG
printk("%x\n", _val);
@@ -254,27 +287,27 @@ pcibios_read_config_dword (unsigned char bus,
int
pcibios_read_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short *val)
+ unsigned char dev, unsigned char offset, unsigned short *val)
{
unsigned short _val;
unsigned short *ptr;
dev >>= 3;
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
#endif
if ((bus != 0) || (dev < 11) || (dev > 16))
{
- *val = 0xFFFFFFFF;
+ *val = (unsigned short)0xFFFFFFFF;
return PCIBIOS_DEVICE_NOT_FOUND;
} else
{
ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("[%x] ", ptr);
#endif
- _val = _LE_to_BE_short(*ptr);
+ _val = le16_to_cpu(*ptr);
}
-#ifdef PCI_DEBUG
+#ifdef PCI_DEBUG
printk("%x\n", _val);
#endif
*val = _val;
@@ -283,7 +316,7 @@ pcibios_read_config_word (unsigned char bus,
int
pcibios_read_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char *val)
+ unsigned char dev, unsigned char offset, unsigned char *val)
{
unsigned char _val;
volatile unsigned char *ptr;
@@ -294,6 +327,9 @@ pcibios_read_config_byte (unsigned char bus,
if (Motherboard_map[dev] <= 4)
{
*val = Motherboard_routes[Motherboard_map[dev]];
+ /*printk("dev %d map %d route %d\n",
+ dev,Motherboard_map[dev],
+ Motherboard_routes[Motherboard_map[dev]]);*/
} else
{ /* Pseudo interrupts [for BeBox] */
*val = Motherboard_map[dev];
@@ -327,12 +363,12 @@ pcibios_read_config_byte (unsigned char bus,
int
pcibios_write_config_dword (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned int val)
+ unsigned char dev, unsigned char offset, unsigned int val)
{
unsigned long _val;
unsigned long *ptr;
dev >>= 3;
- _val = _LE_to_BE_long(val);
+ _val = le32_to_cpu(val);
#ifdef PCI_DEBUG
printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
#endif
@@ -349,12 +385,12 @@ pcibios_write_config_dword (unsigned char bus,
int
pcibios_write_config_word (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned short val)
+ unsigned char dev, unsigned char offset, unsigned short val)
{
unsigned short _val;
unsigned short *ptr;
dev >>= 3;
- _val = _LE_to_BE_short(val);
+ _val = le16_to_cpu(val);
#ifdef PCI_DEBUG
printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
#endif
@@ -371,7 +407,7 @@ pcibios_write_config_word (unsigned char bus,
int
pcibios_write_config_byte (unsigned char bus,
- unsigned char dev, unsigned char offset, unsigned char val)
+ unsigned char dev, unsigned char offset, unsigned char val)
{
unsigned char _val;
unsigned char *ptr;
@@ -420,7 +456,7 @@ pcibios_find_device (unsigned short vendor, unsigned short device_id,
int
pcibios_find_class (unsigned int class_code, unsigned short index,
- unsigned char *bus, unsigned char *dev)
+ unsigned char *bus, unsigned char *dev)
{
int dev_nr, class, indx;
indx = 0;
@@ -437,7 +473,7 @@ pcibios_find_class (unsigned int class_code, unsigned short index,
*bus = 0;
*dev = dev_nr<<3;
#ifdef PCI_DEBUG
- printk(" - device: %x\n", dev_nr);
+ printk(" - device: %x\n", dev_nr);
#endif
return (0);
}
@@ -455,22 +491,22 @@ const char *pcibios_strerror(int error)
static char buf[32];
switch (error)
{ case PCIBIOS_SUCCESSFUL:
- return ("PCI BIOS: no error");
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return ("PCI BIOS: function not supported");
- case PCIBIOS_BAD_VENDOR_ID:
- return ("PCI BIOS: bad vendor ID");
- case PCIBIOS_DEVICE_NOT_FOUND:
- return ("PCI BIOS: device not found");
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return ("PCI BIOS: bad register number");
- case PCIBIOS_SET_FAILED:
- return ("PCI BIOS: set failed");
- case PCIBIOS_BUFFER_TOO_SMALL:
- return ("PCI BIOS: buffer too small");
- default:
- sprintf(buf, "PCI BIOS: invalid error #%d", error);
- return(buf);
+ return ("PCI BIOS: no error");
+ case PCIBIOS_FUNC_NOT_SUPPORTED:
+ return ("PCI BIOS: function not supported");
+ case PCIBIOS_BAD_VENDOR_ID:
+ return ("PCI BIOS: bad vendor ID");
+ case PCIBIOS_DEVICE_NOT_FOUND:
+ return ("PCI BIOS: device not found");
+ case PCIBIOS_BAD_REGISTER_NUMBER:
+ return ("PCI BIOS: bad register number");
+ case PCIBIOS_SET_FAILED:
+ return ("PCI BIOS: set failed");
+ case PCIBIOS_BUFFER_TOO_SMALL:
+ return ("PCI BIOS: buffer too small");
+ default:
+ sprintf(buf, "PCI BIOS: invalid error #%d", error);
+ return(buf);
}
}
@@ -478,42 +514,112 @@ const char *pcibios_strerror(int error)
* Note: This routine has to access the PCI configuration space
* for the PCI bridge chip (Intel 82378).
*/
-
-void route_PCI_interrupts(void)
+unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
+{
+ return mem_start;
+}
+
+unsigned long route_pci_interrupts(void)
{
unsigned char *ibc_pirq = (unsigned char *)0x80800860;
unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
extern unsigned long isBeBox[];
int i;
- /* Decide which motherboard this is & how the PCI interrupts are routed */
- if (isBeBox[0])
- {
- Motherboard_map = BeBox_pci_IRQ_map;
- Motherboard_routes = BeBox_pci_IRQ_routes;
- } else
- if ((_get_PVR()>>16) == 1)
- { /* Nobis */
- Motherboard_map = Nobis_pci_IRQ_map;
- Motherboard_routes = Nobis_pci_IRQ_routes;
- } else
- { /* Motorola hardware */
+
+ if ( _machine == _MACH_Motorola)
+ {
switch (inb(0x800) & 0xF0)
{
- case 0x10: /* MVME16xx */
- Motherboard_map = Genesis_pci_IRQ_map;
- Motherboard_routes = Genesis_pci_IRQ_routes;
- break;
- case 0x20: /* Series E */
- Motherboard_map = Comet_pci_IRQ_map;
- Motherboard_routes = Comet_pci_IRQ_routes;
- break;
- case 0x40: /* PowerStack */
- default: /* Can't hurt, can it? */
- Motherboard_map = Blackhawk_pci_IRQ_map;
- Motherboard_routes = Blackhawk_pci_IRQ_routes;
- break;
+ case 0x10: /* MVME16xx */
+ Motherboard_map_name = "Genesis";
+ Motherboard_map = Genesis_pci_IRQ_map;
+ Motherboard_routes = Genesis_pci_IRQ_routes;
+ break;
+ case 0x20: /* Series E */
+ Motherboard_map_name = "Series E";
+ Motherboard_map = Comet_pci_IRQ_map;
+ Motherboard_routes = Comet_pci_IRQ_routes;
+ break;
+ case 0x40: /* PowerStack */
+ default: /* Can't hurt, can it? */
+ Motherboard_map_name = "Blackhawk (Powerstack)";
+ Motherboard_map = Blackhawk_pci_IRQ_map;
+ Motherboard_routes = Blackhawk_pci_IRQ_routes;
+ break;
+ }
+ } else
+ {
+ if ( _machine == _MACH_IBM )
+ {
+ unsigned char pl_id;
+ unsigned long flags;
+ unsigned index;
+ unsigned char fn, bus;
+ unsigned int addr;
+ unsigned char dma_mode, ide_mode;
+ int i;
+
+ Motherboard_map_name = "IBM 8xx (Carolina)";
+ Motherboard_map = ibm8xx_pci_IRQ_map;
+ Motherboard_routes = ibm8xx_pci_IRQ_routes;
+ll_printk("before loop\n");
+
+ for (index = 0;
+ !pcibios_find_device (PCI_VENDOR_ID_IBM,
+ PCI_DEVICE_ID_IBM_CORAL,
+ index, &bus, &fn); ++index)
+ {
+ pcibios_read_config_dword(bus, fn, 0x10, &addr);
+ addr &= ~0x3;
+ outb(0x26, addr);
+ dma_mode = inb(addr+4);
+ outb(0x25, addr);
+ ide_mode = inb(addr+4);
+ /*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x",
+ addr, dma_mode, ide_mode);*/
+ /* Make CDROM non-DMA */
+ ide_mode = (ide_mode & 0x0F) | 0x20;
+ outb(0x25, addr);
+ outb(ide_mode, addr+4);
+ dma_mode = dma_mode & ~0x80;
+ outb(0x26, addr);
+ outb(dma_mode, addr+4);
+ outb(0x26, addr);
+ dma_mode = inb(addr+4);
+ outb(0x25, addr);
+ ide_mode = inb(addr+4);
+ /*printk("=> DMA mode: %x, IDE mode: %x\n",
+ dma_mode, ide_mode);*/
+ }
+
+ /* Setup the PCI INT mappings for the Carolina */
+ /* These are PCI Interrupt Route Control [1|2] Register */
+ outb(Carolina_PIRQ_routes[0], 0x0890);
+ outb(Carolina_PIRQ_routes[1], 0x0891);
+
+ pl_id=inb(0x0852);
+ /*printk("CPU Planar ID is %#0x\n", pl_id);*/
+
+ if (pl_id == 0x0C) {
+ /* INDI */
+ Motherboard_map[12] = 1;
+ }
+ll_printk("before edge/level\n");
+#if 0
+ /*printk("Changing IRQ mode\n");*/
+ pl_id=inb(0x04d0);
+ /*printk("Low mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
+
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask is %#0x\n", pl_id);*/
+ outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
+ pl_id=inb(0x04d1);
+ /*printk("Hi mask now %#0x\n", pl_id);*/
+#endif
}
}
+
/* Set up mapping from slots */
for (i = 1; i <= 4; i++)
{
@@ -521,4 +627,4 @@ void route_PCI_interrupts(void)
}
/* Enable PCI interrupts */
*ibc_pcicon |= 0x20;
-}
+}
diff --git a/arch/ppc/kernel/port_io.c b/arch/ppc/kernel/port_io.c
index e886705e1..cc8626a3a 100644
--- a/arch/ppc/kernel/port_io.c
+++ b/arch/ppc/kernel/port_io.c
@@ -1,149 +1,146 @@
/*
* I/O 'port' access routines
*/
+#include <asm/byteorder.h>
+#include <asm/io.h>
-/* This is really only correct for the MVME16xx (PreP)? */
+#define inb_asm(port) {( \
+ unsigned char ret; \
+ asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
+ return ret; \
+})
-#define _IO_BASE ((unsigned long)0x80000000)
-
-unsigned char
+inline unsigned char
inb(int port)
{
- return (*((unsigned char *)(_IO_BASE+port)));
+ unsigned char ret;
+ asm("/*inb*/\n");
+ asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
+ return ret;
}
-unsigned short
+inline unsigned short
inw(int port)
{
- return (_LE_to_BE_short(*((unsigned short *)(_IO_BASE+port))));
+ unsigned short ret;
+ asm("/*inw*/\n");
+ asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+ return ret;
}
-unsigned long
+inline unsigned long
inl(int port)
{
- return (_LE_to_BE_long(*((unsigned long *)(_IO_BASE+port))));
+ unsigned long ret;
+ asm("/*inl*/\n");
+ asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
+ return ret;
}
-void insb(int port, char *ptr, int len)
+inline unsigned char
+outb(unsigned char val,int port)
{
- unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = *io_ptr;
- }
+ asm("/*outb*/\n");
+ asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
+ return (val);
}
-#if 0
-void insw(int port, short *ptr, int len)
-{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = _LE_to_BE_short(*io_ptr);
- }
-}
-#else
-void insw(int port, short *ptr, int len)
+inline unsigned short
+outw(unsigned short val,int port)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- _insw(io_ptr, ptr, len);
+ asm("/*outw*/\n");
+ asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+ return (val);
}
-#endif
-void insw_unswapped(int port, short *ptr, int len)
+inline unsigned long
+outl(unsigned long val,int port)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = *io_ptr;
- }
+ asm("/*outl*/\n");
+ asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
+ return (val);
}
-void insl(int port, long *ptr, int len)
+void insb(int port, char *ptr, int len)
{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *ptr++ = _LE_to_BE_long(*io_ptr);
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
}
-unsigned char inb_p(int port) {return (inb(port)); }
-unsigned short inw_p(int port) {return (inw(port)); }
-unsigned long inl_p(int port) {return (inl(port)); }
-
-unsigned char
-outb(unsigned char val,int port)
+void insw(int port, short *ptr, int len)
{
- *((unsigned char *)(_IO_BASE+port)) = (val);
- return (val);
+ asm ("mtctr %2 \n\t"
+ "subi %1,%1,2 \n\t"
+ "00:\n\t"
+ "lhbrx %2,0,%0 \n\t"
+ "sthu %2,2(%1) \n\t"
+ "bdnz 00b \n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-unsigned short
-outw(unsigned short val,int port)
+void insw_unswapped(int port, short *ptr, int len)
{
- *((unsigned short *)(_IO_BASE+port)) = _LE_to_BE_short(val);
- return (val);
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
}
-unsigned long
-outl(unsigned long val,int port)
+void insl(int port, long *ptr, int len)
{
- *((unsigned long *)(_IO_BASE+port)) = _LE_to_BE_long(val);
- return (val);
+ asm ("mtctr %2 \n\t"
+ "subi %1,%1,4 \n\t"
+ "00:\n\t"
+ "lhbrx %2,0,%0 \n\t"
+ "sthu %2,4(%1) \n\t"
+ "bdnz 00b \n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
void outsb(int port, char *ptr, int len)
{
- unsigned char *io_ptr = (unsigned char *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = *ptr++;
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
}
-#if 0
void outsw(int port, short *ptr, int len)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = _LE_to_BE_short(*ptr++);
- }
+ asm ("mtctr %2\n\t"
+ "subi %1,%1,2\n\t"
+ "00:lhzu %2,2(%1)\n\t"
+ "sthbrx %2,0,%0\n\t"
+ "bdnz 00b\n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-#else
-void outsw(int port, short *ptr, int len)
-{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- _outsw(io_ptr, ptr, len);
-}
-#endif
void outsw_unswapped(int port, short *ptr, int len)
{
- unsigned short *io_ptr = (unsigned short *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = *ptr++;
- }
+ memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );
}
void outsl(int port, long *ptr, int len)
{
- unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
- while (len-- > 0)
- {
- *io_ptr = _LE_to_BE_long(*ptr++);
- }
+ asm ("mtctr %2\n\t"
+ "subi %1,%1,4\n\t"
+ "00:lwzu %2,4(%1)\n\t"
+ "sthbrx %2,0,%0\n\t"
+ "bdnz 00b\n\t"
+ :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
}
-unsigned char outb_p(unsigned char val,int port) { return (outb(val,port)); }
-unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-unsigned long outl_p(unsigned long val,int port) { return (outl(val,port)); }
-
+void insl_unswapped(int port, long *ptr, int len)
+{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ while (len-- > 0)
+ {
+ *ptr++ = (*io_ptr);
+ }
+}
-/* makes writing to the ibm acorn power management stuff easier -- Cort */
-/* args in forn of PA.B as in tech spec for ibm carolina */
-void ibm_write(unsigned char val,unsigned int port)
+void outsl_unswapped(int port, long *ptr, int len)
{
+ unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
+ /* Ensure I/O operations complete */
+ __asm__ volatile("eieio");
+ while (len-- > 0)
+ {
+ *io_ptr = (*ptr++);
+ }
}
diff --git a/arch/ppc/kernel/ppc_asm.tmpl b/arch/ppc/kernel/ppc_asm.tmpl
index 5d357be22..e31dea266 100644
--- a/arch/ppc/kernel/ppc_asm.tmpl
+++ b/arch/ppc/kernel/ppc_asm.tmpl
@@ -2,19 +2,10 @@
* This file contains all the macros and symbols which define
* a PowerPC assembly language environment.
*/
-
+#include <linux/config.h>
#define _TEXT()\
.text
-#if 0 /* Old way */
-#define _EXTERN(n) .##n
-
-#define _GLOBAL(n)\
- .globl n;\
-n: .long _EXTERN(n);\
- .globl _EXTERN(n);\
-_EXTERN(n):
-#else
#define _EXTERN(n) n
#define SYMBOL_NAME(x) x
@@ -22,7 +13,6 @@ _EXTERN(n):
#define _GLOBAL(n)\
.globl n;\
n:
-#endif
#ifndef FALSE
#define FALSE 0
@@ -136,9 +126,13 @@ n:
#define SDR1 25 /* MMU hash base register */
#define DAR 19 /* Data Address Register */
#define SPR0 272 /* Supervisor Private Registers */
+#define SPRG0 272
#define SPR1 273
+#define SPRG1 273
#define SPR2 274
+#define SPRG2 274
#define SPR3 275
+#define SPRG3 275
#define DSISR 18
#define SRR0 26 /* Saved Registers (exception) */
#define SRR1 27
@@ -164,7 +158,36 @@ n:
#define SR14 14
#define SR15 15
+#define curptr r2
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
/* Missing instructions */
#define bdne bc 0,2,
-#include "asm/ppc_machine.h"
diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
index ee21c5cbe..f24872063 100644
--- a/arch/ppc/kernel/process.c
+++ b/arch/ppc/kernel/process.c
@@ -1,13 +1,20 @@
/*
* linux/arch/ppc/kernel/process.c
*
- * Copyright (C) 1995 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * This file handles the architecture-dependent parts of process handling..
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/process.c"
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * Modified by Cort Dougan (cort@cs.nmt.edu) and
+ * Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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.
+ *
*/
#include <linux/errno.h>
@@ -22,173 +29,449 @@
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
+#include <asm/smp_lock.h>
-#include <asm/ppc_machine.h>
+int dump_fpu(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void print_backtrace(unsigned long *);
+void show_regs(struct pt_regs * regs);
+void inline zero_paged(void);
+extern unsigned long _get_SP(void);
-/*
- * Initial task structure. Make this a per-architecture thing,
- * because different architectures tend to have different
- * alignment requirements and potentially different initial
- * setup.
- */
-static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
-unsigned long init_user_stack[1024] = { STACK_MAGIC, };
+#undef SHOW_TASK_SWITCHES 1
+#undef CHECK_STACK 1
+#undef IDLE_ZERO 1
+
+unsigned long
+kernel_stack_top(struct task_struct *tsk)
+{
+ return ((unsigned long)tsk) + sizeof(union task_union);
+}
+
+unsigned long
+task_top(struct task_struct *tsk)
+{
+ return ((unsigned long)tsk) + sizeof(struct task_struct);
+}
+
static struct vm_area_struct init_mmap = INIT_MMAP;
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
struct mm_struct init_mm = INIT_MM;
-struct task_struct init_task = INIT_TASK;
-
-
-int dump_fpu(void);
-void hard_reset_now(void);
-void switch_to(struct task_struct *, struct task_struct *);
-void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
- struct pt_regs *);
-void print_backtrace(unsigned long *);
+union task_union init_task_union = { INIT_TASK };
int
dump_fpu(void)
{
- return (1);
+ return (1);
}
-
/* check to make sure the kernel stack is healthy */
int check_stack(struct task_struct *tsk)
{
- extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
- int ret = 0;
- int i;
-
- /* skip check in init_kernel_task -- swapper */
- if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
- return;
- /* check bounds on stack -- above/below kstack page */
- if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
- {
- printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
- ret |= 1;
- }
-
- /* check for magic on kstack */
- if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
- {
- printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
- *(unsigned long *)(tsk->kernel_stack_page));
- ret |= 2;
- }
-
-#ifdef KERNEL_STACK_BUFFER
- /* check extra padding page under kernel stack */
- for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
- {
- struct pt_regs *regs;
-
- if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
- {
- printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
- tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
- *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
- regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
- printk("marker %x trap %x\n", regs->marker,regs->trap);
- print_backtrace((unsigned long *)(tsk->tss.ksp));
-
- ret |= 4;
- break;
- }
- }
+ unsigned long stack_top = kernel_stack_top(tsk);
+ unsigned long tsk_top = task_top(tsk);
+ int ret = 0;
+ unsigned long *i;
+
+#if 0
+ /* check tss magic */
+ if ( tsk->tss.magic != TSS_MAGIC )
+ {
+ ret |= 1;
+ printk("tss.magic bad: %08x\n", tsk->tss.magic);
+ }
#endif
-
-#if 0
- if (ret)
- panic("bad stack");
+
+ if ( !tsk )
+ printk("check_stack(): tsk bad tsk %p\n",tsk);
+
+ /* check if stored ksp is bad */
+ if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
+ {
+ printk("stack out of bounds: %s/%d\n"
+ " tsk_top %08x ksp %08x stack_top %08x\n",
+ tsk->comm,tsk->pid,
+ tsk_top, tsk->tss.ksp, stack_top);
+ ret |= 2;
+ }
+
+ /* check if stack ptr RIGHT NOW is bad */
+ if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
+ {
+ printk("current stack ptr out of bounds: %s/%d\n"
+ " tsk_top %08x sp %08x stack_top %08x\n",
+ current->comm,current->pid,
+ tsk_top, _get_SP(), stack_top);
+ ret |= 4;
+ }
+
+#if 0
+ /* check amount of free stack */
+ for ( i = (unsigned long *)task_top(tsk) ; i < kernel_stack_top(tsk) ; i++ )
+ {
+ if ( !i )
+ printk("check_stack(): i = %p\n", i);
+ if ( *i != 0 )
+ {
+ /* only notify if it's less than 900 bytes */
+ if ( (i - (unsigned long *)task_top(tsk)) < 900 )
+ printk("%d bytes free on stack\n",
+ i - task_top(tsk));
+ break;
+ }
+ }
#endif
- return(ret);
-}
+ if (ret)
+ {
+ panic("bad kernel stack");
+ }
+ return(ret);
+}
void
switch_to(struct task_struct *prev, struct task_struct *new)
{
- struct pt_regs *regs;
struct thread_struct *new_tss, *old_tss;
int s = _disable_interrupts();
- regs = (struct pt_regs *)(new->tss.ksp);
-#if 1
+ struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
+
+#if CHECK_STACK
check_stack(prev);
check_stack(new);
#endif
- /* if a process has used fp 15 times, then turn
- on the fpu for good otherwise turn it on with the fp
- exception handler as needed.
- skip this for kernel tasks.
- -- Cort */
- if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
- {
-#if 0
- printk("turning off fpu: %s/%d fp_used %d\n",
- new->comm,new->pid,new->tss.fp_used);
-#endif
- regs->msr = regs->msr & ~MSR_FP;
- }
-#if 0
- printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
+ /* turn off fpu for task last to run */
+ /*prev->tss.regs->msr &= ~MSR_FP;*/
+
+#ifdef SHOW_TASK_SWITCHES
+ printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
+ prev->comm,prev->pid,prev->tss.regs->nip,
+ new->comm,new->pid,new->tss.regs->nip,new->mm->context);
#endif
new_tss = &new->tss;
old_tss = &current->tss;
- current_set[0] = new;
- _switch(old_tss, new_tss);
+ _switch(old_tss, new_tss, new->mm->context);
+ /* turn off fpu for task last to run */
_enable_interrupts(s);
}
+
+#include <linux/mc146818rtc.h>
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
+{
+#if 1
+ struct task_struct *p;
+ printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
+ printk("last %x\n", last_task_used_math);
+ printk("cur %x regs %x/%x tss %x/%x\n",
+ current, current->tss.regs,regs,&current->tss,current->tss);
+ for_each_task(p)
+ {
+ if ((long)p < KERNELBASE)
+ {
+ printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
+ print_mm_info();
+ __cli();
+ while(1);
+ }
+ }
+ return regs->gpr[3];
+#endif
+#if 0
+ /* set the time in the cmos clock */
+ unsigned long hwtime, nowtime;
+ struct rtc_time tm;
+
+ hwtime = get_cmos_time();
+ to_tm(hwtime, &tm);
+ printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n",
+ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
+ tm.tm_mday, tm.tm_year);
+ return;
+#endif
+}
-asmlinkage int sys_debug(unsigned long r3)
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0; /* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0; /* pointer into the currently being zero'd page */
+unsigned long zerocount = 0; /* # currently pre-zero'd pages */
+unsigned long zerototal = 0; /* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0; /* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
{
- lock_kernel();
- if (!strcmp(current->comm,"crashme"))
- printk("sys_debug(): r3 (syscall) %d\n", r3);
- unlock_kernel();
+ unsigned long page;
+ unsigned long s;
+
+ if ( zero_list )
+ {
+ /* atomically remove this page from the list */
+ asm ( "101:lwarx %1,0,%2\n" /* reserve zero_list */
+ " lwz %0,0(%1)\n" /* get next -- new zero_list */
+ " stwcx. %0,0,%2\n" /* update zero_list */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list), "=&r" (page)
+ : "r" (&zero_list)
+ : "cc" );
+ /* we can update zerocount after the fact since it is not
+ * used for anything but control of a loop which doesn't
+ * matter since it won't effect anything if it zero's one
+ * less page -- Cort
+ */
+ atomic_inc((atomic_t *)&zeropage_hits);
+ atomic_dec((atomic_t *)&zerocount);
+ /* zero out the pointer to next in the page */
+ *(unsigned long *)page = 0;
+ return page;
+ }
return 0;
}
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+void inline zero_paged(void)
+{
+ extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+ unsigned long tmp;
+ pte_t ptep;
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ sprintf(current->comm, "zero_paged");
+ printk("Started zero_paged\n");
+ /* want priority over idle task and powerd */
+ current->priority = -98;
+ current->counter = -98;
+ __sti();
+
+ while ( zerocount < 128 )
+ {
+ /*
+ * Mark a page as reserved so we can mess with it
+ * If we're interrupted we keep this page and our place in it
+ * since we validly hold it and it's reserved for us.
+ */
+ pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+ if ( !pageptr )
+ {
+ printk("!pageptr in zero_paged\n");
+ goto retry;
+ }
+
+ if ( need_resched )
+ schedule();
+
+ /*
+ * Make the page no cache so we don't blow our cache with 0's
+ */
+ dir = pgd_offset( init_task.mm, pageptr );
+ if (dir)
+ {
+ pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+ if (pmd && pmd_present(*pmd))
+ {
+ pte = pte_offset(pmd, pageptr & PAGE_MASK);
+ if (pte && pte_present(*pte))
+ {
+ pte_uncache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+ }
+ }
+ }
+
+ /*
+ * Important here to not take time away from real processes.
+ */
+ for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+ {
+ if ( need_resched )
+ schedule();
+ *(unsigned long *)(bytecount + pageptr) = 0;
+ }
+
+ /*
+ * If we finished zero-ing out a page add this page to
+ * the zero_list atomically -- we can't use
+ * down/up since we can't sleep in idle.
+ * Disabling interrupts is also a bad idea since we would
+ * steal time away from real processes.
+ * We can also have several zero_paged's running
+ * on different processors so we can't interfere with them.
+ * So we update the list atomically without locking it.
+ * -- Cort
+ */
+ /* turn cache on for this page */
+ pte_cache(*pte);
+ flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+
+ /* atomically add this page to the list */
+ asm ( "101:lwarx %0,0,%1\n" /* reserve zero_list */
+ " stw %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+ " sync\n" /* let store settle */
+#endif
+ " mr %0,%2\n" /* update zero_list in reg */
+ " stwcx. %2,0,%1\n" /* update zero_list in mem */
+ " bne- 101b\n" /* if lost reservation try again */
+ : "=&r" (zero_list)
+ : "r" (&zero_list), "r" (pageptr)
+ : "cc" );
+ /*
+ * This variable is used in the above loop and nowhere
+ * else so the worst that could happen is we would
+ * zero out one more or one less page than we want
+ * per processor on the machine. This is because
+ * we could add our page to the list but not have
+ * zerocount updated yet when another processor
+ * reads it. -- Cort
+ */
+ atomic_inc((atomic_t *)&zerocount);
+ atomic_inc((atomic_t *)&zerototal);
+retry:
+ schedule();
+ }
+}
+
+void powerd(void)
+{
+ unsigned long msr, hid0;
+
+ sprintf(current->comm, "powerd");
+ __sti();
+ while (1)
+ {
+ /* want priority over idle task 'swapper' -- Cort */
+ current->priority = -99;
+ current->counter = -99;
+ asm volatile(
+ /* clear powersaving modes and set nap mode */
+ "mfspr %3,1008 \n\t"
+ "andc %3,%3,%4 \n\t"
+ "or %3,%3,%5 \n\t"
+ "mtspr 1008,%3 \n\t"
+ /* enter the mode */
+ "mfmsr %0 \n\t"
+ "oris %0,%0,%2 \n\t"
+ "sync \n\t"
+ "mtmsr %0 \n\t"
+ "isync \n\t"
+ : "=&r" (msr)
+ : "0" (msr), "i" (MSR_POW>>16),
+ "r" (hid0),
+ "r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+ "r" (HID0_NAP));
+ if ( need_resched )
+ schedule();
+ /*
+ * The ibm carolina spec says that the eagle memory
+ * controller will detect the need for a snoop
+ * and wake up the processor so we don't need to
+ * check for cache operations that need to be
+ * snooped. The ppc book says the run signal
+ * must be asserted while napping for this though.
+ * -- Cort
+ */
+ }
+}
+
asmlinkage int sys_idle(void)
{
int ret = -EPERM;
-
- lock_kernel();
if (current->pid != 0)
goto out;
- /* endless idle loop with no priority at all */
+#ifdef IDLE_ZERO
+ /*
+ * want one per cpu since it would be nice to have all
+ * processors who aren't doing anything
+ * zero-ing pages since this daemon is lock-free
+ * -- Cort
+ */
+ kernel_thread(zero_paged, NULL, 0);
+#endif /* IDLE_ZERO */
+
+#ifdef CONFIG_POWERSAVING
+ /* no powersaving modes on 601 - one per processor */
+ if( (_get_PVR()>>16) != 1 )
+ kernel_thread(powerd, NULL, 0);
+#endif /* CONFIG_POWERSAVING */
+
+ /* endless loop with no priority at all */
+ current->priority = -100;
current->counter = -100;
- for (;;) {
+ for (;;)
+ {
schedule();
}
ret = 0;
out:
- unlock_kernel();
return ret;
}
void show_regs(struct pt_regs * regs)
{
+ int i;
+
+ printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+ regs->nip, regs->xer, regs->link, regs,regs->trap);
+ printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+ regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
+ regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
+ regs->msr&MSR_IR ? 1 : 0,
+ regs->msr&MSR_DR ? 1 : 0);
+ printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+ current, current->pid, current->comm, current->mm->pgd);
+ printk("Last syscall: %d ", current->tss.last_syscall);
+ printk("\nlast math %08X\n", last_task_used_math);
+ for (i = 0; i < 32; i++)
+ {
+ long r;
+ if ((i % 8) == 0)
+ {
+ printk("GPR%02d: ", i);
+ }
+
+ if ( get_user(r, &(regs->gpr[i])) )
+ goto out;
+ printk("%08X ", r);
+ if ((i % 8) == 7)
+ {
+ printk("\n");
+ }
+ }
+out:
}
void exit_thread(void)
{
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
}
void flush_thread(void)
{
+ if (last_task_used_math == current)
+ last_task_used_math = NULL;
}
void
@@ -197,50 +480,25 @@ release_thread(struct task_struct *t)
}
/*
- * Copy a thread..
- */
-int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
- struct task_struct * p, struct pt_regs * regs)
+ * Copy a thread..
+ */
+int
+copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ struct task_struct * p, struct pt_regs * regs)
{
int i;
- SEGREG *segs;
struct pt_regs * childregs;
-
- /* Construct segment registers */
- segs = (SEGREG *)(p->tss.segs);
- for (i = 0; i < 8; i++)
- {
- segs[i].ks = 0;
- segs[i].kp = 1;
-#if 0
- segs[i].vsid = i | (nr << 4);
-#else
- segs[i].vsid = i | ((nr * 10000) << 4);
-#endif
- }
- if ((p->mm->context == 0) || (p->mm->count == 1))
- {
-#if 0
- p->mm->context = ((nr)<<4);
-#else
- p->mm->context = ((nr*10000)<<4);
-#endif
- }
-
- /* Last 8 are shared with kernel & everybody else... */
- for (i = 8; i < 16; i++)
- {
- segs[i].ks = 0;
- segs[i].kp = 1;
- segs[i].vsid = i;
- }
-
/* Copy registers */
- childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+ childregs = ((struct pt_regs *)
+ ((unsigned long)p + sizeof(union task_union)
+ - STACK_FRAME_OVERHEAD)) - 2;
+ *childregs = *regs;
- *childregs = *regs; /* STRUCT COPY */
+ if ((childregs->msr & MSR_PR) == 0)
+ childregs->gpr[2] = (unsigned long) p; /* `current' in new task */
childregs->gpr[3] = 0; /* Result from fork() */
- p->tss.ksp = (unsigned long)(childregs);
+ p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
+ p->tss.regs = (struct pt_regs *)(childregs);
if (usp >= (unsigned long)regs)
{ /* Stack is in kernel space - must adjust */
childregs->gpr[1] = (long)(childregs+1);
@@ -248,23 +506,29 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
{ /* Provided stack is in user space */
childregs->gpr[1] = usp;
}
- p->tss.fp_used = 0;
- return 0;
-}
+ p->tss.last_syscall = -1;
-/*
- * fill in the user structure for a core dump..
- */
-void dump_thread(struct pt_regs * regs, struct user * dump)
-{
+ /*
+ * copy fpu info - assume lazy fpu switch now always
+ * this should really be conditional on whether or
+ * not the process has used the fpu
+ * -- Cort
+ */
+ if ( last_task_used_math == current )
+ giveup_fpu();
+
+ memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
+ p->tss.fpscr = current->tss.fpscr;
+ childregs->msr &= ~MSR_FP;
+
+ return 0;
}
-
-asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
+ struct pt_regs *regs)
{
int ret;
-
lock_kernel();
ret = do_fork(SIGCHLD, regs->gpr[1], regs);
unlock_kernel();
@@ -272,46 +536,21 @@ asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct p
}
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs *regs)
+ unsigned long a3, unsigned long a4, unsigned long a5,
+ struct pt_regs *regs)
{
int error;
char * filename;
-
- lock_kernel();
- /* getname does it's own verification of the address
- when it calls get_max_filename() but
- it will assume it's valid if get_fs() == KERNEL_DS
- which is always true on the ppc so we check
- it here
-
- this doesn't completely check any of these data structures,
- it just makes sure that the 1st long is in a good area
- and from there we assume that it's safe then
- -- Cort
- */
- /* works now since get_fs/set_fs work properly */
-#if 0
- if ( verify_area(VERIFY_READ,(void *)a0,1)
- && verify_area(VERIFY_READ,(void *)a1,1)
- && verify_area(VERIFY_READ,(void *)a2,1)
- )
- {
- return -EFAULT;
- }
-#endif
- error = getname((char *) a0, &filename);
- if (error)
+ filename = (int) getname((char *) a0);
+ error = PTR_ERR(filename);
+ if(IS_ERR(filename))
goto out;
- flush_instruction_cache();
+ if ( last_task_used_math == current )
+ last_task_used_math = NULL;
error = do_execve(filename, (char **) a1, (char **) a2, regs);
-#if 0
-if (error)
-{
-printk("EXECVE - file = '%s', error = %d\n", filename, error);
-}
-#endif
+
putname(filename);
+
out:
unlock_kernel();
return error;
@@ -321,7 +560,7 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct
{
unsigned long clone_flags = p1;
int res;
-
+
lock_kernel();
res = do_fork(clone_flags, regs->gpr[1], regs);
unlock_kernel();
@@ -331,13 +570,17 @@ asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct
void
print_backtrace(unsigned long *sp)
{
-#if 0
int cnt = 0;
- printk("... Call backtrace:\n");
- while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
+ int i;
+ printk("Call backtrace: ");
+ while ( !get_user(i, sp) && i)
{
- printk("%08X ", sp[1]);
- sp = (unsigned long *)*sp;
+ if ( get_user( i, &sp[1] ) )
+ return;
+ printk("%08X ", i);
+ if ( get_user( (ulong)sp, sp) )
+ return;
+ if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
if (++cnt == 8)
{
printk("\n");
@@ -345,43 +588,66 @@ print_backtrace(unsigned long *sp)
if (cnt > 32) break;
}
printk("\n");
-#endif
-}
-
-void
-print_user_backtrace(unsigned long *sp)
-{
-#if 0
- int cnt = 0;
- printk("... [User] Call backtrace:\n");
- while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
- {
- printk("%08X ", sp[1]);
- sp = (unsigned long *)*sp;
- if (++cnt == 8)
- {
- printk("\n");
- }
- if (cnt > 16) break;
- }
- printk("\n");
-#endif
}
-void
-print_kernel_backtrace(void)
-{
-#if 0
- unsigned long *_get_SP(void);
- print_backtrace(_get_SP());
-#endif
-}
inline void start_thread(struct pt_regs * regs,
unsigned long eip, unsigned long esp)
{
+ set_fs(USER_DS);
regs->nip = eip;
regs->gpr[1] = esp;
regs->msr = MSR_USER;
- set_fs(USER_DS);
}
+/*
+ * Low level print for debugging - Cort
+ */
+int ll_printk(const char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+ int i;
+
+ va_start(args, fmt);
+ i=sprintf(buf,fmt,args);
+ ll_puts(buf);
+ va_end(args);
+ return i;
+}
+
+char *vidmem = (char *)0xC00B8000;
+int lines = 24, cols = 80;
+int orig_x = 0, orig_y = 0;
+
+void ll_puts(const char *s)
+{
+ int x,y;
+ char c;
+
+ x = orig_x;
+ y = orig_y;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ if ( c == '\n' ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ /*scroll();*/
+ /*y--;*/
+ y = 0;
+ }
+ } else {
+ vidmem [ ( x + cols * y ) * 2 ] = c;
+ if ( ++x >= cols ) {
+ x = 0;
+ if ( ++y >= lines ) {
+ /*scroll();*/
+ /*y--;*/
+ y = 0;
+ }
+ }
+ }
+ }
+
+ orig_x = x;
+ orig_y = y;
+}
diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
index dc8a95302..a5ec62d20 100644
--- a/arch/ppc/kernel/ptrace.c
+++ b/arch/ppc/kernel/ptrace.c
@@ -1,12 +1,14 @@
/*
* linux/arch/ppc/kernel/ptrace.c
*
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/m68k/kernel/ptrace.c"
* Copyright (C) 1994 by Hamish Macdonald
* Taken from linux/kernel/ptrace.c and modified for M680x0.
* linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
*
- * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
- * PowerPC version by Gary Thomas (gdt@linuxppc.org)
* Modified by Cort Dougan (cort@cs.nmt.edu)
*
* This file is subject to the terms and conditions of the GNU General
@@ -34,52 +36,13 @@
* in exit.c or in signal.c.
*/
-/* Find the stack offset for a register, relative to tss.ksp. */
-#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
-/* Mapping from PT_xxx to the stack offset at which the register is
- saved. Notice that usp has no stack-slot and needs to be treated
- specially (see get_reg/put_reg below). */
-static int regoff[] = {
-};
-
/*
* Get contents of register REGNO in task TASK.
*/
static inline long get_reg(struct task_struct *task, int regno)
{
- struct pt_regs *regs = task->tss.regs;
- if (regno <= PT_R31)
- {
- return (regs->gpr[regno]);
- } else
- if (regno == PT_NIP)
- {
- return (regs->nip);
- } else
- if (regno == PT_MSR)
- {
- return (regs->msr);
- } else
- if (regno == PT_ORIG_R3)
- {
- return (regs->orig_gpr3);
- } else
- if (regno == PT_CTR)
- {
- return (regs->ctr);
- } else
- if (regno == PT_LNK)
- {
- return (regs->link);
- } else
- if (regno == PT_XER)
- {
- return (regs->xer);
- } else
- if (regno == PT_CCR)
- {
- return (regs->ccr);
- }
+ if (regno <= PT_CCR)
+ return ((unsigned long *)task->tss.regs)[regno];
return (0);
}
@@ -89,52 +52,21 @@ static inline long get_reg(struct task_struct *task, int regno)
static inline int put_reg(struct task_struct *task, int regno,
unsigned long data)
{
- struct pt_regs *regs = task->tss.regs;
- if (regno <= PT_R31)
- {
- regs->gpr[regno] = data;
- } else
- if (regno == PT_NIP)
- {
- regs->nip = data;
- } else
- if (regno == PT_MSR)
- {
- regs->msr = data;
- } else
- if (regno == PT_CTR)
- {
- regs->ctr = data;
- } else
- if (regno == PT_LNK)
- {
- regs->link = data;
- } else
- if (regno == PT_XER)
- {
- regs->xer = data;
- } else
- if (regno == PT_CCR)
- {
- regs->ccr = data;
- } else
- { /* Invalid register */
- return (-1);
+ if (regno <= PT_CCR) {
+ ((unsigned long *)task->tss.regs)[regno] = data;
+ return 0;
}
- return (0);
+ return -1;
}
-static inline
+static inline void
set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->tss.regs;
-printk("Set single step - Task: %x, Regs: %x", task, regs);
-printk(", MSR: %x/", regs->msr);
regs->msr |= MSR_SE;
-printk("%x\n", regs->msr);
}
-static inline
+static inline void
clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->tss.regs;
@@ -159,33 +91,32 @@ static unsigned long get_long(struct task_struct * tsk,
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (pgd_none(*pgdir)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ printk("ptrace[1]: bad page directory %lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
return 0;
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page directory %08lx\n",
- pmd_val(*pgmiddle));
+ printk("ptrace[3]: bad pmd %lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return 0;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 0);
+ handle_mm_fault(tsk, vma, addr, 0);
goto repeat;
}
page = pte_page(*pgtable);
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page >= high_memory)
+ if (MAP_NR(page) >= max_mapnr)
return 0;
page += addr & ~PAGE_MASK;
return *(unsigned long *) page;
@@ -200,8 +131,8 @@ repeat:
* Now keeps R/W state of page so that a text page stays readonly
* even if a debugger scribbles breakpoints into it. -M.U-
*/
-static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr,
- unsigned long data)
+static void put_long(struct task_struct * tsk, struct vm_area_struct * vma,
+ unsigned long addr, unsigned long data)
{
pgd_t *pgdir;
pmd_t *pgmiddle;
@@ -211,42 +142,40 @@ static void put_long(struct task_struct * tsk, struct vm_area_struct * vma, unsi
repeat:
pgdir = pgd_offset(vma->vm_mm, addr);
if (!pgd_present(*pgdir)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pgd_bad(*pgdir)) {
- printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir));
+ printk("ptrace[2]: bad page directory %lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
return;
}
pgmiddle = pmd_offset(pgdir,addr);
if (pmd_none(*pgmiddle)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
- printk("ptrace: bad page directory %08lx\n",
- pmd_val(*pgmiddle));
+ printk("ptrace[4]: bad pmd %lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
- do_no_page(tsk, vma, addr, 1);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
page = pte_page(*pgtable);
if (!pte_write(*pgtable)) {
- do_wp_page(tsk, vma, addr, 2);
+ handle_mm_fault(tsk, vma, addr, 1);
goto repeat;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
- if (page < high_memory) {
+ if (MAP_NR(page) < max_mapnr)
*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
- }
/* we're bypassing pagetables, so we have to set the dirty bit ourselves */
/* this should also re-instate whatever read-only mode there was before */
- *pgtable = pte_mkdirty(mk_pte(page, vma->vm_page_prot));
+ set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
flush_tlb_all();
}
@@ -366,7 +295,6 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
- struct user * dummy = NULL;
int ret = -EPERM;
lock_kernel();
@@ -436,8 +364,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case PTRACE_PEEKUSR: {
unsigned long tmp;
- if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
- return -EIO;
+ if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+ ret = -EIO;
+ goto out;
+ }
ret = verify_area(VERIFY_WRITE, (void *) data,
sizeof(long));
@@ -445,15 +375,19 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
goto out;
tmp = 0; /* Default return condition */
addr = addr >> 2; /* temporary hack. */
- if (addr < PT_FPR0)
+ if (addr < PT_FPR0) {
tmp = get_reg(child, addr);
-#if 0
- else if (addr >= PT_FPR0 && addr < PT_FPR31)
- tmp = child->tss.fpr[addr - PT_FPR0];
-#endif
+ }
+#if 1
+ else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ if (last_task_used_math == child)
+ giveup_fpu();
+ tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
+ }
+#endif
else
ret = -EIO;
- if(!ret)
+ if (!ret)
put_user(tmp,(unsigned long *) data);
goto out;
}
@@ -486,13 +420,13 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
ret = 0;
goto out;
}
-#if 0
- if (addr >= 21 && addr < 48) {
- child->tss.fp[addr - 21] = data;
+ if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+ if (last_task_used_math == child)
+ giveup_fpu();
+ ((long *)child->tss.fpr)[addr - PT_FPR0] = data;
ret = 0;
goto out;
}
-#endif
goto out;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 25f03cc11..e69de29bb 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -1,409 +0,0 @@
-/*
- * linux/arch/ppc/kernel/setup.c
- *
- * Copyright (C) 1995 Linus Torvalds
- * Adapted from 'alpha' version by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
- */
-
-/*
- * bootup setup stuff..
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/tty.h>
-#include <linux/major.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-
-extern unsigned long *end_of_DRAM;
-extern PTE *Hash;
-extern unsigned long Hash_size, Hash_mask;
-extern int probingmem;
-unsigned long empty_zero_page[1024];
-
-unsigned char aux_device_present;
-#ifdef CONFIG_BLK_DEV_RAM
-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
-
-#undef HASHSTATS
-
-extern unsigned long isBeBox[];
-
-/* copy of the residual data */
-RESIDUAL res;
-unsigned long resptr = 0; /* ptr to residual data from hw */
-
-/*
- * The format of "screen_info" is strange, and due to early
- * i386-setup code. This is just enough to make the console
- * code think we're on a EGA+ colour display.
- */
- /* this is changed only in minor ways from the original
- -- Cort
- */
-struct screen_info screen_info = {
- 0, 25, /* orig-x, orig-y */
- { 0, 0 }, /* unused */
- 0, /* orig-video-page */
- 0, /* orig-video-mode */
- 80, /* orig-video-cols */
- 0,0,0, /* ega_ax, ega_bx, ega_cx */
- 25, /* orig-video-lines */
- 1, /* orig-video-isVGA */
- 16 /* orig-video-points */
-};
-
-
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
- return memory_start;
-}
-
-#ifdef HASHSTATS
-unsigned long *hashhits;
-#endif
-
-extern unsigned long _TotalMemory;
-/* find the physical size of RAM and setup hardware hash table */
-unsigned long *find_end_of_memory(void)
-{
- extern BAT BAT2;
- _TotalMemory = res.TotalMemory;
-
- if (_TotalMemory == 0 )
- {
- printk("Ramsize from residual data was 0 -- Probing for value\n");
- /* this needs be done differently since the bats actually map
- addresses beyond physical memory! -- Cort */
-#if 0
- probingmem = 1;
- while ( probingmem )
- {
- _TotalMemory += 0x00800000; /* 8M */
- *(unsigned long *)_TotalMemory+KERNELBASE;
- }
- _TotalMemory -= 0x00800000;
-#else
- _TotalMemory = 0x03000000;
-#endif
- printk("Ramsize probed to be %dM\n", _TotalMemory>>20);
- }
-
- /* setup BAT2 mapping so that it covers kernelbase to kernelbase+ramsize */
- switch(_TotalMemory)
- {
- case 0x01000000: /* 16M */
- BAT2.batu.bl = BL_16M;
- Hash_size = HASH_TABLE_SIZE_128K;
- Hash_mask = HASH_TABLE_MASK_128K;
- break;
- case 0x00800000: /* 8M */
- BAT2.batu.bl = BL_8M;
- Hash_size = HASH_TABLE_SIZE_64K;
- Hash_mask = HASH_TABLE_MASK_64K;
- break;
- case 0x01800000: /* 24M */
- case 0x02000000: /* 32M */
- BAT2.batu.bl = BL_32M;
- Hash_size = HASH_TABLE_SIZE_256K;
- Hash_mask = HASH_TABLE_MASK_256K;
- break;
- case 0x03000000: /* 48M */
- case 0x04000000: /* 64M */
- BAT2.batu.bl = BL_64M;
- Hash_size = HASH_TABLE_SIZE_512K;
- Hash_mask = HASH_TABLE_MASK_512K;
- break;
- case 0x05000000: /* 80M */
- BAT2.batu.bl = BL_128M;
- Hash_size = HASH_TABLE_SIZE_1M;
- Hash_mask = HASH_TABLE_MASK_1M;
- break;
- default:
- printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n",
- _TotalMemory);
- break;
- }
-
- Hash = (PTE *)((_TotalMemory-Hash_size)+KERNELBASE);
- bzero(Hash, Hash_size);
-
-
-#ifdef HASHSTATS
- hashhits = (unsigned long *)Hash - (Hash_size/sizeof(struct _PTE))/2;
- bzero(hashhits, (Hash_size/sizeof(struct _PTE))/2);
- return ((unsigned long *)hashhits);
-#else
- return ((unsigned long *)Hash);
-#endif
-}
-
-int size_memory;
-
-/*
- * This is set up by the setup-routine at boot-time
- */
-#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
-#ifdef CONFIG_APM
-#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
-#endif
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
-#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
-#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
-#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
-#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-#define COMMAND_LINE ((char *) (PARAM+2048))
-#define COMMAND_LINE_SIZE 256
-
-#define RAMDISK_IMAGE_START_MASK 0x07FF
-#define RAMDISK_PROMPT_FLAG 0x8000
-#define RAMDISK_LOAD_FLAG 0x4000
-
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
- char saved_command_line[COMMAND_LINE_SIZE];
-
-
-void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
- unsigned long * memory_end_p)
-{
- extern int _end;
- extern char cmd_line[];
- unsigned char reg;
- extern int panic_timeout;
- char inf[512];
- int i;
-
- if (isBeBox[0])
- _Processor = _PROC_Be;
- else
- {
- if (strncmp(res.VitalProductData.PrintableModel,"IBM",3))
- {
- _Processor = _PROC_Motorola;
- }
- else
- _Processor = _PROC_IBM;
- }
-
- get_cpuinfo(&inf);
- printk("%s",inf);
-
- /* Set up floppy in PS/2 mode */
- outb(0x09, SIO_CONFIG_RA);
- reg = inb(SIO_CONFIG_RD);
- reg = (reg & 0x3F) | 0x40;
- outb(reg, SIO_CONFIG_RD);
- outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */
-
- switch ( _Processor )
- {
- case _PROC_IBM:
- ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
- break;
- case _PROC_Motorola:
- ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
- break;
- }
- aux_device_present = 0xaa;
-
- panic_timeout = 300; /* reboot on panic */
-
-#if 0
- /* get root via nfs from charon -- was only used for testing */
- ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255); /* nfs */
- /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
- strcpy(cmd_line,
- "nfsaddrs=129.138.6.101:129.138.6.90:129.138.6.1:255.255.255.0:gordito nfsroot=/joplin/ppc/root/");
-#endif
- *cmdline_p = cmd_line;
- *memory_start_p = (unsigned long) &_end;
- (unsigned long *)*memory_end_p = (unsigned long *)end_of_DRAM;
- size_memory = *memory_end_p - KERNELBASE; /* Relative size of memory */
-
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#if 1
- rd_prompt = 1;
- rd_doload = 1;
- rd_image_start = 0;
-#endif
-#endif
-
- /* Save unparsed command line copy for /proc/cmdline */
- memcpy(saved_command_line, cmd_line,strlen(cmd_line)+1);
- printk("Command line: %s\n", cmd_line);
-}
-
-asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
- return -EIO;
-}
-
-
-int
-get_cpuinfo(char *buffer)
-{
- extern unsigned long loops_per_sec;
- int i;
- int pvr = _get_PVR();
- int len;
- char *model;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
- PTE *ptr;
-
- switch (pvr>>16)
- {
- case 3:
- model = "603";
- break;
- case 4:
- model = "604";
- break;
- case 6:
- model = "603e";
- break;
- case 7:
- model = "603ev";
- break;
- default:
- model = "unknown";
- break;
- }
-
-#ifdef __SMP__
-#define CD(X) (cpu_data[n].X)
-#else
-#define CD(X) (X)
-#define CPUN 0
-#endif
-
- len = sprintf(buffer, "PowerPC %s/%dMHz revision %d.%d %s\n",
- model,
- (res.VitalProductData.ProcessorHz > 1024) ?
- res.VitalProductData.ProcessorHz>>20 :
- res.VitalProductData.ProcessorHz,
- MAJOR(pvr), MINOR(pvr),
- (inb(IBM_EQUIP_PRESENT) & 2) ? "" : "upgrade");
-#if 1
- if ( res.VitalProductData.PrintableModel[0] )
- len += sprintf(buffer+len,"%s\n",res.VitalProductData.PrintableModel);
-
- len += sprintf(buffer+len,"Bus %dMHz\n",
- (res.VitalProductData.ProcessorBusHz > 1024) ?
- res.VitalProductData.ProcessorBusHz>>20 :
- res.VitalProductData.ProcessorBusHz);
-
- /* make sure loops_per_sec has been setup -- ie not at boottime -- Cort */
- if ( CD(loops_per_sec+2500)/500000 > 0)
- len += sprintf(buffer+len,
- "bogomips: %lu.%02lu\n",
- CD(loops_per_sec+2500)/500000,
- (CD(loops_per_sec+2500)/5000) % 100);
-
-
- len += sprintf(buffer+len,"Total Ram: %dM Hash Table: %dkB (%dk buckets)\n",
- _TotalMemory>>20, Hash_size>>10,
- (Hash_size/(sizeof(PTE)*8)) >> 10);
-
- for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
- {
- if (i == 0)
- len += sprintf(buffer+len,"SIMM Banks: ");
- if ( res.Memories[i].SIMMSize != 0 )
- len += sprintf(buffer+len,"%d:%dM ",i,
- (res.Memories[i].SIMMSize > 1024) ?
- res.Memories[i].SIMMSize>>20 :
- res.Memories[i].SIMMSize);
- if ( i == MAX_MEMS-1)
- len += sprintf(buffer+len,"\n");
- }
-
- /* TLB */
- len += sprintf(buffer+len,"TLB");
- switch(res.VitalProductData.TLBAttrib)
- {
- case CombinedTLB:
- len += sprintf(buffer+len,": %d entries\n",
- res.VitalProductData.TLBSize);
- break;
- case SplitTLB:
- len += sprintf(buffer+len,": (split I/D) %d/%d entries\n",
- res.VitalProductData.I_TLBSize,
- res.VitalProductData.D_TLBSize);
- break;
- case NoneTLB:
- len += sprintf(buffer+len,": not present\n");
- break;
- }
-
- /* L1 */
- len += sprintf(buffer+len,"L1: ");
- switch(res.VitalProductData.CacheAttrib)
- {
- case CombinedCAC:
- len += sprintf(buffer+len,"%dkB LineSize\n",
- res.VitalProductData.CacheSize,
- res.VitalProductData.CacheLineSize);
- break;
- case SplitCAC:
- len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
- res.VitalProductData.I_CacheSize,
- res.VitalProductData.D_CacheSize,
- res.VitalProductData.D_CacheLineSize,
- res.VitalProductData.D_CacheLineSize);
- break;
- case NoneCAC:
- len += sprintf(buffer+len,"not present\n");
- break;
- }
-
- /* L2 */
- if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
- {
- int size;
-
- len += sprintf(buffer+len,"L2: %dkB %s\n",
- ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
- (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
- }
- else
- {
- len += sprintf(buffer+len,"L2: not present\n");
- }
-#if 0
- len+= sprintf(buffer+len,"Equip register %x\n",
- inb(IBM_EQUIP_PRESENT));
- len+= sprintf(buffer+len,"L2Status register %x\n",
- inb(IBM_L2_STATUS));
-#endif
-#endif
-
-
- return len;
-}
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index ba8864251..2f602059c 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -1,9 +1,17 @@
/*
* linux/arch/ppc/kernel/signal.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Adapted for PowerPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/signal.c"
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * 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.
+ *
*/
#include <linux/sched.h>
@@ -22,6 +30,12 @@
#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
+#define DEBUG_SIGNALS
+#undef DEBUG_SIGNALS
+
+#define PAUSE_AFTER_SIGNAL
+#undef PAUSE_AFTER_SIGNAL
+
asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
/*
@@ -30,79 +44,85 @@ asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
asmlinkage int sys_sigsuspend(unsigned long set, int p2, int p3, int p4, int p6, int p7, struct pt_regs *regs)
{
unsigned long mask;
- int ret = -EINTR;
- lock_kernel();
+ spin_lock_irq(&current->sigmask_lock);
mask = current->blocked;
current->blocked = set & _BLOCKABLE;
+ spin_unlock_irq(&current->sigmask_lock);
+
regs->gpr[3] = -EINTR;
-#if 0
+#ifdef DEBUG_SIGNALS
printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set);
#endif
while (1) {
current->state = TASK_INTERRUPTIBLE;
schedule();
- if (do_signal(mask,regs))
- goto out;
+ if (do_signal(mask,regs)) {
+ /*
+ * If a signal handler needs to be called,
+ * do_signal() has set R3 to the signal number (the
+ * first argument of the signal handler), so don't
+ * overwrite that with EINTR !
+ * In the other cases, do_signal() doesn't touch
+ * R3, so it's still set to -EINTR (see above).
+ */
+ return regs->gpr[3];
+ }
}
-out:
- unlock_kernel();
- return ret;
}
+/*
+ * This sets regs->esp even though we don't actually use sigstacks yet..
+ */
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigcontext_struct *sc;
struct pt_regs *int_regs;
int signo, ret;
- lock_kernel();
#if 1
if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
- || (regs->gpr[1] >=KERNELBASE))
+ || (regs->gpr[1] >= KERNELBASE))
goto badframe;
#endif
- sc = (struct sigcontext_struct *)regs->gpr[1];
- current->blocked = sc->oldmask & _BLOCKABLE;
- int_regs = sc->regs;
- signo = sc->signal;
- sc++; /* Pop signal 'context' */
+ sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
+ get_user(current->blocked, &sc->oldmask);
+ current->blocked &= _BLOCKABLE;
+ get_user(int_regs, &sc->regs);
+ get_user(signo, &sc->signal);
+ sc++; /* Pop signal 'context' */
+#ifdef DEBUG_SIGNALS
+printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+#endif
if (sc == (struct sigcontext_struct *)(int_regs)) {
/* Last stacked signal */
-#if 0
- /* This doesn't work - it blows away the return address! */
memcpy(regs, int_regs, sizeof(*regs));
-#else
- /* Don't mess up 'my' stack frame */
- memcpy(&regs->gpr, &int_regs->gpr, sizeof(*regs)-sizeof(regs->_overhead));
-#endif
- if ((int)regs->orig_gpr3 >= 0 &&
+ if (regs->trap == 0x0C00 /* System Call! */ &&
((int)regs->result == -ERESTARTNOHAND ||
(int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR))
- {
+ (int)regs->result == -ERESTARTNOINTR)) {
regs->gpr[3] = regs->orig_gpr3;
regs->nip -= 4; /* Back up & retry system call */
regs->result = 0;
}
- ret = (regs->result);
- } else { /* More signals to go */
- regs->gpr[1] = (unsigned long)sc;
- regs->gpr[3] = sc->signal;
- regs->gpr[4] = sc->regs;
- regs->link = (unsigned long)((sc->regs)+1);
- regs->nip = sc->handler;
- ret = sc->signal;
+ ret = regs->result;
+ } else {
+ /* More signals to go */
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+ get_user(regs->gpr[3], &sc->signal);
+ get_user(int_regs, (struct pt_regs **) &sc->regs);
+ regs->gpr[4] = (unsigned long) int_regs;
+ regs->link = (unsigned long) (int_regs+1);
+ get_user(regs->nip, &sc->handler);
+ ret = regs->gpr[3];
}
- goto out;
+ return ret;
badframe:
- /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
- regs,current->comm,current->pid);*/
+ lock_kernel();
do_exit(SIGSEGV);
-out:
unlock_kernel();
- return ret;
+ return -EFAULT;
}
@@ -120,21 +140,24 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
unsigned long mask;
unsigned long handler_signal = 0;
unsigned long *frame = NULL;
- unsigned long *trampoline, *regs_ptr;
+ unsigned long *trampoline;
+ unsigned long *regs_ptr;
unsigned long nip = 0;
unsigned long signr;
struct sigcontext_struct *sc;
struct sigaction * sa;
- int bitno, s, ret;
+ int bitno;
- lock_kernel();
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
+#if 0
+ signr = ffz(~signr); /* Compute bit # */
+#else
for (bitno = 0; bitno < 32; bitno++)
if (signr & (1<<bitno))
break;
signr = bitno;
-
+#endif
current->signal &= ~(1<<signr); /* Clear bit */
sa = current->sig->action + signr;
signr++;
@@ -150,6 +173,8 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
continue;
if (_S(signr) & current->blocked) {
current->signal |= _S(signr);
+ spin_lock_irq(&current->sigmask_lock);
+ spin_unlock_irq(&current->sigmask_lock);
continue;
}
sa = current->sig->action + signr - 1;
@@ -169,32 +194,45 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
case SIGCONT: case SIGCHLD: case SIGWINCH:
continue;
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (is_orphaned_pgrp(current->pgrp))
+ continue;
+ case SIGSTOP:
if (current->flags & PF_PTRACED)
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ SA_NOCLDSTOP))
notify_parent(current);
schedule();
continue;
case SIGQUIT: case SIGILL: case SIGTRAP:
case SIGIOT: case SIGFPE: case SIGSEGV:
+ lock_kernel();
if (current->binfmt && current->binfmt->core_dump) {
if (current->binfmt->core_dump(signr, regs))
signr |= 0x80;
}
+ unlock_kernel();
/* fall through */
default:
+ spin_lock_irq(&current->sigmask_lock);
current->signal |= _S(signr & 0x7f);
+ spin_unlock_irq(&current->sigmask_lock);
+
+ current->flags |= PF_SIGNALED;
+
+ lock_kernel(); /* 8-( */
do_exit(signr);
+ unlock_kernel();
}
}
-
- /* handle signal */
- if ((int)regs->orig_gpr3 >= 0) {
+ /*
+ * OK, we're invoking a handler
+ */
+ if (regs->trap == 0x0C00 /* System Call! */) {
if ((int)regs->result == -ERESTARTNOHAND ||
((int)regs->result == -ERESTARTSYS &&
!(sa->sa_flags & SA_RESTART)))
@@ -203,9 +241,18 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
handler_signal |= 1 << (signr-1);
mask &= ~sa->sa_mask;
}
- ret = 0;
- if (!handler_signal) /* no handler will be called - return 0 */
- goto out;
+
+ if (regs->trap == 0x0C00 /* System Call! */ &&
+ ((int)regs->result == -ERESTARTNOHAND ||
+ (int)regs->result == -ERESTARTSYS ||
+ (int)regs->result == -ERESTARTNOINTR)) {
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4; /* Back up & retry system call */
+ regs->result = 0;
+ }
+
+ if (!handler_signal) /* no handler will be called - return 0 */
+ return 0;
nip = regs->nip;
frame = (unsigned long *) regs->gpr[1];
@@ -213,20 +260,18 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
/* Build trampoline code on stack */
frame -= 2;
trampoline = frame;
-#if 1
/* verify stack is valid for writing regs struct */
if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
- || (frame >= KERNELBASE ))
+ || ((unsigned long) frame >= KERNELBASE ))
goto badframe;
-#endif
- trampoline[0] = 0x38007777; /* li r0,0x7777 */
- trampoline[1] = 0x44000002; /* sc */
+ put_user(0x38007777UL, trampoline); /* li r0,0x7777 */
+ put_user(0x44000002UL, trampoline+1); /* sc */
frame -= sizeof(*regs) / sizeof(long);
regs_ptr = frame;
- memcpy(regs_ptr, regs, sizeof(*regs));
+ copy_to_user(regs_ptr, regs, sizeof(*regs));
signr = 1;
sa = current->sig->action;
-
+
for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
if (mask > handler_signal)
break;
@@ -234,50 +279,39 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
continue;
frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-#if 1
if (verify_area(VERIFY_WRITE,(void *)frame,
sizeof(struct sigcontext_struct)/sizeof(long)))
goto badframe;
-#endif
sc = (struct sigcontext_struct *)frame;
nip = (unsigned long) sa->sa_handler;
-#if 0 /* Old compiler */
- nip = *(unsigned long *)nip;
-#endif
if (sa->sa_flags & SA_ONESHOT)
sa->sa_handler = NULL;
- sc->handler = nip;
- sc->oldmask = current->blocked;
- sc->regs = (unsigned long)regs_ptr;
- sc->signal = signr;
+ put_user(nip, &sc->handler);
+ put_user(oldmask, &sc->oldmask); /* was current->blocked */
+ put_user(regs_ptr, &sc->regs);
+ put_user(signr, &sc->signal);
current->blocked |= sa->sa_mask;
regs->gpr[3] = signr;
regs->gpr[4] = (unsigned long)regs_ptr;
}
regs->link = (unsigned long)trampoline;
regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc;
+ regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
- /* The DATA cache must be flushed here to insure coherency
- * between the DATA & INSTRUCTION caches. Since we just
- * created an instruction stream using the DATA [cache] space
- * and since the instruction cache will not look in the DATA
- * cache for new data, we have to force the data to go on to
- * memory and flush the instruction cache to force it to look
- * there. The following function performs this magic
- */
- flush_instruction_cache();
- ret = 1;
- goto out;
+ /* The DATA cache must be flushed here to insure coherency */
+ /* between the DATA & INSTRUCTION caches. Since we just */
+ /* created an instruction stream using the DATA [cache] space */
+ /* and since the instruction cache will not look in the DATA */
+ /* cache for new data, we have to force the data to go on to */
+ /* memory and flush the instruction cache to force it to look */
+ /* there. The following function performs this magic */
+ store_cache_range((unsigned long) trampoline,
+ (unsigned long) (trampoline + 2));
+ return 1;
badframe:
-#if 0
- printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
- signr, frame, regs, current->comm, current->pid);
-#endif
+ lock_kernel();
do_exit(SIGSEGV);
-
-out:
unlock_kernel();
- return ret;
+ return 0;
}
diff --git a/arch/ppc/kernel/stubs.c b/arch/ppc/kernel/stubs.c
index 30f028279..e69de29bb 100644
--- a/arch/ppc/kernel/stubs.c
+++ b/arch/ppc/kernel/stubs.c
@@ -1,58 +0,0 @@
-/*#include <linux/in.h>*/
-#include <linux/autoconf.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-void sys_iopl(void)
-{
- lock_kernel();
- panic("sys_iopl");
- unlock_kernel();
-}
-void sys_vm86(void)
-{
- lock_kernel();
- panic("sys_vm86");
- unlock_kernel();
-}
-void sys_modify_ldt(void)
-{
- lock_kernel();
- panic("sys_modify_ldt");
- unlock_kernel();
-}
-
-void sys_ipc(void)
-{
- lock_kernel();
- panic("sys_ipc");
- unlock_kernel();
-}
-
-void sys_newselect(void)
-{
- lock_kernel();
- panic("sys_newselect");
- unlock_kernel();
-}
-
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
- lock_kernel();
- panic("scsi_register_module");
- unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
- lock_kernel();
- panic("scsi_unregister_module");
- unlock_kernel();
-}
-#endif
-
-
-
diff --git a/arch/ppc/kernel/support.c b/arch/ppc/kernel/support.c
index cd2b58b8a..e69de29bb 100644
--- a/arch/ppc/kernel/support.c
+++ b/arch/ppc/kernel/support.c
@@ -1,84 +0,0 @@
-/*
- * Miscellaneous support routines
- */
-
-#include <asm/bitops.h>
-
-/*extern __inline__*/ int find_first_zero_bit(void *add, int len)
-{
- int mask, nr, i;
- BITFIELD *addr = add;
- nr = 0;
- while (len)
- {
- if (~*addr != 0)
- { /* Contains at least one zero */
- for (i = 0; i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
- return (nr);
- }
- }
- }
- len -= 32;
- addr++;
- nr += 32;
- }
- return (0); /* Shouldn't happen */
-}
-
-/*extern __inline__*/ int find_next_zero_bit(void *add, int last_bit, int nr)
-{
- int mask, i;
- BITFIELD *addr = add;
-#if 0
-printk("Find next (%x, %x)", addr, nr);
-#endif
- addr += nr >> 5;
-#if 0
-printk(" - Pat: %x(%08X)\n", addr, *addr);
-#endif
- if ((nr & 0x1F) != 0)
- {
- if (*addr != 0xFFFFFFFF)
- { /* At least one more bit available in this longword */
- for (i = (nr&0x1F); i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
-#if 0
-printk("(1)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
- return (nr);
- }
- }
- }
- addr++;
- nr = (nr + 0x1F) & ~0x1F;
- }
- while (nr < last_bit)
- {
- if (*addr != 0xFFFFFFFF)
- { /* Contains at least one zero */
- for (i = 0; i < 32; i++, nr++)
- {
- mask = BIT(nr);
- if ((mask & *addr) == 0)
- {
-#if 0
-printk("(2)Bit: %x(%d), Pat: %x(%08x)\n", nr, nr&0x1F, addr, *addr);
-#endif
- return (nr);
- }
- }
- }
- addr++;
- nr += 32;
- }
- return (nr); /* Shouldn't happen */
-}
-
-
diff --git a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
index 9d18c45ab..bfdccdee6 100644
--- a/arch/ppc/kernel/syscalls.c
+++ b/arch/ppc/kernel/syscalls.c
@@ -9,6 +9,7 @@
* platform.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -19,105 +20,45 @@
#include <linux/shm.h>
#include <linux/stat.h>
#include <linux/mman.h>
+#include <linux/ipc.h>
#include <asm/uaccess.h>
+#include <asm/ipc.h>
-/*
- * sys_pipe() is the normal C calling standard for creating
- * a pipe. It's not the way unix traditionally does this, though.
- */
-asmlinkage int sys_pipe(unsigned long * fildes)
-{
- int error;
- lock_kernel();
- error = verify_area(VERIFY_WRITE,fildes,8);
- if (error)
- goto out;
- error = do_pipe(fildes);
-out:
- unlock_kernel();
- return error;
+void
+check_bugs(void)
+{
}
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, int prot,
- int flags, int fd, off_t offset)
+asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
{
- struct file * file = NULL;
- int ret = -EBADF;
+ printk("sys_ioperm()\n");
+ return -EIO;
+}
+int sys_iopl(int a1, int a2, int a3, int a4)
+{
lock_kernel();
- if (!(flags & MAP_ANONYMOUS)) {
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
- }
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- ret = do_mmap(file, addr, len, prot, flags, offset);
-out:
+ printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return ret;
+ return (ENOSYS);
}
-/*
- * Perform the select(nd, in, out, ex, tv) and mmap() system
- * calls. Linux/i386 didn't use to be able to handle more than
- * 4 system call parameters, so these system calls used a memory
- * block for parameter passing..
- */
-asmlinkage int old_mmap(unsigned long *buffer)
+int sys_vm86(int a1, int a2, int a3, int a4)
{
- int error;
- unsigned long flags;
- long a,b,c,d,e;
- struct file * file = NULL;
-
lock_kernel();
- error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
- if (error)
- goto out;
- get_user(flags,buffer+3);
- if (!(flags & MAP_ANONYMOUS)) {
- unsigned long fd;
- get_user(fd,buffer+4);
- error = -EBADF;
- if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
- goto out;
- }
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- error = -EFAULT;
- if ( get_user(a,buffer) || get_user(b,buffer+1) ||
- get_user(c,buffer+2)||get_user(d,buffer+5) )
- goto out;
- error = do_mmap(file,a,b,c, flags, d);
-out:
+ printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return error;
+ return (ENOSYS);
}
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
-
-asmlinkage int old_select(unsigned long *buffer)
+int sys_modify_ldt(int a1, int a2, int a3, int a4)
{
- int n;
- fd_set *inp;
- fd_set *outp;
- fd_set *exp;
- struct timeval *tvp;
-
lock_kernel();
- n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
- if (n)
- goto out;
- get_user(n,buffer);
- get_user(inp,buffer+1);
- get_user(outp,buffer+2);
- get_user(exp,buffer+3);
- get_user(tvp,buffer+4);
- n = sys_select(n, inp, outp, exp, tvp);
-out:
+ printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
unlock_kernel();
- return n;
+ return (ENOSYS);
}
-#if 0
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
@@ -145,12 +86,12 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
ret = -EINVAL;
if (!ptr)
goto out;
- if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))))
- goto out;
- fourth.__pad = (void *) get_fs_long(ptr);
+ ret = -EFAULT;
+ if (get_user(fourth.__pad, (void **) ptr))
+ goto out;
ret = sys_semctl (first, second, third, fourth);
goto out;
- }
+ }
default:
ret = -EINVAL;
goto out;
@@ -168,13 +109,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
ret = -EINVAL;
if (!ptr)
goto out;
- if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
- goto out;
- memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
- sizeof (tmp));
+ ret = -EFAULT;
+ if (copy_from_user(&tmp,(struct ipc_kludge *) ptr,
+ sizeof (tmp)))
+ goto out;
ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
goto out;
- }
+ }
case 1: default:
ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
goto out;
@@ -195,15 +136,12 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr,
switch (version) {
case 0: default: {
ulong raddr;
- if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, sizeof(ulong))))
- goto out;
ret = sys_shmat (first, (char *) ptr, second, &raddr);
if (ret)
goto out;
- put_fs_long (raddr, (ulong *) third);
- ret = 0;
+ ret = put_user (raddr, (ulong *) third);
goto out;
- }
+ }
case 1: /* iBCS2 emulator entry point */
ret = -EINVAL;
if (get_fs() != get_ds())
@@ -230,4 +168,81 @@ out:
unlock_kernel();
return ret;
}
+
+
+#ifndef CONFIG_MODULES
+void
+scsi_register_module(void)
+{
+ lock_kernel();
+ panic("scsi_register_module");
+ unlock_kernel();
+}
+
+void
+scsi_unregister_module(void)
+{
+ lock_kernel();
+ panic("scsi_unregister_module");
+ unlock_kernel();
+}
#endif
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long * fildes)
+{
+ int fd[2];
+ int error;
+
+ error = verify_area(VERIFY_WRITE,fildes,8);
+ if (error)
+ return error;
+ error = do_pipe(fd);
+ if (error)
+ return error;
+ put_user(fd[0],0+fildes);
+ put_user(fd[1],1+fildes);
+ return 0;
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, off_t offset)
+{
+ struct file * file = NULL;
+ if (!(flags & MAP_ANONYMOUS)) {
+ if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ return -EBADF;
+ }
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+
+ return do_mmap(file, addr, len, prot, flags, offset);
+}
+
+extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+
+/*
+ * Due to some executables calling the wrong select we sometimes
+ * get wrong args. This determines how the args are being passed
+ * (a single ptr to them all args passed) then calls
+ * sys_select() with the appropriate args. -- Cort
+ */
+asmlinkage int
+ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
+{
+ int err;
+ if ( (unsigned long)n >= 4096 )
+ {
+ unsigned long *buffer = (unsigned long *)n;
+ if ( get_user(n, buffer) ||
+ get_user(inp,buffer+1) ||
+ get_user(outp,buffer+2) ||
+ get_user(exp,buffer+3) ||
+ get_user(tvp,buffer+4) )
+ return -EFAULT;
+ }
+ return sys_select(n, inp, outp, exp, tvp);
+}
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index cdcad8204..e69de29bb 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -1,465 +0,0 @@
-/*
- * linux/arch/i386/kernel/time.c
- *
- * Copyright (C) 1991, 1992, 1995 Linus Torvalds
- *
- * Adapted for PowerPC (PreP) by Gary Thomas
- *
- * This file contains the PC-specific time handling details:
- * reading the RTC at bootup, etc..
- * 1994-07-02 Alan Modra
- * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
- * 1995-03-26 Markus Kuhn
- * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
- * precision CMOS clock update
- */
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/nvram.h>
-#include <asm/mc146818rtc.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-#include <linux/config.h>
-
-extern int isBeBox[];
-
-#define TIMER_IRQ 0
-
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
-
-static inline int CMOS_READ(int addr)
-{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- return (inb(NVRAM_DATA));
-}
-
-static inline int CMOS_WRITE(int addr, int val)
-{
- outb(addr>>8, NVRAM_AS1);
- outb(addr, NVRAM_AS0);
- return (outb(val, NVRAM_DATA));
-}
-
-/* This function must be called with interrupts disabled
- * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
- *
- * However, the pc-audio speaker driver changes the divisor so that
- * it gets interrupted rather more often - it loads 64 into the
- * counter rather than 11932! This has an adverse impact on
- * do_gettimeoffset() -- it stops working! What is also not
- * good is that the interval that our timer function gets called
- * is no longer 10.0002 ms, but 9.9767 ms. To get around this
- * would require using a different timing source. Maybe someone
- * could use the RTC - I know that this can interrupt at frequencies
- * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
- * it so that at startup, the timer code in sched.c would select
- * using either the RTC or the 8253 timer. The decision would be
- * based on whether there was any other device around that needed
- * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
- * and then do some jiggery to have a version of do_timer that
- * advanced the clock by 1/1024 s. Every time that reached over 1/100
- * of a second, then do all the old code. If the time was kept correct
- * then do_gettimeoffset could just return 0 - there is no low order
- * divider that can be accessed.
- *
- * Ideally, you would be able to use the RTC for the speaker driver,
- * but it appears that the speaker driver really needs interrupt more
- * often than every 120 us or so.
- *
- * Anyway, this needs more thought.... pjsg (1993-08-28)
- *
- * If you are really that interested, you should be reading
- * comp.protocols.time.ntp!
- */
-
-#define TICK_SIZE tick
-
-static unsigned long do_slow_gettimeoffset(void)
-{
- int count;
- unsigned long offset = 0;
-
- /* timer count may underflow right here */
- outb_p(0x00, 0x43); /* latch the count ASAP */
- count = inb_p(0x40); /* read the latched count */
- count |= inb(0x40) << 8;
- /* we know probability of underflow is always MUCH less than 1% */
- if (count > (LATCH - LATCH/100)) {
- /* check for pending timer interrupt */
- outb_p(0x0a, 0x20);
- if (inb(0x20) & 1)
- offset = TICK_SIZE;
- }
- count = ((LATCH-1) - count) * TICK_SIZE;
- count = (count + LATCH/2) / LATCH;
- return offset + count;
-}
-
-static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
-{
- cli();
- /* This is revolting. We need to set the xtime.tv_usec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
- tv->tv_usec -= do_gettimeoffset();
-
- if (tv->tv_usec < 0) {
- tv->tv_usec += 1000000;
- tv->tv_sec--;
- }
-
- xtime = *tv;
- time_state = TIME_BAD;
- time_maxerror = 0x70000000;
- time_esterror = 0x70000000;
- set_rtc(xtime.tv_sec);
- sti();
-}
-
-static int month_days[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define FEBRUARY 2
-#define STARTOFTIME 1970
-#define SECDAY 86400L
-#define SECYR (SECDAY * 365)
-#define leapyear(year) ((year) % 4 == 0)
-#define days_in_year(a) (leapyear(a) ? 366 : 365)
-#define days_in_month(a) (month_days[(a) - 1])
-
-struct _tm
-{
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_day;
- int tm_month;
- int tm_year;
-};
-
-static _to_tm(int tim, struct _tm * tm)
-{
- register int i;
- register long hms, day;
-
- day = tim / SECDAY;
- hms = tim % SECDAY;
-
- /* Hours, minutes, seconds are easy */
- tm->tm_hour = hms / 3600;
- tm->tm_min = (hms % 3600) / 60;
- tm->tm_sec = (hms % 3600) % 60;
-
- /* Number of years in days */
- for (i = STARTOFTIME; day >= days_in_year(i); i++)
- day -= days_in_year(i);
- tm->tm_year = i;
-
- /* Number of months in days left */
- if (leapyear(tm->tm_year))
- days_in_month(FEBRUARY) = 29;
- for (i = 1; day >= days_in_month(i); i++)
- day -= days_in_month(i);
- days_in_month(FEBRUARY) = 28;
- tm->tm_month = i;
-
- /* Days are what is left over (+1) from all that. */
- tm->tm_day = day + 1;
-}
-
-/*
- * Set the time into the CMOS
- */
-static void set_rtc(unsigned long nowtime)
-{
- int retval = 0;
- struct _tm tm;
- unsigned char save_control, save_freq_select;
-
- /*if (_Processor != _PROC_IBM) return;*/
-
- _to_tm(nowtime, &tm);
-
- /* tell the clock it's being set */
- save_control = CMOS_MCRTC_READ(MCRTC_CONTROL);
- CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
- /* stop and reset prescaler */
- save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT);
- CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
- printk("Set RTC H:M:S M/D/Y %d:%02d:%02d %d/%d/%d\n",
- tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_month, tm.tm_day, tm.tm_year);
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
- BIN_TO_BCD(tm.tm_sec);
- BIN_TO_BCD(tm.tm_min);
- BIN_TO_BCD(tm.tm_hour);
- BIN_TO_BCD(tm.tm_month);
- BIN_TO_BCD(tm.tm_day);
- BIN_TO_BCD(tm.tm_year);
- }
-
- CMOS_MCRTC_WRITE(tm.tm_sec, MCRTC_SECONDS);
- CMOS_MCRTC_WRITE(tm.tm_min, MCRTC_MINUTES);
- CMOS_MCRTC_WRITE(tm.tm_hour, MCRTC_HOURS);
- CMOS_MCRTC_WRITE(tm.tm_month, MCRTC_MONTH);
- CMOS_MCRTC_WRITE(tm.tm_day, MCRTC_MINUTES);
- CMOS_MCRTC_WRITE(tm.tm_year - 1900, MCRTC_MINUTES);
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
- CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- */
-static int set_rtc_mmss(unsigned long nowtime)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- unsigned char save_control, save_freq_select;
-
-#ifdef __powerpc__
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
-return (-1); /* Not implemented */
-#else
-
-printk("%s: %d - set TOD\n", __FILE__, __LINE__);
- save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); /* tell the clock it's being set */
- CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
-
- save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT); /* stop and reset prescaler */
- CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
-
- cmos_minutes = CMOS_MCRTC_READ(MCRTC_MINUTES);
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD)
- BCD_TO_BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- }
- CMOS_MCRTC_WRITE(real_seconds,MCRTC_SECONDS);
- CMOS_MCRTC_WRITE(real_minutes,MCRTC_MINUTES);
- } else
- retval = -1;
-
- /* The following flags have to be released exactly in this order,
- * otherwise the DS12887 (popular MC146818A clone with integrated
- * battery and quartz) will not reset the oscillator and will not
- * update precisely 500 ms later. You won't find this mentioned in
- * the Dallas Semiconductor data sheets, but who believes data
- * sheets anyway ... -- Markus Kuhn
- */
- CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
- CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
-
- return retval;
-#endif
-}
-
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
-{
- static int timeints = 0;
-
- do_timer(regs);
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- */
- if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
- xtime.tv_usec > 500000 - (tick >> 1) &&
- xtime.tv_usec < 500000 + (tick >> 1))
- if (set_rtc_mmss(xtime.tv_sec) == 0)
- last_rtc_update = xtime.tv_sec;
- else
- last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-
-
- /* use hard disk LED as a heartbeat instead -- much more useful
- -- Cort */
- switch(timeints)
- {
- /* act like an actual heart beat -- ie thump-thump-pause... */
- case 0:
- case 20:
- hard_disk_LED(1);
- break;
- case 7:
- case 27:
- hard_disk_LED(0);
- break;
- case 100:
- timeints = -1;
- break;
- }
- timeints++;
-}
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
- unsigned int day, unsigned int hour,
- unsigned int min, unsigned int sec)
-{
- if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
- mon += 12; /* Puts Feb last since it has leap day */
- year -= 1;
- }
- return (((
- (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
- year*365 - 719499
- )*24 + hour /* now have hours */
- )*60 + min /* now have minutes */
- )*60 + sec; /* finally seconds */
-}
-
-unsigned long get_cmos_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- int i;
-
- if (_Processor == _PROC_IBM)
- {
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
- min = CMOS_MCRTC_READ(MCRTC_MINUTES);
- hour = CMOS_MCRTC_READ(MCRTC_HOURS);
- day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
- mon = CMOS_MCRTC_READ(MCRTC_MONTH);
- year = CMOS_MCRTC_READ(MCRTC_YEAR);
- } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- } else
- if (_Processor == _PROC_Be)
- {
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
- min = CMOS_MCRTC_READ(MCRTC_MINUTES);
- hour = CMOS_MCRTC_READ(MCRTC_HOURS);
- day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
- mon = CMOS_MCRTC_READ(MCRTC_MONTH);
- year = CMOS_MCRTC_READ(MCRTC_YEAR);
- } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
- } else
- { /* Motorola PowerStack etc. */
- do { /* Isn't this overkill ? UIP above should guarantee consistency */
- sec = CMOS_READ(RTC_SECONDS);
- min = CMOS_READ(RTC_MINUTES);
- hour = CMOS_READ(RTC_HOURS);
- day = CMOS_READ(RTC_DAY_OF_MONTH);
- mon = CMOS_READ(RTC_MONTH);
- year = CMOS_READ(RTC_YEAR);
- } while (sec != CMOS_READ(RTC_SECONDS));
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- }
-#if 0
-printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
-#endif
- if ((year += 1900) < 1970)
- year += 100;
- return mktime(year, mon, day, hour, min, sec);
-}
-
-void time_init(void)
-{
- void (*irq_handler)(int, struct pt_regs *);
- xtime.tv_sec = get_cmos_time();
- xtime.tv_usec = 0;
-
- /* If we have the CPU hardware time counters, use them */
- irq_handler = timer_interrupt;
- if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
- panic("Could not allocate timer IRQ!");
-}
-
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index a637e0acb..84ce1c5ca 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -20,14 +20,14 @@
#include <linux/malloc.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
#include <asm/pgtable.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/ppc_machine.h>
-
/*
* Trap & Exception support
*/
@@ -40,122 +40,98 @@ trap_init(void)
void
_exception(int signr, struct pt_regs *regs)
{
- /* dump_regs(regs);*/
- force_sig(signr, current);
- if (!user_mode(regs))
- {
- printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
- while (1) ;
- }
+ if (!user_mode(regs))
+ {
+ show_regs(regs);
+ print_backtrace(regs->gpr[1]);
+ panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+ }
+ force_sig(signr, current);
}
MachineCheckException(struct pt_regs *regs)
{
- printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
- _exception(SIGSEGV, regs);
-}
-
-ProgramCheckException(struct pt_regs *regs)
-{
-#if 0
- printk("Program check at PC: %x[%x], SR: %x\n",
- regs->nip, va_to_phys(regs->nip), regs->msr);
- #endif
- if (current->flags & PF_PTRACED)
- {
- _exception(SIGTRAP, regs);
- } else
- {
- _exception(SIGILL, regs);
- }
+ if ( !user_mode(regs) )
+ {
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from msr): ");
+ printk("regs %08x ",regs);
+ switch( regs->msr & 0x0000F000)
+ {
+ case (1<<12) :
+ printk("Machine check signal - probably due to mm fault\n"
+ "with mmu off\n");
+ break;
+ case (1<<13) :
+ printk("Transfer error ack signal\n");
+ break;
+ case (1<<14) :
+ printk("Data parity signal\n");
+ break;
+ case (1<<15) :
+ printk("Address parity signal\n");
+ break;
+ default:
+ printk("Unknown values in msr\n");
+ }
+ show_regs(regs);
+ print_backtrace(regs->gpr[1]);
+ panic("");
+ }
+ _exception(SIGSEGV, regs);
}
-SingleStepException(struct pt_regs *regs)
+void
+UnknownException(struct pt_regs *regs)
{
- regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+ printk("Bad trap at PC: %lx, SR: %lx, vector=%lx\n",
+ regs->nip, regs->msr, regs->trap);
_exception(SIGTRAP, regs);
}
-FloatingPointCheckException(struct pt_regs *regs)
+void
+InstructionBreakpoint(struct pt_regs *regs)
{
- /* if fpu already on -- then exception was generated by an error */
- if ( (unsigned long)(regs->msr) & (unsigned long)MSR_FP )
- {
- _exception(SIGFPE, regs);
- return 0;
- }
-
-#if 0
- printk("fpu off -- turning on: %s pc %x fpscr %x msr %x ksp %x r1 %x\n",
- current->comm,regs->nip,regs->fpcsr,regs->msr,regs,regs->gpr[1]);
+#ifdef CONFIG_XMON
+ if (xmon_iabr_match(regs))
+ return;
#endif
-
- /* if the fpu is off then turn it on and return */
- regs->msr |= MSR_FP;
- current->tss.fp_used++;
- /* tells return_from_int to restore fp regs since fp was turned on
- see head.S -- Cort */
- return MSR_FP;
+ _exception(SIGTRAP, regs);
}
-AlignmentException(struct pt_regs *regs)
+void
+RunModeException(struct pt_regs *regs)
{
-/* printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr);
- dump_regs(regs);
- printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
- _exception(SIGBUS, regs);
+ _exception(SIGTRAP, regs);
}
+ProgramCheckException(struct pt_regs *regs)
+{
+ if (current->flags & PF_PTRACED)
+ _exception(SIGTRAP, regs);
+ else
+ _exception(SIGILL, regs);
+}
-/* see CHECK_STACK macro in head.S for argument definitions */
-bad_stack(unsigned int r3, unsigned int r4, unsigned int r5, unsigned int r6)
+SingleStepException(struct pt_regs *regs)
{
- /* r6 (was r1) kernel stack pointer */
- /* r5 (was r2) kernel stack page */
- /* r4 kernel stack magic */
- /* r3 stack magic or ksp masked to page boundary */
- printk("bad_stack(): Kernel stack bad.\n");
- printk("ksp %x kpage %x stack magic %x r3 %x\n",
- r6,r5,r4,r3);
- printk("current: %s/%d\n",
- current->comm,current->pid);
- while(1);
+ regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */
+ _exception(SIGTRAP, regs);
}
-dump_regs(struct pt_regs *regs)
+AlignmentException(struct pt_regs *regs)
{
- int i;
- printk("NIP: %08X, MSR: %08X, XER: %08X, LR: %08X, FRAME: %08X\n", regs->nip, regs->msr, regs->xer, regs->link, regs);
-#if 0
- printk("HASH = %08X/%08X, MISS = %08X/%08X, CMP = %08X/%08X\n", regs->hash1, regs->hash2, regs->imiss, regs->dmiss, regs->icmp, regs->dcmp);
-#endif
- printk("TASK = %x[%d] '%s'\n", current, current->pid, current->comm);
- for (i = 0; i < 32; i++)
- {
- if ((i % 8) == 0)
- {
- printk("GPR%02d: ", i);
- }
- printk("%08X ", regs->gpr[i]);
- if ((i % 8) == 7)
- {
- printk("\n");
- }
- }
-#if 0
- if (regs->nip >= 0x1000)
- dump_buf(regs->nip-32, 64);
- dump_buf((regs->nip&0x0FFFFFFF)|KERNELBASE, 32);
-#endif
+ _exception(SIGBUS, regs);
}
trace_syscall(struct pt_regs *regs)
{
static int count;
- printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n", current, current->pid, regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
+ printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+ current, current->pid, regs->nip, regs->link, regs->gpr[0],
+ regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
if (++count == 20)
{
count = 0;
}
}
-
diff --git a/arch/ppc/kernel/usercpy.c b/arch/ppc/kernel/usercpy.c
index 7ef0f2280..e69de29bb 100644
--- a/arch/ppc/kernel/usercpy.c
+++ b/arch/ppc/kernel/usercpy.c
@@ -1,116 +0,0 @@
-#include <linux/types.h>
-#include <asm/string.h>
-#include <asm/errno.h>
-#include <linux/sched.h>
-
-/*
- * bad data accesses from these functions should be handled specially
- * since they are to user areas and may or may not be valid.
- * on error -EFAULT should be returned. -- Cort
- */
-int __copy_tofrom_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-
-int __copy_tofrom_user(unsigned long to, unsigned long from, int size)
-{
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__copy_tofrom_user_failure;
-
- if (memcpy( (void *)to, (void *)from, (size_t) size) == -EFAULT )
- {
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return -EFAULT;
- }
- current->tss.excount = 0;
- return 0; /* successful return */
-}
-
-/* Just like strncpy except in the return value:
- *
- * -EFAULT if an exception occurs before the terminator is copied.
- * N if the buffer filled.
- *
- * Otherwise the length of the string is returned.
- */
-asmlinkage int __strncpy_from_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-
-int __strncpy_from_user(unsigned long dest, unsigned long src, int count)
-{
- int i = 0;
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__strncpy_from_user_failure;
-
- while ( i != count )
- {
- *(char *)(dest+i) = *(char *)(src+i);
- if ( *(char *)(src+i) == 0 )
- {
- return i;
- }
- i++;
- }
- *(char *)(dest+i) = (char)0;
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return i;
-}
-
-int __clear_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-int __clear_user(unsigned long addr, int size)
-{
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )__clear_user_failure;
-
- if ((int)memset((void *)addr,(int)0, (__kernel_size_t)size) == -EFAULT )
- {
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return -EFAULT;
- }
- /* take down exception handler stuff */
- current->tss.excount = 0;
- return size;
-}
-
-/*
- * Return the length of the string including the NUL terminator
- * (strlen+1) or zero if an error occured.
- */
-size_t strlen_user_failure(void)
-{
- current->tss.excount = 0;
- return -EFAULT;
-}
-size_t strlen_user(char * s)
-{
- size_t i;
- /* setup exception handling stuff */
- current->tss.excount++;
- current->tss.expc = (unsigned long )strlen_user_failure;
-
- i = strlen(s)+1;
-
- if ( i == -EFAULT)
- return -EFAULT;
-
- /* take down exception handler stuff */
- current->tss.excount = 0;
-
- return(i);
-}
-
diff --git a/arch/ppc/ld.script b/arch/ppc/ld.script
index 319292840..ab5b070db 100644
--- a/arch/ppc/ld.script
+++ b/arch/ppc/ld.script
@@ -31,12 +31,16 @@ SECTIONS
.text :
{
*(.text)
- *(.rodata)
- *(.rodata1)
+ *(.fixup)
*(.got1)
}
_etext = .;
PROVIDE (etext = .);
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
.fini : { *(.fini) } =0
.ctors : { *(.ctors) }
.dtors : { *(.dtors) }
@@ -45,31 +49,33 @@ SECTIONS
.data :
{
*(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt) *(.got)
+ *(.dynamic)
CONSTRUCTORS
}
- .data1 : { *(.data1) }
- .got : { *(.got.plt) *(.got) }
- .dynamic : { *(.dynamic) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata : { *(.sdata) }
_edata = .;
+/*
+ . = ALIGN(4096);
+ __init_begin = .;
+ .text.init : { *(.text.init) }
+ .data.init : { *(.data.init) }
+ . = ALIGN(4096);
+ __init_end = .;
+*/
+ __bss_start = .; /* BSS */
PROVIDE (edata = .);
__bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
.bss :
{
+ *(.sbss) *(.scommon)
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
- /* These are needed for ELF backends which have not yet been
- converted to the new style linker. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- /* These must appear regardless of . */
}
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index baace0862..68b33f047 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -1,12 +1,38 @@
-#
-# Makefile for i386-specific library files..
-#
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) $(ASFLAGS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+.S.s:
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+.S.o:
+ $(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
+ $(AS) $(ASFLAGS) -o $*.o $*.s
+ rm $*.s
+
+HOST_CC = gcc
L_TARGET = lib.o
-L_OBJS = checksum.o cksum_support.o
-CC = gcc -I$(TOPDIR)/include
+L_OBJS = checksum.o cksum_support.o string.o
${L_TARGET}: $(L_OBJS)
$(LD) -r -o ${L_TARGET} $(L_OBJS)
+
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
+
+dep:
+ $(CPP) -M *.S *.c > .depend
+
+modules:
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
index ac6ef0213..13aeab6ca 100644
--- a/arch/ppc/mm/Makefile
+++ b/arch/ppc/mm/Makefile
@@ -14,7 +14,7 @@
.c.s:
$(CC) $(CFLAGS) -S $<
-OBJS = fault.o init.o
+OBJS = fault.o init.o extable.o
mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS)
@@ -22,9 +22,9 @@ mm.o: $(OBJS)
modules:
dep:
- $(CPP) -M *.c > .depend
-
+
fastdep:
+ $(TOPDIR)/scripts/mkdep *.[Sch] > .depend
#
# include a dependency file if one exists
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 7104d6bbb..fea722780 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -1,9 +1,14 @@
/*
- * ARCH/ppc/mm/fault.c
+ * arch/ppc/mm/fault.c
*
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
* Ported to PPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * Modified by Cort Dougan and Paul Mackerras.
+ *
+ * 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.
*/
#include <linux/config.h>
@@ -17,132 +22,151 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
-extern void die_if_kernel(char *, struct pt_regs *, long);
-extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void new_page_fault(unsigned long address, unsigned long code, unsigned long text,
- struct pt_regs *regs);
-
+#ifdef CONFIG_PMAC
+extern void (*xmon_fault_handler)(void);
+#endif
-#undef SHOW_FAULTS
-#undef NOISY_INSTRFAULT
-#undef NOISY_DATAFAULT
+/* the linux norm for the function name is show_regs() so
+ make it call dump_regs() on the mac -- Cort */
+#ifdef CONFIG_PMAC
+#define show_regs dump_regs
+#endif
-unsigned int probingmem = 0;
-#define NEWMM 1
+extern void die_if_kernel(char *, struct pt_regs *, long);
+void bad_page_fault(struct pt_regs *, unsigned long);
+void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+void print_pte(struct _PTE);
-void new_page_fault(unsigned long address, unsigned long ppc_code,
- unsigned long text, struct pt_regs *regs)
+void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
{
- struct vm_area_struct * vma;
- struct mm_struct *mm = current->mm;
-
- int intel_code = 0;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*
- * bit 0 == 0 means no page found, 1 means protection fault
- * bit 1 == 0 means read, 1 means write
- * bit 2 == 0 means kernel, 1 means user-mode
- */
- if (user_mode(regs)) intel_code |= 0x04;
- if (!text && (ppc_code & 0x02000000)) intel_code |= 0x02; /* Load/store */
- if (!text && (ppc_code & 0x08000000))
- {
- intel_code |= 0x01; /* prot viol */
- goto do_page;
- }
-
- dir = pgd_offset(mm, address & PAGE_MASK);
- if (dir)
- {
- pmd = pmd_offset(dir, address & PAGE_MASK);
- if (pmd && pmd_present(*pmd))
- {
- pte = pte_offset(pmd, address & PAGE_MASK);
- if (pte && pte_present(*pte))
- {
- MMU_hash_page(&current->tss, address & PAGE_MASK, pte);
- return;
- }
- }
- }
-
+ struct task_struct *tsk = current;
+ extern unsigned _end[];
+ struct vm_area_struct * vma;
+ struct mm_struct *mm = current->mm;
+ pgd_t *dir;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
+ current->comm,current->pid,address,regs->nip,regs,error_code);*/
+#ifdef CONFIG_PMAC
+ if (xmon_fault_handler && regs->trap == 0x300) {
+ xmon_fault_handler();
+ return;
+ }
+#endif
+ if (in_interrupt()) {
+ static int complained;
+ if (complained < 20) {
+ ++complained;
+ printk("page fault in interrupt handler, addr=%lx\n",
+ address);
+ show_regs(regs);
+ }
+ }
+ if (current == NULL)
+ goto bad_area;
+
do_page:
- down(&mm->mmap_sem);
- vma = find_vma(current->mm, address);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
+ down(&mm->mmap_sem);
+ vma = find_vma(tsk->mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
good_area:
- /* a write */
- if (intel_code & 2) {
- if (!(vma->vm_flags & VM_WRITE))
- {
- goto bad_area;
- }
- /* a read */
- } else {
- /* protection fault */
- if (intel_code & 1)
- {
- printk("prot fault\n");
- goto bad_area;
- }
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- {
- printk("no read or exec\n");
- goto bad_area;
- }
- }
- handle_mm_fault(vma, address, intel_code & 2);
- up(&mm->mmap_sem); flush_page(address); /* Flush & Invalidate cache - note: address is OK now */
- return;
+ if (error_code & 0xb5700000)
+ /* an error such as lwarx to I/O controller space,
+ address matching DABR, eciwx, etc. */
+ goto bad_area;
+
+ /* a write */
+ if (error_code & 0x02000000) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ /* a read */
+ } else {
+ /* protection fault */
+ if ( error_code & 0x08000000 )
+ goto bad_area;
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ handle_mm_fault(current, vma, address, error_code & 0x02000000);
+ up(&mm->mmap_sem);
+ /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
+ current->comm,current->pid,address,regs->msr);*/
+ /* not needed since flush_page_to_ram() works */
+#if 0
+ flush_page(address);
+#endif
+ return;
bad_area:
- up(&mm->mmap_sem);
+ up(&current->mm->mmap_sem);
+ bad_page_fault(regs, address);
+}
+
+
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address)
+{
+ extern unsigned int probingmem;
+ struct task_struct *tsk = current;
+ unsigned long fixup;
+
+
+ /* Are we prepared to handle this fault? */
+ if ((fixup = search_exception_table(regs->nip)) != 0) {
+ if ( user_mode(regs) )
+ printk("Exception from user mode\n");
+#if 0
+ printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
+#endif
+ regs->nip = fixup;
+ return;
+ }
- /* Did we have an exception handler installed? */
- if(current->tss.excount != 0) {
- if(user_mode(regs)) {
- printk("Exception signalled from user mode!\n");
- } else {
-#if 0
- printk("Exception from kernel mode. pc %x expc %x count %d\n",
- regs->nip,current->tss.expc,current->tss.excount);
-#endif
- current->tss.excount = 0;
- regs->gpr[3] = -EFAULT;
- regs->nip = current->tss.expc;
- return;
- }
- }
+ if ( user_mode(regs) )
+ {
+ force_sig(SIGSEGV, tsk);
+ return;
+ }
- if (user_mode(regs))
- {
- force_sig(SIGSEGV, current);
- return;
- }
- panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
- regs->nip,address,vma->vm_flags);
+bad_kernel_access:
+ /* make sure it's not a bootup probe test */
+ if ( probingmem )
+ {
+ probingmem = 0;
+ return;
+ }
+ /* kernel has accessed a bad area */
+ show_regs(regs);
+ print_backtrace( regs->gpr[1] );
+#ifdef CONFIG_PMAC
+ xmon(regs);
+#endif
+ panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
+ regs->nip,address,tsk->comm,tsk->pid);
}
-va_to_phys(unsigned long address)
+unsigned long va_to_phys(unsigned long address)
{
pgd_t *dir;
pmd_t *pmd;
pte_t *pte;
+
dir = pgd_offset(current->mm, address & PAGE_MASK);
if (dir)
{
@@ -165,8 +189,28 @@ va_to_phys(unsigned long address)
return (0);
}
-inline void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t _pte)
+void print_pte(struct _PTE p)
{
- MMU_hash_page(&current->tss, address & PAGE_MASK, (pte *)&_pte);
+ printk(
+"%08x %08x vsid: %06x h: %01x api: %02x rpn: %05x rcwimg: %d%d%d%d%d%d pp: %02x\n",
+ *((unsigned long *)(&p)), *((long *)&p+1),
+ p.vsid, p.h, p.api, p.rpn,
+ p.r,p.c,p.w,p.i,p.m,p.g,p.pp);
+}
+
+/*
+ * Search the hw hash table for a mapping to the given physical
+ * address. -- Cort
+ */
+unsigned long htab_phys_to_va(unsigned long address)
+{
+ extern PTE *Hash, *Hash_end;
+ PTE *ptr;
+
+ for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
+ {
+ if ( ptr->rpn == (address>>12) )
+ printk("phys %08X -> va ???\n",
+ address);
+ }
}
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index ee2381dba..d46975996 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -1,9 +1,21 @@
/*
* arch/ppc/mm/init.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
- * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ * and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ * Copyright (C) 1996 Paul Mackerras
+ *
+ * Derived from "arch/i386/mm/init.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
+ * 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.
+ *
*/
#include <linux/config.h>
@@ -18,57 +30,354 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
+#include <linux/stddef.h>
+#ifdef CONFIG_PMAC
+#include <asm/prom.h>
+#endif
+#include <asm/io.h>
+#include <asm/mmu_context.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#ifdef CONFIG_PREP
#include <asm/residual.h>
+#endif
-extern pgd_t swapper_pg_dir[1024];
-extern unsigned long empty_zero_page[1024];
+int next_mmu_context;
+extern pgd_t swapper_pg_dir[];
+extern char _start[], _end[];
+extern char etext[], _stext[];
+/* References to section boundaries */
+extern char __init_begin, __init_end;
extern void die_if_kernel(char *,struct pt_regs *,long);
extern void show_net_buffers(void);
-void flush_hash_table(void);
+extern unsigned long *find_end_of_memory(void);
-#undef HASHSTATS
+#undef MAP_RAM_WITH_SEGREGS 1
-unsigned long _SDR1; /* Hardware SDR1 image */
-PTE *Hash;
-int Hash_size, Hash_mask;
+#ifdef CONFIG_PMAC
+void *find_mem_piece(unsigned, unsigned);
+static void mapin_ram(void);
+static void inherit_prom_translations(void);
+#endif
+#ifdef CONFIG_PREP
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
+int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);
+#endif
+
+static void hash_init(void);
+static void *MMU_get_page(void);
+void map_page(struct thread_struct *, unsigned long va,
+ unsigned long pa, int flags);
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
unsigned long *end_of_DRAM;
-int cache_is_copyback = 1;
-int kernel_pages_are_copyback = 1;
-/* Note: these need to be in 'data' so they live over the boot */
-unsigned char *BeBox_IO_page = 0;
-unsigned long isBeBox[2] = {0, 0};
+int mem_init_done;
+#ifdef CONFIG_PREP
#ifdef HASHSTATS
-extern unsigned long *hashhits;
-#endif
-
+extern unsigned long evicts;
+#endif /* HASHSTATS */
+/*
+ * these are used to setup the initial page tables
+ * They can waste up to an entire page since the
+ * I'll fix this shortly -- Cort
+ */
+#define MAX_MMU_PAGES 16
+unsigned int probingmem = 0;
+unsigned int mmu_pages_count = 0;
+char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
+unsigned long _TotalMemory;
+#endif /* CONFIG_PREP */
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+unsigned long empty_bad_page_table;
pte_t * __bad_pagetable(void)
{
- panic("__bad_pagetable");
+ memset((void *)empty_bad_page_table, 0, PAGE_SIZE);
+ return (pte_t *) empty_bad_page_table;
}
+unsigned long empty_bad_page;
+
pte_t __bad_page(void)
{
- panic("__bad_page");
+ memset((void *)empty_bad_page, 0, PAGE_SIZE);
+ return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
+}
+
+#ifdef CONFIG_PMAC
+#define MAX_MEM_REGIONS 32
+phandle memory_pkg;
+
+struct mem_pieces {
+ int n_regions;
+ struct reg_property regions[MAX_MEM_REGIONS];
+};
+
+struct mem_pieces phys_mem;
+struct mem_pieces phys_avail;
+struct mem_pieces prom_mem;
+
+static void get_mem_prop(char *, struct mem_pieces *);
+static void remove_mem_piece(struct mem_pieces *, unsigned, unsigned, int);
+static void print_mem_pieces(struct mem_pieces *);
+
+unsigned long avail_start;
+int prom_trashed;
+
+/*
+ * Read in a property describing some pieces of memory.
+ */
+static void
+get_mem_prop(char *name, struct mem_pieces *mp)
+{
+ int s, i;
+
+ s = (int) call_prom("getprop", 4, 1, memory_pkg, name,
+ mp->regions, sizeof(mp->regions));
+ if (s < sizeof(mp->regions[0])) {
+ printk("getprop /memory %s returned %d\n", name, s);
+ abort();
+ }
+ mp->n_regions = s / sizeof(mp->regions[0]);
+
+ /*
+ * Make sure the pieces are sorted.
+ */
+ for (i = 1; i < mp->n_regions; ++i) {
+ unsigned long a, s;
+ int j;
+
+ a = mp->regions[i].address;
+ s = mp->regions[i].size;
+ for (j = i - 1; j >= 0; --j) {
+ if (a >= mp->regions[j].address)
+ break;
+ mp->regions[j+1] = mp->regions[j];
+ }
+ mp->regions[j+1].address = a;
+ mp->regions[j+1].size = s;
+ }
+}
+
+/*
+ * Remove some memory from an array of pieces
+ */
+static void
+remove_mem_piece(struct mem_pieces *mp, unsigned start, unsigned size,
+ int must_exist)
+{
+ int i, j;
+ unsigned end, rs, re;
+ struct reg_property *rp;
+
+ end = start + size;
+ for (i = 0, rp = mp->regions; i < mp->n_regions; ++i, ++rp) {
+ if (end > rp->address && start < rp->address + rp->size)
+ break;
+ }
+ if (i >= mp->n_regions) {
+ if (must_exist)
+ printk("remove_mem_piece: [%x,%x) not in any region\n",
+ start, end);
+ return;
+ }
+ for (; i < mp->n_regions && end > rp->address; ++i, ++rp) {
+ rs = rp->address;
+ re = rs + rp->size;
+ if (must_exist && (start < rs || end > re)) {
+ printk("remove_mem_piece: bad overlap [%x,%x) with",
+ start, end);
+ print_mem_pieces(mp);
+ must_exist = 0;
+ }
+ if (start > rs) {
+ rp->size = start - rs;
+ if (end < re) {
+ /* need to split this entry */
+ if (mp->n_regions >= MAX_MEM_REGIONS)
+ panic("eek... mem_pieces overflow");
+ for (j = mp->n_regions; j > i + 1; --j)
+ mp->regions[j] = mp->regions[j-1];
+ ++mp->n_regions;
+ rp[1].address = end;
+ rp[1].size = re - end;
+ }
+ } else {
+ if (end < re) {
+ rp->address = end;
+ rp->size = re - end;
+ } else {
+ /* need to delete this entry */
+ for (j = i; j < mp->n_regions - 1; ++j)
+ mp->regions[j] = mp->regions[j+1];
+ --mp->n_regions;
+ --i;
+ --rp;
+ }
+ }
+ }
+}
+
+static void
+print_mem_pieces(struct mem_pieces *mp)
+{
+ int i;
+
+ for (i = 0; i < mp->n_regions; ++i)
+ printk(" [%x, %x)", mp->regions[i].address,
+ mp->regions[i].address + mp->regions[i].size);
+ printk("\n");
+}
+
+void *
+find_mem_piece(unsigned size, unsigned align)
+{
+ int i;
+ unsigned a, e;
+ struct mem_pieces *mp = &phys_avail;
+
+ for (i = 0; i < mp->n_regions; ++i) {
+ a = mp->regions[i].address;
+ e = a + mp->regions[i].size;
+ a = (a + align - 1) & -align;
+ if (a + size <= e) {
+ remove_mem_piece(mp, a, size, 1);
+ return __va(a);
+ }
+ }
+ printk("Couldn't find %u bytes at %u alignment\n", size, align);
+ abort();
+ return NULL;
+}
+
+/*
+ * Collect information about RAM and which pieces are already in use.
+ * At this point, we have the first 8MB mapped with a BAT.
+ * Our text, data, bss use something over 1MB, starting at 0.
+ * Open Firmware may be using 1MB at the 4MB point.
+ */
+unsigned long *find_end_of_memory(void)
+{
+ unsigned long a, total;
+ unsigned long h, kstart, ksize;
+ extern char _stext[], _end[];
+ int i;
+
+ memory_pkg = call_prom("finddevice", 1, 1, "/memory");
+ if (memory_pkg == (void *) -1)
+ panic("can't find memory package");
+
+ /*
+ * Find out where physical memory is, and check that it
+ * starts at 0 and is contiguous. It seems that RAM is
+ * always physically contiguous on Power Macintoshes,
+ * because MacOS can't cope if it isn't.
+ */
+ get_mem_prop("reg", &phys_mem);
+ if (phys_mem.n_regions == 0)
+ panic("No RAM??");
+ a = phys_mem.regions[0].address;
+ if (a != 0)
+ panic("RAM doesn't start at physical address 0");
+ total = phys_mem.regions[0].size;
+ for (i = 1; i < phys_mem.n_regions; ++i) {
+ a = phys_mem.regions[i].address;
+ if (a != total) {
+ printk("RAM starting at 0x%lx is not contiguous\n", a);
+ printk("Using RAM from 0 to 0x%lx\n", total-1);
+ phys_mem.n_regions = i;
+ break;
+ }
+ total += phys_mem.regions[i].size;
+ }
+
+ /* record which bits the prom is using */
+ get_mem_prop("available", &phys_avail);
+ prom_mem = phys_mem;
+ for (i = 0; i < phys_avail.n_regions; ++i)
+ remove_mem_piece(&prom_mem, phys_avail.regions[i].address,
+ phys_avail.regions[i].size, 1);
+
+ /*
+ * phys_avail records memory we can use now.
+ * prom_mem records memory allocated by the prom that we
+ * don't want to use now, but we'll reclaim later.
+ * Make sure the kernel text/data/bss is in neither.
+ */
+ kstart = __pa(_stext); /* should be 0 */
+ ksize = PAGE_ALIGN(_end - _stext);
+ remove_mem_piece(&phys_avail, kstart, ksize, 0);
+ remove_mem_piece(&prom_mem, kstart, ksize, 0);
+
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < total / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* Find some memory for the hash table. */
+ Hash = find_mem_piece(Hash_size, Hash_size);
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ total >> 20, Hash_size >> 10, Hash);
+
+ return __va(total);
+}
+
+/*
+ * Find some memory for setup_arch to return.
+ * We use the last chunk of available memory as the area
+ * that setup_arch returns, making sure that there are at
+ * least 32 pages unused before this for MMU_get_page to use.
+ */
+unsigned long find_available_memory(void)
+{
+ int i;
+ unsigned long a, free;
+ unsigned long start, end;
+
+ free = 0;
+ for (i = 0; i < phys_avail.n_regions - 1; ++i) {
+ start = phys_avail.regions[i].address;
+ end = start + phys_avail.regions[i].size;
+ free += (end & PAGE_MASK) - PAGE_ALIGN(start);
+ }
+ a = PAGE_ALIGN(phys_avail.regions[i].address);
+ if (free < 32 * PAGE_SIZE)
+ a += 32 * PAGE_SIZE - free;
+ avail_start = (unsigned long) __va(a);
+ return avail_start;
}
+#endif /* CONFIG_PMAC */
void show_mem(void)
{
+ int i,free = 0,total = 0,reserved = 0;
+ int shared = 0;
struct task_struct *p;
- unsigned long i,free = 0,total = 0,reserved = 0;
- unsigned long shared = 0;
- PTE *ptr;
- unsigned long full = 0, overflow = 0;
- unsigned int ti;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = MAP_NR(high_memory);
+ i = max_mapnr;
while (i-- > 0) {
total++;
if (PageReserved(mem_map+i))
@@ -78,105 +387,185 @@ void show_mem(void)
else
shared += atomic_read(&mem_map[i].count) - 1;
}
- printk("%lu pages of RAM\n",total);
- printk("%lu free pages\n",free);
- printk("%lu reserved pages\n",reserved);
- printk("%lu pages shared\n",shared);
+ printk("%d pages of RAM\n",total);
+ printk("%d free pages\n",free);
+ printk("%d reserved pages\n",reserved);
+ printk("%d pages shared\n",shared);
show_buffers();
#ifdef CONFIG_NET
show_net_buffers();
#endif
-#ifdef HASHSTATS
- printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
- for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ ) {
- if ( hashhits[i] >= 20 )
- printk("[%lu] \t %lu\n", i,hashhits[i]);
- }
-#endif
-
- for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++) {
- if (ptr->v) {
- full++;
- if (ptr->h == 1)
- overflow++;
- }
- }
- printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
- Hash_size>>10, (Hash_size/(sizeof(PTE)*8)) >> 10,
- full,Hash_size/sizeof(PTE),
- (full*100)/(Hash_size/sizeof(PTE)),
- overflow);
- printk(" Task context vsid0\n");
- read_lock(&tasklist_lock);
- for_each_task(p) {
- printk("%5d %8x %8x\n",
- p->pid,p->mm->context,
- ((SEGREG *)p->tss.segs)[0].vsid);
+ printk("%-8s %3s %3s %8s %8s %8s %9s %8s\n", "Process", "Pid", "Cnt",
+ "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
+ for_each_task(p)
+ {
+ printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+ p->comm,p->pid,
+ p->mm->count,p->mm->context,
+ p->mm->context<<4, p->tss.last_syscall,
+ user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
+ p);
+ if ( p == current )
+ printk(" current");
+ printk("\n");
}
- read_unlock(&tasklist_lock);
}
extern unsigned long free_area_init(unsigned long, unsigned long);
+/*
+ * paging_init() sets up the page tables - in fact we've already done this.
+ */
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
{
- return free_area_init(start_mem, end_mem);
+ /*
+ * Grab some memory for bad_page and bad_pagetable to use.
+ */
+ empty_bad_page = start_mem;
+ empty_bad_page_table = start_mem + PAGE_SIZE;
+ start_mem += 2 * PAGE_SIZE;
+
+ /* note: free_area_init uses its second argument
+ to size the mem_map array. */
+ start_mem = free_area_init(start_mem, end_mem);
+ return start_mem;
}
void mem_init(unsigned long start_mem, unsigned long end_mem)
{
- int codepages = 0;
- int datapages = 0;
- unsigned long tmp;
- extern int etext;
+ unsigned long addr;
+#ifdef CONFIG_PMAC
+ int i;
+ unsigned long lim;
+#endif
+ int codepages = 0;
+ int datapages = 0;
+ int initpages = 0;
+
+ end_mem &= PAGE_MASK;
+ high_memory = (void *) end_mem;
+ num_physpages = max_mapnr = MAP_NR(high_memory);
- end_mem &= PAGE_MASK;
- high_memory = (void *)end_mem;
- max_mapnr = MAP_NR(end_mem);
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
+ /* clear the zero-page */
+ memset(empty_zero_page, 0, PAGE_SIZE);
/* mark usable pages in the mem_map[] */
- start_mem = PAGE_ALIGN(start_mem);
+ start_mem = PAGE_ALIGN(start_mem);
+
+#ifdef CONFIG_PMAC
+ remove_mem_piece(&phys_avail, __pa(avail_start),
+ start_mem - avail_start, 1);
+
+ for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
+ set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+
+ for (i = 0; i < phys_avail.n_regions; ++i) {
+ a = (unsigned long) __va(phys_avail.regions[i].address);
+ lim = a + phys_avail.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ mem_map[MAP_NR(a)].count = 1;
+ free_page(a);
+ }
+ }
+ phys_avail.n_regions = 0;
- for (tmp = KERNELBASE ; tmp < (long)high_memory ; tmp += PAGE_SIZE)
- {
- if (tmp < start_mem)
+ /* free the prom's memory */
+ for (i = 0; i < prom_mem.n_regions; ++i) {
+ a = (unsigned long) __va(prom_mem.regions[i].address);
+ lim = a + prom_mem.regions[i].size;
+ a = PAGE_ALIGN(a);
+ for (; a < lim; a += PAGE_SIZE) {
+ clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+ mem_map[MAP_NR(a)].count = 1;
+ free_page(a);
+ }
+ }
+ prom_trashed = 1;
+#endif /* CONFIG_PMAC */
+
+#ifdef CONFIG_PREP
+ /* mark mem used by kernel as reserved, mark other unreserved */
+ for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
{
- set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
- if (tmp < (unsigned long) &etext)
- {
- codepages++;
- } else
- {
- datapages++;
- }
- continue;
- }
- clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
- atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
- free_page(tmp);
- }
- tmp = nr_free_pages << PAGE_SHIFT;
- printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
- tmp >> 10,
- ((int)high_memory - (int)KERNELBASE) >> 10,
- codepages << (PAGE_SHIFT-10),
- datapages << (PAGE_SHIFT-10));
- /* invalidate();*/
- return;
+ /* skip hash table gap */
+ if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+ continue;
+ if ( addr < (ulong) /*Hash_end*/ start_mem )
+ set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ else
+ clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+ }
+
+ for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
+ if(PageReserved(mem_map + MAP_NR(addr))) {
+ if (addr < (ulong) etext)
+ codepages++;
+ /*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+ initpages++;*/
+ else if (addr < (ulong) start_mem)
+ datapages++;
+ continue;
+ }
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (!initrd_start ||
+ (addr < initrd_start || addr >= initrd_end))
+#endif /* CONFIG_BLK_DEV_INITRD */
+ free_page(addr);
+ }
+
+#endif /* CONFIG_PREP */
+ printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+ (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
+ codepages << (PAGE_SHIFT-10),
+ datapages << (PAGE_SHIFT-10),
+ initpages << (PAGE_SHIFT-10),
+ PAGE_OFFSET, end_mem);
+ mem_init_done = 1;
}
+/*
+ * this should reclaim gap between _end[] and hash table
+ * as well as unused mmu_pages[] on prep systems.
+ * When I get around to it, I'll put initialization functions
+ * (called only at boot) in their own .section and free that -- Cort
+ */
void free_initmem(void)
{
- /* To be written */
+ unsigned long addr;
+ unsigned long a;
+ unsigned long num_freed_pages = 0;
+
+ /* free unused mmu_pages[] */
+ a = PAGE_ALIGN( (unsigned long) mmu_pages) + (mmu_pages_count*PAGE_SIZE);
+ for ( ; a < PAGE_ALIGN((unsigned long)mmu_pages)+(MAX_MMU_PAGES*PAGE_SIZE); a += PAGE_SIZE )
+ {
+ clear_bit( PG_reserved, &mem_map[MAP_NR(a)].flags );
+ atomic_set(&mem_map[MAP_NR(a)].count, 1);
+ free_page(a);
+ num_freed_pages++;
+ }
+
+#if 0
+ addr = (unsigned long)(&__init_begin);
+ for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+ num_freed_pages++;
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ mem_map[MAP_NR(addr)].count = 1;
+ free_page(addr);
+ }
+#endif
+ printk ("Freeing unused kernel memory: %dk freed\n",
+ (num_freed_pages * PAGE_SIZE) >> 10);
}
void si_meminfo(struct sysinfo *val)
{
int i;
- i = ((int)high_memory & 0x00FFFFFF) >> PAGE_SHIFT;
+ i = max_mapnr;
val->totalram = 0;
val->sharedram = 0;
val->freeram = nr_free_pages << PAGE_SHIFT;
@@ -187,526 +576,637 @@ void si_meminfo(struct sysinfo *val)
val->totalram++;
if (!atomic_read(&mem_map[i].count))
continue;
- val->sharedram += atomic_read(&mem_map[i].count) - 1;
+ val->sharedram += atomic_read(&mem_map[i].count)-1;
}
val->totalram <<= PAGE_SHIFT;
val->sharedram <<= PAGE_SHIFT;
return;
}
+/* Kernel MMU setup & lowest level hardware support */
+
+unsigned long _SDR1; /* Hardware SDR1 image */
+
+#ifdef CONFIG_PREP
+
BAT BAT0 =
- {
- {
- 0x80000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs -- supervisor mode valid */
- 1, /* vp -- user mode valid */
- },
- {
- 0x80000000>>17, /* brpn */
- 1, /* write-through */
- 1, /* cache-inhibited */
- 0, /* memory coherence */
- 1, /* guarded */
- BPP_RW /* protection */
- }
- };
+{
+ {
+ 0x80000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 1, /* vs -- supervisor mode valid */
+ 1, /* vp -- user mode valid */
+ },
+ {
+ 0x80000000>>17, /* brpn */
+ 1, /* write-through */
+ 1, /* cache-inhibited */
+ 0, /* memory coherence */
+ 1, /* guarded */
+ BPP_RW /* protection */
+ }
+};
BAT BAT1 =
- {
- {
- 0xC0000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs */
- 1, /* vp */
- },
- {
- 0xC0000000>>17, /* brpn */
- 1, /* w */
- 1, /* i (cache disabled) */
- 0, /* m */
- 1, /* g */
- BPP_RW /* pp */
- }
- };
+{
+ {
+ 0xC0000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 1, /* vs */
+ 1, /* vp */
+ },
+ {
+ 0xC0000000>>17, /* brpn */
+ 1, /* w */
+ 1, /* i (cache disabled) */
+ 0, /* m */
+ 1, /* g */
+ BPP_RW /* pp */
+ }
+};
BAT BAT2 =
- {
- {
- 0x90000000>>17, /* bepi */
- BL_256M, /* this gets set to amount of phys ram */
- 1, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 0, /* w */
- 0, /* i */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
+{
+ {
+ 0x90000000>>17, /* bepi */
+ BL_256M, /* this gets set to amount of phys ram */
+ 1, /* vs */
+ 0, /* vp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 0, /* w */
+ 0, /* i */
+ 1, /* m */
+ 0, /* g */
+ BPP_RW /* pp */
+ }
+};
BAT BAT3 =
- {
- {
- 0x00000000>>17, /* bepi */
- BL_256M, /* bl */
- 0, /* vs */
- 0, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 1, /* w */
- 1, /* i (cache disabled) */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
-BAT TMP_BAT2 =
- { /* 0x9XXXXXXX -> 0x0XXXXXXX */
- {
- 0x90000000>>17, /* bepi */
- BL_256M, /* bl */
- 1, /* vs */
- 1, /* vp */
- },
- {
- 0x00000000>>17, /* brpn */
- 1, /* w */
- 0, /* i (cache enabled) */
- 0, /* m */
- 0, /* g */
- BPP_RW /* pp */
- }
- };
-
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/*
- * This code is called to create a minimal mapped environment.
- * It is called with the MMU on, but with only a BAT register
- * set up to cover the code/data. After this routine runs,
- * the BAT mapping is withdrawn and all mappings must be complete.
- */
+{
+ {
+ 0x00000000>>17, /* bepi */
+ BL_256M, /* bl */
+ 0, /* vs */
+ 0, /* vp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 0, /* w */
+ 0, /* i (cache disabled) */
+ 1, /* m */
+ 0, /* g */
+ BPP_RW /* pp */
+ }
+};
+P601_BAT BAT0_601 =
+{
+ {
+ 0x80000000>>17, /* bepi */
+ 1,1,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x80000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
+P601_BAT BAT1_601 =
+{
+ {
+ 0xC0000000>>17, /* bepi */
+ 1,1,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0xC0000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
+P601_BAT BAT2_601 =
+{
+ {
+ 0x90000000>>17, /* bepi */
+ 0,0,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x00000000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
+ }
+};
-extern char _start[], _end[];
-
-void MMU_init(void)
+P601_BAT BAT3_601 =
{
- extern RESIDUAL res;
- extern unsigned long resptr;
- int i, p;
- SEGREG *segs;
-
- /* copy residual data */
- if ( resptr )
- memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
- else
- bzero( &res, sizeof(RESIDUAL) ); /* clearing bss probably clears this but... */
-
- end_of_DRAM = (unsigned long *)find_end_of_memory();
- _SDR1 = ((unsigned long)Hash - KERNELBASE) | Hash_mask;
-#if 0
- printk("Hash %08x\n",(unsigned long)Hash);
- printk("Hash_mask %08x\n",Hash_mask);
- printk("Hash_size %08x\n",Hash_size);
- printk("SDR1 %08x\n",_SDR1);
-#endif
- /* Segment registers */
- segs = (SEGREG *)init_task.tss.segs;
- for (i = 0; i < 16; i++)
{
- segs[i].ks = 0;
- segs[i].kp = 1;
-#if 1
- if ( i < 8 )
- segs[i].vsid = i+10000;
- else
-#else
- if ( i < 8 )
- segs[i].vsid = i<<5;
-#endif
- segs[i].vsid = i;
+ 0x90800000>>17, /* bepi */
+ 0,0,0, /* wim */
+ 1, 0, /* vs, vp */
+ BPP_RW, /* pp */
+ },
+ {
+ 0x00800000>>17, /* brpn */
+ 1, /* v */
+ BL_8M, /* bl */
}
-
-
-
- /* Hard map in any special local resources */
- if (isBeBox[0])
- {
- /* Map in one page for the BeBox motherboard I/O */
- end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - PAGE_SIZE);
-#if 0
- BeBox_IO_page = (unsigned char *)0x7FFFF000;
-#endif
- BeBox_IO_page = (unsigned char *)end_of_DRAM;
- MMU_disable_cache_for_page(&init_task.tss, BeBox_IO_page);
- }
-}
+};
/*
- * Insert(create) a hardware page table entry
+ * This finds the amount of physical ram and does necessary
+ * setup for prep. This is pretty architecture specific so
+ * this will likely stay seperate from the pmac.
+ * -- Cort
*/
-int inline MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
-{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *empty, *slot;
- PTE *slot0, *slot1;
- extern char _etext;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = ((SEGREG *)tss->segs)[segment].vsid;
- empty = slot = (PTE *)NULL;
-
- if ( (va <= _etext) && (va >= KERNELBASE))
- {
- printk("MMU_hash_page: called on kernel page mapped with bats va %x\n",
- va);
- }
+unsigned long *find_end_of_memory(void)
+{
+ extern RESIDUAL res;
+ extern unsigned long resptr;
+ int i, p;
+ unsigned long h;
- /* check first hash bucket */
- h = 0;
- hash = page_index ^ vsid;
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* 8 entries in each bucket */
- _pte = &Hash[hash];
- slot0 = _pte;
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
- {
- slot = _pte;
- goto found_it;
- }
- if ((empty == NULL) && (!_pte->v))
+ /* copy residual data */
+ if ( resptr )
+ memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
+ else
+ /* clearing bss probably clears this but... */
+ memset( &res, sizeof(RESIDUAL), 0 );
+ _TotalMemory = res.TotalMemory;
+
+ /* this really has nothing to do with the mmu_init() but is
+ necessary for early setup -- Cort */
+ if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
{
- empty = _pte;
- _h = h;
+ _machine = _MACH_IBM;
}
- }
-
- /* check second hash bucket */
- h = 1;
- hash = page_index ^ vsid;
- hash = ~hash;
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* 8 entries in each bucket */
- _pte = &Hash[hash];
- slot1 = _pte;
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+ else
+ _machine = _MACH_Motorola;
+
+ /* setup the hash table */
+ if (_TotalMemory == 0 )
{
- slot = _pte;
- goto found_it;
+ /*
+ * I need a way to probe the amount of memory if the residual
+ * data doesn't contain it. -- Cort
+ */
+ printk("Ramsize from residual data was 0 -- Probing for value\n");
+ _TotalMemory = 0x03000000;
+ printk("Ramsize default to be %dM\n", _TotalMemory>>20);
}
- if ((empty == NULL) && (!_pte->v))
+
+#if 0
+ /* linux has trouble with > 64M ram -- Cort */
+ if ( _TotalMemory > 0x04000000 /* 64M */ )
{
- empty = _pte;
- _h = h;
+ printk("Only using first 64M of ram.\n");
+ _TotalMemory = 0x04000000;
}
- }
+#endif
+
+ /* setup the bat2 mapping to cover physical ram */
+ BAT2.batu.bl = 0x1; /* 256k mapping */
+ for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+ h *= 2 )
+ BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
+ /*
+ * Allow 64k of hash table for every 16MB of memory,
+ * up to a maximum of 2MB.
+ */
+ for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+ ;
+ Hash_size = h;
+ Hash_mask = (h >> 6) - 1;
+
+ /* align htab on a Hash_size boundry above _end[] */
+ Hash = (PTE *)_ALIGN( (unsigned long)&_end, Hash_size);
+ memset(Hash, Hash_size, 0 );
- if (empty == (PTE *)NULL)
- {
-#if 1
- printk("Both hash buckets full! va %x vsid %x current %s (%d)\n",
- va,vsid,current->comm,current->pid);
-#endif
- slot = slot1;
- h = 1;
- }
- else
- {
- slot = empty;
- h = _h;
- }
-found_it:
-#ifdef HASHSTATS
- hashhits[hash]++;
-#endif
- _tlbie(va); /* Clear TLB */
- /* Fill in table */
- slot->v = 1;
- slot->vsid = vsid;
- slot->h = h;
- slot->api = api;
- if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
+ /*
+ * if this is a 601, we can only map sizes of 8M with the BAT's
+ * so we have to map what we can't map with the bats with the segregs
+ * head.S will copy in the appropriate BAT's according to the processor
+ * since the 601_BAT{2,3} structures are already setup to map
+ * the first 16M correctly
+ * -- Cort
+ */
+#ifndef MAP_RAM_WITH_SEGREGS /* don't need to do it twice */
+ if ( _get_PVR() == 1 )
{
- slot->rpn = pg->page_num - (KERNELBASE>>12);
- } else
- {
- slot->rpn = pg->page_num;
- }
- slot->r = 0;
- slot->c = 0;
- slot->i = 0;
- slot->g = 0;
- if (cache_is_copyback)
- {
- if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
- { /* All User & Kernel TEXT pages are copy-back */
- slot->w = 0;
- slot->m = 1;
- } else
- { /* Kernel DATA pages are write-thru */
- slot->w = 1;
- slot->m = 0;
- }
- } else
- {
- slot->w = 1;
- slot->m = 0;
- }
- if (pg->flags & _PAGE_USER)
+ /* map in rest of ram with seg regs */
+ if ( _TotalMemory > 0x01000000 /* 16M */)
+ {
+ for (i = KERNELBASE+0x01000000;
+ i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+ }
+ }
+#endif /* MAP_RAM_WITH_SEGREGS */
+
+#ifdef MAP_RAM_WITH_SEGREGS
+ /* turn off bat mapping kernel since being done with segregs */
+ memset(&BAT2, sizeof(BAT2), 0);
+ memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
+ memset(&BAT3_601, sizeof(BAT2), 0);
+ /* map all of ram for kernel with segregs */
+ for (i = KERNELBASE; i < KERNELBASE+_TotalMemory; i += PAGE_SIZE)
{
- if (pg->flags & _PAGE_RW)
- { /* Read/write page */
- perms = PP_RWRW;
- } else
- { /* Read only page */
- perms = PP_RWRX;
- perms = PP_RXRX;
- }
- } else
- { /* Kernel pages */
- perms = PP_RWRW;
- perms = PP_RWXX;
- }
- slot->pp = perms;
- return (0);
+ if ( i < (unsigned long)etext )
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
+ else
+ map_page(&init_task.tss, i, __pa(i),
+ _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
+ }
+#endif /* MAP_RAM_WITH_SEGREGS */
+
+ printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+ _TotalMemory >> 20, Hash_size >> 10, Hash);
+ return ((unsigned long *)_TotalMemory);
}
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
/*
- * Disable cache for a particular page
+ * Map in all of physical memory starting at KERNELBASE.
*/
-MMU_disable_cache_for_page(struct thread_struct *tss, unsigned long va)
+extern int n_mem_regions;
+extern struct reg_property mem_regions[];
+
+#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+static void mapin_ram()
{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *empty, *slot;
- PTE *slot0, *slot1;
- extern char _etext;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = ((SEGREG *)tss->segs)[segment].vsid;
- empty = slot = (PTE *)NULL;
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- /* Save slot addresses in case we have to purge */
- if (_h)
- {
- slot1 = _pte;
- } else
- {
- slot0 = _pte;
- }
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- h = _h;
- slot = _pte;
- goto found_it;
- }
- if ((empty == (PTE *)NULL) && !_pte->v)
- {
- h = _h;
- empty = _pte;
- }
- }
+ int i;
+ unsigned long v, p, s, f;
+
+ v = KERNELBASE;
+ for (i = 0; i < phys_mem.n_regions; ++i) {
+ p = phys_mem.regions[i].address;
+ for (s = 0; s < phys_mem.regions[i].size; s += PAGE_SIZE) {
+ f = _PAGE_PRESENT | _PAGE_ACCESSED;
+ if ((char *) v < _stext || (char *) v >= etext)
+ f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
+ map_page(&init_task.tss, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
}
-found_it:
- _tlbie(va); /* Clear TLB */
- slot->i = 1;
- slot->m = 0;
+ }
}
+#define MAX_PROM_TRANSLATIONS 64
-/*
- * invalidate a hardware hash table pte
- */
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
+static struct translation_property prom_translations[MAX_PROM_TRANSLATIONS];
+int n_translations;
+phandle mmu_pkg;
+extern ihandle prom_chosen;
+
+static void inherit_prom_translations()
{
- int hash, page_index, segment, i, h, _h, api, vsid, perms;
- PTE *_pte, *slot;
- int flags = 0;
- page_index = ((int)va & 0x0FFFF000) >> 12;
- segment = (unsigned int)va >> 28;
- api = page_index >> 10;
- vsid = mm->context | segment;
- for (_h = 0; _h < 2; _h++)
- {
- hash = page_index ^ vsid;
- if (_h)
- {
- hash = ~hash; /* Secondary hash uses ones-complement */
- }
- hash &= 0x3FF | (Hash_mask << 10);
- hash *= 8; /* Eight entries / hash bucket */
- _pte = &Hash[hash];
- for (i = 0; i < 8; i++, _pte++)
- {
- if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
- { /* Found it! */
- _tlbie(va); /* Clear TLB */
- if (_pte->r) flags |= _PAGE_ACCESSED;
- if (_pte->c) flags |= _PAGE_DIRTY;
- _pte->v = 0;
- return (flags);
- }
+ int s, i, f;
+ unsigned long v, p, n;
+ struct translation_property *tp;
+ ihandle mmu_inst;
+
+ if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+ &mmu_inst, sizeof(mmu_inst)) != sizeof(mmu_inst))
+ panic("couldn't get /chosen mmu property");
+ mmu_pkg = call_prom("instance-to-package", 1, 1, mmu_inst);
+ if (mmu_pkg == (phandle) -1)
+ panic("couldn't get mmu package");
+ s = (int) call_prom("getprop", 4, 1, mmu_pkg, "translations",
+ &prom_translations, sizeof(prom_translations));
+ if (s < sizeof(prom_translations[0]))
+ panic("couldn't get mmu translations property");
+ n_translations = s / sizeof(prom_translations[0]);
+
+ for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
+ /* ignore stuff mapped down low */
+ if (tp->virt < 0x10000000)
+ continue;
+ /* map PPC mmu flags to linux mm flags */
+ f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
+ | _PAGE_COHERENT | _PAGE_GUARDED))
+ | pgprot_val(PAGE_KERNEL);
+ /* add these pages to the mappings */
+ v = tp->virt;
+ p = tp->phys;
+ n = tp->size;
+ for (; n != 0; n -= PAGE_SIZE) {
+ map_page(&init_task.tss, v, p, f);
+ v += PAGE_SIZE;
+ p += PAGE_SIZE;
}
}
- _tlbie(va);
- return (flags);
}
+#endif
-
-inline void
-flush_cache_all(void)
+/*
+ * Initialize the hash table and patch the instructions in head.S.
+ */
+static void hash_init(void)
{
+ int Hash_bits;
+
+ extern unsigned int hash_page_patch_A[], hash_page_patch_B[],
+ hash_page_patch_C[];
+
+ memset(Hash, 0, Hash_size);
+ Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+ /*
+ * Patch up the instructions in head.S:hash_page
+ */
+ Hash_bits = ffz(~Hash_size) - 6;
+ hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+ | (__pa(Hash) >> 16);
+ hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ if (Hash_bits > 16)
+ Hash_bits = 16;
+ hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+ | ((26 - Hash_bits) << 6);
+ hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+ | (Hash_mask >> 10);
+ hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+ | (Hash_mask >> 10);
+
+ /*
+ * Ensure that the locations we've patched have been written
+ * out from the data cache and invalidated in the instruction
+ * cache, on those machines with split caches.
+ */
+ store_cache_range((unsigned long) hash_page_patch_A,
+ (unsigned long) (hash_page_patch_C + 1));
}
-inline void
-flush_cache_mm(struct mm_struct *mm)
+
+
+/*
+ * Do very early mm setup such as finding the size of memory
+ * and setting up the hash table.
+ * A lot of this is prep/pmac specific but a lot of it could
+ * still be merged.
+ * -- Cort
+ */
+void
+MMU_init(void)
{
-}
-inline void
-flush_cache_page(struct vm_area_struct *vma, long va)
+ end_of_DRAM = find_end_of_memory();
+ hash_init();
+ _SDR1 = __pa(Hash) | (Hash_mask >> 10);
+#ifdef CONFIG_PMAC
+ /* Force initial page tables */
+ /* this done by INIT_TSS in processor.h on prep -- Cort */
+ init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
+
+ /* Map in all of RAM starting at KERNELBASE */
+ mapin_ram();
+ /* Copy mappings from the prom */
+ inherit_prom_translations();
+#endif /* CONFIG_PMAC */
+}
+
+static void *
+MMU_get_page()
{
-}
-inline void
-flush_cache_range(struct mm_struct *mm, unsigned long va_start, unsigned long va_end)
+ void *p;
+
+ if (mem_init_done) {
+ p = (void *) __get_free_page(GFP_KERNEL);
+ if (p == 0)
+ panic("couldn't get a page in MMU_get_page");
+ } else {
+#ifdef CONFIG_PREP
+ mmu_pages_count++;
+ if ( mmu_pages_count > MAX_MMU_PAGES )
+ printk("out of mmu pages!\n");
+ p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+ (mmu_pages_count+PAGE_SIZE));
+#endif
+#ifdef CONFIG_PMAC
+ p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+#endif
+ }
+ memset(p, 0, PAGE_SIZE);
+ return p;
+}
+
+#ifdef CONFIG_PMAC
+void *
+ioremap(unsigned long addr, unsigned long size)
{
-}
+ unsigned long p, end = addr + size;
+
+ for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
+ map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+ return (void *) addr;
+}
+#endif
-inline void
-cache_mode(char *str, int *ints)
+void
+map_page(struct thread_struct *tss, unsigned long va,
+ unsigned long pa, int flags)
{
- cache_is_copyback = ints[0];
+ pmd_t *pd;
+ pte_t *pg;
+
+ if (tss->pg_tables == NULL) {
+ /* Allocate upper level page map */
+ tss->pg_tables = (unsigned long *) MMU_get_page();
+ }
+ /* Use upper 10 bits of VA to index the first level map */
+ pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+ if (pmd_none(*pd)) {
+ /* Need to allocate second-level table */
+ pg = (pte_t *) MMU_get_page();
+ pmd_val(*pd) = (unsigned long) pg;
+ }
+ /* Use middle 10 bits of VA to index the second-level map */
+ pg = pte_offset(pd, va);
+ set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+ /*flush_hash_page(va >> 28, va);*/
+ flush_hash_page(0, va);
}
/*
* TLB flushing:
*
- * - flush_tlb() flushes the current mm struct TLBs
* - flush_tlb_all() flushes all processes TLBs
* - flush_tlb_mm(mm) flushes the specified mm context TLB's
* - flush_tlb_page(vma, vmaddr) flushes one page
* - flush_tlb_range(mm, start, end) flushes a range of pages
*
* since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush them too.
+ * tlb as far as the linux tables are concerned, flush it too.
* -- Cort
*/
-inline void
-flush_tlb(void)
-{
- PTE *ptep;
- int context = current->mm->context;
- struct vm_area_struct *v;
- unsigned int i;
-
- v = current->mm->mmap;
- /* for every virtual memory address in the current context -- flush
- the hash table */
- while ( v != NULL )
- {
- for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
- {
- MMU_invalidate_page(v->vm_mm,i);
- }
- v = v->vm_next;
- }
-
- _tlbia();
-}
-
-/* flush all tlb/hash table entries except for kernels
-
- although the kernel is mapped with the bats, it's dynamic areas
- obtained via kmalloc are mapped by the seg regs
- -- Cort
- */
-inline void
+/*
+ * Flush all tlb/hash table entries except for the kernel's.
+ * We use the fact that only kernel mappings use VSIDs 0 - 15.
+ */
+void
flush_tlb_all(void)
{
- PTE *ptep;
-
- /* flush hash table */
- for ( ptep = Hash ; ptep < (PTE *)((unsigned long)Hash+Hash_size) ; ptep++ )
- {
- /* if not kernel vsids 0-7 (vsid greater than that for process 0)*/
- if ( (ptep->vsid > 7 ) && (ptep->v))
- {
- ptep->v = 0;
- }
- }
+ struct task_struct *tsk;
- _tlbia();
+ read_lock(&tasklist_lock);
+ for_each_task(tsk) {
+ if (tsk->mm)
+ tsk->mm->context = NO_CONTEXT;
+ }
+ read_unlock(&tasklist_lock);
+ get_mmu_context(current);
+ set_context(current->mm->context);
}
-inline void
+
+/*
+ * Flush all the (user) entries for the address space described
+ * by mm. We can't rely on mm->mmap describing all the entries
+ * that might be in the hash table.
+ */
+void
flush_tlb_mm(struct mm_struct *mm)
{
- PTE *ptep;
- int context = mm->context;
- struct vm_area_struct *v;
- unsigned int i;
-
- v = mm->mmap;
- while ( v != NULL )
- {
- for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
- {
- MMU_invalidate_page(v->vm_mm,i);
- }
- v = v->vm_next;
- }
-
- _tlbia();
+ mm->context = NO_CONTEXT;
+ if (mm == current->mm) {
+ get_mmu_context(current);
+ /* done by get_mmu_context() now -- Cort */
+ /*set_context(current->mm->context);*/
+ }
}
-inline void
-flush_tlb_page(struct vm_area_struct *vma, long vmaddr)
+void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
{
- MMU_invalidate_page(vma->vm_mm,vmaddr);
+ unsigned vsid;
+
+ if ( vmaddr < TASK_SIZE) {
+ /*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
+ flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
+ /* this is needed on prep at the moment -- don't know why
+ -- Cort*/
+ MMU_invalidate_page(vma->vm_mm,vmaddr);
+ }
+ else
+ {
+ /*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
+ }
}
-/* for each page addr in the range, call mmu_invalidat_page()
+/* for each page addr in the range, call MMU_invalidate_page()
if the range is very large and the hash table is small it might be faster to
do a search of the hash table and just invalidate pages that are in the range
but that's for study later.
-- Cort
*/
-inline void
-flush_tlb_range(struct mm_struct *mm, long start, long end)
+void
+flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
{
- long i;
- for ( i = PAGE_ALIGN(start-PAGE_SIZE) ; i < PAGE_ALIGN(end) ; i += PAGE_SIZE)
- {
- MMU_invalidate_page(mm,i);
- }
+ start &= PAGE_MASK;
+ for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
+ {
+ /*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
+ start );*/
+ flush_hash_page(mm->context, start);
+ /* this is needed on prep at the moment -- don't know why
+ -- Cort*/
+ MMU_invalidate_page(mm,start);
+ }
}
-inline void
-flush_page_to_ram(unsigned long page)
+/*
+ * The context counter has overflowed.
+ * We set mm->context to NO_CONTEXT for all mm's in the system.
+ * We assume we can get to all mm's by looking as tsk->mm for
+ * all tasks in the system.
+ */
+void
+mmu_context_overflow(void)
+{
+ struct task_struct *tsk;
+ int nr;
+
+ printk(KERN_INFO "mmu_context_overflow\n");
+ for (nr = 0; nr < NR_TASKS; ++nr) {
+ tsk = task[nr];
+ if (tsk && tsk->mm)
+ tsk->mm->context = NO_CONTEXT;
+ }
+ flush_hash_segments(0x10, 0xffffff);
+ _tlbia();
+ next_mmu_context = 0;
+}
+
+#ifdef CONFIG_PREP
+/*
+ * it's not a simple matter to get rid of these and switch to the
+ * ones paul is using. it will take some time and thought -- Cort
+ */
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
{
+ int hash, page_index, segment, i, h, _h, api, vsid, perms;
+ PTE *_pte, *slot;
+ int flags = 0;
+ page_index = ((int)va & 0x0FFFF000) >> 12;
+ segment = (unsigned int)va >> 28;
+ api = page_index >> 10;
+ vsid = VSID_FROM_CONTEXT(segment,mm->context);
+ for (_h = 0; _h < 2; _h++)
+ {
+ hash = page_index ^ vsid;
+ if (_h)
+ {
+ hash = ~hash; /* Secondary hash uses ones-complement */
+ }
+ hash &= 0x3FF | (Hash_mask /*<< 10*/);
+ hash *= 8; /* Eight entries / hash bucket */
+ _pte = &Hash[hash];
+ for (i = 0; i < 8; i++, _pte++)
+ {
+ if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
+ { /* Found it! */
+ _tlbie(va); /* Clear TLB */
+ if (_pte->r) flags |= _PAGE_ACCESSED;
+ if (_pte->c) flags |= _PAGE_DIRTY;
+ _pte->v = 0;
+ return /*(flags)*/;
+ }
+ }
+ }
+ _tlbie(va);
+ return /*(flags)*/;
+}
+#endif
+
+#include <asm/mmu.h>
+void print_mm_info(void)
+{
+ struct _SEGREG s;
+ long a;
+ struct _BATU bu;
+ struct _BATL bl;
+ unsigned long i;
+
+ for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
+ {
+ a = get_SR(i);
+ memcpy(&s,&a,4);
+ printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x %x\n",
+ i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
+ }
+
+ asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
+ printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
+ bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
}
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 9d64ee85d..80e114585 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -42,7 +42,7 @@ SUN_FB_CGFOURTEEN=y
SUN_FB_BWTWO=y
SUN_FB_LEO=y
TADPOLE_FB_WEITEK=y
-#SUN_FB_CREATOR is not set
+SUN_FB_CREATOR=y
#
# Misc Linux/SPARC drivers
@@ -180,15 +180,12 @@ CONFIG_MYRI_SBUS=m
# Filesystems
#
CONFIG_QUOTA=y
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
-CONFIG_UMSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
CONFIG_ROOT_NFS=y
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 5d0ea0840..f60ecbe9c 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
+/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
* sys_sunos.c: SunOS specific syscall compatibility support.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -842,8 +842,9 @@ asmlinkage int sunos_nfs_mount(char *dir_name, int linux_flags, void *data)
linux_nfs_mount.acdirmin = sunos_mount->acdirmin;
linux_nfs_mount.acdirmax = sunos_mount->acdirmax;
- if (getname (sunos_mount->hostname, &the_name))
- return -EFAULT;
+ the_name = getname(sunos_mount->hostname);
+ if(IS_ERR(the_name))
+ return PTR_ERR(the_name);
strncpy (linux_nfs_mount.hostname, the_name, 254);
linux_nfs_mount.hostname [255] = 0;
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 3b9970551..ad9aa8953 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.148 1997/06/24 15:48:02 jj Exp $
+/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -2214,7 +2214,8 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
{
if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
struct vm_area_struct *vmaring;
- struct inode *inode;
+ struct dentry *dentry;
+ struct inode *inode = NULL;
unsigned long flags, offset, vaddr, start;
int alias_found = 0;
pgd_t *pgdp;
@@ -2223,7 +2224,9 @@ static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
save_and_cli(flags);
- inode = vma->vm_inode;
+ dentry = vma->vm_dentry;
+ if(dentry)
+ inode = dentry->d_inode;
if (!inode)
goto done;
offset = (address & PAGE_MASK) - vma->vm_start;
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index a0ffc10ed..7ffca1033 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.148 1997/05/18 21:11:19 davem Exp $
+/* $Id: sun4c.c,v 1.149 1997/07/20 05:59:38 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -2435,11 +2435,14 @@ static pgd_t *sun4c_pgd_alloc(void)
*/
static void sun4c_vac_alias_fixup(struct vm_area_struct *vma, unsigned long address, pte_t pte)
{
- struct inode *inode;
+ struct dentry *dentry;
+ struct inode *inode = NULL;
pgd_t *pgdp;
pte_t *ptep;
- inode = vma->vm_inode;
+ dentry = vma->vm_dentry;
+ if(dentry)
+ inode = dentry->d_inode;
if(inode) {
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
struct vm_area_struct *vmaring = inode->i_mmap;
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 92a003853..c9c92b987 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -160,14 +160,11 @@ CONFIG_MYRI_SBUS=m
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
CONFIG_MINIX_FS=m
CONFIG_EXT2_FS=y
CONFIG_FAT_FS=m
CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
# CONFIG_UMSDOS_FS is not set
CONFIG_PROC_FS=y
CONFIG_NFS_FS=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 9e9013735..aecb9fd47 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.28 1997/07/05 09:52:20 davem Exp $
+# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
# Makefile for the linux kernel.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+ifdef SMP
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
.S.s:
$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+endif
+
all: kernel.o head.o init_task.o
O_TARGET := kernel.o
@@ -22,6 +34,10 @@ O_OBJS := process.o setup.o cpu.o idprom.o \
unaligned.o sys_sunos32.o sunos_ioctl32.o
OX_OBJS := sparc64_ksyms.o
+ifdef SMP
+O_OBJS += smp.o trampoline.o
+endif
+
ifdef CONFIG_SPARC32_COMPAT
O_OBJS += sys32.o sys_sparc32.o signal32.o ioctl32.o
endif
@@ -36,7 +52,7 @@ endif
head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \
winfixup.S entry.S
- $(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o
#
# This is just to get the dependencies...
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 6c3ff9174..00e5f2722 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -4,6 +4,9 @@
*/
#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <linux/init.h>
#include <asm/oplib.h>
#include <asm/io.h>
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index d6cdf9162..2c96a83e9 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -6,6 +6,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <asm/asi.h>
#include <asm/system.h>
#include <asm/fpumacro.h>
@@ -56,12 +58,7 @@ __initfunc(void cpu_probe(void))
long ver, fpu_vers;
long fprs;
-#ifndef __SMP__
- cpuid = 0;
-#else
-#error SMP not supported on sparc64 yet
- /* cpuid = get_cpuid(); */
-#endif
+ cpuid = smp_processor_id();
fprs = fprs_read ();
fprs_write (FPRS_FEF);
diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c
index 5e6705896..9327058a8 100644
--- a/arch/sparc64/kernel/devices.c
+++ b/arch/sparc64/kernel/devices.c
@@ -13,7 +13,7 @@
#include <asm/system.h>
#include <asm/smp.h>
-struct prom_cpuinfo linux_cpus[NCPUS];
+struct prom_cpuinfo linux_cpus[NR_CPUS];
int linux_num_cpus = 0;
extern void cpu_probe(void);
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index a410cfe80..425c2d873 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $
+/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -206,7 +206,7 @@ fpdis_exit:
* flushing very quickly.
*/
.align 32
- .globl do_ivec
+ .globl do_ivec, do_ivec_return
do_ivec:
ldxa [%g0] ASI_INTR_RECEIVE, %g1
andcc %g1, 0x20, %g0
diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
index b7a0f312d..81eb45e42 100644
--- a/arch/sparc64/kernel/ioctl32.c
+++ b/arch/sparc64/kernel/ioctl32.c
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
+/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -30,6 +30,7 @@
#include <asm/kbio.h>
#include <asm/vuid_event.h>
#include <asm/rtc.h>
+#include <asm/openpromio.h>
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
@@ -697,6 +698,22 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
case RTCGET:
case RTCSET:
+ /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have
+ * embedded pointers in the arg which we'd need to clean up...
+ */
+ case OPROMGETOPT:
+ case OPROMSETOPT:
+ case OPROMNXTOPT:
+ case OPROMSETOPT2:
+ case OPROMNEXT:
+ case OPROMCHILD:
+ case OPROMGETPROP:
+ case OPROMNXTPROP:
+ case OPROMU2P:
+ case OPROMGETCONS:
+ case OPROMGETFBNAME:
+ case OPROMGETBOOTARGS:
+
/* Socket level stuff */
case FIOSETOWN:
case SIOCSPGRP:
diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c
index 390c33517..7d1580b39 100644
--- a/arch/sparc64/kernel/ioport.c
+++ b/arch/sparc64/kernel/ioport.c
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.10 1997/06/30 09:24:02 jj Exp $
+/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
* ioport.c: Simple io mapping allocator.
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -83,7 +83,7 @@ void sparc_free_io (void *virtual, int len)
unsigned long vaddr = (unsigned long) virtual & PAGE_MASK;
unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK;
- if (virtual >= PAGE_OFFSET + 0x10000000000UL)
+ if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL)
return;
release_region(vaddr, plen);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index c4e7f0e74..f76c27c57 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $
+/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
* irq.c: UltraSparc IRQ handling/init/registry.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
#include <asm/iommu.h>
#include <asm/upa.h>
#include <asm/oplib.h>
+#include <asm/timer.h>
#include <asm/smp.h>
#include <asm/hardirq.h>
#include <asm/softirq.h>
@@ -76,7 +77,7 @@ int get_irq_list(char *buf)
}
/* INO number to Sparc PIL level. */
-static unsigned char ino_to_pil[] = {
+unsigned char ino_to_pil[] = {
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */
0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */
@@ -391,7 +392,116 @@ int __sparc64_bh_counter = 0;
#define irq_exit(cpu, irq) (local_irq_count[cpu]--)
#else
-#error SMP not supported on sparc64 just yet
+
+atomic_t __sparc64_bh_counter = ATOMIC_INIT(0);
+
+/* Who has global_irq_lock. */
+unsigned char global_irq_holder = NO_PROC_ID;
+
+/* This protects IRQ's. */
+spinlock_t global_irq_lock = SPIN_LOCK_UNLOCKED;
+
+/* This protects BH software state (masks, things like that). */
+spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
+
+/* Global IRQ locking depth. */
+atomic_t global_irq_count = ATOMIC_INIT(0);
+
+static inline void wait_on_irq(int cpu)
+{
+ int local_count = local_irq_count[cpu];
+
+ while(local_count != atomic_read(&global_irq_count)) {
+ atomic_sub(local_count, &global_irq_count);
+ spin_unlock(&global_irq_lock);
+ for(;;) {
+ if (atomic_read(&global_irq_count))
+ continue;
+ if (*((unsigned char *)&global_irq_lock))
+ continue;
+ if (spin_trylock(&global_irq_lock))
+ break;
+ }
+ atomic_add(local_count, &global_irq_count);
+ }
+}
+
+static inline void get_irqlock(int cpu)
+{
+ if (!spin_trylock(&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ return;
+ do {
+ barrier();
+ } while (!spin_trylock(&global_irq_lock));
+ }
+ wait_on_irq(cpu);
+ global_irq_holder = cpu;
+}
+
+void __global_cli(void)
+{
+ int cpu = smp_processor_id();
+
+ __cli();
+ get_irqlock(cpu);
+}
+
+void __global_sti(void)
+{
+ release_irqlock(smp_processor_id());
+ __sti();
+}
+
+unsigned long __global_save_flags(void)
+{
+ return global_irq_holder == (unsigned char) smp_processor_id();
+}
+
+void __global_restore_flags(unsigned long flags)
+{
+ if (flags & 1) {
+ __global_cli();
+ } else {
+ if (global_irq_holder == (unsigned char) smp_processor_id()) {
+ global_irq_holder = NO_PROC_ID;
+ spin_unlock(&global_irq_lock);
+ }
+ if (!(flags & 2))
+ __sti();
+ }
+}
+
+void irq_enter(int cpu, int irq)
+{
+ hardirq_enter(cpu);
+ barrier();
+ while (*((unsigned char *)&global_irq_lock)) {
+ if ((unsigned char) cpu == global_irq_holder)
+ printk("irq_enter: Frosted Lucky Charms, "
+ "they're magically delicious!\n");
+ barrier();
+ }
+}
+
+void irq_exit(int cpu, int irq)
+{
+ hardirq_exit(cpu);
+ release_irqlock(cpu);
+}
+
+void synchronize_irq(void)
+{
+ int cpu = smp_processor_id();
+ int local_count = local_irq_count[cpu];
+ unsigned long flags;
+
+ if (local_count != atomic_read(&global_irq_count)) {
+ save_and_cli(flags);
+ restore_flags(flags);
+ }
+}
+
#endif /* __SMP__ */
void report_spurious_ivec(struct pt_regs *regs)
@@ -432,9 +542,7 @@ void handler_irq(int irq, struct pt_regs *regs)
struct irqaction *action;
int cpu = smp_processor_id();
- /* XXX */
- if(irq != 14)
- clear_softint(1 << irq);
+ clear_softint(1 << irq);
irq_enter(cpu, irq);
action = *(irq + irq_action);
@@ -575,53 +683,46 @@ int probe_irq_off(unsigned long mask)
return 0;
}
-/* XXX This is a hack, make it per-cpu so that SMP port will work correctly
- * XXX with mixed MHZ Ultras in the machine. -DaveM
- */
-static unsigned long cpu_cfreq;
-static unsigned long tick_offset;
+struct sun5_timer *linux_timers = NULL;
-/* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */
-static void timer_handler(int irq, void *dev_id, struct pt_regs *regs)
+/* This is called from sbus_init() to get the jiffies timer going.
+ * We need to call this after there exists a valid SBus_chain so
+ * that the IMAP/ICLR registers can be accessed.
+ *
+ * XXX That is because the whole startup sequence is broken. I will
+ * XXX fix it all up very soon. -DaveM
+ */
+void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
{
- if (!(get_softint () & 1)) {
- /* Just to be sure... */
- clear_softint(1 << 14);
- printk("Spurious level14 at %016lx\n", regs->tpc);
- return;
- } else {
- unsigned long compare, tick;
-
- do {
- extern void timer_interrupt(int, void *, struct pt_regs *);
-
- timer_interrupt(irq, dev_id, regs);
-
- /* Acknowledge INT_TIMER */
- clear_softint(1 << 0);
+ struct linux_prom64_registers pregs[3];
+ u32 pirqs[2];
+ int node, err;
- /* Set up for next timer tick. */
- __asm__ __volatile__("rd %%tick_cmpr, %0\n\t"
- "add %0, %2, %0\n\t"
- "wr %0, 0x0, %%tick_cmpr\n\t"
- "rd %%tick, %1"
- : "=&r" (compare), "=r" (tick)
- : "r" (tick_offset));
- } while(tick >= compare);
+ node = prom_finddevice("/counter-timer");
+ if(node == 0) {
+ prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
+ prom_halt();
}
-}
+ err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'reg' for counter-timer.\n");
+ prom_halt();
+ }
+ err = prom_getproperty(node, "interrupts", (char *)&pirqs[0], sizeof(pirqs));
+ if(err == -1) {
+ prom_printf("init_timers: Cannot obtain 'interrupts' "
+ "for counter-timer.\n");
+ prom_halt();
+ }
+ linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
-/* This is called from time_init() to get the jiffies timer going. */
-void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
-{
- int node, err;
+ /* Shut it up first. */
+ linux_timers->limit0 = 0;
+
+ /* Register IRQ handler. */
+ err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
+ cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
- /* XXX FIX this for SMP -JJ */
- node = linux_cpus [0].prom_node;
- cpu_cfreq = prom_getint(node, "clock-frequency");
- tick_offset = cpu_cfreq / HZ;
- err = request_irq(14, timer_handler, (SA_INTERRUPT|SA_STATIC_ALLOC),
- "timer", NULL);
if(err) {
prom_printf("Serious problem, cannot register timer interrupt\n");
prom_halt();
@@ -630,27 +731,33 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
save_and_cli(flags);
- __asm__ __volatile__("wr %0, 0x0, %%tick_cmpr\n\t"
- "wrpr %%g0, 0x0, %%tick"
- : /* No outputs */
- : "r" (tick_offset));
-
- clear_softint (get_softint ());
+ /* Set things up so user can access tick register for profiling
+ * purposes.
+ */
+ __asm__ __volatile__("
+ sethi %%hi(0x80000000), %%g1
+ sllx %%g1, 32, %%g1
+ rd %%tick, %%g2
+ add %%g2, 6, %%g2
+ andn %%g2, %%g1, %%g2
+ wrpr %%g2, 0, %%tick
+" : /* no outputs */
+ : /* no inputs */
+ : "g1", "g2");
+
+ linux_timers->limit0 =
+ (SUN5_LIMIT_ENABLE | SUN5_LIMIT_ZRESTART | SUN5_LIMIT_TOZERO |
+ (SUN5_HZ_TO_LIMIT(HZ) & SUN5_LIMIT_CMASK));
restore_flags(flags);
}
+
sti();
}
-/* We use this nowhere else, so only define it's layout here. */
-struct sun5_timer {
- volatile u32 count0, _unused0;
- volatile u32 limit0, _unused1;
- volatile u32 count1, _unused2;
- volatile u32 limit1, _unused3;
-} *prom_timers;
+struct sun5_timer *prom_timers;
-static u32 prom_limit0, prom_limit1;
+static u64 prom_limit0, prom_limit1;
static void map_prom_timers(void)
{
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 89f63f78f..afd5af8d0 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
+/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
* arch/sparc64/kernel/process.c
*
* Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -50,9 +50,12 @@ asmlinkage int sys_idle(void)
return -EPERM;
/* endless idle loop with no priority at all */
+ current->priority = -100;
current->counter = -100;
- for (;;)
+ for (;;) {
+ run_task_queue(&tq_scheduler);
schedule();
+ }
return 0;
}
@@ -61,42 +64,27 @@ asmlinkage int sys_idle(void)
/*
* the idle loop on a UltraMultiPenguin...
*/
-asmlinkage int sys_idle(void)
+asmlinkage int cpu_idle(void)
{
- if (current->pid != 0)
- return -EPERM;
-
- /* endless idle loop with no priority at all */
- current->counter = -100;
- schedule();
- return 0;
+ current->priority = -100;
+ while(1) {
+ if(tq_scheduler) {
+ lock_kernel();
+ run_task_queue(&tq_scheduler);
+ unlock_kernel();
+ }
+ current->counter = -100;
+ schedule();
+ }
}
-/* This is being executed in task 0 'user space'. */
-int cpu_idle(void *unused)
+asmlinkage int sys_idle(void)
{
- volatile int *spap = &smp_process_available;
- volatile int cval;
+ if(current->pid != 0)
+ return -EPERM;
- while(1) {
- if(0==*spap)
- continue;
- cli();
- /* Acquire exclusive access. */
- while((cval = smp_swap(spap, -1)) == -1)
- while(*spap == -1)
- ;
- if (0==cval) {
- /* ho hum, release it. */
- *spap = 0;
- sti();
- continue;
- }
- /* Something interesting happened, whee... */
- *spap = (cval - 1);
- sti();
- idle();
- }
+ cpu_idle();
+ return 0;
}
#endif
@@ -467,7 +455,11 @@ void fault_in_user_windows(struct pt_regs *regs)
* allocate the task_struct and kernel stack in
* do_fork().
*/
+#ifdef __SMP__
+extern void ret_from_smpfork(void);
+#else
extern void ret_from_syscall(void);
+#endif
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
struct task_struct *p, struct pt_regs *regs)
@@ -485,7 +477,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
child_trap_frame = ((char *)p) + stack_offset;
memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size);
p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS;
+#ifdef __SMP__
+ p->tss.kpc = ((unsigned long) ret_from_smpfork) - 0x8;
+#else
p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
+#endif
p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
p->tss.cwp = regs->u_regs[UREG_G0];
if(regs->tstate & TSTATE_PRIV) {
@@ -495,6 +491,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
p->tss.ctx = 0;
p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p;
} else {
+ if(current->tss.flags & SPARC_FLAG_32BIT) {
+ sp &= 0x00000000ffffffff;
+ regs->u_regs[UREG_FP] &= 0x00000000ffffffff;
+ }
p->tss.kregs->u_regs[UREG_FP] = sp;
p->tss.flags &= ~SPARC_FLAG_KTHREAD;
p->tss.current_ds = USER_DS;
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 680baf7de..7eb47e976 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $
+/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $
* linux/arch/sparc64/kernel/setup.c
*
* Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -405,11 +405,7 @@ extern char *mmu_info(void);
int get_cpuinfo(char *buffer)
{
-#ifndef __SMP__
- int cpuid=0;
-#else
-#error SMP not supported on sparc64 yet
-#endif
+ int cpuid=smp_processor_id();
return sprintf(buffer, "cpu\t\t: %s\n"
"fpu\t\t: %s\n"
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 88d7a8ecf..77ccf40a0 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -3,6 +3,26 @@
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tasks.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/spinlock.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -13,8 +33,9 @@ volatile int smp_processors_ready = 0;
unsigned long cpu_present_map = 0;
int smp_num_cpus = 1;
int smp_threads_ready = 0;
+volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
-struct cpuinfo_sparc64 cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS];
static unsigned char boot_cpu_id = 0;
static int smp_activated = 0;
@@ -52,11 +73,11 @@ void smp_store_cpu_info(int id)
void smp_commence(void)
{
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_commenced = 1;
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
}
static void smp_setup_percpu_timer(void);
@@ -67,8 +88,8 @@ void smp_callin(void)
{
int cpuid = hard_smp_processor_id();
- local_flush_cache_all();
- local_flush_tlb_all();
+ flush_cache_all();
+ flush_tlb_all();
smp_setup_percpu_timer();
@@ -76,7 +97,7 @@ void smp_callin(void)
smp_store_cpu_info(cpuid);
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
- "flush %g6" : : : "memory");
+ "flush %%g6" : : : "memory");
while(!task[cpuid])
barrier();
@@ -103,11 +124,18 @@ int start_secondary(void *unused)
return cpu_idle(NULL);
}
+void cpu_panic(void)
+{
+ printk("CPU[%d]: Returns from cpu_idle!\n", smp_processor_id());
+ panic("SMP bolixed\n");
+}
+
extern struct prom_cpuinfo linux_cpus[NR_CPUS];
+extern unsigned long sparc64_cpu_startup;
void smp_boot_cpus(void)
{
- int cpucount = 0, i, first, prev;
+ int cpucount = 0, i;
printk("Entering UltraSMPenguin Mode...\n");
__sti();
@@ -133,15 +161,15 @@ void smp_boot_cpus(void)
continue;
if(cpu_present_map & (1 << i)) {
- extern unsigned long sparc64_cpu_startup;
- unsigned long entry = (unsigned long)&sparc_cpu_startup;
struct task_struct *p;
int timeout;
kernel_thread(start_secondary, NULL, CLONE_PID);
p = task[++cpucount];
p->processor = i;
- prom_startcpu(linux_cpus[i].prom_node, entry, i);
+ prom_startcpu(linux_cpus[i].prom_node,
+ ((unsigned long)&sparc64_cpu_startup),
+ ((unsigned long)p));
for(timeout = 0; timeout < 5000000; timeout++) {
if(cpu_callin_map[i])
break;
@@ -190,49 +218,46 @@ void smp_message_pass(int target, int msg, unsigned long data, int wait)
barrier();
}
-/* XXX Make it fast later. */
+static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
+{
+ u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+
+ __asm__ __volatile__("
+ wrpr %0, %1, %%pstate
+ wr %%g0, %2, %%asi
+ stxa %3, [0x40] %%asi
+ stxa %4, [0x50] %%asi
+ stxa %5, [0x60] %%asi
+ stxa %%g0, [%6] %%asi
+ membar #Sync"
+ : /* No outputs */
+ : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
+ "r" (data0), "r" (data1), "r" (data2), "r" (target));
+
+ /* NOTE: PSTATE_IE is still clear. */
+ do {
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (result)
+ : "i" (ASI_INTR_DISPATCH_STAT));
+ } while(result & 0x1);
+ __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+ : : "r" (pstate));
+ if(result & 0x2)
+ panic("Penguin NACK's master!");
+}
+
void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
if(smp_processors_ready) {
- unsigned long mask;
- u64 data0 = (((unsigned long)ctx)<<32 |
- (((unsigned long)func) & 0xffffffff));
- u64 pstate;
+ unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+ u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
int i, ncpus = smp_num_cpus;
__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
- mask = (cpu_present_map & ~(1 << smp_processor_id()));
for(i = 0; i < ncpus; i++) {
- if(mask & (1 << i)) {
- u64 target = mid<<14 | 0x70;
- u64 result;
-
- __asm__ __volatile__("
- wrpr %0, %1, %%pstate
- wrpr %%g0, %2, %%asi
- stxa %3, [0x40] %%asi
- stxa %4, [0x50] %%asi
- stxa %5, [0x60] %%asi
- stxa %%g0, [%6] %7
- membar #Sync"
- : /* No outputs */
- : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
- "r" (data0), "r" (data1), "r" (data2),
- "r" (target), "i" (ASI_UDB_INTR_W));
-
- /* NOTE: PSTATE_IE is still clear. */
- do {
- __asm__ __volatile__("ldxa [%%g0] %1, %0",
- : "=r" (result)
- : "i" (ASI_INTR_DISPATCH_STAT));
- } while(result & 0x1);
- __asm__ __volatile__("wrpr %0, 0x0, %%pstate"
- : : "r" (pstate));
- if(result & 0x2)
- panic("Penguin NACK's master!");
- }
+ if(mask & (1 << i))
+ xcall_deliver(data0, data1, data2, pstate, i);
}
-
/* NOTE: Caller runs local copy on master. */
}
}
@@ -246,17 +271,19 @@ extern unsigned long xcall_flush_cache_all;
void smp_flush_cache_all(void)
{
smp_cross_call(&xcall_flush_cache_all, 0, 0, 0);
+ __flush_cache_all();
}
void smp_flush_tlb_all(void)
{
smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0);
+ __flush_tlb_all();
}
void smp_flush_tlb_mm(struct mm_struct *mm)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
__flush_tlb_mm(ctx);
}
@@ -265,7 +292,7 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
__flush_tlb_range(ctx, start, end);
}
@@ -275,7 +302,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
struct mm_struct *mm = vma->vm_mm;
u32 ctx = mm->context & 0x1fff;
- if(mm->cpu_vm_mask != (1 << smp_processor_id()))
+ if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
__flush_tlb_page(ctx, page);
}
@@ -308,12 +335,12 @@ extern void update_one_process(struct task_struct *p, unsigned long ticks,
void smp_percpu_timer_interrupt(struct pt_regs *regs)
{
int cpu = smp_processor_id();
+ int user = user_mode(regs);
- clear_profile_irq(cpu);
- if(!user_mode(regs))
- sparc_do_profile(regs->pc);
+ /* XXX clear_profile_irq(cpu); */
+ if(!user)
+ sparc64_do_profile(regs->tpc);
if(!--prof_counter[cpu]) {
- int user = user_mode(regs);
if(current->pid) {
update_one_process(current, 1, user, !user);
if(--current->counter < 0) {
@@ -344,4 +371,5 @@ static void smp_setup_percpu_timer(void)
int setup_profiling_timer(unsigned int multiplier)
{
/* XXX implement me */
+ return 0;
}
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index ad40a5fb5..df6a1c05e 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.3 1997/06/17 13:25:29 jj Exp $
+/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
* time.c: UltraSparc timer and TOD clock support.
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
#include <asm/oplib.h>
#include <asm/mostek.h>
+#include <asm/timer.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -35,11 +36,17 @@ static int set_rtc_mmss(unsigned long);
* NOTE: On SUN5 systems the ticker interrupt comes in using 2
* interrupts, one at level14 and one with softint bit 0.
*/
-void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+extern struct sun5_timer *linux_timers;
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
/* last time the cmos clock got updated */
static long last_rtc_update=0;
+ __asm__ __volatile__("ldx [%0], %%g0"
+ : /* no outputs */
+ : "r" (&((linux_timers)->limit0)));
+
do_timer(regs);
/* Determine when to update the Mostek clock. */
@@ -239,14 +246,12 @@ __initfunc(static void clock_probe(void))
__initfunc(void time_init(void))
{
- extern void init_timers(void (*func)(int, void *, struct pt_regs *));
unsigned int year, mon, day, hour, min, sec;
struct mostek48t02 *mregs;
do_get_fast_time = do_gettimeofday;
clock_probe();
- init_timers(timer_interrupt);
mregs = mstk48t02_regs;
if(!mregs) {
@@ -266,6 +271,13 @@ __initfunc(void time_init(void))
mregs->creg &= ~MSTK_CREG_READ;
}
+extern void init_timers(void (*func)(int, void *, struct pt_regs *));
+
+__initfunc(void sun4u_start_timers(void))
+{
+ init_timers(timer_interrupt);
+}
+
static __inline__ unsigned long do_gettimeoffset(void)
{
unsigned long offset = 0;
@@ -286,16 +298,39 @@ static __inline__ unsigned long do_gettimeoffset(void)
void do_gettimeofday(struct timeval *tv)
{
- unsigned long flags;
-
- save_and_cli(flags);
- *tv = xtime;
- tv->tv_usec += do_gettimeoffset();
- if(tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
- restore_flags(flags);
+ /* Load doubles must be used on xtime so that what we get
+ * is guarenteed to be atomic, this is why we can run this
+ * with interrupts on full blast. Don't touch this... -DaveM
+ */
+ __asm__ __volatile__("
+ sethi %hi(linux_timers), %o1
+ sethi %hi(xtime), %g2
+ ldx [%o1 + %lo(linux_timers)], %g3
+1: ldd [%g2 + %lo(xtime)], %o4
+ ldx [%g3], %o1
+ ldd [%g2 + %lo(xtime)], %o2
+ xor %o4, %o2, %o2
+ xor %o5, %o3, %o3
+ orcc %o2, %o3, %g0
+ bne,pn %icc, 1b
+ cmp %o1, 0
+ bge,pt %icc, 1f
+ sethi %hi(tick), %o3
+ ld [%o3 + %lo(tick)], %o3
+ sethi %hi(0x1fffff), %o2
+ or %o2, %lo(0x1fffff), %o2
+ add %o5, %o3, %o5
+ and %o1, %o2, %o1
+1: add %o5, %o1, %o5
+ sethi %hi(1000000), %o2
+ or %o2, %lo(1000000), %o2
+ cmp %o5, %o2
+ bl,a,pn %icc, 1f
+ st %o4, [%o0 + 0x0]
+ add %o4, 0x1, %o4
+ sub %o5, %o2, %o5
+ st %o4, [%o0 + 0x0]
+1: st %o5, [%o0 + 0x4]");
}
void do_settimeofday(struct timeval *tv)
diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S
index a1154cb6d..74054f63a 100644
--- a/arch/sparc64/lib/locks.S
+++ b/arch/sparc64/lib/locks.S
@@ -1,77 +1,77 @@
-/* $Id: locks.S,v 1.2 1997/03/10 12:28:02 jj Exp $
+/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
* locks.S: SMP low-level lock primitives on Sparc64.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <asm/asm_offsets.h>
#include <asm/ptrace.h>
+#include <asm/smp.h>
.text
- .align 4
-
- .globl __spinlock_waitfor
-__spinlock_waitfor:
-1: orcc %g2, 0x0, %g0
- bne 1b
- ldub [%g1], %g2
- ldstub [%g1], %g2
- jmpl %o7 - 12, %g0
- mov %g5, %o7
-
- .globl ___become_idt
-___become_idt:
-#if 0 /* Don't know how to do this on the Ultra yet... */
-#endif
- jmpl %o7 + 8, %g0
- mov %g5, %o7
+ .align 32
___lk_busy_spin:
- orcc %g2, 0, %g0
- bne ___lk_busy_spin
- ldub [%g1 + 0], %g2
- b 1f
- ldstub [%g1 + 0], %g2
+ orcc %g2, 0, %g0
+ bne,pt %icc, ___lk_busy_spin
+ ldub [%g1 + 0], %g2
+ b,pt %xcc, 1f
+ ldstub [%g1 + 0], %g2
- .globl ___lock_kernel
+ .globl ___lock_kernel
___lock_kernel:
- addcc %g2, -1, %g2
- rdpr %pil, %g3
- bcs,a 9f
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr 15, %pil
- ldstub [%g1 + 0], %g2
-1: orcc %g2, 0, %g0
- bne,a ___lk_busy_spin
- ldub [%g1 + 0], %g2
- ldub [%g1 + 2], %g2
- cmp %g2, %g5
- be 2f
- stb %g5, [%g1 + 1]
- stb %g5, [%g1 + 2]
-#ifdef __SMP__
- /* XXX Figure out how to become interrupt receiver in SMP system. */
-#endif
-2: mov -1, %g2
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, %pil
-9: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
+ addcc %g2, -1, %g2
+ rdpr %pil, %g3
+ bcs,a,pn %icc, 9f
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr %g0, 15, %pil
+ ldstub [%g1 + 0], %g2
+1: brnz,a,pn %g2, ___lk_busy_spin
+ ldub [%g1 + 0], %g2
+ lduw [%g6 + AOFF_task_processor], %g2
+ membar #LoadLoad | #LoadStore
+ stb %g2, [%g1 + 1]
+2: mov -1, %g2
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr %g3, 0, %pil
+9: jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
+
+ .globl ___lock_reacquire_kernel
+___lock_reacquire_kernel:
+ rdpr %pil, %g3
+ wrpr %g0, 15, %pil
+ st %g2, [%g6 + AOFF_task_lock_depth]
+ ldstub [%g1 + 0], %g2
+1: brz,pt %g2, 3f
+ ldub [%g1 + 0], %g2
+2: brnz,a,pt %g2, 2b
+ ldub [%g1 + 0], %g2
+ b,pt %xcc, 1b
+ ldstub [%g1 + 0], %g2
+3: lduw [%g6 + AOFF_task_processor], %g2
+ membar #LoadLoad | #LoadStore
+ stb %g2, [%g1 + 1]
+ wrpr %g3, 0, %pil
+ jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
#undef NO_PROC_ID
#define NO_PROC_ID 0xff
- .globl ___unlock_kernel
+ .globl ___unlock_kernel
___unlock_kernel:
- addcc %g2, 1, %g2
- rdpr %pil, %g3
- bne,a 1f
- st %g2, [%g6 + AOFF_task_lock_depth]
- wrpr 15, %pil
- mov NO_PROC_ID, %g2
- stb %g2, [%g1 + 1]
- stb %g0, [%g1 + 0]
- st %g0, [%g6 + AOFF_task_lock_depth]
- wrpr %g3, %pil
-1: jmpl %o7 + 0x8, %g0
- mov %g5, %o7
+ addcc %g2, 1, %g2
+ rdpr %pil, %g3
+ bne,a,pn %icc, 1f
+ stw %g2, [%g6 + AOFF_task_lock_depth]
+ wrpr 15, %pil
+ mov NO_PROC_ID, %g2
+ stb %g2, [%g1 + 1]
+ membar #StoreStore | #LoadStore
+ stb %g0, [%g1 + 0]
+ stw %g0, [%g6 + AOFF_task_lock_depth]
+ wrpr %g3, 0, %pil
+1: jmpl %o7 + 0x8, %g0
+ mov %g5, %o7
diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
index dddf3153b..72f4fa079 100644
--- a/arch/sparc64/mm/Makefile
+++ b/arch/sparc64/mm/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.3 1997/06/27 14:53:38 jj Exp $
+# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $
# Makefile for the linux Sparc64-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -7,12 +7,24 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
+ifdef SMP
+
+.S.s:
+ $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s
+
+.S.o:
+ $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o
+
+else
+
.S.s:
$(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o
+endif
+
O_TARGET := mm.o
O_OBJS := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index a8d903b25..386c8540f 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.39 1997/07/07 02:50:57 davem Exp $
+/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
* arch/sparc64/mm/init.c
*
* Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -431,8 +431,17 @@ void prom_reload_locked(void)
membar("#Sync");
}
+void __flush_cache_all(void)
+{
+ unsigned long va;
+
+ flushw_all();
+ for(va = 0; va < (PAGE_SIZE << 1); va += 32)
+ spitfire_put_icache_tag(va, 0x0);
+}
+
/* If not locked, zap it. */
-void flush_tlb_all(void)
+void __flush_tlb_all(void)
{
unsigned long flags;
int i;
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index b11903a25..18f9a363d 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -1,10 +1,11 @@
-/* $Id: ultra.S,v 1.1 1997/07/18 06:26:55 ralf Exp $
+/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
* ultra.S: Don't expand these all over the place...
*
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
*/
#include <asm/asi.h>
+#include <asm/pgtable.h>
#include <asm/spitfire.h>
/* All callers check mm->context != NO_CONTEXT for us. */
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index a4aea63b8..40b33da4b 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -1,4 +1,4 @@
-/* $Id: console.c,v 1.6 1997/03/18 17:59:59 jj Exp $
+/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
@@ -88,6 +88,7 @@ prom_query_input_device()
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
@@ -116,6 +117,7 @@ prom_query_output_device()
if(strncmp("serial", propb, sizeof("serial")))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
+ memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
if (strncmp (propb, "tty", 3) || !propb[3] || propb[4])
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 8b738fd41..9720f1a70 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -1,4 +1,4 @@
-/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $
+/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
@@ -135,7 +135,7 @@ void prom_set_trap_table(unsigned long tba)
}
#ifdef __SMP__
-void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0)
+void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0)
{
p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0);
}
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index 18de40deb..0703b5cd7 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.10 1997/06/27 04:18:30 davem Exp $
+/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
* p1275.c: Sun IEEE 1275 PROM low level interface routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -6,6 +6,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
#include <linux/string.h>
#include <asm/openprom.h>
diff --git a/drivers/Makefile b/drivers/Makefile
index df324c4bb..c152af2eb 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -9,7 +9,7 @@
SUB_DIRS := block char net misc #streams
MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sound cdrom isdn misc pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sound cdrom isdn pnp
ifdef CONFIG_PCI
SUB_DIRS += pci
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 740a3780a..e14cf09c7 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -370,7 +370,7 @@ static void redo_acsi_request( void );
static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int acsi_open( struct inode * inode, struct file * filp );
-static void acsi_release( struct inode * inode, struct file * file );
+static int acsi_release( struct inode * inode, struct file * file );
static void acsi_prevent_removal( int target, int flag );
static int acsi_change_blk_size( int target, int lun);
static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
@@ -1200,7 +1200,7 @@ static int acsi_open( struct inode * inode, struct file * filp )
* be forgotten about...
*/
-static void acsi_release( struct inode * inode, struct file * file )
+static int acsi_release( struct inode * inode, struct file * file )
{
int device;
@@ -1210,6 +1210,7 @@ static void acsi_release( struct inode * inode, struct file * file )
if (--access_count[device] == 0 && acsi_info[device].removable)
acsi_prevent_removal(device, 0);
MOD_DEC_USE_COUNT;
+ return( 0 );
}
/*
@@ -1821,7 +1822,7 @@ void cleanup_module(void)
{
del_timer( &acsi_timer );
blk_dev[MAJOR_NR].request_fn = 0;
- free_pages( acsi_buffer, ACSI_BUFFER_ORDER );
+ free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER );
if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
printk( KERN_ERR "acsi: cleanup_module failed\n");
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index da9af49b0..97957c0ea 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -117,7 +117,9 @@ static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 };
static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 };
static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 };
static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 };
+#if 0
static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 };
+#endif
#define MAX_SLM 2
@@ -262,11 +264,13 @@ static long slm_write( struct inode *node, struct file *file, const char *buf,
static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int slm_open( struct inode *inode, struct file *file );
-static void slm_release( struct inode *inode, struct file *file );
+static int slm_release( struct inode *inode, struct file *file );
static int slm_req_sense( int device );
static int slm_mode_sense( int device, char *buffer, int abs_flag );
+#if 0
static int slm_mode_select( int device, char *buffer, int len, int
default_flag );
+#endif
static int slm_get_pagesize( int device, int *w, int *h );
/************************* End of Prototypes **************************/
@@ -794,7 +798,7 @@ static int slm_open( struct inode *inode, struct file *file )
}
-static void slm_release( struct inode *inode, struct file *file )
+static int slm_release( struct inode *inode, struct file *file )
{ int device;
struct slm *sip;
@@ -806,6 +810,8 @@ static void slm_release( struct inode *inode, struct file *file )
sip->wbusy = 0;
if (file->f_mode & 1)
sip->rbusy = 0;
+
+ return( 0 );
}
@@ -876,6 +882,8 @@ static int slm_mode_sense( int device, char *buffer, int abs_flag )
}
+#if 0
+/* currently unused */
static int slm_mode_select( int device, char *buffer, int len,
int default_flag )
@@ -911,6 +919,7 @@ static int slm_mode_select( int device, char *buffer, int len,
stdma_release();
return( rv );
}
+#endif
static int slm_get_pagesize( int device, int *w, int *h )
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 0217dcb52..1ee709737 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -979,14 +979,14 @@ static inline void setup_dev(struct gendisk *dev)
__initfunc(void device_setup(void))
{
extern void console_map_init(void);
-#ifdef CONFIG_PNP_PARPORT
- extern int pnp_parport_init(void);
+#ifdef CONFIG_PARPORT
+ extern int parport_init(void);
#endif
struct gendisk *p;
int nr=0;
-#ifdef CONFIG_PNP_PARPORT
- pnp_parport_init();
+#ifdef CONFIG_PARPORT
+ parport_init();
#endif
chr_dev_init();
blk_dev_init();
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 0ef43d101..65407caf6 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -99,5 +99,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 18d50bf74..ad3664204 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -267,6 +267,16 @@ M = y
L_OBJS += rtc.o
endif
+ifeq ($(CONFIG_NVRAM),y)
+M = y
+L_OBJS += nvram.o
+else
+ ifeq ($(CONFIG_NVRAM),m)
+ MM = m
+ M_OBJS += nvram.o
+ endif
+endif
+
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
else
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index 7db3b5dba..4a5bea195 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -221,8 +221,7 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
if (remap_page_range(vma->vm_start, vma->vm_offset,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+ vma->vm_dentry = dget(file->f_dentry);
return 0;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d29653c8a..932578806 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -37,6 +37,7 @@
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
#include <linux/kbd_ll.h>
+#include <linux/sysrq.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
@@ -148,8 +149,6 @@ static unsigned char handle_diacr(unsigned char);
struct pt_regs * kbd_pt_regs;
#ifdef CONFIG_MAGIC_SYSRQ
-#define SYSRQ_KEY 0x54
-extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
static int sysrq_pressed;
#endif
@@ -239,7 +238,7 @@ void handle_scancode(unsigned char scancode)
return;
} else if (sysrq_pressed) {
if (!up_flag)
- handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+ handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
return;
}
#endif
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index caf5b5ccf..59bb0a0a2 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -500,7 +500,7 @@ static int lp_release(struct inode * inode, struct file * file)
unsigned int minor = MINOR(inode->i_rdev);
unsigned int irq;
- if ((irq = LP_IRQ(minor))) {
+ if ((irq = LP_IRQ(minor)) != PARPORT_IRQ_NONE) {
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
lp_table[minor].lp_buffer = NULL;
}
@@ -642,7 +642,7 @@ void lp_setup(char *str, int *ints)
parport[0] = -3;
} else {
if (ints[0] == 0 || ints[1] == 0) {
- /* disable driver on "parport=" or "parport=0" */
+ /* disable driver on "lp=" or "lp=0" */
parport[0] = -2;
} else {
printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
@@ -652,19 +652,18 @@ void lp_setup(char *str, int *ints)
#endif
-int lp_wakeup(void *ref)
+void lp_wakeup(void *ref)
{
struct lp_struct *lp_dev = (struct lp_struct *) ref;
if (!lp_dev->lp_wait_q)
- return 1; /* Wake up whom? */
+ return; /* Wake up whom? */
/* Claim the Parport */
if (parport_claim(lp_dev->dev))
- return 1; /* Shouldn't happen */
+ return; /* Shouldn't happen */
wake_up(&lp_dev->lp_wait_q);
- return 0;
}
static int inline lp_searchfor(int list[], int a)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 063503595..6e9eb5766 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -133,6 +133,10 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
if (x86 > 3 && offset >= __pa(high_memory))
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
#endif
+#ifdef __powerpc__
+ if (offset >= __pa(high_memory))
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+#endif
if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_dentry = dget(file->f_dentry);
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 6262792b6..4495f881d 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -76,6 +76,7 @@ extern void wdt_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
extern int dsp56k_init(void);
+extern int nvram_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -244,6 +245,9 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
+#ifdef CONFIG_NVRAM
+ nvram_init();
+#endif
#ifdef CONFIG_SGI_GRAPHICS
gfx_register ();
streamable_init ();
diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
index 7a6b8cde0..d9c5ac453 100644
--- a/drivers/char/pc110pad.c
+++ b/drivers/char/pc110pad.c
@@ -492,7 +492,7 @@ static int close_pad(struct inode * inode, struct file * file)
{
fasync_pad(inode, file, 0);
if (--active)
- return;
+ return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
MOD_DEC_USE_COUNT;
return 0;
@@ -640,7 +640,7 @@ static struct miscdevice pc110_pad = {
};
-static int pc110pad_init(void)
+int pc110pad_init(void)
{
current_params = default_params;
diff --git a/drivers/char/pc110pad.h b/drivers/char/pc110pad.h
index 56d8d82e0..d0ea0b0d3 100644
--- a/drivers/char/pc110pad.h
+++ b/drivers/char/pc110pad.h
@@ -26,6 +26,6 @@ struct pc110pad_params {
#define PC110PAD_IOCTL_TYPE 0x9a
#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
#endif /* _PC110PAD_H */
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index fd1c8e862..866a4170f 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -7,6 +7,8 @@
* Major cleanup by Martin Mares, May 1997
*/
+#include <linux/config.h>
+
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -25,21 +27,38 @@
#include "pc_keyb.h"
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char pckbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
/*
* In case we run on a non-x86 hardware we need to initialize both the keyboard
* controller and the keyboard. On a x86, the BIOS will already have initialized
* them.
*/
+#ifndef __i386__
+#define INIT_KBD
+#endif
+
#ifdef INIT_KBD
__initfunc(static int kbd_wait_for_input(void))
{
- int n;
- int status, data;
+ int n;
+ int status, data;
+ unsigned long start = jiffies;
- n = KBD_TIMEOUT;
- do {
+ do {
status = kbd_read_status();
/*
* Wait for input data to become available. This bit will
@@ -62,7 +81,7 @@ __initfunc(static int kbd_wait_for_input(void))
continue;
}
return (data & 0xff);
- } while (--n);
+ } while (jiffies - start < KBD_INIT_TIMEOUT);
return -1; /* timed-out if fell through to here... */
}
@@ -165,12 +184,11 @@ __initfunc(static char *initialize_kbd2(void))
__initfunc(void initialize_kbd(void))
{
- unsigned long flags;
char *msg;
- save_flags(flags); cli();
+ disable_irq(KEYBOARD_IRQ);
msg = initialize_kbd2();
- restore_flags(flags);
+ enable_irq(KEYBOARD_IRQ);
if (msg)
printk(KERN_WARNING "initialize_kbd: %s\n", msg);
@@ -191,12 +209,15 @@ static volatile unsigned char resend = 0;
static inline void kb_wait(void)
{
- int i;
+ unsigned long start = jiffies;
- for (i=0; i<KBD_TIMEOUT; i++)
+ do {
if (! (kbd_read_status() & KBD_STAT_IBF))
return;
+ } while (jiffies - start < KBC_TIMEOUT);
+#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timed out\n");
+#endif
}
/*
@@ -374,7 +395,7 @@ static int do_acknowledge(unsigned char scancode)
}
if (scancode == 0) {
#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "keyboard buffer overflow\n");
+ printk(KERN_INFO "Keyboard buffer overflow\n");
#endif
prev_scancode = 0;
return 0;
@@ -390,7 +411,7 @@ int pckbd_pretranslate(unsigned char scancode, char raw_mode)
#ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR
if (!raw_mode)
- printk(KERN_DEBUG "keyboard error\n");
+ printk(KERN_DEBUG "Keyboard error\n");
#endif
#endif
prev_scancode = 0;
@@ -505,15 +526,17 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned char scancode;
/* mouse data? */
- if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF)
+ if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF){
+ printk ("MOUSE!\n");
break;
+ }
scancode = kbd_read_input();
if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
handle_scancode(scancode);
status = kbd_read_status();
- } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
+ } while (status & KBD_STAT_OBF);
mark_bh(KEYBOARD_BH);
enable_keyboard();
@@ -527,7 +550,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int send_data(unsigned char data)
{
int retries = 3;
- int i;
+ unsigned long start;
do {
kb_wait();
@@ -536,16 +559,21 @@ static int send_data(unsigned char data)
reply_expected = 1;
kbd_write_output(data);
kbd_pause();
- for(i=0; i<0x200000; i++) {
- kbd_read_status(); /* just as a delay */
+ start = jiffies;
+ do {
if (acknowledge)
return 1;
- if (resend)
- break;
- }
- if (!resend)
- return 0;
+ if (jiffies - start >= KBD_TIMEOUT) {
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "Keyboard timeout\n");
+#endif
+ return 0;
+ }
+ } while (!resend);
} while (retries-- > 0);
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
+#endif
return 0;
}
@@ -557,7 +585,7 @@ void pckbd_leds(unsigned char leds)
__initfunc(void pckbd_init_hw(void))
{
- request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard-aaa", NULL);
keyboard_setup();
#ifdef INIT_KBD
initialize_kbd();
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index f12ddab08..ffbfc49e2 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -12,8 +12,12 @@
#define KBD_REPORT_ERR /* Report keyboard errors */
#define KBD_REPORT_UNKN /* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_TIMEOUT 0x100000 /* Timeout for sending of commands */
+
+#define KBD_INIT_TIMEOUT HZ /* Timeout for initializing the keyboard */
+#define KBC_TIMEOUT (HZ/4) /* Timeout for sending to keyboard controller */
+#define KBD_TIMEOUT (HZ/4) /* Timeout for keyboard command acknowledge */
/*
* Internal variables of the driver
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index d329a6883..78089e833 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -53,6 +53,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/semaphore.h>
#include <linux/config.h>
@@ -143,25 +144,7 @@ static int poll_aux_status(void)
schedule();
retries++;
}
- return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
- int retries = 0;
- unsigned char status;
-
- while ((kbd_read_status() & (KBD_STAT_IBF | KBD_STAT_OBF))
- && retries < 1000000) {
- status = kbd_read_status();
- kbd_pause();
- if ((status & AUX_STAT_OBF) == AUX_STAT_OBF) {
- kbd_read_input();
- kbd_pause();
- }
- retries++;
- }
- return !(retries == 1000000);
+ return (retries < MAX_RETRIES);
}
/*
@@ -181,18 +164,10 @@ static void aux_write_dev(int val)
*/
#ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
- poll_aux_status_nosleep();
- kbd_write_command(KBD_CCMD_WRITE_MOUSE);
- poll_aux_status_nosleep();
- kbd_write_output(val);
-}
-
__initfunc(static int aux_write_ack(int val))
{
- aux_write_dev_nosleep(val);
- poll_aux_status_nosleep();
+ aux_write_dev(val);
+ poll_aux_status();
if ((kbd_read_status() & AUX_STAT_OBF) == AUX_STAT_OBF)
{
@@ -215,6 +190,31 @@ static void aux_write_cmd(int val)
}
/*
+ * AUX handler critical section start and end.
+ *
+ * Only one process can be in the critical section and all keyboard sends are
+ * deferred as long as we're inside. This is necessary as we may sleep when
+ * waiting for the keyboard controller and other processes / BH's can
+ * preempt us. Please note that the input buffer must be flushed when
+ * aux_end_atomic() is called and the interrupt is no longer enabled as not
+ * doing so might cause the keyboard driver to ignore all incoming keystrokes.
+ */
+
+static struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+ down(&aux_sema4);
+ disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+ enable_bh(KEYBOARD_BH);
+ up(&aux_sema4);
+}
+
+/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
*/
@@ -273,14 +273,12 @@ static int release_aux(struct inode * inode, struct file * file)
fasync_aux(inode, file, 0);
if (--aux_count)
return 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+ aux_start_atomic();
aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
poll_aux_status();
kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable Aux device */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
ps2_free_irq(inode);
MOD_DEC_USE_COUNT;
return 0;
@@ -291,27 +289,31 @@ static int open_aux(struct inode * inode, struct file * file)
{
if (!aux_present)
return -ENODEV;
- if (aux_count++)
+ aux_start_atomic();
+ if (aux_count++) {
+ aux_end_atomic();
return 0;
- if (!poll_aux_status()) {
+ }
+ if (!poll_aux_status()) { /* FIXME: Race condition */
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
queue->head = queue->tail = 0; /* Flush input queue */
if(ps2_request_irq()) {
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
MOD_INC_USE_COUNT;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+
+
poll_aux_status();
kbd_write_command(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux */
aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
aux_ready = 0;
return 0;
@@ -329,9 +331,7 @@ static long write_aux(struct inode * inode, struct file * file,
if (count) {
int written = 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
-
+ aux_start_atomic();
do {
char c;
if (!poll_aux_status())
@@ -343,8 +343,7 @@ static long write_aux(struct inode * inode, struct file * file,
kbd_write_output(c);
written++;
} while (--count);
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
retval = -EIO;
if (written) {
retval = written;
@@ -628,11 +627,7 @@ __initfunc(int psaux_init(void))
psaux_fops.release = release_qp;
} else
#endif
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
- if (1) {
-#else
if (aux_device_present == 0xaa) {
-#endif
printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
aux_present = 1;
#ifdef CONFIG_VT
@@ -647,20 +642,33 @@ __initfunc(int psaux_init(void))
queue->head = queue->tail = 0;
queue->proc_list = NULL;
if (!qp_found) {
+ printk ("AUX--1\n");
+ aux_start_atomic();
#ifdef INITIALIZE_DEVICE
+ printk ("AUX--2\n");
kbd_write_command(AUX_ENABLE); /* Enable Aux */
aux_write_ack(AUX_SET_SAMPLE);
+ printk ("AUX--3\n");
aux_write_ack(100); /* 100 samples/sec */
aux_write_ack(AUX_SET_RES);
aux_write_ack(3); /* 8 counts per mm */
+ printk ("AUX--4\n");
aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
- poll_aux_status_nosleep();
+ poll_aux_status();
+ printk ("AUX--5\n");
#endif /* INITIALIZE_DEVICE */
+ printk ("AUX--6\n");
kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable Aux device */
- poll_aux_status_nosleep();
- kbd_write_command(KBD_CCMD_WRITE_MODE);
- poll_aux_status_nosleep(); /* Disable interrupts */
- kbd_write_output(AUX_INTS_OFF); /* on the controller */
+ poll_aux_status();
+ printk ("AUX--7\n");
+ kbd_write_command(KBD_CCMD_WRITE_MODE); /* Disable controller interrupts */
+ kbd_pause ();
+ poll_aux_status();
+ printk ("AUX--8\n");
+ kbd_write_output (AUX_INTS_OFF);
+ kbd_pause ();
+ poll_aux_status();
+ aux_end_atomic();
}
return 0;
}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1e0e1a2a0..25396c3c1 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
*
- * $Id: sysrq.c,v 1.1 1997/06/17 13:24:07 ralf Exp $
+ * $Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
*
* Linux Magic System Request Key Hacks
*
@@ -63,72 +63,72 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
console_loglevel = 7;
printk(KERN_INFO "SysRq: ");
switch (key) {
- case 19: /* R -- Reset raw mode */
- kbd->kbdmode = VC_XLATE;
- printk("Keyboard mode set to XLATE\n");
+ case 'r': /* R -- Reset raw mode */
+ if (kbd) {
+ kbd->kbdmode = VC_XLATE;
+ printk("Keyboard mode set to XLATE\n");
+ }
break;
- case 30: /* A -- SAK */
+ case 'a': /* A -- SAK */
printk("SAK\n");
- do_SAK(tty);
+ if (tty)
+ do_SAK(tty);
reset_vc(fg_console);
break;
- case 48: /* B -- boot immediately */
+ case 'b': /* B -- boot immediately */
printk("Resetting\n");
machine_restart(NULL);
break;
#ifdef __sparc__
- case 35: /* H -- halt immediately */
+ case 'h': /* H -- halt immediately */
printk("Halting\n");
halt_now();
break;
#endif
#ifdef CONFIG_APM
- case 24: /* O -- power off */
+ case 'o': /* O -- power off */
printk("Power off\n");
apm_set_power_state(APM_STATE_OFF);
break;
#endif
- case 31: /* S -- emergency sync */
+ case 's': /* S -- emergency sync */
printk("Emergency Sync\n");
emergency_sync_scheduled = EMERG_SYNC;
wakeup_bdflush(0);
break;
- case 22: /* U -- emergency remount R/O */
+ case 'u': /* U -- emergency remount R/O */
printk("Emergency Remount R/O\n");
emergency_sync_scheduled = EMERG_REMOUNT;
wakeup_bdflush(0);
break;
- case 25: /* P -- show PC */
+ case 'p': /* P -- show PC */
printk("Show Regs\n");
if (pt_regs)
show_regs(pt_regs);
break;
- case 20: /* T -- show task info */
+ case 't': /* T -- show task info */
printk("Show State\n");
show_state();
break;
- case 50: /* M -- show memory info */
+ case 'm': /* M -- show memory info */
printk("Show Memory\n");
show_mem();
break;
- case 2 ... 11: /* 0-9 -- set console logging level */
- key--;
- if (key == 10)
- key = 0;
- orig_log_level = key;
- printk("Log level set to %d\n", key);
+ case '0' ... '9': /* 0-9 -- set console logging level */
+ orig_log_level = key - '0';
+ printk("Log level set to %d\n", orig_log_level);
break;
- case 18: /* E -- terminate all user processes */
+ case 'e': /* E -- terminate all user processes */
printk("Terminate All Tasks\n");
send_sig_all(SIGTERM, 0);
orig_log_level = 8; /* We probably have killed syslogd */
break;
- case 37: /* K -- kill all user processes */
+ case 'k': /* K -- kill all user processes */
printk("Kill All Tasks\n");
send_sig_all(SIGKILL, 0);
orig_log_level = 8;
break;
- case 38: /* L -- kill all processes including init */
+ case 'l': /* L -- kill all processes including init */
printk("Kill ALL Tasks (even init)\n");
send_sig_all(SIGKILL, 1);
orig_log_level = 8;
@@ -154,7 +154,7 @@ static void all_files_read_only(void) /* Kill write permissions of all files
struct file *file;
for (file = inuse_filps; file; file = file->f_next)
- if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+ if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
file->f_mode &= ~2;
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index d63578c55..4c6ecae22 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -688,7 +688,6 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
return -ENODEV;
idx = MINOR(device) - driver->minor_start;
- tty = driver->table[idx];
/*
* Check whether we need to acquire the tty semaphore to avoid
@@ -697,7 +696,8 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
down_tty_sem(idx);
/* check whether we're reopening an existing tty */
- if(tty) goto fast_track;
+ tty = driver->table[idx];
+ if (tty) goto fast_track;
/*
* First time open is complex, especially for PTY devices.
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
index afce24c98..c3fee1ae7 100644
--- a/drivers/char/vga.c
+++ b/drivers/char/vga.c
@@ -84,6 +84,12 @@ unsigned long video_port_base;
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
+#ifdef __powerpc__
+#define VGA_OFFSET 0xC0000000;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
/*
* By replacing the four outb_p with two back to back outw, we can reduce
* the window of opportunity to see text mislocated to the RHS of the
@@ -241,20 +247,20 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
#endif
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
- video_mem_base = 0xb0000;
+ video_mem_base = 0xb0000 + VGA_OFFSET;
video_port_reg = 0x3b4;
video_port_val = 0x3b5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAM;
- video_mem_term = 0xb8000;
+ video_mem_term = 0xb8000 + VGA_OFFSET;
*display_desc = "EGA+";
request_region(0x3b0,16,"ega");
}
else
{
video_type = VIDEO_TYPE_MDA;
- video_mem_term = 0xb2000;
+ video_mem_term = 0xb2000 + VGA_OFFSET;
*display_desc = "*MDA";
request_region(0x3b0,12,"mda");
request_region(0x3bf, 1,"mda");
@@ -263,14 +269,14 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
else /* If not, it is color. */
{
can_do_color = 1;
- video_mem_term = 0xb8000;
+ video_mem_term = 0xb8000 + VGA_OFFSET;
video_port_reg = 0x3d4;
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
int i ;
- video_mem_term = 0xc0000;
+ video_mem_term = 0xc0000 + VGA_OFFSET;
if (!ORIG_VIDEO_ISVGA) {
video_type = VIDEO_TYPE_EGAC;
@@ -288,8 +294,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
* controllers (it seems like setting MM=01
* and COE=1 isn't necessarily a good idea)
*/
- video_mem_base = 0xa0000;
- video_mem_term = 0xb0000;
+ video_mem_base = 0xa0000 + VGA_OFFSET;
+ video_mem_term = 0xb0000 + VGA_OFFSET;
outb_p (6, 0x3ce) ;
outb_p (6, 0x3cf) ;
#endif
@@ -321,7 +327,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
else
{
video_type = VIDEO_TYPE_CGA;
- video_mem_term = 0xba000;
+ video_mem_term = 0xba000 + VGA_OFFSET;
*display_desc = "*CGA";
request_region(0x3d4,2,"cga");
}
diff --git a/drivers/misc/parport_arc.c b/drivers/misc/parport_arc.c
index 8ceaee794..932ecab8c 100644
--- a/drivers/misc/parport_arc.c
+++ b/drivers/misc/parport_arc.c
@@ -1,4 +1,4 @@
-/* $Id: parport_arc.c,v 1.1 1997/07/25 01:53:12 ralf Exp $
+/* $Id: parport_arc.c,v 1.1 1997/07/29 03:59:12 ralf Exp $
* Parallel-port routines for ARC onboard hardware.
*
* Author: Phil Blundell <pjb27@cam.ac.uk>
@@ -10,7 +10,6 @@
#include <asm/io.h>
#include <asm/dma.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c
index 52f3c6e33..a0f280b2f 100644
--- a/drivers/misc/parport_init.c
+++ b/drivers/misc/parport_init.c
@@ -1,4 +1,4 @@
-/* $Id: parport_init.c,v 1.1 1997/07/25 01:53:14 ralf Exp $
+/* $Id: parport_init.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port initialisation code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -56,6 +56,7 @@ __initfunc(void parport_setup(char *str, int *ints))
#ifdef MODULE
int init_module(void)
{
+ parport_proc_init();
return 0;
}
@@ -79,7 +80,8 @@ __initfunc(int parport_init(void))
{
struct parport *pb;
- if (io[0] == PARPORT_DISABLE) return 1;
+ if (io[0] == PARPORT_DISABLE) return 1;
+ parport_proc_init();
#ifdef CONFIG_PARPORT_PC
parport_pc_init(io, irq, dma);
#endif
@@ -92,12 +94,15 @@ __initfunc(int parport_init(void))
EXPORT_SYMBOL(parport_claim);
EXPORT_SYMBOL(parport_release);
EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_unregister_port);
EXPORT_SYMBOL(parport_quiesce);
EXPORT_SYMBOL(parport_register_device);
EXPORT_SYMBOL(parport_unregister_device);
EXPORT_SYMBOL(parport_enumerate);
EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_proc_register);
+EXPORT_SYMBOL(parport_proc_unregister);
void inc_parport_count(void)
{
diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c
index 925f697f6..6c6dbd033 100644
--- a/drivers/misc/parport_pc.c
+++ b/drivers/misc/parport_pc.c
@@ -1,4 +1,4 @@
-/* $Id: parport_pc.c,v 1.1 1997/07/25 01:53:16 ralf Exp $
+/* $Id: parport_pc.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port routines for PC architecture
*
* Authors: Phil Blundell <pjb27@cam.ac.uk>
@@ -10,6 +10,7 @@
* and Philip Blundell <Philip.Blundell@pobox.com>
*/
+#include <linux/stddef.h>
#include <linux/tasks.h>
#include <asm/ptrace.h>
@@ -140,7 +141,7 @@ static void pc_enable_irq(struct parport *p)
static void pc_release_resources(struct parport *p)
{
if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
release_region(p->base+0x400, 3);
@@ -439,9 +440,10 @@ static int parport_SPP_supported(struct parport *pb)
*/
static int parport_ECR_present(struct parport *pb)
{
- int r, octr = pc_read_control(pb), oecr = pc_read_econtrol(pb);
+ unsigned int r, octr = pc_read_control(pb),
+ oecr = pc_read_econtrol(pb);
- r= pc_read_control(pb);
+ r = pc_read_control(pb);
if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03)) {
pc_write_control(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
@@ -820,7 +822,10 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
if (p->irq != PARPORT_IRQ_NONE)
printk(", irq %d", p->irq);
- if (p->irq != PARPORT_DMA_NONE)
+ if (p->dma == PARPORT_DMA_AUTO)
+ p->dma = (p->modes & PARPORT_MODE_PCECP)?
+ parport_dma_probe(p):PARPORT_DMA_NONE;
+ if (p->dma != PARPORT_DMA_NONE)
printk(", dma %d", p->dma);
printk(" [");
#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
@@ -835,6 +840,7 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
#undef printmode
printk("]\n");
+ parport_proc_register(p);
return 1;
}
@@ -868,7 +874,7 @@ MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
static int init_module(void)
{
- return (parport_pc_init(NULL, NULL, NULL)?0:1);
+ return (parport_pc_init(io, irq, dma)?0:1);
}
static void cleanup_module(void)
@@ -878,6 +884,8 @@ static void cleanup_module(void)
if (p->modes & PARPORT_MODE_PCSPP) {
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
+ parport_proc_unregister(p);
+ parport_unregister_port(p);
}
p = p->next;
}
diff --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c
index 5365c0df7..0fd03fddf 100644
--- a/drivers/misc/parport_procfs.c
+++ b/drivers/misc/parport_procfs.c
@@ -1,4 +1,4 @@
-/* $Id: parport_procfs.c,v 1.1 1997/07/25 01:53:18 ralf Exp $
+/* $Id: parport_procfs.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel port /proc interface code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -8,12 +8,12 @@
* and Philip Blundell <Philip.Blundell@pobox.com>
*/
+#include <linux/stddef.h>
#include <linux/tasks.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -131,7 +131,10 @@ static int hardware_read_proc(char *page, char **start, off_t off,
len += sprintf(page+len, "irq:\tnone\n");
else
len += sprintf(page+len, "irq:\t%d\n",pp->irq);
- len += sprintf(page+len, "dma:\t%d\n",pp->dma);
+ if (pp->dma == PARPORT_DMA_NONE)
+ len += sprintf(page+len, "dma:\tnone\n");
+ else
+ len += sprintf(page+len, "dma:\t%d\n",pp->dma);
#if 0
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index 55b64e856..256cbcee6 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.1 1997/07/25 01:53:19 ralf Exp $
+/* $Id: parport_share.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -88,6 +88,23 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
return tmp;
}
+void parport_unregister_port(struct parport *port)
+{
+ struct parport *p;
+ kfree(port->name);
+ if (portlist == port) {
+ portlist = port->next;
+ } else {
+ for (p = portlist; (p != NULL) && (p->next != port);
+ p=p->next);
+ if (p) {
+ if ((p->next = port->next) == NULL)
+ portlist_tail = p;
+ }
+ }
+ kfree(port);
+}
+
void parport_quiesce(struct parport *port)
{
if (port->devices) {
@@ -106,7 +123,7 @@ void parport_quiesce(struct parport *port)
}
struct pardevice *parport_register_device(struct parport *port, const char *name,
- int (*pf)(void *), int (*kf)(void *),
+ int (*pf)(void *), void (*kf)(void *),
void (*irq_func)(int, void *, struct pt_regs *),
int flags, void *handle)
{
@@ -223,7 +240,6 @@ int parport_claim(struct pardevice *dev)
pd1 = dev->port->cad;
if (dev->port->cad) {
if (dev->port->cad->preempt) {
- /* Now try to preempt */
if (dev->port->cad->preempt(dev->port->cad->private))
return -EAGAIN;
dev->port->ops->save_state(dev->port, dev->state);
@@ -301,19 +317,10 @@ void parport_release(struct pardevice *dev)
}
/* Now give the lurker a chance.
- * There should be a wakeup callback because we checked for it
+ * There must be a wakeup callback because we checked for it
* at registration.
*/
if (dev->port->lurker && (dev->port->lurker != dev)) {
- if (dev->port->lurker->wakeup) {
- dev->port->lurker->wakeup(dev->port->lurker->private);
- }
-#ifdef PARPORT_PARANOID
- else { /* can't happen */
- printk(KERN_DEBUG
- "%s (%s): lurker's wakeup callback went away!\n",
- dev->port->name, dev->name);
- }
-#endif
+ dev->port->lurker->wakeup(dev->port->lurker->private);
}
}
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 4ae7aa069..4647f0fea 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -275,7 +275,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
mp->rx_skbs[i] = skb;
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- rxd[i].myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd[i].myri_scatters[0].addr = (unsigned long) skb->data;
rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;
rxd[i].ctx = i;
rxd[i].num_sg = 1;
@@ -429,7 +429,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
drops++;
DRX(("DROP "));
mp->enet_stats.rx_dropped++;
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -450,7 +450,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
- rxd->myri_scatters[0].addr = (unsigned int) new_skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) new_skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -474,7 +474,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
/* Reuse original ring buffer. */
DRX(("reuse "));
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -618,7 +618,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
txd = &sq->myri_txd[entry];
mp->tx_skbs[entry] = skb;
- txd->myri_gathers[0].addr = (unsigned int) skb->data;
+ txd->myri_gathers[0].addr = (unsigned long) skb->data;
txd->myri_gathers[0].len = len;
txd->num_sg = 1;
txd->chan = KERNEL_CHANNEL;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index f06a66afc..2e2f3f3e2 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -1,4 +1,4 @@
-/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ */
+/* $Id: plip.c,v 1.1.1.1 1997/06/01 03:17:24 ralf Exp $ */
/* PLIP: A parallel port "network" driver for Linux. */
/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
/*
@@ -204,7 +204,7 @@ struct net_local {
struct tq_struct deferred;
struct plip_local snd_data;
struct plip_local rcv_data;
- struct ppd *pardev;
+ struct pardevice *pardev;
unsigned long trigger;
unsigned long nibble;
enum plip_connection_state connection;
@@ -228,7 +228,7 @@ __initfunc(int
plip_init_dev(struct device *dev, struct parport *pb))
{
struct net_local *nl;
- struct ppd *pardev;
+ struct pardevice *pardev;
dev->irq = pb->irq;
dev->base_addr = pb->base;
@@ -239,8 +239,8 @@ plip_init_dev(struct device *dev, struct parport *pb))
}
pardev = parport_register_device(pb, dev->name, plip_preempt,
- plip_wakeup,
- plip_interrupt, PARPORT_DEV_LURK, dev);
+ plip_wakeup, plip_interrupt,
+ PARPORT_DEV_LURK, dev);
printk(version);
printk("%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
@@ -1045,7 +1045,7 @@ plip_preempt(void *handle)
return 0;
}
-static int
+static void
plip_wakeup(void *handle)
{
struct device *dev = (struct device *)handle;
@@ -1058,12 +1058,12 @@ plip_wakeup(void *handle)
/* bus_owner is already set (but why?) */
printk(KERN_DEBUG "%s: I'm broken.\n", dev->name);
else
- return 1;
+ return;
}
if (!(dev->flags & IFF_UP))
/* Don't need the port when the interface is down */
- return 1;
+ return;
if (!parport_claim(nl->pardev)) {
nl->port_owner = 1;
@@ -1072,7 +1072,7 @@ plip_wakeup(void *handle)
outb (0x00, PAR_DATA(dev));
}
- return 0;
+ return;
}
static struct net_device_stats *
diff --git a/drivers/net/soundmodem/sm_sbc.c b/drivers/net/soundmodem/sm_sbc.c
index 2a2f874aa..fc26b57bf 100644
--- a/drivers/net/soundmodem/sm_sbc.c
+++ b/drivers/net/soundmodem/sm_sbc.c
@@ -339,6 +339,7 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
@@ -352,10 +353,8 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
dma_init_receive(sm);
setup_dma_dsp(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
diff --git a/drivers/net/soundmodem/sm_wss.c b/drivers/net/soundmodem/sm_wss.c
index 021ecc165..ef129930a 100644
--- a/drivers/net/soundmodem/sm_wss.c
+++ b/drivers/net/soundmodem/sm_wss.c
@@ -402,6 +402,7 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
@@ -415,10 +416,8 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
dma_init_receive(sm);
setup_dma_wss(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c
index 0e7b56294..7ffde6f53 100644
--- a/drivers/pnp/parport_probe.c
+++ b/drivers/pnp/parport_probe.c
@@ -1,4 +1,4 @@
-/* $Id: parport_probe.c,v 1.1.1.1 1997/06/01 03:17:25 ralf Exp $
+/* $Id: parport_probe.c,v 1.2 1997/07/29 03:59:29 ralf Exp $
* Parallel port device probing code
*
* Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
@@ -86,15 +86,15 @@ static long read_polled(struct parport *port, char *buf,
static struct wait_queue *wait_q = NULL;
-static int wakeup(void *ref)
+static void wakeup(void *ref)
{
struct pardevice **dev = (struct pardevice **)ref;
if (!wait_q || parport_claim(*dev))
- return 1;
+ return;
wake_up(&wait_q);
- return 0;
+ return;
}
int parport_probe(struct parport *port, char *buffer, int len)
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 4ce803b34..a5d2b3016 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -32,7 +32,9 @@ ifdef TADPOLE_FB_WEITEK
FB_OBJS += weitek.o
endif
ifdef SUN_FB_CREATOR
+ ifeq ($(ARCH),sparc64)
FB_OBJS += creator.o
+ endif
endif
#ifdef SUN_FB_FAST_ONE
# FB_OBJS += sun_8bit_fast1.o
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
index 086f9b40e..3ce90092a 100644
--- a/drivers/sbus/char/creator.c
+++ b/drivers/sbus/char/creator.c
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
* creator.c: Creator/Creator3D frame buffer driver
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -235,7 +235,6 @@ ffb_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
int err;
#ifdef CONFIG_SPARC32_COMPAT
@@ -287,7 +286,6 @@ ffb_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
#ifdef CONFIG_SPARC32_COMPAT
if (current->tss.flags & SPARC_FLAG_32BIT) {
@@ -464,8 +462,6 @@ ffb_loadcmap (fbinfo_t *fb, int index, int count)
static int
ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
{
- int i;
-
switch (cmd) {
case FBIO_WID_GET:
return ffb_wid_get (fb, (struct fb_wid_list *)arg);
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index cad446904..111f65f97 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
+/* $Id: suncons.c,v 1.67 1997/07/20 05:59:42 davem Exp $
*
* suncons.c: Sun SparcStation console support.
*
@@ -931,7 +931,7 @@ __initfunc(static void
leo_setup (&fbinfo [n], n, base, io);
break;
#endif
-#ifdef SUN_FB_CREATOR
+#if defined(SUN_FB_CREATOR) && defined(__sparc_v9__)
case FBTYPE_CREATOR:
creator_setup (&fbinfo [n], n, con_node, base, io);
break;
diff --git a/drivers/sbus/char/tcx.c b/drivers/sbus/char/tcx.c
index 20c14a687..9eaad5bc7 100644
--- a/drivers/sbus/char/tcx.c
+++ b/drivers/sbus/char/tcx.c
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
+/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
* tcx.c: SUNW,tcx 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -309,9 +309,9 @@ __initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, u32 tcx, struct lin
tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
if (!fb->base){
- fb->base = (uint)
- sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
- fb->type.fb_size, "tcx_ram", fb->space, 0);
+ fb->base = (unsigned long)
+ sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET],
+ 0, fb->type.fb_size, "tcx_ram", fb->space, 0);
}
if (prom_getbool (node, "hw-cursor")) {
diff --git a/drivers/sbus/char/weitek.c b/drivers/sbus/char/weitek.c
index 7b7b1bd72..7de26c2f7 100644
--- a/drivers/sbus/char/weitek.c
+++ b/drivers/sbus/char/weitek.c
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
+/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
* weitek.c: Tadpole P9100/P9000 console driver
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -99,8 +99,6 @@ weitek_loadcmap (void *fbinfo, int index, int count)
__initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
{
- extern struct screen_info screen_info;
-
printk ("weitek%d at 0x%8.8x\n", slot, addr);
/* Fill in parameters we left out */
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 4d59647cc..cf06585ff 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -385,5 +385,12 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+
+ sun4u_start_timers();
+ }
+#endif
return memory_start;
}
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 44a78b12c..3d28dae2f 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -560,7 +560,7 @@ issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
* sure what the relationship between the NCR structures
* and host structures were going to be.
*/
- (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
+ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (le32_to_cpu(issue[1])) -
(hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
offsetof(struct NCR53c7x0_cmd, dsa))
/* If the IF TRUE bit is not set, it's a NOP */
@@ -795,18 +795,18 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- curr[1] = (u32) virt_to_bus (hostdata->script) +
- hostdata->E_wait_reselect;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE);
+ curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_wait_reselect);
hostdata->reconnect_dsa_head = 0;
hostdata->addr_reconnect_dsa_head = (u32)
- virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+ le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head)));
hostdata->expecting_iid = 0;
hostdata->expecting_sto = 0;
if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
- hostdata->initiate_sdtr = 0xffff;
+ hostdata->initiate_sdtr = le32_to_cpu(0xffff);
else
hostdata->initiate_sdtr = 0;
hostdata->talked_to = 0;
@@ -877,7 +877,7 @@ clock_to_ccf (int clock) {
* Returns : 0 on success, -1 on failure.
*/
-static inline int
+static int
NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
int i, ccf, expected_ccf;
@@ -899,6 +899,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
* will differ.
*/
int expected_mapping = OPTION_IO_MAPPED;
+
NCR53c7x0_local_setup(host);
switch (hostdata->chip) {
@@ -929,10 +930,10 @@ NCR53c7x0_init (struct Scsi_Host *host) {
/* Assign constants accessed by NCR */
hostdata->NCR53c7xx_zero = 0;
- hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
- hostdata->NCR53c7xx_msg_abort = ABORT;
- hostdata->NCR53c7xx_msg_nop = NOP;
- hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+ hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT);
+ hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT);
+ hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP);
+ hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24);
if (expected_mapping == -1 ||
(hostdata->options & (OPTION_MEMORY_MAPPED)) !=
@@ -1131,7 +1132,14 @@ NCR53c7x0_init (struct Scsi_Host *host) {
search->irq == host->irq && search != host); search=search->next);
if (!search) {
- if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL)) {
+#ifdef __powerpc__
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL))
+#else
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+#endif
+ {
+
+
printk("scsi%d : IRQ%d not free, detaching\n"
" You have either a configuration problem, or a\n"
" broken BIOS. You may wish to manually assign\n"
@@ -1453,6 +1461,21 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
return -1;
}
+#ifdef __powerpc__
+ if ( ! (command & PCI_COMMAND_MASTER)) {
+ printk("SCSI: PCI Master Bit has not been set. Setting...\n");
+ command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ if (io_port >= 0x10000000) {
+ /* Mapping on PowerPC can't handle this! */
+ unsigned long new_io_port;
+ new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
+ io_port = new_io_port;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ }
+ }
+#endif
/*
* Bit 0 is the address space indicator and must be one for I/O
@@ -1613,6 +1636,9 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
unsigned char tmp;
int i, ncr_to_memory, memory_to_ncr;
u32 base;
+#ifdef __powerpc__
+ unsigned long *script_ptr;
+#endif
NCR53c7x0_local_setup(host);
@@ -1801,6 +1827,14 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
printk("scsi%d : NCR dsa_fields start is %d not %d\n",
host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
Ent_dsa_zero);
+#ifdef __powerpc__
+/* The PowerPC is Big Endian - adjust script appropriately */
+ script_ptr = hostdata->script;
+ for (i = 0; i < sizeof(SCRIPT); i += sizeof(long))
+ {
+ *script_ptr++ = le32_to_cpu(*script_ptr);
+ }
+#endif
printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(hostdata->script), hostdata->script);
@@ -1884,7 +1918,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
" also verify that the board is jumpered to use PCI INTA, since\n"
" most PCI motherboards lack support for INTB, INTC, and INTD.\n"
: "");
- else if (hostdata->test_completed != 1)
+ else if (hostdata->test_completed != 1)
printk ("scsi%d : test 1 bad interrupt value (%d)\n",
host->host_no, hostdata->test_completed);
else
@@ -1922,16 +1956,17 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
cmd[4] = sizeof(data);
- dsa[2] = 1;
- dsa[3] = virt_to_bus(&identify);
- dsa[4] = 6;
- dsa[5] = virt_to_bus(&cmd);
- dsa[6] = sizeof(data);
- dsa[7] = virt_to_bus(&data);
- dsa[8] = 1;
- dsa[9] = virt_to_bus(&status);
- dsa[10] = 1;
- dsa[11] = virt_to_bus(&msg);
+/* Need to adjust for endian-ness */
+ dsa[2] = le32_to_cpu(1);
+ dsa[3] = le32_to_cpu(virt_to_bus(&identify));
+ dsa[4] = le32_to_cpu(6);
+ dsa[5] = le32_to_cpu(virt_to_bus(&cmd));
+ dsa[6] = le32_to_cpu(sizeof(data));
+ dsa[7] = le32_to_cpu(virt_to_bus(&data));
+ dsa[8] = le32_to_cpu(1);
+ dsa[9] = le32_to_cpu(virt_to_bus(&status));
+ dsa[10] = le32_to_cpu(1);
+ dsa[11] = le32_to_cpu(virt_to_bus(&msg));
for (i = 0; i < 3; ++i) {
cli();
@@ -1942,7 +1977,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
}
/* SCNTL3 SDID */
- dsa[0] = (0x33 << 24) | (i << 16) ;
+ dsa[0] = le32_to_cpu((0x33 << 24) | (i << 16)) ;
hostdata->idle = 0;
hostdata->test_running = 2;
hostdata->test_completed = -1;
@@ -2004,9 +2039,22 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
int i;
+#ifdef __powerpc__
+ int len;
+ unsigned long *dsa_ptr;
+#endif
memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+#ifdef __powerpc__
+ /* Note: the script has already been 'endianized' */
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
/*
* Note : within the NCR 'C' code, dsa points to the _start_
@@ -2046,6 +2094,14 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
/* XXX - new start stuff */
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+#ifdef __powerpc__
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
}
@@ -2125,7 +2181,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd)
{
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
++found;
break;
}
@@ -2140,13 +2196,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
*/
for (left = host->can_queue,
- ncr_search = hostdata->reconnect_dsa_head,
+ ncr_search = le32_to_cpu(hostdata->reconnect_dsa_head),
ncr_prev = &hostdata->reconnect_dsa_head;
left >= 0 && ncr_search &&
((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
!= (char *) cmd->dsa;
ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
- hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+ hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
if (left < 0)
printk("scsi%d: loop detected in ncr reconnect list\n",
@@ -2491,7 +2547,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
dsps = NCR53c7x0_read32(DSPS_REG);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
- if (hostdata->options & OPTION_DEBUG_INTR)
+ if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
switch (dsps) {
@@ -2584,9 +2640,9 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
hostdata->msg_buf[4] = 0; /* 0 offset = async */
asynchronous (host, c->target);
}
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, le32_to_cpu(5));
patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
- virt_to_bus ((void *)&hostdata->msg_buf));
+ le32_to_cpu(virt_to_bus ((void *)&hostdata->msg_buf)));
hostdata->dsp = hostdata->script +
hostdata->E_respond_message / sizeof(u32);
hostdata->dsp_changed = 1;
@@ -2649,14 +2705,14 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
* agrees with this being an untagged queue'd command.
*/
- patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32 (cmd->dsa, dsa_msgout, 0, le32_to_cpu(1));
/*
* Modify the table indirect for COMMAND OUT phase, since
* Request Sense is a six byte command.
*/
- patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+ patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, le32_to_cpu(6));
c->cmnd[0] = REQUEST_SENSE;
c->cmnd[1] &= 0xe0; /* Zero all but LUN */
@@ -2672,17 +2728,17 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
*/
patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
- virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+ le32_to_cpu(virt_to_bus(hostdata->script) + hostdata->E_other_transfer));
patch_dsa_32 (cmd->dsa, dsa_datain, 0,
- virt_to_bus(cmd->data_transfer_start));
- cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
- DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
- cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+ le32_to_cpu(virt_to_bus(cmd->data_transfer_start)));
+ cmd->data_transfer_start[0] = le32_to_cpu((((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
+ DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer));
+ cmd->data_transfer_start[1] = (u32) le32_to_cpu(virt_to_bus(c->sense_buffer));
- cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd->data_transfer_start[2] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->data_transfer_start[3] = (u32) le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
/*
* Currently, this command is flagged as completed, ie
@@ -2691,7 +2747,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
* status, etc are used.
*/
- cmd->cmd->result = 0xffff;
+ cmd->cmd->result = le32_to_cpu(0xffff);
/*
* Restart command as a REQUEST SENSE.
@@ -2732,7 +2788,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt(cmd->saved_data_pointer));
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)));
print_insn (host, hostdata->script + Ent_reselected_ok /
sizeof(u32), "", 1);
printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
@@ -2765,7 +2821,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (dsa) {
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
#if 0
printk("scsi%d : template code :\n", host->host_no);
for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
@@ -2794,7 +2850,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
" (temp was 0x%x (virt 0x%p))\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer),
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)),
NCR53c7x0_read32 (TEMP_REG),
bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
}
@@ -2888,7 +2944,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
OPTION_DEBUG_DISCONNECT)) {
printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
print_progress (c);
}
return SPECIFIC_INT_RESTART;
@@ -2901,11 +2957,11 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
int size;
printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer, bus_to_virt (
- cmd->saved_data_pointer));
+ le32_to_cpu(cmd->saved_data_pointer)));
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)), "", 1);
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)) + size, "", 1);
print_progress (c);
}
#if 0
@@ -2947,8 +3003,8 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
(int) NCR53c7x0_read8(SCNTL3_REG_800),
datapath_residual (host)) ;
print_insn (host, dsp, "", 1);
- size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
- print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+ size = print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])), "", 1);
+ print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])) + size, "", 1);
}
return SPECIFIC_INT_RESTART;
#endif
@@ -3543,7 +3599,6 @@ create_cmd (Scsi_Cmnd *cmd) {
case MODE_SELECT:
case WRITE_6:
case WRITE_10:
- case START_STOP: /* also SCAN, which may do DATA OUT */
#if 0
printk("scsi%d : command is ", host->host_no);
print_command(cmd->cmnd);
@@ -3562,6 +3617,7 @@ create_cmd (Scsi_Cmnd *cmd) {
* These commands do no data transfer, we should force an
* interrupt if a data phase is attempted on them.
*/
+ case START_STOP: /* also SCAN, which may do DATA OUT */
case TEST_UNIT_READY:
datain = dataout = 0;
break;
@@ -3612,8 +3668,8 @@ create_cmd (Scsi_Cmnd *cmd) {
* will start the data transfer over at the beginning.
*/
- tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
- hostdata->E_data_transfer;
+ tmp->saved_data_pointer = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_data_transfer);
/*
* Initialize Linux specific fields.
@@ -3622,9 +3678,9 @@ create_cmd (Scsi_Cmnd *cmd) {
tmp->cmd = cmd;
tmp->next = NULL;
tmp->flags = 0;
- tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
- hostdata->dsa_start;
- tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+ tmp->dsa_next_addr = le32_to_cpu(virt_to_bus(tmp->dsa) + hostdata->dsa_next -
+ hostdata->dsa_start);
+ tmp->dsa_addr = le32_to_cpu(virt_to_bus(tmp->dsa) - hostdata->dsa_start);
/*
* Calculate addresses of dynamic code to fill in DSA
@@ -3650,8 +3706,8 @@ create_cmd (Scsi_Cmnd *cmd) {
if (hostdata->dsa_fixup)
hostdata->dsa_fixup(tmp);
- patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
- patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+ patch_dsa_32(tmp->dsa, dsa_next, 0, le32_to_cpu(0));
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, le32_to_cpu(virt_to_bus(cmd)));
if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
if (hostdata->sync[cmd->target].select_indirect !=
@@ -3664,8 +3720,8 @@ create_cmd (Scsi_Cmnd *cmd) {
}
- patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
- select_indirect);
+ patch_dsa_32(tmp->dsa, dsa_select, 0, le32_to_cpu(hostdata->sync[cmd->target].
+ select_indirect));
/*
* Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
* different commands; although it should be trivial to do them
@@ -3674,7 +3730,7 @@ create_cmd (Scsi_Cmnd *cmd) {
if (hostdata->initiate_wdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
sizeof(wdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(wdtr_message)));
save_flags(flags);
cli();
hostdata->initiate_wdtr &= ~(1 << cmd->target);
@@ -3682,7 +3738,7 @@ create_cmd (Scsi_Cmnd *cmd) {
} else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
sizeof(sdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(sdtr_message)));
tmp->flags |= CMD_FLAG_SDTR;
save_flags(flags);
cli();
@@ -3695,40 +3751,40 @@ create_cmd (Scsi_Cmnd *cmd) {
!(hostdata->options & OPTION_NO_ASYNC)) {
memcpy ((void *) (tmp->select + 1), (void *) async_message,
sizeof(async_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(async_message)));
tmp->flags |= CMD_FLAG_SDTR;
}
#endif
else
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1));
hostdata->talked_to |= (1 << cmd->target);
tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
- patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
- patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
- patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
- patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+ patch_dsa_32(tmp->dsa, dsa_msgout, 1, le32_to_cpu(virt_to_bus(tmp->select)));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, le32_to_cpu(cmd->cmd_len));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 1, le32_to_cpu(virt_to_bus(cmd->cmnd)));
+ patch_dsa_32(tmp->dsa, dsa_dataout, 0, le32_to_cpu(cmd_dataout ?
virt_to_bus (cmd_dataout)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
+ patch_dsa_32(tmp->dsa, dsa_datain, 0, le32_to_cpu(cmd_datain ?
virt_to_bus (cmd_datain)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
/*
* XXX - need to make endian aware, should use separate variables
* for both status and message bytes.
*/
- patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgin, 0, le32_to_cpu(1));
/*
* FIXME : these only works for little endian. We probably want to
* provide message and status fields in the NCR53c7x0_cmd
* structure, and assign them to cmd->result when we're done.
*/
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, le32_to_cpu(virt_to_bus(&cmd->result) + 1));
+ patch_dsa_32(tmp->dsa, dsa_status, 0, le32_to_cpu(1));
+ patch_dsa_32(tmp->dsa, dsa_status, 1, le32_to_cpu(virt_to_bus(&cmd->result)));
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, le32_to_cpu(1));
patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+ le32_to_cpu(virt_to_bus(&(hostdata->NCR53c7xx_msg_nop))));
/*
* Generate code for zero or more of the DATA IN, DATA OUT phases
@@ -3779,15 +3835,15 @@ create_cmd (Scsi_Cmnd *cmd) {
if (datain) {
/* CALL other_in, WHEN NOT DATA_IN */
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
DCMD_TCI_IO) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_datain[1] = virt_to_bus (hostdata->script) +
- hostdata->E_other_in;
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_other_in);
/* MOVE count, buf, WHEN DATA_IN */
- cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
- << 24) | count;
- cmd_datain[3] = buf;
+ cmd_datain[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
+ << 24) | count);
+ cmd_datain[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_datain, "dynamic ", 1);
print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -3795,14 +3851,14 @@ create_cmd (Scsi_Cmnd *cmd) {
}
if (dataout) {
/* CALL other_out, WHEN NOT DATA_OUT */
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_out;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_out);
/* MOVE count, buf, WHEN DATA+OUT */
- cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
- | count;
- cmd_dataout[3] = buf;
+ cmd_dataout[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
+ | count);
+ cmd_dataout[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_dataout, "dynamic ", 1);
print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3817,10 +3873,10 @@ create_cmd (Scsi_Cmnd *cmd) {
if (datain) {
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_datain[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_datain, "dynamic jump ", 1);
#endif
@@ -3834,10 +3890,10 @@ create_cmd (Scsi_Cmnd *cmd) {
}
#endif
if (dataout) {
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_dataout, "dynamic jump ", 1);
#endif
@@ -3894,26 +3950,25 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
|| hostdata->state == STATE_DISABLED) {
printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
cmd->target, cmd->lun);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
(hostdata->debug_count_limit == 0)) {
printk("scsi%d : maximum commands exceeded\n", host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
}
} else {
if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
hostdata->debug_count_limit != -1)
--hostdata->debug_count_limit;
restore_flags (flags);
- cmd->result = 0xffff; /* The NCR will overwrite message
+ cmd->result = le32_to_cpu(0xffff); /* The NCR will overwrite message
and status with valid data */
cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
}
@@ -3967,7 +4022,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
int i;
NCR53c7x0_local_setup(host);
-#if 0
+#if 0
printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(dsa), dsa);
#endif
@@ -3982,7 +4037,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
if (hostdata->state == STATE_DISABLED) {
printk("scsi%d : driver disabled\n", host->host_no);
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
@@ -4001,18 +4056,18 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
/* Restore this instruction to a NOP once the command starts */
cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
+ sizeof(u32)] = (u32) le32_to_cpu(virt_to_bus ((void *)curr));
/* Replace the current jump operand. */
curr[1] =
- virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template;
+ le32_to_cpu(virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template);
/* Replace the NOP instruction with a JUMP */
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
} else {
printk ("scsi%d: no free slot\n", host->host_no);
disable(host);
- tmp->result = (DID_ERROR << 16);
+ tmp->result = DID_ERROR << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
@@ -4101,7 +4156,7 @@ process_issue_queue (unsigned long flags) {
if (hostdata->state == STATE_DISABLED) {
tmp = (Scsi_Cmnd *) hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
if (tmp->host_scribble) {
((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
hostdata->free;
@@ -4133,6 +4188,7 @@ process_issue_queue (unsigned long flags) {
(struct NCR53c7x0_cmd *)
tmp->host_scribble);
} else {
+ tmp->result = le32_to_cpu(tmp->result);
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00)) {
printk ("scsi%d : danger Will Robinson!\n",
@@ -4370,7 +4426,6 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
char buf[80]; /* Debugging sprintf buffer */
size_t buflen; /* Length of same */
#endif
-
do {
done = 1;
for (host = first_host; host; host = host->next)
@@ -4449,10 +4504,16 @@ restart:
printk ("scsi%d : looking at result of 0x%x\n",
host->host_no, cmd->cmd->result);
#endif
-
+
+#ifdef __powerpc__
+ if (tmp->result == le32_to_cpu(0xffff))
+ continue;
+ tmp->result = le32_to_cpu(tmp->result);
+#else
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00))
continue;
+#endif
search_found = 1;
@@ -4537,7 +4598,6 @@ restart:
printk("scsi%d : no active command\n", host->host_no);
}
}
-
if (istat & ISTAT_SIP) {
if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : ISTAT_SIP\n", host->host_no);
@@ -4872,12 +4932,12 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
* from normal dynamic code.
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd->residual[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd->residual[1] = virt_to_bus(hostdata->script)
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd->residual[1] = le32_to_cpu(virt_to_bus(hostdata->script)
+ ((dcmd & DCMD_BMI_IO)
- ? hostdata->E_other_in : hostdata->E_other_out);
+ ? hostdata->E_other_in : hostdata->E_other_out));
}
/*
@@ -4885,17 +4945,17 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
* move instruction, reflecting the pointer and count at the
* time of the phase mismatch.
*/
- cmd->residual[2] = dbc_dcmd + residual;
- cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+ cmd->residual[2] = le32_to_cpu(dbc_dcmd + residual);
+ cmd->residual[3] = le32_to_cpu(NCR53c7x0_read32(DNAD_REG) - residual);
/*
* The third and final instruction is a jump to the instruction
* which follows the instruction which had to be 'split'
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->residual[5] = virt_to_bus(dsp_next);
+ cmd->residual[4] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->residual[5] = le32_to_cpu(virt_to_bus(dsp_next));
}
/*
@@ -5375,11 +5435,11 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
*/
sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
(prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
- insn[0], insn[1], bus_to_virt (insn[1]));
+ insn[0], insn[1], bus_to_virt (le32_to_cpu(insn[1])));
tmp = buf + strlen(buf);
if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
- bus_to_virt(insn[2]));
+ bus_to_virt(le32_to_cpu(insn[2])));
size = 3;
} else {
sprintf (tmp, "\n");
@@ -5439,6 +5499,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
host->hostdata : NULL;
unsigned long flags;
+ unsigned long result;
struct NCR53c7x0_cmd *curr, **prev;
Scsi_Cmnd *me, **last;
#if 0
@@ -5530,7 +5591,8 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
&(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
if (curr) {
- if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+ result = le32_to_cpu(cmd->result);
+ if ((result & 0xff) != 0xff && (result & 0xff00) != 0xff00) {
if (prev)
*prev = (struct NCR53c7x0_cmd *) curr->next;
curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5561,8 +5623,9 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
cmd->host_scribble = NULL;
}
- if (((cmd->result & 0xff00) == 0xff00) ||
- ((cmd->result & 0xff) == 0xff)) {
+ result = le32_to_cpu(cmd->result);
+ if (((result & 0xff00) == 0xff00) ||
+ ((result & 0xff) == 0xff)) {
printk ("scsi%d : did this command ever run?\n", host->host_no);
cmd->result = DID_ABORT << 16;
} else {
@@ -5709,7 +5772,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
(insn >= ncmd->residual &&
insn < (ncmd->residual +
sizeof(ncmd->residual))))) {
- ptr = bus_to_virt(insn[3]);
+ ptr = bus_to_virt(le32_to_cpu(insn[3]));
if ((buffers = cmd->use_sg)) {
for (offset = 0,
@@ -5764,7 +5827,7 @@ print_progress (Scsi_Cmnd *cmd) {
continue;
if (!i) {
where = "saved";
- ptr = bus_to_virt(ncmd->saved_data_pointer);
+ ptr = bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer));
} else {
where = "active";
ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
@@ -5782,9 +5845,9 @@ print_progress (Scsi_Cmnd *cmd) {
cmd->host->host_no, where);
if (ncmd) {
size = print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)), "", 1);
print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)) + size * sizeof(u32),
"", 1);
}
}
@@ -5809,9 +5872,9 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
" + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
prefix ? prefix : "",
host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
- dsa[hostdata->dsa_msgout / sizeof(u32)],
- dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
- bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]),
+ bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])));
/*
* Only print messages if they're sane in length so we don't
@@ -5819,10 +5882,10 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
* anything.
*/
- if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
+ if (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]) <
sizeof (hostdata->free->select))
- for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
- ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
+ for (i = le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ ptr = bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
i > 0 && !check_address ((unsigned long) ptr, 1);
ptr += len, i -= len) {
printk(" ");
@@ -5833,8 +5896,8 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
}
printk(" + %d : select_indirect = 0x%x\n",
- hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ hostdata->dsa_select, le32_to_cpu(dsa[hostdata->dsa_select / sizeof(u32)]));
+ cmd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_cmnd / sizeof(u32)]));
printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
(u32) virt_to_bus(cmd));
if (cmd) {
@@ -5844,7 +5907,7 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
} else
printk("\n");
printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
- dsa[hostdata->dsa_next / sizeof(u32)]);
+ le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
if (cmd) {
printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
" script : ",
@@ -5891,8 +5954,7 @@ print_queues (struct Scsi_Host *host) {
host->host_no, cmd->pid);
/* print_dsa does sanity check on address, no need to check */
else
- print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
- -> dsa, "");
+ print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), "");
} else
printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
host->host_no, cmd->pid, cmd->target, cmd->lun);
@@ -5917,7 +5979,7 @@ print_queues (struct Scsi_Host *host) {
left > 0; curr += 2, --left)
if (curr[0] != hostdata->NOP_insn)
/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (curr[1] -
+ print_dsa (host, bus_to_virt (le32_to_cpu(curr[1]) -
(hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template)), "");
printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -5925,7 +5987,7 @@ print_queues (struct Scsi_Host *host) {
printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
for (left = host->can_queue,
- dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ dsa = bus_to_virt (le32_to_cpu(hostdata->reconnect_dsa_head));
left >= 0 && dsa;
dsa = next_dsa) {
save_flags (flags);
@@ -5937,7 +5999,7 @@ print_queues (struct Scsi_Host *host) {
}
else
{
- next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ next_dsa = bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
print_dsa (host, dsa, "");
}
restore_flags(flags);
@@ -6131,7 +6193,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
hostdata->curr = NULL;
}
diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h
index cfddfa681..cb0071e9d 100644
--- a/drivers/scsi/53c7,8xx.h
+++ b/drivers/scsi/53c7,8xx.h
@@ -1574,7 +1574,7 @@ struct NCR53c7x0_hostdata {
if (hostdata->options & OPTION_DEBUG_DSA) \
printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
#dsa, #symbol, hostdata->##symbol, \
- (word), (u32) (value)); \
+ (word), (u32) le32_to_cpu(value)); \
}
/* Paranoid people could use panic() here. */
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index ce08d4873..3f24e681f 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -21,7 +21,14 @@ dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
-dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
+if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
+ bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
+ int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+ bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+ int ' delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+fi
dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 02c066202..dcb47e47e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -429,12 +429,8 @@ BusLogic.o: BusLogic.c FlashPoint.c
aha152x.o: aha152x.c
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
-aic7xxx_asm: aic7xxx_asm.c
- $(HOSTCC) -o $@ aic7xxx_asm.c
-
-aic7xxx.c: aic7xxx_seq.h
-aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
- ./aic7xxx_asm -o $@ aic7xxx.seq
+aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
+ $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
seagate.o: seagate.c
$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index ccbf4a6e2..5ec8a51d2 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -1,5 +1,5 @@
AIC7xxx Driver for Linux
- April 15, 1996
+ July 20, 1997
Introduction
------------------------
@@ -31,6 +31,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
-----------------------
AIC-777x
AIC-785x
+ AIC-786x
AIC-787x
AIC-788x
@@ -58,6 +59,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Dan Eischen deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
Dean Gehnert deang@teleport.com (Linux FTP/patch maintainer)
Jess Johnson jester@frenzy.com (AIC7xxx FAQ author)
+ Doug Ledford dledford@dialnet.net (Stress tester/bug squasher)
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
@@ -82,10 +84,17 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
- Command line options
- ------------------------
+ Command line options ("aic7xxx=option[,option...]")
+ ---------------------------------------------------
"aic7xxx=no_reset" - Eliminate the SCSI reset delay during startup.
Some SCSI devices need some extra time to reset.
+ "aic7xxx=extended" - Force extended translation.
+ "aic7xxx=ultra" - Force Ultra mode
+ "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
+ interrupts. AFAIK, the driver only works with level triggered
+ interrupts. This only applies to EISA adapters.
+ "aic7xxx=verbose" - Enable more bootup messages. PLEASE use this
+ if you have problems with the driver.
/proc support
------------------------
@@ -106,10 +115,37 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
- US Linux mirror of Teleport site
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
- European Linux mirror of Teleport site
+ ftp://ftp.pcnet.com/users/eischen/Linux/
+ - Daniel Eischens experimental/development ftp site that is
+ also home of the Linux aic7xxx sequencer assembler source.
+
+ Sequencer assembler
+ ------------------------
+ The sequencer assembler is no longer being distributed with the
+ Linux kernel. The sequencer assembler (aic7xxx_asm) is now being
+ maintained by Justin Gibbs under a BSD copyright (which pretty
+ much lets you do anything you want with it). I keep a Linux
+ version of the assembler at my ftp site should you wish to hack
+ the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
+ Please note that you do NOT need the assembler to build a kernel
+ with aic7xxx support. The assembler generates the code that is
+ downloaded to the aic7xxx controllers; this code IS part of the
+ Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
+
+ Problems compiling the kernel with aic7xxx support
+ --------------------------------------------------
+ This is probably due to having modified the sequencer files in
+ some way. If you are not modifying the sequencer source (in
+ drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
+ the necessary files from your kernel tarball. Otherwise, visit
+ my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
+ assembler source.
Dean W. Gehnert
deang@teleport.com
-$Revision: 3.0 $
+(Modified by D. Eischen, 7/20/97)
+
+$Revision: 3.1a $
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 96e66defd..005c889d7 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -1,5 +1,3 @@
-#define EXPERIMENTAL_FLAGS 0
-
/*+M*************************************************************************
* Adaptec AIC7xxx device driver for Linux.
*
@@ -29,21 +27,73 @@
* the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
* ANSI SCSI-2 specification (draft 10c), ...
*
- * ----------------------------------------------------------------
- * Modified to include support for wide and twin bus adapters,
- * DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * --------------------------------------------------------------------------
+ *
+ * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ * Substantially modified to include support for wide and twin bus
+ * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
* SCB paging, and other rework of the code.
*
- * Parts of this driver are based on the FreeBSD driver by Justin
- * T. Gibbs.
+ * Parts of this driver were also based on the FreeBSD driver by
+ * Justin T. Gibbs. His copyright follows:
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ * Thanks also go to (in alphabetical order) the following:
+ *
+ * Rory Bolt - Sequencer bug fixes
+ * Jay Estabrook - Initial DEC Alpha support
+ * Doug Ledford - Much needed abort/reset bug fixes
+ * Kai Makisara - DMAing of SCBs
*
* A Boot time option was also added for not resetting the scsi bus.
*
- * Form: aic7xxx=extended,no_reset
+ * Form: aic7xxx=extended
+ * aic7xxx=no_reset
+ * aic7xxx=ultra
+ * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level
+ * aic7xxx=verbose
*
- * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
*
- * $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
@@ -67,7 +117,11 @@
#include "scsi.h"
#include "hosts.h"
#include "aic7xxx.h"
+
+#include "aic7xxx/sequencer.h"
+#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
+#include "aic7xxx_seq.h"
#include <linux/stat.h>
#include <linux/malloc.h> /* for kmalloc() */
@@ -79,16 +133,20 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-static struct proc_dir_entry proc_scsi_aic7xxx = {
+struct proc_dir_entry proc_scsi_aic7xxx = {
PROC_SCSI_AIC7XXX, 7, "aic7xxx",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "$Revision: 4.0 $"
+#define AIC7XXX_C_VERSION "$Revision: 4.1 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b) ((a < b) ? a : b)
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define ALL_TARGETS -1
+#define ALL_CHANNELS '\0'
+#define ALL_LUNS -1
#ifndef TRUE
# define TRUE 1
#endif
@@ -107,11 +165,8 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* support because all PCI dependent code is bracketed with
* "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
*
- * o Twin bus support - this has been tested and does work.
- *
- * o DMAing of SCBs - thanks to Kai Makisara, this now works.
- * This define is now taken out and DMAing of SCBs is always
- * performed (8/12/95 - DE).
+ * o Twin bus support - this has been tested and does work. It is
+ * not an option anymore.
*
* o Tagged queueing - this driver is capable of tagged queueing
* but I am unsure as to how well the higher level driver implements
@@ -140,16 +195,16 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* LUN using its own heuristic based on the number of available
* SCBs.
*
- * o 3985 support - The 3985 adapter is much like the 3940, but
- * has three 7870 controllers as opposed to two for the 3940.
- * It will get probed and recognized as three different adapters,
- * but all three controllers can share the same external bank of
- * 255 SCBs. If you enable AIC7XXX_SHARE_SCBS, then the driver
- * will attempt to share the common bank of SCBs between the three
- * controllers of the 3985. This is experimental and hasn't
- * been tested. By default, we do not share the bank of SCBs,
- * and force the controllers to use their own internal bank of
- * 16 SCBs. Please let us know if sharing the SCB array works.
+ * o 3985 support - The 3985 adapter is much like the 3940, but has
+ * three 7870 controllers as opposed to two for the 3940. It will
+ * be probed and recognized as three different adapters, but all
+ * three controllers can share the same external bank of 255 SCBs.
+ * If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
+ * to use and share the common bank of SCBs between the three
+ * controllers of the 3985. This is experimental and hasn't been
+ * been tested. By default, we do not use external SCB RAM, and
+ * force the controllers to use their own internal bank of 16 SCBs.
+ * Please let us know if using the external SCB array works.
*
* o SCB paging support - SCB paging is enabled by defining
* AIC7XXX_PAGE_ENABLE. Support for this was taken from the
@@ -162,43 +217,54 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* Note that sharing of IRQs is not an option any longer. Linux supports
* it so we support it.
*
- * Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
*/
-/* Uncomment this for testing twin bus support. */
-#define AIC7XXX_TWIN_SUPPORT
-
/* Uncomment this for tagged queueing. */
-/* #define AIC7XXX_TAGGED_QUEUEING */
+#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
+#define AIC7XXX_TAGGED_QUEUEING
+#endif
/*
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-/* #define AIC7XXX_CMDS_PER_LUN 8 */
+#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
+#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#endif
/* Set this to the delay in seconds after SCSI bus reset. */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
#define AIC7XXX_RESET_DELAY 15
+#endif
/*
- * Uncomment the following define for collection of SCSI transfer statistics
- * for the /proc filesystem.
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
*
* NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
* NOTE: This does affect performance since it has to maintain statistics.
*/
-/* #define AIC7XXX_PROC_STATS */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
/*
- * Uncomment the following to enable SCB paging.
+ * Enable SCB paging.
*/
-/* #define AIC7XXX_PAGE_ENABLE */
+#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
+#define AIC7XXX_PAGE_ENABLE
+#endif
/*
- * Uncomment the following to enable sharing of the external bank
- * of 255 SCBs for the 3985.
+ * Uncomment the following to enable use of the external bank
+ * of 255 SCBs. For 3985 adapters, this will also enable sharing
+ * of the SCB array across all three controllers.
*/
-#define AIC7XXX_SHARE_SCBS
+#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
+#define AIC7XXX_USE_EXT_SCBRAM
+#endif
/*
* For debugging the abort/reset code.
@@ -211,6 +277,87 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
#define AIC7XXX_DEBUG
/*
+ * Set this for defining the number of tagged commands on a device
+ * by device, and controller by controller basis. The first set
+ * of tagged commands will be used for the first detected aic7xxx
+ * controller, the second set will be used for the second detected
+ * aic7xxx controller, and so on. These values will *only* be used
+ * for targets that are tagged queueing capable; these values will
+ * be ignored in all other cases. The tag_commands is an array of
+ * 16 to allow for wide and twin adapters. Twin adapters will use
+ * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
+ *
+ * *** Determining commands per LUN ***
+ *
+ * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * own algorithm to determine the commands/LUN. If SCB paging is
+ * enabled, the commands/LUN is 8. When SCB paging is not enabled,
+ * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
+ * and 4 commands/LUN for adapters with 3 or 4 SCBs.
+ *
+ */
+/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
+
+#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+typedef struct
+{
+ char tag_commands[16]; /* Allow for wide/twin channel adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver to use it's own algorithm
+ * for determining commands/LUN (see Determining commands per LUN
+ * above).
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * Modify this as you see fit for your system. By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above). When -1, the driver will
+ * not enable tagged queueing for that particular device. When positive
+ * (> 0) the values in the array are used for the queue_depth. Note
+ * that the maximum value for an entry is 127.
+ *
+ * In this example, the first line will enable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter and tells the driver
+ * to use it's own algorithm for determining commands/LUN.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3. It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+ {DEFAULT_TAG_COMMANDS},
+ {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+#endif
+
+/*
+ * Don't define this unless you have problems with the driver
+ * interrupt handler. The old method would register the drivers
+ * interrupt handler as a "fast" type interrupt handler that would
+ * lock out other interrupts. Since this driver can spend a lot
+ * of time in the interrupt handler, this is _not_ a good idea.
+ * It also conflicts with some of the more common ethernet drivers
+ * that don't use fast interrupts. Currently, Linux does not allow
+ * IRQ sharing unless both drivers can agree on the type of interrupt
+ * handler.
+ */
+/* #define AIC7XXX_OLD_ISR_TYPE */
+
+
+/*
* Controller type and options
*/
typedef enum {
@@ -232,14 +379,15 @@ typedef enum {
AIC_7882, /* PCI aic7882 on 3940 Ultra */
AIC_7883, /* PCI aic7883 on 3985 Ultra */
AIC_7884 /* PCI aic7884 on 294x Ultra Differential */
-} aha_type;
+} aha_chip_type;
typedef enum {
AIC_777x, /* AIC-7770 based */
- AIC_785x, /* AIC-7850 based */
+ AIC_785x, /* AIC-7850 based (3 SCBs)*/
+ AIC_786x, /* AIC-7860 based (7850 ultra) */
AIC_787x, /* AIC-7870 based */
- AIC_788x /* AIC-7880 based */
-} aha_chip_type;
+ AIC_788x /* AIC-7880 based (ultra) */
+} aha_chip_class_type;
typedef enum {
AIC_SINGLE, /* Single Channel */
@@ -269,24 +417,24 @@ typedef enum {
* Don't forget to change this when changing the types!
*/
static const char *board_names[] = {
- "<AIC-7xxx Unknown>", /* AIC_NONE */
- "AIC-7770", /* AIC_7770 */
- "AHA-2740", /* AIC_7771 */
- "AHA-2840", /* AIC_284x */
- "AIC-7850", /* AIC_7850 */
- "AIC-7855", /* AIC_7855 */
- "AIC-7850 Ultra", /* AIC_7860 */
- "AHA-2940A Ultra", /* AIC_7861 */
- "AIC-7870", /* AIC_7870 */
- "AHA-2940", /* AIC_7871 */
- "AHA-3940", /* AIC_7872 */
- "AHA-3985", /* AIC_7873 */
- "AHA-2940 Differential", /* AIC_7874 */
- "AIC-7880 Ultra", /* AIC_7880 */
- "AHA-2940 Ultra", /* AIC_7881 */
- "AHA-3940 Ultra", /* AIC_7882 */
- "AHA-3985 Ultra", /* AIC_7883 */
- "AHA-2940 Ultra Differential" /* AIC_7884 */
+ "AIC-7xxx Unknown", /* AIC_NONE */
+ "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
+ "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
+ "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
+ "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
+ "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
+ "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
+ "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
+ "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
+ "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
+ "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
+ "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
+ "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
+ "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
+ "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
+ "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
+ "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
+ "Adaptec AHA-2944 Ultra SCSI host adapter" /* AIC_7884 */
};
/*
@@ -310,12 +458,17 @@ static const char *board_names[] = {
*/
#define DID_RETRY_COMMAND DID_ERROR
+#define HSCSIID 0x07
+#define HWSCSIID 0x0F
+#define SCSI_RESET 0x040
+
/*
* EISA/VL-bus stuff
*/
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
/*
* Standard EISA Host ID regs (Offset from slot base)
@@ -334,14 +487,6 @@ static const char *board_names[] = {
#define INTDEF 0x5C /* Interrupt Definition Register */
/*
- * Some defines for the HCNTRL register.
- */
-#define REQ_PAUSE IRQMS | INTEN | PAUSE
-#define UNPAUSE_274X IRQMS | INTEN
-#define UNPAUSE_284X INTEN
-#define UNPAUSE_294X IRQMS | INTEN
-
-/*
* AIC-78X0 PCI registers
*/
#define CLASS_PROGIF_REVID 0x08
@@ -377,7 +522,7 @@ static const char *board_names[] = {
* each word, while the C56 and C66 (4096 bits) use 8 bits to
* address each word.
*/
-typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
/*
*
@@ -417,15 +562,15 @@ struct seeprom_config {
/*
* Host Adapter Control Bits
*/
-/* UNUSED 0x0001 */
+#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
-#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+#define CFSTERM 0x0004 /* SCSI low byte termination */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
-#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
+#define CFRESETB 0x0040 /* reset SCSI bus at boot */
/* UNUSED 0xFF80 */
unsigned short adapter_control; /* word 17 */
@@ -448,36 +593,17 @@ struct seeprom_config {
unsigned short checksum; /* word 31 */
};
+#define SELBUS_MASK 0x0a
+#define SELNARROW 0x00
+#define SELBUSB 0x08
+#define SINGLE_BUS 0x00
-#define SCSI_RESET 0x040
-
-/*
- * Pause the sequencer and wait for it to actually stop - this
- * is important since the sequencer can disable pausing for critical
- * sections.
- */
-#define PAUSE_SEQUENCER(p) \
- synchronize_irq(); \
- outb(p->pause, HCNTRL + p->base); \
- while ((inb(HCNTRL + p->base) & PAUSE) == 0) \
- ; \
-
-/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p) \
- outb(p->unpause, HCNTRL + p->base)
-
-/*
- * Restart the sequencer program from address zero
- */
-#define RESTART_SEQUENCER(p) \
- do { \
- outb(SEQRESET | FASTMODE, SEQCTL + p->base); \
- } while (inb(SEQADDR0 + p->base) != 0 && \
- inb(SEQADDR1 + p->base) != 0); \
- UNPAUSE_SEQUENCER(p);
+#define SCB_TARGET(scb) \
+ (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb) \
+ ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb) \
+ (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
/*
* If an error occurs during a data transfer phase, run the command
@@ -541,12 +667,6 @@ static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
static int aic7xxx_spurious_count;
/*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 25 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookkeeping.
- */
-
-/*
* As of Linux 2.1, the mid-level SCSI code uses virtual addresses
* in the scatter-gather lists. We need to convert the virtual
* addresses to physical addresses.
@@ -559,20 +679,28 @@ struct hw_scatterlist {
/*
* Maximum number of SG segments these cards can support.
*/
-#define MAX_SG 256
+#define AIC7XXX_MAX_SG 27
-struct aic7xxx_scb {
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB 255
+
+
+struct aic7xxx_hwscb {
/* ------------ Begin hardware supported fields ---------------- */
/* 0*/ unsigned char control;
/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */
/* 2*/ unsigned char target_status;
/* 3*/ unsigned char SG_segment_count;
-/* 4*/ unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 4*/ unsigned int SG_list_pointer;
/* 8*/ unsigned char residual_SG_segment_count;
-/* 9*/ unsigned char residual_data_count[3] __attribute__ ((packed));
-/*12*/ unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/ unsigned int data_count __attribute__ ((packed)); /* must be 32 bits */
-/*20*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/* 9*/ unsigned char residual_data_count[3];
+/*12*/ unsigned int data_pointer;
+/*16*/ unsigned int data_count;
+/*20*/ unsigned int SCSI_cmd_pointer;
/*24*/ unsigned char SCSI_cmd_length;
/*25*/ u_char tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
@@ -580,29 +708,47 @@ struct aic7xxx_scb {
#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
* via PIO to initialize a transaction.
*/
-/*26*/ u_char next; /* Used to thread SCBs awaiting selection
+/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection
* or disconnected down in the sequencer.
*/
- /*-----------------end of hardware supported fields----------------*/
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- struct aic7xxx_scb *q_next; /* next scb in queue */
-#define SCB_FREE 0x00
-#define SCB_ACTIVE 0x01
-#define SCB_ABORTED 0x02
-#define SCB_DEVICE_RESET 0x04
-#define SCB_IMMED 0x08
-#define SCB_SENSE 0x10
-#define SCB_QUEUED_FOR_DONE 0x40
-#define SCB_PAGED_OUT 0x80
-#define SCB_WAITINGQ 0x100
-#define SCB_ASSIGNEDQ 0x200
-#define SCB_SENTORDEREDTAG 0x400
-#define SCB_IN_PROGRESS (SCB_ACTIVE | SCB_PAGED_OUT | \
- SCB_WAITINGQ | SCB_ASSIGNEDQ)
- int state; /* current state of scb */
- unsigned int position; /* Position in scb array */
- struct hw_scatterlist sg_list[MAX_SG]; /* SG list in adapter format */
- unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */
+/*27*/ unsigned char prev;
+/*28*/ unsigned int pad; /*
+ * Unused by the kernel, but we require
+ * the padding so that the array of
+ * hardware SCBs is alligned on 32 byte
+ * boundaries so the sequencer can index
+ */
+};
+
+typedef enum {
+ SCB_FREE = 0x0000,
+ SCB_ACTIVE = 0x0001,
+ SCB_ABORTED = 0x0002,
+ SCB_DEVICE_RESET = 0x0004,
+ SCB_SENSE = 0x0008,
+ SCB_TIMEDOUT = 0x0010,
+ SCB_QUEUED_FOR_DONE = 0x0020,
+ SCB_RECOVERY_SCB = 0x0040,
+ SCB_WAITINGQ = 0x0080,
+ SCB_ASSIGNEDQ = 0x0100,
+ SCB_SENTORDEREDTAG = 0x0200,
+ SCB_MSGOUT_SDTR = 0x0400,
+ SCB_MSGOUT_WDTR = 0x0800,
+ SCB_ABORT = 0x1000,
+ SCB_QUEUED_ABORT = 0x2000
+} scb_flag_type;
+
+struct aic7xxx_scb {
+ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+ struct aic7xxx_scb *q_next; /* next scb in queue */
+ scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char sg_count;
+ unsigned char sense_cmd[6]; /*
+ * Allocate 6 characters for
+ * sense command.
+ */
};
/*
@@ -627,20 +773,17 @@ static unsigned char
generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
typedef struct {
+ struct aic7xxx_hwscb *hscbs;
scb_queue_type free_scbs; /*
* SCBs assigned to free slot on
* card (no paging required)
*/
- int numscbs; /* current number of scbs */
- int activescbs; /* active scbs */
-} scb_usage_type;
-
-/*
- * The maximum number of SCBs we could have for ANY type
- * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
- * SEQUENCER CODE IF THIS IS MODIFIED!
- */
-#define AIC7XXX_MAXSCB 255
+ unsigned char numscbs; /* current number of scbs */
+ unsigned char maxhscbs; /* hardware scbs */
+ unsigned char maxscbs; /* max scbs including pageable scbs */
+ struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB];
+ unsigned int reserve[100];
+} scb_data_type;
/*
* Define a structure used for each host adapter, only one per IRQ.
@@ -648,17 +791,26 @@ typedef struct {
struct aic7xxx_host {
struct Scsi_Host *host; /* pointer to scsi host */
int host_no; /* SCSI host number */
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ int irq; /* IRQ for this adapter */
int base; /* card base address */
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
-#define A_SCANNED 0x0001
-#define B_SCANNED 0x0002
-#define EXTENDED_TRANSLATION 0x0004
-#define HAVE_SEEPROM 0x0008
-#define ULTRA_ENABLED 0x0010
-#define PAGE_ENABLED 0x0020
-#define IN_ISR 0x0040
-#define USE_DEFAULTS 0x0080
+ unsigned int mbase; /* I/O memory address */
+ volatile unsigned char *maddr; /* memory mapped address */
+#define A_SCANNED 0x0001
+#define B_SCANNED 0x0002
+#define EXTENDED_TRANSLATION 0x0004
+#define FLAGS_CHANNEL_B_PRIMARY 0x0008
+#define MULTI_CHANNEL 0x0010
+#define ULTRA_ENABLED 0x0020
+#define PAGE_ENABLED 0x0040
+#define USE_DEFAULTS 0x0080
+#define BIOS_ENABLED 0x0100
+#define IN_ISR 0x0200
+#define IN_TIMEOUT 0x0400
+#define SHARED_SCBDATA 0x0800
+#define HAVE_SEEPROM 0x1000
unsigned int flags;
unsigned int isr_count; /* Interrupt count */
unsigned short needsdtr_copy; /* default config */
@@ -669,36 +821,22 @@ struct aic7xxx_host {
unsigned short wdtr_pending;
unsigned short orderedtag;
unsigned short discenable; /* Targets allowed to disconnect */
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
+ aha_chip_type chip_type; /* card type */
+ aha_chip_class_type chip_class;
aha_bus_type bus_type; /* normal/twin/wide bus */
- char * mbase; /* I/O memory address */
- unsigned char chan_num; /* for 3940/3985, channel number */
+ unsigned char chan_num; /* for 39xx, channel number */
unsigned char unpause; /* unpause value for HCNTRL */
unsigned char pause; /* pause value for HCNTRL */
unsigned char qcntmask;
- struct seeprom_config seeprom;
+ unsigned char qfullcount;
+ unsigned char curqincnt;
struct Scsi_Host *next; /* allow for multiple IRQs */
- struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; /* active commands */
- struct aic7xxx_scb *pagedout_ntscbs[16]; /*
- * paged-out, non-tagged scbs
- * indexed by target.
- */
- scb_queue_type page_scbs; /*
- * SCBs that will require paging
- * before use (no assigned slot)
- */
+ unsigned char activescbs; /* active scbs */
scb_queue_type waiting_scbs; /*
- * SCBs waiting to be paged and
- * started.
+ * SCBs waiting for space in
+ * the QINFIFO.
*/
- scb_queue_type assigned_scbs; /*
- * SCBs that were waiting but have
- * have now been assigned a slot
- * by aic7xxx_free_scb
- */
- scb_usage_type scb_usage;
- scb_usage_type *scb_link;
+ scb_data_type *scb_data;
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
@@ -710,6 +848,7 @@ struct aic7xxx_host {
#define BUS_DEVICE_RESET_PENDING 0x02
int flags;
int commands_sent;
+ int active_cmds;
} device_status[16];
#ifdef AIC7XXX_PROC_STATS
/*
@@ -735,34 +874,10 @@ struct aic7xxx_host {
#endif /* AIC7XXX_PROC_STATS */
};
-struct aic7xxx_host_config {
- int irq; /* IRQ number */
- int mbase; /* memory base address*/
- int base; /* I/O base address*/
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
- int unpause; /* unpause value for HCNTRL */
- int pause; /* pause value for HCNTRL */
- int scsi_id; /* host SCSI ID */
- int scsi_id_b; /* host SCSI ID B channel for twin cards */
- unsigned int flags; /* used the same as struct aic7xxx_host flags */
- int chan_num; /* for 3940/3985, channel number */
- unsigned char busrtime; /* bus release time */
- unsigned char bus_speed; /* bus speed */
- unsigned char qcntmask;
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
- aha_bus_type bus_type; /* normal/twin/wide bus */
- aha_status_type bios; /* BIOS is enabled/disabled */
- aha_status_type parity; /* bus parity enabled/disabled */
- aha_status_type low_term; /* bus termination low byte */
- aha_status_type high_term; /* bus termination high byte (wide cards only) */
-};
-
/*
* Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns to the proper value to
- * stick in the scsiscfr reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
*/
static struct {
short period;
@@ -771,17 +886,17 @@ static struct {
short rate;
const char *english;
} aic7xxx_syncrates[] = {
- { 50, 0x100, "20.0" },
- { 62, 0x110, "16.0" },
- { 75, 0x120, "13.4" },
- { 100, 0x000, "10.0" },
- { 125, 0x010, "8.0" },
- { 150, 0x020, "6.67" },
- { 175, 0x030, "5.7" },
- { 200, 0x040, "5.0" },
- { 225, 0x050, "4.4" },
- { 250, 0x060, "4.0" },
- { 275, 0x070, "3.6" }
+ { 12, 0x100, "20.0" },
+ { 15, 0x110, "16.0" },
+ { 18, 0x120, "13.4" },
+ { 25, 0x000, "10.0" },
+ { 31, 0x010, "8.0" },
+ { 37, 0x020, "6.67" },
+ { 43, 0x030, "5.7" },
+ { 50, 0x040, "5.0" },
+ { 56, 0x050, "4.4" },
+ { 62, 0x060, "4.0" },
+ { 68, 0x070, "3.6" }
};
static int num_aic7xxx_syncrates =
@@ -790,166 +905,51 @@ static int num_aic7xxx_syncrates =
#ifdef CONFIG_PCI
static int number_of_3940s = 0;
static int number_of_3985s = 0;
-#ifdef AIC7XXX_SHARE_SCBS
-static scb_usage_type *shared_3985_scbs = NULL;
-#endif
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
#ifdef AIC7XXX_DEBUG
-static void
-debug_config(struct aic7xxx_host_config *p)
-{
- int scsi_conf;
- unsigned char brelease;
- unsigned char dfthresh;
-
- static int DFT[] = { 0, 50, 75, 100 };
- static int SST[] = { 256, 128, 64, 32 };
- static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
-
- scsi_conf = inb(SCSICONF + p->base);
-
- /*
- * Scale the Data FIFO Threshhold and the Bus Release Time; they are
- * stored in formats compatible for writing to sequencer registers.
- */
- dfthresh = p->bus_speed >> 6;
-
- if (p->chip_type == AIC_777x)
- {
- brelease = p->busrtime >> 2;
- }
- else
- {
- brelease = p->busrtime;
- }
- if (brelease == 0)
- {
- brelease = 2;
- }
-
- switch (p->type)
- {
- case AIC_7770:
- case AIC_7771:
- printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_284x:
- printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
- BUSW[p->bus_type], p->base, p->mbase);
- break;
-
- default:
- panic("aic7xxx: (debug_config) internal error.\n");
- }
-
- printk(" irq %d\n"
- " bus release time %d bclks\n"
- " data fifo threshold %d%%\n",
- p->irq,
- brelease,
- DFT[dfthresh]);
-
- printk(" SCSI CHANNEL A:\n"
- " scsi id %d\n"
- " scsi selection timeout %d ms\n"
- " scsi bus reset at power-on %sabled\n",
- scsi_conf & 0x07,
- SST[(scsi_conf >> 3) & 0x03],
- (scsi_conf & 0x40) ? "en" : "dis");
-
- if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
- {
- /*
- * Set the parity for 7770 based cards.
- */
- p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->parity != AIC_UNKNOWN)
- {
- printk(" scsi bus parity %sabled\n",
- (p->parity == AIC_ENABLED) ? "en" : "dis");
- }
-
- if ((p->type == AIC_7770) || (p->type == AIC_7771))
- {
- p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->low_term != AIC_UNKNOWN)
- {
- printk(" scsi bus termination (low byte) %sabled\n",
- (p->low_term == AIC_ENABLED) ? "en" : "dis");
- }
- if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
- {
- printk(" scsi bus termination (high byte) %sabled\n",
- (p->high_term == AIC_ENABLED) ? "en" : "dis");
- }
-}
-
#if 0
static void
debug_scb(struct aic7xxx_scb *scb)
{
- printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
- scb->control, scb->target_channel_lun, scb->SG_segment_count,
- (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
- (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
- (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
- (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
- scb->SCSI_cmd_length);
- printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
- (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
- scb->residual_SG_segment_count,
- ((scb->residual_data_count[2] << 16) |
- (scb->residual_data_count[1] << 8) |
- (scb->residual_data_count[0]));
- printk("data ptr 0x%x, data count %d, next waiting %d\n",
- (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
- (scb->data_pointer[1] << 8) | scb->data_pointer[0],
- scb->data_count, scb->next_waiting);
- printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
- (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
- scb->position);
+ struct aic7xxx_hwscb *hscb = scb->hscb;
+
+ printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
+ scb,
+ hscb->control,
+ hscb->target_channel_lun,
+ hscb->SCSI_cmd_length,
+ hscb->SCSI_cmd_pointer );
+ printk(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+ hscb->data_count,
+ hscb->data_pointer,
+ hscb->SG_segment_count,
+ hscb->SG_list_pointer);
+ printk(" sg_addr:%lx sg_len:%ld\n",
+ hscb->sg_list[0].address,
+ hscb->sg_list[0].length);
}
#endif
#else
-# define debug_config(x)
# define debug_scb(x)
#endif AIC7XXX_DEBUG
-#define TCL_OF_SCB(x) (((x)->target_channel_lun >> 4) & 0xf), \
- (((x)->target_channel_lun >> 3) & 0x01), \
- ((x)->target_channel_lun & 0x07)
+#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+ ((scb->hscb)->target_channel_lun & 0x07)
+
+#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01)
-#define TARGET_INDEX(x) ((x)->target | ((x)->channel << 3))
+#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+
+#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3))
/*
* XXX - these options apply unilaterally to _all_ 274x/284x/294x
- * cards in the system. This should be fixed, but then,
- * does anyone really have more than one in a machine?
+ * cards in the system. This should be fixed.
*/
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
@@ -959,6 +959,53 @@ static int aic7xxx_irq_trigger = -1; /*
* 1 use level triggered
*/
static int aic7xxx_enable_ultra = 0; /* enable ultra SCSI speeds */
+static int aic7xxx_verbose = 0; /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * These functions are not used yet, but when we do memory mapped
+ * IO, we'll use them then.
+ *
+ ***************************************************************************/
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+ if (p->maddr != NULL)
+ return (p->maddr[port]);
+ else
+ return (inb(p->base + port));
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+ if (p->maddr != NULL)
+ p->maddr[port] = val;
+ else
+ outb(val, p->base + port);
+}
+
+static inline void
+aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
+{
+ if (p->maddr != NULL)
+ {
+ __asm __volatile("
+ cld;
+ 1: lodsb;
+ movb %%al,(%0);
+ loop 1b" :
+ :
+ "r" ((p)->maddr + (port)),
+ "S" ((valp)), "c" ((size)) :
+ "%esi", "%ecx", "%eax");
+ }
+ else
+ {
+ outsb(p->base + port, valp, size);
+ }
+}
/*+F*************************************************************************
* Function:
@@ -983,6 +1030,7 @@ aic7xxx_setup(char *s, int *dummy)
{ "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
{ "ultra", &aic7xxx_enable_ultra },
+ { "verbose", &aic7xxx_verbose },
{ NULL, NULL }
};
@@ -1008,58 +1056,230 @@ aic7xxx_setup(char *s, int *dummy)
/*+F*************************************************************************
* Function:
+ * pause_sequencer
+ *
+ * Description:
+ * Pause the sequencer and wait for it to actually stop - this
+ * is important since the sequencer can disable pausing for critical
+ * sections.
+ *-F*************************************************************************/
+static inline void
+pause_sequencer(struct aic7xxx_host *p)
+{
+ outb(p->pause, p->base + HCNTRL);
+ while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+ {
+ ;
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * unpause_sequencer
+ *
+ * Description:
+ * Unpause the sequencer. Unremarkable, yet done often enough to
+ * warrant an easy way to do it.
+ *-F*************************************************************************/
+static inline void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
+{
+ if (unpause_always ||
+ ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+ {
+ outb(p->unpause, p->base + HCNTRL);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * restart_sequencer
+ *
+ * Description:
+ * Restart the sequencer program from address zero. This assumes
+ * that the sequencer is already paused.
+ *-F*************************************************************************/
+static inline void
+restart_sequencer(struct aic7xxx_host *p)
+{
+ /* Set the sequencer address to 0. */
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ /*
+ * Reset and unpause the sequencer. The reset is suppose to
+ * start the sequencer running, but we do an unpause to make
+ * sure.
+ */
+ outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_next_patch
+ *
+ * Description:
+ * Find the next patch to download.
+ *-F*************************************************************************/
+static struct patch *
+aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+{
+ while (cur_patch != NULL)
+ {
+ if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
+ || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
+ || (instrptr >= cur_patch->end))
+ {
+ /*
+ * Either we want to keep this section of code, or we have consumed
+ * this patch. Skip to the next patch.
+ */
+ cur_patch++;
+ if (cur_patch->options == 0)
+ {
+ /* Out of patches. */
+ cur_patch = NULL;
+ }
+ }
+ else
+ {
+ /* Found an OK patch. */
+ break;
+ }
+ }
+ return (cur_patch);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_download_instr
+ *
+ * Description:
+ * Find the next patch to download.
+ *-F*************************************************************************/
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
+{
+ unsigned char opcode;
+ struct ins_format3 *instr;
+
+ instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+ /* Pull the opcode */
+ opcode = instr->opcode_addr >> 1;
+ switch (opcode)
+ {
+ case AIC_OP_JMP:
+ case AIC_OP_JC:
+ case AIC_OP_JNC:
+ case AIC_OP_CALL:
+ case AIC_OP_JNE:
+ case AIC_OP_JNZ:
+ case AIC_OP_JE:
+ case AIC_OP_JZ:
+ {
+ int address_offset;
+ struct ins_format3 new_instr;
+ unsigned int address;
+ struct patch *patch;
+ int i;
+
+ address_offset = 0;
+ new_instr = *instr; /* Strucure copy */
+ address = new_instr.address;
+ address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+ for (i = 0; i < NUMBER(patches); i++)
+ {
+ patch = &patches[i];
+ if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
+ (((patch->options & options) != 0) && (patch->negative == TRUE)))
+ {
+ if (address >= patch->end)
+ {
+ address_offset += patch->end - patch->begin;
+ }
+ }
+ }
+ address -= address_offset;
+ new_instr.address = address &0xFF;
+ new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
+ new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ outsb(p->base + SEQRAM, &new_instr.immediate, 4);
+ break;
+ }
+
+ case AIC_OP_OR:
+ case AIC_OP_AND:
+ case AIC_OP_XOR:
+ case AIC_OP_ADD:
+ case AIC_OP_ADC:
+ case AIC_OP_ROL:
+ outsb(p->base + SEQRAM, &instr->immediate, 4);
+ break;
+
+ default:
+ panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+ break;
+ }
+}
+
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_loadseq
*
* Description:
* Load the sequencer code into the controller memory.
*-F*************************************************************************/
static void
-aic7xxx_loadseq(int base)
+aic7xxx_loadseq(struct aic7xxx_host *p)
{
- static unsigned char seqprog[] = {
- /*
- * Each sequencer instruction is 29 bits
- * long (fill in the excess with zeroes)
- * and has to be loaded from least -> most
- * significant byte, so this table has the
- * byte ordering reversed.
- */
-# include "aic7xxx_seq.h"
- };
+ int options;
+ struct patch *cur_patch;
+ int i;
+ int downloaded;
- /*
- * When the AIC-7770 is paused (as on chip reset), the
- * sequencer address can be altered and a sequencer
- * program can be loaded by writing it, byte by byte, to
- * the sequencer RAM port - the Adaptec documentation
- * recommends using REP OUTSB to do this, hence the inline
- * assembly. Since the address autoincrements as we load
- * the program, reset it back to zero afterward. Disable
- * sequencer RAM parity error detection while loading, and
- * make sure the LOADRAM bit is enabled for loading.
- */
- outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+ }
+ options = 1; /* Code for all options. */
+ downloaded = 0;
+ if ((p->flags & ULTRA_ENABLED) != 0)
+ options |= ULTRA;
+ if (p->bus_type == AIC_TWIN)
+ options |= TWIN_CHANNEL;
+ if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+ options |= SCB_PAGING;
- outsb(SEQRAM + base, seqprog, sizeof(seqprog));
+ cur_patch = patches;
+ outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
- /*
- * WARNING! This is a magic sequence! After extensive
- * experimentation, it seems that you MUST turn off the
- * LOADRAM bit before you play with SEQADDR again, else
- * you will end up with parity errors being flagged on
- * your sequencer program. (You would also think that
- * turning off LOADRAM and setting SEQRESET to reset the
- * address to zero would work, but you need to do it twice
- * for it to take effect on the address. Timing problem?)
- */
- do {
- /*
- * Actually, reset it until
- * the address shows up as
- * zero just to be safe..
- */
- outb(SEQRESET | FASTMODE, SEQCTL + base);
- } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
+ for (i = 0; i < sizeof(seqprog) / 4; i++)
+ {
+ cur_patch = aic7xxx_next_patch(cur_patch, options, i);
+ if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+ {
+ /* Skip this instruction for this configuration. */
+ continue;
+ }
+ aic7xxx_download_instr(p, options, i);
+ downloaded++;
+ }
+
+ outb(FASTMODE, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ if (aic7xxx_verbose)
+ {
+ printk(" %d instructions downloaded\n", downloaded);
+ }
}
/*+F*************************************************************************
@@ -1067,18 +1287,22 @@ aic7xxx_loadseq(int base)
* aic7xxx_delay
*
* Description:
- * Delay for specified amount of time.
+ * Delay for specified amount of time. We use udelay because the timer
+ * interrupt is not guaranteed to be enabled. This will cause an
+ * infinite loop since jiffies (clock ticks) is not updated.
*-F*************************************************************************/
static void
aic7xxx_delay(int seconds)
{
- unsigned long i;
-
- i = jiffies + (seconds * HZ); /* compute time to stop */
+ int i;
- while (jiffies < i)
+ /*
+ * Call udelay() for 1 millisecond inside a loop for
+ * the requested amount of seconds.
+ */
+ for (i=0; i < seconds*1000; i++)
{
- ; /* Do nothing! */
+ udelay(1000); /* Delay for 1 millisecond. */
}
}
@@ -1090,7 +1314,7 @@ aic7xxx_delay(int seconds)
* Return a string containing just the RCS version number from either
* an Id or Revision RCS clause.
*-F*************************************************************************/
-static const char *
+const char *
rcs_version(const char *version_info)
{
static char buf[10];
@@ -1150,8 +1374,10 @@ aic7xxx_info(struct Scsi_Host *notused)
strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+#if 0
strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
+#endif
return buffer;
}
@@ -1161,9 +1387,12 @@ aic7xxx_info(struct Scsi_Host *notused)
* aic7xxx_length
*
* Description:
- * How much data should be transferred for this SCSI command? Stop
- * at segment sg_last if it's a scatter-gather command so we can
- * compute underflow easily.
+ * How much data should be transferred for this SCSI command? Assume
+ * all segments are to be transferred except for the last sg_last
+ * segments. This will allow us to compute underflow easily. To
+ * calculate the total length of the command, use sg_last = 0. To
+ * calculate the length of all but the last 2 SG segments, use
+ * sg_last = 2.
*-F*************************************************************************/
static unsigned
aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
@@ -1177,7 +1406,7 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
if (cmd->use_sg)
{
- for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
+ for (i = length = 0; i < segments; i++)
{
length += sg[i].length;
}
@@ -1199,9 +1428,9 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
*-F*************************************************************************/
static void
aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
- short period, unsigned char offset, int target, char channel)
+ unsigned char *period, unsigned char *offset, int target, char channel)
{
- int i;
+ int i = num_aic7xxx_syncrates;
unsigned long ultra_enb_addr;
unsigned char ultra_enb, sxfrctl0;
@@ -1209,11 +1438,11 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
* If the offset is 0, then the device is requesting asynchronous
* transfers.
*/
- if (offset != 0)
+ if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
{
for (i = 0; i < num_aic7xxx_syncrates; i++)
{
- if ((aic7xxx_syncrates[i].period - period) >= 0)
+ if (*period <= aic7xxx_syncrates[i].period)
{
/*
* Watch out for Ultra speeds when ultra is not enabled and
@@ -1229,99 +1458,57 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
*/
continue;
}
- *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+ *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
+ *period = aic7xxx_syncrates[i].period;
- /*
- * Ensure Ultra mode is set properly for this target.
- */
- ultra_enb_addr = ULTRA_ENB;
- if ((channel == 'B') || (target > 7))
- {
- ultra_enb_addr++;
- }
- ultra_enb = inb(p->base + ultra_enb_addr);
- sxfrctl0 = inb(p->base + SXFRCTL0);
- if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+ if (aic7xxx_verbose)
{
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= ULTRAEN;
+ printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+ "offset %d.\n", p->host_no, target, channel,
+ aic7xxx_syncrates[i].english, *offset);
}
- else
- {
- ultra_enb &= ~(0x01 << (target & 0x07));
- sxfrctl0 &= ~ULTRAEN;
- }
- outb(ultra_enb, p->base + ultra_enb_addr);
- outb(sxfrctl0, p->base + SXFRCTL0);
-
- printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
- "offset %d.\n", p->host_no, target, channel,
- aic7xxx_syncrates[i].english, offset);
- return;
+ break;
}
}
}
- /*
- * Default to asynchronous transfer
- */
- *scsirate = 0;
- printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
- p->host_no, target, channel);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_putscb
- *
- * Description:
- * Transfer a SCB to the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- outb(SCBAUTO, SCBCNT + base);
+ if (i >= num_aic7xxx_syncrates)
+ {
+ /*
+ * Use asynchronous transfers.
+ */
+ *scsirate = 0;
+ *period = 0;
+ *offset = 0;
+ if (aic7xxx_verbose)
+ {
+ printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+ p->host_no, target, channel);
+ }
+ }
/*
- * By turning on the SCB auto increment, any reference
- * to the SCB I/O space postincrements the SCB address
- * we're looking at. So turn this on and dump the relevant
- * portion of the SCB to the card.
- *
- * We can do 16bit transfers on all but 284x.
+ * Ensure Ultra mode is set properly for this target.
*/
- if (p->type == AIC_284x)
+ ultra_enb_addr = ULTRA_ENB;
+ if ((channel == 'B') || (target > 7))
+ {
+ ultra_enb_addr++;
+ }
+ ultra_enb = inb(p->base + ultra_enb_addr);
+ sxfrctl0 = inb(p->base + SXFRCTL0);
+ if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
{
- outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+ ultra_enb |= 0x01 << (target & 0x07);
+ sxfrctl0 |= FAST20;
}
else
{
- outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+ ultra_enb &= ~(0x01 << (target & 0x07));
+ sxfrctl0 &= ~FAST20;
}
-
- outb(0, SCBCNT + base);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_getscb
- *
- * Description:
- * Get a SCB from the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- /*
- * This is almost identical to aic7xxx_putscb().
- */
- outb(SCBAUTO, SCBCNT + base);
- insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
- outb(0, SCBCNT + base);
+ outb(ultra_enb, p->base + ultra_enb_addr);
+ outb(sxfrctl0, p->base + SXFRCTL0);
}
/*+F*************************************************************************
@@ -1375,6 +1562,47 @@ scbq_remove_head(scb_queue_type *queue)
/*+F*************************************************************************
* Function:
+ * scbq_remove
+ *
+ * Description:
+ * Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+ if (queue->head == scb)
+ {
+ /* At beginning of queue, remove from head. */
+ scbq_remove_head(queue);
+ }
+ else
+ {
+ struct aic7xxx_scb *curscb = queue->head;
+
+ /*
+ * Search until the next scb is the one we're looking for, or
+ * we run out of queue.
+ */
+ while ((curscb != NULL) && (curscb->q_next != scb))
+ {
+ curscb = curscb->q_next;
+ }
+ if (curscb != NULL)
+ {
+ /* Found it. */
+ curscb->q_next = scb->q_next;
+ if (scb->q_next == NULL)
+ {
+ /* Update the tail when removing the tail. */
+ queue->tail = curscb;
+ }
+ }
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
* scbq_insert_tail
*
* Description:
@@ -1404,23 +1632,87 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
* to be reset and all devices on that channel must be aborted.
*-F*************************************************************************/
static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
+ int lun, unsigned char tag)
{
- int targ = (scb->target_channel_lun >> 4) & 0x0F;
- char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+ char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int slun = scb->hscb->target_channel_lun & 0x07;
+ int match;
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
- target, channel, targ, chan);
+ printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
+ scb->cmd->device->host->host_no, target, channel, targ, chan);
#endif
- if (target == ALL_TARGETS)
+ match = ((chan == channel) || (channel == ALL_CHANNELS));
+ if (match != 0)
+ match = ((targ == target) || (target == ALL_TARGETS));
+ if (match != 0)
+ match = ((lun == slun) || (lun == ALL_LUNS));
+ if (match != 0)
+ match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+ return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ * Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+ /*
+ * Invalidate the tag so that aic7xxx_find_scb doesn't think
+ * it's active
+ */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG);
+
+ outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
+ outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ * Removes the current SCB from the disconnected list and adds it
+ * to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+{
+ unsigned char next;
+ unsigned char prev;
+
+ outb(scbptr, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
+ prev = inb(p->base + SCB_PREV);
+
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
+
+ if (prev != SCB_LIST_NULL)
{
- return (chan == channel);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
else
{
- return ((chan == channel) && (targ == target));
+ outb(next, p->base + DISCONNECTED_SCBH);
}
+
+ if (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ outb(prev, p->base + SCB_PREV);
+ }
+ return next;
}
/*+F*************************************************************************
@@ -1428,51 +1720,93 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
* aic7xxx_busy_target
*
* Description:
- * Set the specified target active.
+ * Set the specified target busy.
*-F*************************************************************************/
static void
-aic7xxx_busy_target(unsigned char target, char channel, int base)
+aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, unsigned char scbid)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
+
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ outb(scbid, p->base + scb_offset);
+ outb(active_scb, p->base + SCBPTR);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_index_busy_target
+ *
+ * Description:
+ * Returns the index of the busy target, and optionally sets the
+ * target inactive.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, int unbusy)
+{
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned char busy_scbid;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
- if ((target > 0x07) || (channel == 'B'))
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ busy_scbid = inb(p->base + scb_offset);
+ if (unbusy)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(SCB_LIST_NULL, p->base + scb_offset);
}
- active = inb(active_port);
- active |= (0x01 << (target & 0x07));
- outb(active, active_port);
+ outb(active_scb, p->base + SCBPTR);
+ return (busy_scbid);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_unbusy_target
+ * aic7xxx_find_scb
*
* Description:
- * Set the specified target inactive.
+ * Look through the SCB array of the card and attempt to find the
+ * hardware SCB that corresponds to the passed in SCB. Return
+ * SCB_LIST_NULL if unsuccessful. This routine assumes that the
+ * card is already paused.
*-F*************************************************************************/
-static void
-aic7xxx_unbusy_target(unsigned char target, char channel, int base)
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char saved_scbptr;
+ unsigned char curindex;
- if ((target > 0x07) || (channel == 'B'))
+ saved_scbptr = inb(p->base + SCBPTR);
+ curindex = 0;
+ for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(curindex, p->base + SCBPTR);
+ if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+ {
+ break;
+ }
}
- active = inb(active_port);
- active &= ~(0x01 << (target & 0x07));
- outb(active, active_port);
+ outb(saved_scbptr, p->base + SCBPTR);
+ if (curindex >= p->scb_data->maxhscbs)
+ {
+ curindex = SCB_LIST_NULL;
+ }
+
+ return (curindex);
}
/*+F*************************************************************************
@@ -1480,68 +1814,60 @@ aic7xxx_unbusy_target(unsigned char target, char channel, int base)
* aic7xxx_allocate_scb
*
* Description:
- * Get a free SCB either from one already assigned to a hardware
- * slot, or one that will require an SCB to be paged out before
- * use. If there are none, attempt to allocate a new one.
+ * Get an SCB from the free list or by allocating a new one.
*-F*************************************************************************/
static struct aic7xxx_scb *
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
- struct aic7xxx_scb *scbp = NULL;
- int maxscbs;
+ struct aic7xxx_scb *scbp = NULL;
+ struct aic7xxx_hwscb *hscbp = NULL;
+#ifdef AGRESSIVE
+ long processor_flags;
- scbp = p->scb_link->free_scbs.head;
+ save_flags(processor_flags);
+ cli();
+#endif
+
+ scbp = p->scb_data->free_scbs.head;
if (scbp != NULL)
{
- scbq_remove_head(&p->scb_link->free_scbs);
+ scbq_remove_head(&p->scb_data->free_scbs);
}
else
{
- /*
- * This should always be NULL if paging is not enabled.
- */
- scbp = p->page_scbs.head;
- if (scbp != NULL)
+ if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
- scbq_remove_head(&p->page_scbs);
- }
- else
- {
- /*
- * Set limit the SCB allocation to the maximum number of
- * hardware SCBs if paging is not enabled; otherwise use
- * the maximum (255).
- */
- if (p->flags & PAGE_ENABLED)
- maxscbs = p->maxscbs;
- else
- maxscbs = p->maxhscbs;
- if (p->scb_link->numscbs < maxscbs)
- {
- int scb_index = p->scb_link->numscbs;
- int scb_size = sizeof(struct aic7xxx_scb);
+ int scb_index = p->scb_data->numscbs;
+ int scb_size = sizeof(struct aic7xxx_scb) +
+ sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
- p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
- scbp = (p->scb_array[scb_index]);
- if (scbp != NULL)
- {
- memset(scbp, 0, sizeof(*scbp));
- scbp->tag = scb_index;
- if (scb_index < p->maxhscbs)
- scbp->position = scb_index;
- else
- scbp->position = SCB_LIST_NULL;
- p->scb_link->numscbs++;
- }
+ scbp = kmalloc(scb_size, GFP_ATOMIC);
+ if (scbp != NULL)
+ {
+ memset(scbp, 0, sizeof(struct aic7xxx_scb));
+ hscbp = &p->scb_data->hscbs[scb_index];
+ scbp->hscb = hscbp;
+ scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
+ memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
+ hscbp->tag = scb_index;
+ p->scb_data->numscbs++;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[scb_index] = scbp;
}
}
}
+#ifdef AIC7XXX_DEBUG
if (scbp != NULL)
{
-#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs++;
-#endif
+ p->activescbs++;
}
+#endif
+
+#ifdef AGRESSIVE
+ restore_flags(processor_flags);
+#endif
return (scbp);
}
@@ -1581,6 +1907,7 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
+ p->device_status[TARGET_INDEX(cmd)].active_cmds--;
cmd->scsi_done(cmd);
}
p->completeq.tail = NULL;
@@ -1591,53 +1918,29 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
* aic7xxx_free_scb
*
* Description:
- * Free the scb and update the page, waiting, free scb lists.
+ * Free the scb and insert into the free scb list.
*-F*************************************************************************/
static void
aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_scb *wscb;
+ struct aic7xxx_hwscb *hscb;
+ long flags;
+
+ hscb = scb->hscb;
+ save_flags(flags);
+ cli();
- scb->state = SCB_FREE;
+ scb->flags = SCB_FREE;
scb->cmd = NULL;
- scb->control = 0;
- scb->state = 0;
+ hscb->control = 0;
+ hscb->target_status = 0;
- if (scb->position == SCB_LIST_NULL)
- {
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- /*
- * If there are any SCBS on the waiting queue, assign the slot of this
- * "freed" SCB to the first one. We'll run the waiting queues after
- * all command completes for a particular interrupt are completed or
- * when we start another command.
- */
- wscb = p->waiting_scbs.head;
- if (wscb != NULL)
- {
- scbq_remove_head(&p->waiting_scbs);
- wscb->position = scb->position;
- scbq_insert_tail(&p->assigned_scbs, wscb);
- wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
-
- /*
- * The "freed" SCB will need to be assigned a slot before being
- * used, so put it in the page_scbs queue.
- */
- scb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- scbq_insert_head(&p->scb_link->free_scbs, scb);
- }
+ scbq_insert_head(&p->scb_data->free_scbs, scb);
#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs--; /* For debugging purposes. */
+ p->activescbs--; /* For debugging purposes. */
#endif
- }
+
+ restore_flags(flags);
}
/*+F*************************************************************************
@@ -1652,68 +1955,113 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
Scsi_Cmnd *cmd = scb->cmd;
+ if (scb->flags & SCB_RECOVERY_SCB)
+ {
+ p->flags &= ~IN_TIMEOUT;
+ }
+ if (cmd->result == DID_OK)
+ {
+ if (scb->flags & SCB_ABORTED)
+ {
+ cmd->result = (DID_RESET << 16);
+ }
+ }
+ if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+ {
+ unsigned short mask;
+
+ mask = 0x01 << TARGET_INDEX(scb->cmd);
+ if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ p->wdtr_pending &= ~mask;
+ }
+ if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ p->sdtr_pending &= ~mask;
+ }
+ }
aic7xxx_free_scb(p, scb);
aic7xxx_queue_cmd_complete(p, cmd);
+#ifdef AIC7XXX_PROC_STATS
+ {
+ int actual;
+
+ /*
+ * XXX: we should actually know how much actually transferred
+ * XXX: for each command, but apparently that's too difficult.
+ */
+ actual = aic7xxx_length(cmd, 0);
+ if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
+ && (aic7xxx_error(cmd) == 0))
+ {
+ struct aic7xxx_xferstats *sp;
+ long *ptr;
+ int x;
+
+ sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+ sp->xfers++;
+
+ if (cmd->request.cmd == WRITE)
+ {
+ sp->w_total++;
+ sp->w_total512 += (actual >> 9);
+ ptr = sp->w_bins;
+ }
+ else
+ {
+ sp->r_total++;
+ sp->r_total512 += (actual >> 9);
+ ptr = sp->r_bins;
+ }
+ for (x = 9; x <= 17; x++)
+ {
+ if (actual < (1 << x))
+ {
+ ptr[x - 9]++;
+ break;
+ }
+ }
+ if (x > 17)
+ {
+ ptr[x - 9]++;
+ }
+ }
+ }
+#endif /* AIC7XXX_PROC_STATS */
}
/*+F*************************************************************************
* Function:
- * aic7xxx_done_aborted_scbs
+ * aic7xxx_run_done_queue
*
* Description:
- * Calls the scsi_done() for the Scsi_Cmnd of each scb in the
- * aborted list, and adds each scb to the free list.
+ * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ * aborted list, and adds each scb to the free list. If complete
+ * is TRUE, we also process the commands complete list.
*-F*************************************************************************/
static void
-aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
{
- Scsi_Cmnd *cmd;
struct aic7xxx_scb *scb;
int i;
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if (scb->state & SCB_QUEUED_FOR_DONE)
+ scb = p->scb_data->scb_array[i];
+ if (scb->flags & SCB_QUEUED_FOR_DONE)
{
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ printk("(scsi%d:%d:%d) Aborting scb %d\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
#endif
- /*
- * Process the command after marking the scb as free
- * and adding it to the free list.
- */
- cmd = scb->cmd;
- p->device_status[TARGET_INDEX(cmd)].flags = 0;
- aic7xxx_free_scb(p, scb);
- cmd->scsi_done(cmd); /* call the done function */
+ aic7xxx_done(p, scb);
}
}
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_add_waiting_scb
- *
- * Description:
- * Add this SCB to the head of the "waiting for selection" list.
- *-F*************************************************************************/
-static void
-aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
-{
- unsigned char next;
- unsigned char curscb;
-
- curscb = inb(SCBPTR + base);
- next = inb(WAITING_SCBH + base);
-
- outb(scb->position, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- outb(scb->position, WAITING_SCBH + base);
-
- outb(curscb, SCBPTR + base);
+ if (complete)
+ {
+ aic7xxx_done_cmds_complete(p);
+ }
}
/*+F*************************************************************************
@@ -1726,26 +2074,23 @@ aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
*-F*************************************************************************/
static unsigned char
aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
- unsigned char prev)
+ unsigned char scbpos, unsigned char prev)
{
unsigned char curscb, next;
- int target = (scb->target_channel_lun >> 4) & 0x0F;
- char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
- int base = p->base;
/*
* Select the SCB we want to abort and pull the next pointer out of it.
*/
- curscb = inb(SCBPTR + base);
- outb(scb->position, SCBPTR + base);
- next = inb(SCB_NEXT + base);
+ curscb = inb(p->base + SCBPTR);
+ outb(scbpos, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
/*
* Clear the necessary fields
*/
- outb(0, SCB_CONTROL + base);
- outb(SCB_LIST_NULL, SCB_NEXT + base);
- aic7xxx_unbusy_target(target, channel, base);
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
/*
* Update the waiting list
@@ -1755,22 +2100,23 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*
* First in the list
*/
- outb(next, WAITING_SCBH + base);
+ outb(next, p->base + WAITING_SCBH);
}
else
{
/*
* Select the scb that pointed to us and update its next pointer.
*/
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
/*
* Point us back at the original scb position and inform the SCSI
* system that the command has been aborted.
*/
- outb(curscb, SCBPTR + base);
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ outb(curscb, p->base + SCBPTR);
+ scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scb->flags &= ~SCB_ACTIVE;
scb->cmd->result = (DID_RESET << 16);
return (next);
@@ -1778,6 +2124,75 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*+F*************************************************************************
* Function:
+ * aic7xxx_search_qinfifo
+ *
+ * Description:
+ * Search the queue-in FIFO for matching SCBs and conditionally
+ * requeue. Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag, int flags, int requeue)
+{
+ unsigned char saved_queue[AIC7XXX_MAXSCB];
+ int queued = inb(p->base + QINCNT) & p->qcntmask;
+ int i;
+ int found;
+ struct aic7xxx_scb *scbp;
+ scb_queue_type removed_scbs;
+
+ found = 0;
+ scbq_init (&removed_scbs);
+ for (i = 0; i < (queued - found); i++)
+ {
+ saved_queue[i] = inb(p->base + QINFIFO);
+ scbp = p->scb_data->scb_array[saved_queue[i]];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ /*
+ * We found an scb that needs to be removed.
+ */
+ if (requeue)
+ {
+ scbq_insert_head(&removed_scbs, scbp);
+ }
+ else
+ {
+ scbp->flags = flags;
+ scbp->flags &= ~SCB_ACTIVE;
+ /*
+ * XXX - Don't know what error to use here.
+ */
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+ }
+ i--;
+ found++;
+ }
+ }
+ /* Now put the saved scbs back. */
+ for (queued = 0; queued < i; queued++)
+ outb(saved_queue[queued], p->base + QINFIFO);
+
+ if (requeue)
+ {
+ scbp = removed_scbs.head;
+ while (scbp != NULL)
+ {
+ scbq_remove_head(&removed_scbs);
+ /*
+ * XXX - Shouldn't we be adding this to the free list?
+ */
+ scbq_insert_head(&p->waiting_scbs, scbp);
+ scbp->flags |= SCB_WAITINGQ;
+ scbp = removed_scbs.head;
+ }
+ }
+
+ return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_reset_device
*
* Description:
@@ -1785,131 +2200,280 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
* all active and queued scbs for that target/channel.
*-F*************************************************************************/
static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag)
{
- int base = p->base;
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scbp;
unsigned char active_scb;
int i = 0;
- int found = 0;
+ int found;
/*
* Restore this when we're done
*/
- active_scb = inb(SCBPTR + base);
+ active_scb = inb(p->base + SCBPTR);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
- target, channel, active_scb);
+ printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
+ p->host_no, target, CHAN_TO_INT(channel), active_scb);
#endif
+
/*
- * Search the QINFIFO.
+ * Deal with the busy target and linked next issues.
*/
{
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
+ int min_target, max_target;
+ unsigned char busy_scbid;
- for (i = 0; i < (queued - found); i++)
+ /* Make all targets 'relative' to bus A. */
+ if (target == ALL_TARGETS)
{
- saved_queue[i] = inb(QINFIFO + base);
- outb(saved_queue[i], SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- if (aic7xxx_match_scb(scb, target, channel))
+ switch (channel)
{
- /*
- * We found an scb that needs to be aborted.
- */
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
- saved_queue[i], TCL_OF_SCB(scb));
-#endif
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- outb(0, SCB_CONTROL + base);
- i--;
- found++;
+ case 'A':
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
+ case 'B':
+ min_target = 8;
+ max_target = 15;
+ break;
+ case ALL_CHANNELS:
+ default:
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
}
}
- /*
- * Now put the saved scbs back.
- */
- for (queued = 0; queued < i; queued++)
+ else
+ {
+ min_target = target + channel == 'B' ? 8 : 0;
+ max_target = min_target;
+ }
+
+ for (i = min_target; i <= max_target; i++)
{
- outb(saved_queue[queued], QINFIFO + base);
+ busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
+ if (busy_scbid < p->scb_data->numscbs)
+ {
+ struct aic7xxx_scb *busy_scb;
+ struct aic7xxx_scb *next_scb;
+ unsigned char next_scbid;
+
+ busy_scb = p->scb_data->scb_array[busy_scbid];
+
+ next_scbid = busy_scb->hscb->data_count >> 24;
+
+ if (next_scbid == SCB_LIST_NULL)
+ {
+ busy_scbid = aic7xxx_find_scb(p, busy_scb);
+
+ if (busy_scbid != SCB_LIST_NULL)
+ {
+ outb(busy_scbid, p->base + SCBPTR);
+ next_scbid = inb(p->base + SCB_LINKED_NEXT);
+ }
+ }
+
+ if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+ {
+ aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
+ }
+
+ if (next_scbid != SCB_LIST_NULL)
+ {
+ next_scb = p->scb_data->scb_array[next_scbid];
+ if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ continue;
+ }
+ /* Requeue for later processing */
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
}
}
+ found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+ SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
+
/*
* Search waiting for selection list.
*/
{
- unsigned char next, prev;
+ unsigned char next, prev, scb_index;
- next = inb(WAITING_SCBH + base); /* Start at head of list. */
+ next = inb(p->base + WAITING_SCBH); /* Start at head of list. */
prev = SCB_LIST_NULL;
while (next != SCB_LIST_NULL)
{
- outb(next, SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- /*
- * Select the SCB.
- */
- if (aic7xxx_match_scb(scb, target, channel))
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index >= p->scb_data->numscbs)
+ {
+ panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
+ scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
{
- next = aic7xxx_abort_waiting_scb(p, scb, prev);
+ unsigned char linked_next;
+
+ next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ if (linked_next != SCB_LIST_NULL)
+ {
+ struct aic7xxx_scb *next_scb;
+ /*
+ * Requeue the waiting SCB via the waiting list.
+ */
+ next_scb = p->scb_data->scb_array[linked_next];
+ if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
found++;
}
else
{
prev = next;
- next = inb(SCB_NEXT + base);
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through disconnected list and remove any entries we have queued
+ * for completion, zeroing their control byte too.
+ */
+ {
+ unsigned char next, prev, scb_index;
+
+ next = inb(p->base + DISCONNECTED_SCBH);
+ prev = SCB_LIST_NULL;
+
+ while (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index > p->scb_data->numscbs)
+ {
+ panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
+ "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ next = aic7xxx_rem_scb_from_disc_list(p, next);
+ }
+ else
+ {
+ prev = next;
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through the hardware SCB array looking for commands that
+ * were active but not on any list.
+ */
+ for (i = 0; i < p->scb_data->maxhscbs; i++)
+ {
+ unsigned char scbid;
+
+ outb(i, p->base + SCBPTR);
+ scbid = inb(p->base + SCB_TAG);
+ if (scbid < p->scb_data->numscbs)
+ {
+ scbp = p->scb_data->scb_array[scbid];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ aic7xxx_add_curscb_to_free_list(p);
}
}
}
/*
* Go through the entire SCB array now and look for commands for
- * for this target that are active. These are other (most likely
+ * for this target that are stillactive. These are other (most likely
* tagged) commands that were disconnected when the reset occurred.
*/
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
+ scbp = p->scb_data->scb_array[i];
+ if (((scbp->flags & SCB_ACTIVE) != 0) &&
+ aic7xxx_match_scb(scbp, target, channel, lun, tag))
{
- /*
- * Ensure the target is "free"
- */
- aic7xxx_unbusy_target(target, channel, base);
- if (! (scb->state & SCB_PAGED_OUT))
+ scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scbp->flags &= ~SCB_ACTIVE;
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+
+ found++;
+
+ if ((scbp->flags & SCB_WAITINGQ) != 0)
{
- outb(scb->position, SCBPTR + base);
- outb(0, SCB_CONTROL + base);
+ scbq_remove(&p->waiting_scbs, scbp);
+ scbp->flags &= ~SCB_WAITINGQ;
}
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- found++;
}
}
- outb(active_scb, SCBPTR + base);
+ outb(active_scb, p->base + SCBPTR);
return (found);
}
/*+F*************************************************************************
* Function:
+ * aic7xxx_clear_intstat
+ *
+ * Description:
+ * Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+ /* Clear any interrupt conditions this may have caused. */
+ outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
+ outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+ CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_reset_current_bus
*
* Description:
* Reset the current SCSI bus.
*-F*************************************************************************/
static void
-aic7xxx_reset_current_bus(int base)
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
{
- outb(SCSIRSTO, SCSISEQ + base);
+ unsigned char scsiseq;
+
+ /* Disable reset interrupts. */
+ outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+
+ /* Turn on the bus reset. */
+ scsiseq = inb(p->base + SCSISEQ);
+ outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+
+ udelay(1000);
+
+ /* Turn off the bus reset. */
+ outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+
+ aic7xxx_clear_intstat(p);
+
+ /* Re-enable reset interrupts. */
+ outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+
udelay(1000);
- outb(0, SCSISEQ + base);
}
/*+F*************************************************************************
@@ -1922,25 +2486,24 @@ aic7xxx_reset_current_bus(int base)
static int
aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
{
- int base = p->base;
- unsigned char sblkctl;
- char cur_channel;
unsigned long offset, offset_max;
int found;
+ unsigned char sblkctl;
+ char cur_channel;
+ pause_sequencer(p);
/*
- * Clean up all the state information for the
- * pending transactions on this bus.
+ * Clean up all the state information for the pending transactions
+ * on this bus.
*/
- found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
+ found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
if (channel == 'B')
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
p->sdtr_pending &= 0x00FF;
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base + 8;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH + 8;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
@@ -1950,132 +2513,100 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
p->needwdtr = p->needwdtr_copy;
p->sdtr_pending = 0x0;
p->wdtr_pending = 0x0;
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
+ /* Channel A */
p->needsdtr |= (p->needsdtr_copy & 0x00FF);
p->sdtr_pending &= 0xFF00;
- outb(0, ACTIVE_A + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 8;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 8;
}
}
+
while (offset < offset_max)
{
/*
- * Revert to async/narrow transfers
- * until we renegotiate.
+ * Revert to async/narrow transfers until we renegotiate.
*/
u_char targ_scratch;
- targ_scratch = inb(offset);
+
+ targ_scratch = inb(p->base + offset);
targ_scratch &= SXFR;
- outb(targ_scratch, offset);
+ outb(targ_scratch, p->base + offset);
offset++;
}
/*
* Reset the bus and unpause/restart the controller
*/
-
- /*
- * Case 1: Command for another bus is active
- */
- sblkctl = inb(SBLKCTL + base);
+ sblkctl = inb(p->base + SBLKCTL);
cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
if (cur_channel != channel)
{
+ /*
+ * Case 1: Command for another bus is active
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
- channel);
+ printk("scsi%d: Stealthily resetting channel %c\n",
+ p->host_no, channel);
#endif
/*
- * Stealthily reset the other bus without upsetting the current bus
+ * Stealthily reset the other bus without upsetting the current bus.
*/
- outb(sblkctl ^ SELBUSB, SBLKCTL + base);
+ outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- outb(sblkctl, SBLKCTL + base);
-
- UNPAUSE_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ outb(sblkctl, p->base + SBLKCTL);
+ unpause_sequencer(p, /* unpause_always */ FALSE);
}
- /*
- * Case 2: A command from this bus is active or we're idle
- */
else
{
+ /*
+ * Case 2: A command from this bus is active or we're idle.
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
- channel);
+ printk("scsi%d: Resetting current channel %c\n",
+ p->host_no, channel);
#endif
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+#if 0
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+#endif
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- RESTART_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ restart_sequencer(p);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+ printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
#endif
}
/*
- * Cause the mid-level SCSI code to delay any further
- * queueing by the bus settle time for us.
- */
- p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-
- /*
* Now loop through all the SCBs that have been marked for abortion,
* and call the scsi_done routines.
*/
- aic7xxx_done_aborted_scbs(p);
- return found;
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_page_scb
- *
- * Description:
- * Swap in_scbp for out_scbp down in the cards SCB array.
- * We assume that the SCB for out_scbp is already selected in SCBPTR.
- *
- *-F*************************************************************************/
-static inline void
-aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
- struct aic7xxx_scb *in_scbp)
-{
- int index;
-
- /* Page-out */
-#if 0
-printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
- out_scbp->cmd->target, in_scbp->cmd->target);
-#endif
- aic7xxx_getscb(p, out_scbp);
- out_scbp->state |= SCB_PAGED_OUT;
- if (!(out_scbp->control & TAG_ENB))
- {
- /* Stick in non-tagged array */
- index = (out_scbp->target_channel_lun >> 4) |
- (out_scbp->target_channel_lun & SELBUSB);
- p->pagedout_ntscbs[index] = out_scbp;
- }
-
- /* Page-in */
- in_scbp->position = out_scbp->position;
- out_scbp->position = SCB_LIST_NULL;
- aic7xxx_putscb(p, in_scbp);
- in_scbp->state &= ~SCB_PAGED_OUT;
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ return (found);
}
/*+F*************************************************************************
@@ -2083,1159 +2614,1326 @@ printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
* aic7xxx_run_waiting_queues
*
* Description:
- * Scan the assigned_scbs and waiting_scbs queues. For scbs in the
- * assigned_scbs queue, we download and start them. For scbs in the
- * waiting_scbs queue, we page in as many as we can being careful
- * not to cause a deadlock for a reconnecting target.
- *
+ * Scan the awaiting_scbs queue downloading and starting as many
+ * scbs as we can.
*-F*************************************************************************/
static inline void
aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scb;
- u_char cur_scb, intstat;
- u_long base = p->base;
- long flags;
- if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
+ if (p->waiting_scbs.head == NULL)
return;
- save_flags(flags);
- cli();
-
- PAUSE_SEQUENCER(p);
- cur_scb = inb(SCBPTR + base);
- intstat = inb(INTSTAT + base);
-
+ pause_sequencer(p);
/*
* First handle SCBs that are waiting but have been assigned a slot.
*/
- scb = p->assigned_scbs.head;
- while (scb != NULL)
- {
- scbq_remove_head(&(p->assigned_scbs));
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
- outb(scb->position, QINFIFO + base);
- scb = p->assigned_scbs.head;
- }
-
- /* Now deal with SCBs that require paging. */
scb = p->waiting_scbs.head;
- if (scb != NULL)
+ while (scb != NULL)
{
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
- int count = 0;
- u_char next_scb;
-
- while (scb != NULL)
+ if (p->curqincnt >= p->qfullcount)
{
- /* Attempt to page this SCB in */
- if (disc_scb == SCB_LIST_NULL)
- break;
-
- /*
- * Advance disc_scb to the next one in the list.
- */
- outb(disc_scb, SCBPTR + base);
- next_scb = inb(SCB_NEXT + base);
-
- /*
- * We have to be careful about when we allow an SCB to be paged out.
- * There must always be at least one slot availible for a reconnecting
- * target in case it references an SCB that has been paged out. Our
- * heuristic is that either the disconnected list has at least two
- * entries in it or there is one entry and the sequencer is activily
- * working on an SCB which implies that it will either complete or
- * disconnect before another reconnection can occur.
- */
- if ((next_scb != SCB_LIST_NULL) || active)
+ p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
+ if (p->curqincnt >= p->qfullcount)
{
- u_char out_scbi;
- struct aic7xxx_scb *out_scbp;
-
- scbq_remove_head(&(p->waiting_scbs));
-
- /*
- * Find the in-core SCB for the one we're paging out.
- */
- out_scbi = inb(SCB_TAG + base);
- out_scbp = (p->scb_array[out_scbi]);
-
- /* Do the page out and mark the paged in SCB as active. */
- aic7xxx_page_scb(p, out_scbp, scb);
-
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
-
- /* Queue the command */
- outb(scb->position, QINFIFO + base);
- count++;
-
- /* Advance to the next disconnected SCB */
- disc_scb = next_scb;
- scb = p->waiting_scbs.head;
+ break;
}
- else
- scb = NULL;
}
- if (count)
+ /*
+ * We have some space.
+ */
+ scbq_remove_head(&(p->waiting_scbs));
+ scb->flags &= ~SCB_WAITINGQ;
+
+ outb(scb->hscb->tag, p->base + QINFIFO);
+
+ if ((p->flags & PAGE_ENABLED) != 0)
{
- /*
- * Update the head of the disconnected list.
+ /*
+ * We only care about this statistic when paging
+ * since it's impossible to overflow the qinfifo
+ * in the non-paging case.
*/
- outb(disc_scb, DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
- {
- outb(disc_scb, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- }
+ p->curqincnt++;
}
+ scb = p->waiting_scbs.head;
}
- /* Restore old position */
- outb(cur_scb, SCBPTR + base);
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
+ unpause_sequencer(p, FALSE);
+}
- restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_construct_sdtr
+ *
+ * Description:
+ * Constucts a synchronous data transfer message in the message
+ * buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char period, unsigned char offset)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_SDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(period, p->base + MSG_OUT + 3 + start_byte);
+ outb(offset, p->base + MSG_OUT + 4 + start_byte);
+ outb(start_byte + 5, p->base + MSG_LEN);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_isr
+ * aic7xxx_construct_wdtr
*
* Description:
- * SCSI controller interrupt handler.
+ * Constucts a wide data transfer message in the message buffer
+ * on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char bus_width)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_WDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(bus_width, p->base + MSG_OUT + 3 + start_byte);
+ outb(start_byte + 4, p->base + MSG_LEN);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_calc_residual
*
- * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- * be disabled all through this function unless we say otherwise.
+ * Description:
+ * Calculate the residual data not yet transferred.
*-F*************************************************************************/
static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
- struct aic7xxx_host *p;
- struct aic7xxx_scb *scb = NULL;
- short transfer;
- unsigned char ha_flags, scsi_id, bus_width;
- unsigned char offset, rate, scratch, scratch_offset;
- unsigned char max_offset, rej_byte;
- unsigned short target_mask;
- char channel;
- unsigned int addr; /* must be 32 bits */
+ struct aic7xxx_hwscb *hscb;
Scsi_Cmnd *cmd;
+ int actual;
- p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+ cmd = scb->cmd;
+ hscb = scb->hscb;
/*
- * Search for the host with a pending interrupt. If we can't find
- * one, then we've encountered a spurious interrupt.
+ * Don't destroy valid residual information with
+ * residual coming from a check sense operation.
*/
- while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+ if (((scb->hscb->control & DISCONNECTED) == 0) &&
+ (scb->flags & SCB_SENSE) == 0)
{
- if (p->next == NULL)
- {
- p = NULL;
- }
- else
+ /*
+ * We had an underflow. At this time, there's only
+ * one other driver that bothers to check for this,
+ * and cmd->underflow seems to be set rather half-
+ * heartedly in the higher-level SCSI code.
+ */
+ actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
+
+ actual -= (hscb->residual_data_count[2] << 16) |
+ (hscb->residual_data_count[1] << 8) |
+ hscb->residual_data_count[0];
+
+ if (actual < cmd->underflow)
{
- p = (struct aic7xxx_host *) p->next->hostdata;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
+ "Wanted at least %u, got %u, residual SG count %d.\n",
+ p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
+ hscb->residual_SG_segment_count);
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ aic7xxx_status(cmd) = hscb->target_status;
}
}
- if (p == NULL)
- return;
-
/*
- * Keep track of interrupts for /proc/scsi
+ * Clean out the residual information in the SCB for the
+ * next consumer.
*/
- p->isr_count++;
+ hscb->residual_data_count[2] = 0;
+ hscb->residual_data_count[1] = 0;
+ hscb->residual_data_count[0] = 0;
+ hscb->residual_SG_segment_count = 0;
+}
- if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_device_reset
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+{
+ unsigned short targ_mask;
+ unsigned char targ_scratch;
+ int scratch_offset = target;
+ int found;
+
+ if (channel == 'B')
{
- /*
- * We must only have one card at this IRQ and it must have been
- * added to the board data before the spurious interrupt occurred.
- * It is sufficient that we check isr_count and not the spurious
- * interrupt count.
- */
- printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
- return;
+ scratch_offset += 8;
}
-
- base = p->base;
+ targ_mask = (0x01 << scratch_offset);
/*
- * Handle all the interrupt sources - especially for SCSI
- * interrupts, we won't get a second chance at them.
+ * Go back to async/narrow transfers and renegotiate.
*/
- intstat = inb(INTSTAT + base);
+ p->needsdtr |= p->needsdtr_copy & targ_mask;
+ p->needwdtr |= p->needwdtr_copy & targ_mask;
+ p->sdtr_pending &= ~targ_mask;
+ p->wdtr_pending &= ~targ_mask;
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ targ_scratch &= SXFR;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
+ "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
- /*
- * Indicate that we're in the interrupt handler.
- */
- p->flags |= IN_ISR;
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_seqint
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ struct aic7xxx_scb *scb;
+ unsigned short target_mask;
+ unsigned char target, scratch_offset;
+ char channel;
- if (intstat & BRKADRINT)
+ if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
{
- int i;
- unsigned char errno = inb(ERROR + base);
-
- printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
- for (i = 0; i < NUMBER(hard_error); i++)
- {
- if (errno & hard_error[i].errno)
- {
- printk(KERN_ERR " %s\n", hard_error[i].errmesg);
- }
- }
- panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
- inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+ target = (inb(p->base + SELID) >> 4) & 0x0F;
}
+ else
+ {
+ target = (inb(p->base + SCSIID) >> 4) & 0x0F;
+ }
+ scratch_offset = target;
+ channel = 'A';
+ if (inb(p->base + SBLKCTL) & SELBUSB)
+ {
+ channel = 'B';
+ scratch_offset += 8;
+ }
+ target_mask = (0x01 << scratch_offset);
- if (intstat & SEQINT)
+ switch (intstat & SEQINT_MASK)
{
- /*
- * Although the sequencer is paused immediately on
- * a SEQINT, an interrupt for a SCSIINT condition will
- * unpaused the sequencer before this point.
- */
- PAUSE_SEQUENCER(p);
+ case NO_MATCH:
+ {
+ /*
+ * This could be for a normal abort request. Figure out
+ * which SCB we were trying to find and only give an error
+ * if we didn't ask for this to happen.
+ */
+ unsigned char scb_index;
+ unsigned char busy_scbid;
+ unsigned char arg1;
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- scratch_offset = scsi_id;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- scratch_offset += 8;
- }
- target_mask = (0x01 << scratch_offset);
+ busy_scbid = aic7xxx_index_busy_target(p, target, channel,
+ /*unbusy*/ FALSE);
+ arg1 = inb(p->base + ARG_1);
- switch (intstat & SEQINT_MASK)
- {
- case NO_MATCH:
- if (p->flags & PAGE_ENABLED)
+ if (arg1 == SCB_LIST_NULL)
{
- /* SCB Page-in request */
- struct aic7xxx_scb *outscb;
- u_char arg_1 = inb(ARG_1 + base);
- int use_disconnected = FALSE;
-
- /*
- * The sequencer expects this value upon return. Assume
- * we will find the paged out SCB and set the value now.
- * If we don't, and one of the methods used to acquire an
- * SCB calls aic7xxx_done(), we will end up in our queue
- * routine and unpause the sequencer without giving it the
- * correct return value, which causes a hang.
- */
- outb(SCB_PAGEDIN, RETURN_1 + base);
- if (arg_1 == SCB_LIST_NULL)
- {
- /* Non-tagged command */
- int index = scsi_id;
- if (channel == 'B')
- {
- index |= SELBUSB;
- }
- scb = p->pagedout_ntscbs[index];
- }
- else
- scb = (p->scb_array[arg_1]);
+ /* untagged request */
+ scb_index = busy_scbid;
+ }
+ else
+ {
+ scb_index = arg1;
+ }
- if (!(scb->state & SCB_PAGED_OUT))
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb->hscb->control & ABORT_SCB)
{
- printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * We expected this. Let the busfree handler take care
+ * of this when we the abort is finially sent. Set
+ * IDENTIFY_SEEN so that the busfree handler knows that
+ * there is an SCB to cleanup.
+ */
+ outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
+ printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
+ p->host_no, TC_OF_SCB(scb));
break;
}
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
+ "target - Issuing BUS DEVICE RESET.\n",
+ p->host_no, target, CHAN_TO_INT(channel));
+
+ printk(KERN_WARNING " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+ inb(p->base + SAVED_TCL), arg1,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_handle_device_reset(p, target, channel);
+ }
+ break;
- /*
- * Now to pick the SCB to page out. Either take a free SCB, an
- * assigned SCB, an SCB that just completed, or the first one
- * on the disconnected SCB list.
- */
- if (p->scb_link->free_scbs.head != NULL)
- {
- outscb = p->scb_link->free_scbs.head;
- scbq_remove_head(&p->scb_link->free_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, outscb);
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (p->assigned_scbs.head != NULL)
- {
- outscb = p->assigned_scbs.head;
- scbq_remove_head(&p->assigned_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (intstat & CMDCMPLT)
- {
- int scb_index;
+ case NO_MATCH_BUSY:
+ {
+ /*
+ * XXX - Leave this as a panic for the time being since it
+ * indicates a bug in the timeout code for this to happen.
+ */
+ unsigned char scb_index;
- outb(CLRCMDINT, CLRINT + base);
- scb_index = inb(QOUTFIFO + base);
- if (!(inb(QOUTCNT + base) & p->qcntmask))
- {
- intstat &= ~CMDCMPLT;
- }
- outscb = (p->scb_array[scb_index]);
- if (!(outscb->state & SCB_ACTIVE))
+ scb_index = inb(p->base + CUR_SCBID);
+ scb = p->scb_data->scb_array[scb_index];
+
+ panic("scsi%d: Target %d, channel %c, Target busy link failure, "
+ "but busy SCB exists!\n",
+ p->host_no, target, channel);
+ }
+ break;
+
+ case SEND_REJECT:
+ {
+ unsigned char rej_byte;
+
+ rej_byte = inb(p->base + REJBYTE);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
+ "received from target, SEQ_FLAGS=0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel), rej_byte,
+ inb(p->base + SEQ_FLAGS));
+ }
+ break;
+
+ case NO_IDENT:
+ {
+ /*
+ * The reconnecting target either did not send an identify
+ * message, or did, but we didn't find and SCB to match and
+ * before it could respond to our ATN/abort, it hit a dataphase.
+ * The only safe thing to do is to blow it away with a bus
+ * reset.
+ */
+ int found;
+
+ printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
+ "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel),
+ inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+
+ found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+
+ printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
+ "%d SCBs aborted\n", p->host_no, channel, found);
+ }
+ break;
+
+ case BAD_PHASE:
+ if (inb(p->base + LASTPHASE) == P_BUSFREE)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
+ p->host_no, CHAN_TO_INT(channel), target);
+ restart_sequencer(p);
+ }
+ else
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
+ "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+ }
+ break;
+
+ case EXTENDED_MSG:
+ {
+ unsigned char message_length;
+ unsigned char message_code;
+ unsigned char scb_index;
+
+ message_length = inb(p->base + MSGIN_EXT_LEN);
+ message_code = inb(p->base + MSGIN_EXT_OPCODE);
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+
+ switch (message_code)
+ {
+ case MSG_EXT_SDTR:
+ {
+ unsigned char period;
+ unsigned char offset;
+ unsigned char saved_offset;
+ unsigned char targ_scratch;
+ unsigned char max_offset;
+ unsigned char rate;
+
+ if (message_length != MSG_EXT_SDTR_LEN)
{
- printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
- "during NO_MATCH interrupt\n", scb_index, p->host_no);
- use_disconnected = TRUE;
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
}
+
+ period = inb(p->base + MSGIN_EXT_BYTES);
+ saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if (targ_scratch & WIDEXFER)
+ max_offset = MAX_OFFSET_16BIT;
else
+ max_offset = MAX_OFFSET_8BIT;
+ offset = MIN(saved_offset, max_offset);
+
+ aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+
+ /*
+ * Preserve the WideXfer flag.
+ */
+ targ_scratch = rate | (targ_scratch & WIDEXFER);
+
+ /*
+ * Update both the target scratch area and current SCSIRATE.
+ */
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
+
+ /*
+ * See if we initiated Sync Negotiation and didn't have
+ * have to fall down to async transfers.
+ */
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
- if ((outscb->cmd->flags & WAS_SENSE) &&
- !(outscb->cmd->flags & ASKED_FOR_SENSE))
+ /* We started it. */
+ if (saved_offset == offset)
{
- /*
- * Got sense information.
- */
- outscb->cmd->flags &= ASKED_FOR_SENSE;
+ /*
+ * Don't send an SDTR back to the target.
+ */
+ outb(0, p->base + RETURN_1);
+ }
+ else
+ {
+ /* We went too low - force async. */
+ outb(SEND_REJ, p->base + RETURN_1);
}
- p->device_status[TARGET_INDEX(outscb->cmd)].flags
- |= DEVICE_SUCCESS;
- aic7xxx_done(p, outscb);
}
+ else
+ {
+ /*
+ * Send our own SDTR in reply.
+ *
+ * We want to see this message as we don't expect a target
+ * to send us a SDTR request first.
+ */
+ printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
+ aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
+ outb(SEND_MSG, p->base + RETURN_1);
+ }
+ /*
+ * Clear the flags.
+ */
+ p->needsdtr &= ~target_mask;
+ break;
}
- else
- {
- use_disconnected = TRUE;
- }
- if (use_disconnected)
+
+ case MSG_EXT_WDTR:
{
- u_char tag;
- u_char next;
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
+ unsigned char scratch, bus_width;
+
+ if (message_length != MSG_EXT_WDTR_LEN)
{
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- next = inb(SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- outb(disc_scb, SCBPTR + base);
- }
- outb(next, DISCONNECTED_SCBH + base);
- aic7xxx_page_scb(p, outscb, scb);
- }
- else if (inb(QINCNT + base) & p->qcntmask)
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ }
+
+ bus_width = inb(p->base + MSGIN_EXT_BYTES);
+ scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
{
- /* Pull one of our queued commands as a last resort. */
- disc_scb = inb(QINFIFO + base);
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- if ((outscb->control & 0x23) != TAG_ENB)
+ /*
+ * Don't send an WDTR back to the target, since we asked first.
+ */
+ outb(0, p->base + RETURN_1);
+ switch (bus_width)
{
- /*
- * This is not a simple tagged command so its position
- * in the queue matters. Take the command at the end of
- * the queue instead.
- */
- int i;
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
-
- /* Count the command we removed already */
- saved_queue[0] = disc_scb;
- queued++;
-
- /* Empty the input queue. */
- for (i = 1; i < queued; i++)
- {
- saved_queue[i] = inb(QINFIFO + base);
- }
-
- /* Put everyone back but the last entry. */
- queued--;
- for (i = 0; i < queued; i++)
- {
- outb(saved_queue[i], QINFIFO + base);
- }
-
- outb(saved_queue[queued], SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_16_BIT:
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ }
+ scratch |= WIDEXFER;
+ break;
+
+ case BUS_32_BIT:
+ outb(SEND_REJ, p->base + RETURN_1);
+ /* No verbose here! We want to see this condition. */
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
+ "requesting 32 bit transfers, rejecting...\n",
+ p->host_no, target, channel);
+ break;
+
+ default:
+ break;
}
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state |= SCB_WAITINGQ;
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
}
else
{
- printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * Send our own WDTR in reply.
+ */
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_32_BIT:
+ case BUS_16_BIT:
+ if (p->bus_type == AIC_WIDE)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ bus_width = BUS_16_BIT;
+ scratch |= WIDEXFER;
+ }
+ else
+ {
+ bus_width = BUS_8_BIT;
+ scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */
+ }
+ break;
+
+ default:
+ break;
+ }
+ aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+ outb(SEND_MSG, p->base + RETURN_1);
}
- }
- }
- else
- {
- printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
- }
- break;
-
- case BAD_PHASE:
- panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
- break;
-
- case SEND_REJECT:
- rej_byte = inb(REJBYTE + base);
- if ((rej_byte & 0xF0) == 0x20)
- {
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- printk(KERN_WARNING "scsi%d: Tagged message received without identify."
- "Disabling tagged commands for target %d channel %c.\n",
- p->host_no, scsi_id, channel);
- scb->cmd->device->tagged_supported = 0;
- scb->cmd->device->tagged_queue = 0;
- }
- else
- {
- printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
- "from target %d channel %c.\n",
- p->host_no, rej_byte, scsi_id, channel);
- }
- break;
+ p->needwdtr &= ~target_mask;
+ outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(scratch, p->base + SCSIRATE);
+ break;
+ } /* case MSG_EXT_WDTR */
- case NO_IDENT:
- panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
- "message. SAVED_TCL 0x%x.\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- break;
+ default:
+ /*
+ * Unknown extended message - reject it.
+ */
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ } /* switch (message_code) */
+ } /* case EXTENDED_MSG */
+ break;
- case SDTR_MSG:
- /*
- * Help the sequencer to translate the negotiated
- * transfer rate. Transfer is 1/4 the period
- * in ns as is returned by the sync negotiation
- * message. So, we must multiply by four.
- */
- transfer = (inb(ARG_1 + base) << 2);
- offset = inb(ACCUM + base);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
+ case REJECT_MSG:
+ {
/*
- * The maximum offset for a wide device is 0x08; for a
- * 8-bit bus device the maximum offset is 0x0F.
+ * What we care about here is if we had an outstanding SDTR
+ * or WDTR message for this target. If we did, this is a
+ * signal that the target is refusing negotiation.
*/
- if (scratch & WIDEXFER)
+ unsigned char targ_scratch;
+ unsigned char scb_index;
+
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
{
- max_offset = 0x08;
+ /*
+ * note 8bit xfers and clear flag
+ */
+ targ_scratch &= 0x7F;
+ p->needwdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+ "negotiation; using 8 bit transfers.\n",
+ p->host_no, target, channel);
}
else
{
- max_offset = 0x0F;
- }
- aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
- scsi_id, channel);
- /*
- * Preserve the wide transfer flag.
- */
- scratch = rate | (scratch & WIDEXFER);
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- if ((scratch & 0x0F) == 0)
- {
- /*
- * One of two things happened. Either the device requested
- * asynchronous data transfers, or it requested a synchronous
- * data transfer rate that was so low that asynchronous
- * transfers are faster (not to mention the controller won't
- * support them). In both cases the synchronous data transfer
- * rate and the offset are set to 0 indicating asynchronous
- * transfers.
- *
- * If the device requested an asynchronous transfer, then
- * accept the request. If the device is being forced to
- * asynchronous data transfers and this is the first time
- * we've seen the request, accept the request. If we've
- * already seen the request, then attempt to force
- * asynchronous data transfers by rejecting the message.
- */
- if ((offset == 0) || (p->sdtr_pending & target_mask))
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
/*
- * Device requested asynchronous transfers or we're
- * forcing asynchronous transfers for the first time.
+ * note asynch xfers and clear flag
*/
- outb(0, RETURN_1 + base);
+ targ_scratch &= 0xF0;
+ p->needsdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+ "synchronous negotiation; using asynchronous transfers.\n",
+ p->host_no, target, channel);
}
- else
- {
- /*
- * The first time in forcing asynchronous transfers
- * failed, so we try sending a reject message.
- */
- outb(SEND_REJ, RETURN_1 + base);
- }
- }
- else
- {
- /*
- * See if we initiated Sync Negotiation
- */
- if (p->sdtr_pending & target_mask)
- {
- /*
- * Don't send an SDTR back to the target.
- */
- outb(0, RETURN_1 + base);
- }
- else
- {
- /*
- * Send our own SDTR in reply.
- */
- printk("aic7xxx: Sending SDTR!!\n");
- outb(SEND_SDTR, RETURN_1 + base);
- }
- }
- /*
- * Clear the flags.
- */
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- break;
-
- case WDTR_MSG:
- {
- bus_width = inb(ARG_1 + base);
- printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
- "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
-
- if (p->wdtr_pending & target_mask)
- {
- /*
- * Don't send an WDTR back to the target, since we asked first.
- */
- outb(0, RETURN_1 + base);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
-
- case BUS_32_BIT:
- outb(SEND_REJ, RETURN_1 + base);
- printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
- "transfers, rejecting...\n", p->host_no, scsi_id, channel);
- break;
- }
- }
- else
- {
- /*
- * Send our own WDTR in reply.
- */
- printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_32_BIT:
- /*
- * Negotiate 16 bits.
- */
- bus_width = BUS_16_BIT;
- /* Yes, we mean to fall thru here. */
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
- }
- outb(bus_width | SEND_WDTR, RETURN_1 + base);
+ /*
+ * Otherwise, we ignore it.
+ */
}
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
}
+ break;
- case REJECT_MSG:
+ case BAD_STATUS:
{
- /*
- * What we care about here is if we had an
- * outstanding SDTR or WDTR message for this
- * target. If we did, this is a signal that
- * the target is refusing negotiation.
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ Scsi_Cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
*/
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ hscb = scb->hscb;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
-
- if (p->wdtr_pending & target_mask)
- {
- /*
- * note 8bit xfers and clear flag
- */
- scratch &= 0x7F;
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
- "negotiation; using 8 bit transfers.\n",
- p->host_no, scsi_id, channel);
- }
- else
- {
- if (p->sdtr_pending & target_mask)
- {
- /*
- * note asynch xfers and clear flag
- */
- scratch &= 0xF0;
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
- "synchronous negotiation; using asynchronous transfers.\n",
- p->host_no, scsi_id, channel);
- }
- /*
- * Otherwise, we ignore it.
- */
- }
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
- }
-
- case BAD_STATUS:
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencerrunning in the common case of command completes
- * without error.
- */
-
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- outb(0, RETURN_1 + base); /* CHECK_CONDITION may change this */
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ /*
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
+ outb(0, p->base + RETURN_1);
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+ printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+ "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
+ intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
}
else
{
- cmd = scb->cmd;
- scb->target_status = inb(SCB_TARGET_STATUS + base);
- aic7xxx_status(cmd) = scb->target_status;
+ cmd = scb->cmd;
+ hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+ aic7xxx_status(cmd) = hscb->target_status;
- cmd->result |= scb->target_status;
+ cmd->result |= hscb->target_status;
- switch (status_byte(scb->target_status))
- {
- case GOOD:
- printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
- break;
-
- case CHECK_CONDITION:
- if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
- {
- unsigned char tcl;
- unsigned int req_buf; /* must be 32 bits */
+ switch (status_byte(hscb->target_status))
+ {
+ case GOOD:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
+ "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+ break;
- tcl = scb->target_channel_lun;
+ case CHECK_CONDITION:
+ if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+ {
+ unsigned int addr; /* must be 32 bits */
+ /*
+ * XXX - How do we save the residual (if there is one).
+ */
+ aic7xxx_calculate_residual(p, scb);
+
+ /*
+ * Send a sense command to the requesting target.
+ * XXX - revisit this and get rid of the memcopys.
+ */
+ memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+ sizeof(generic_sense));
+
+ scb->sense_cmd[1] = (cmd->lun << 5);
+ scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+ scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+ scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
- /*
- * Send a sense command to the requesting target.
+ /*
+ * XXX - We should allow disconnection, but can't as it
+ * might allow overlapped tagged commands.
*/
- cmd->flags |= WAS_SENSE;
- memcpy((void *) scb->sense_cmd, (void *) generic_sense,
- sizeof(generic_sense));
-
- scb->sense_cmd[1] = (cmd->lun << 5);
- scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
- scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
- scb->sg_list[0].length = sizeof(cmd->sense_buffer);
- req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- scb->control = scb->control & DISCENB;
- scb->target_channel_lun = tcl;
- addr = VIRT_TO_BUS(scb->sense_cmd);
- scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
- memcpy(scb->SCSI_cmd_pointer, &addr,
- sizeof(scb->SCSI_cmd_pointer));
- scb->SG_segment_count = 1;
- memcpy(scb->SG_list_pointer, &req_buf,
- sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
-
- aic7xxx_putscb(p, scb);
+ /* hscb->control &= DISCENB; */
+ hscb->control = 0;
+ hscb->target_status = 0;
+ hscb->SG_segment_count = 1;
+
+ addr = VIRT_TO_BUS(&scb->sg_list[0]);
+ memcpy(&hscb->SG_list_pointer, &addr,
+ sizeof(hscb->SG_list_pointer));
+
+ memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
+ sizeof(hscb->data_pointer));
+ /* Maintain SCB_LINKED_NEXT */
+ hscb->data_count &= 0xFF000000;
+ hscb->data_count |= scb->sg_list[0].length;
+
+ addr = VIRT_TO_BUS(scb->sense_cmd);
+ memcpy(&hscb->SCSI_cmd_pointer, &addr,
+ sizeof(hscb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+
+ scb->sg_count = hscb->SG_segment_count;
+ scb->flags |= SCB_SENSE;
/*
- * Ensure that the target is "BUSY" so we don't get overlapping
- * commands if we happen to be doing tagged I/O.
+ * Ensure the target is busy since this will be an
+ * an untagged request.
*/
- aic7xxx_busy_target(scsi_id, channel, base);
+ aic7xxx_busy_target(p, target, channel, hscb->tag);
+ outb(SEND_SENSE, p->base + RETURN_1);
+ } /* first time sense, no errors */
+ else
+ {
+ if (aic7xxx_error(cmd) == 0)
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ }
+ break;
- aic7xxx_add_waiting_scb(base, scb);
- outb(SEND_SENSE, RETURN_1 + base);
- } /* first time sense, no errors */
- else
+ case QUEUE_FULL:
+#ifdef NOT_YET
+ if (scb->hscb->control & TAG_ENB)
{
- cmd->flags &= ~ASKED_FOR_SENSE;
- if (aic7xxx_error(cmd) == 0)
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
+ if (cmd->device->queue_depth > 2)
+ {
+ cmd->device->queue_depth--; /* Not correct */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
+ "reduced to %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth);
+ }
+ /*
+ * XXX - Requeue this unconditionally?
+ */
+
+ /*
+ * We'd like to be able to give the SCB some more time
+ * (untimeout, then timeout).
+ */
+ break;
}
- break;
-
- case BUSY:
- printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
- p->host_no, scb->target_channel_lun);
- if (!aic7xxx_error(cmd))
- {
- /* The error code here used to be DID_BUS_BUSY,
- * but after extensive testing, it has been determined
- * that a DID_BUS_BUSY return is a waste of time. If
- * the problem is something that will go away, then it
- * will, if it isn't, then you don't want the endless
- * looping that you get with a DID_BUS_BUSY. Better
- * to be on the safe side and specify an error condition
- * that will eventually lead to a reset or abort of some
- * sort instead of an endless loop.
- */
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
-
- case QUEUE_FULL:
- printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
- scb->state |= SCB_ASSIGNEDQ;
- scbq_insert_tail(&p->assigned_scbs, scb);
- break;
-
- default:
- printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
- p->host_no, scb->target_status);
- if (!aic7xxx_error(cmd))
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
- } /* end switch */
+#endif
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
+ "queue depth %d, active %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth,
+ p->device_status[TARGET_INDEX(cmd)].active_cmds);
+
+ /* Else treat this as if it was a BUSY condition. */
+ scb->hscb->target_status = (BUSY << 1) |
+ (scb->hscb->target_status & 0x01);
+ /* Fall through to the BUSY case. */
+
+ case BUSY:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
+ p->host_no, TC_OF_SCB(scb));
+ if (!aic7xxx_error(cmd))
+ {
+ /*
+ * The mid-level SCSI code should be fixed to
+ * retry the command at a later time instead of
+ * trying right away.
+ */
+ aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+ }
+ udelay(1000); /* A small pause (1ms) to help the drive */
+ break;
+
+ default:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
+ "status 0x%x.\n", p->host_no,
+ TC_OF_SCB(scb), scb->hscb->target_status);
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ break;
+ } /* end switch */
} /* end else of */
- break;
+ }
+ break;
- case RESIDUAL:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * Don't destroy valid residual information with
- * residual coming from a check sense operation.
- */
- if (!(cmd->flags & WAS_SENSE))
- {
- /*
- * We had an underflow. At this time, there's only
- * one other driver that bothers to check for this,
- * and cmd->underflow seems to be set rather half-
- * heartedly in the higher-level SCSI code.
- */
- actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
-
- actual -= (inb(SCB_RESID_DCNT2 + base) << 16) |
- (inb(SCB_RESID_DCNT1 + base) << 8) |
- inb(SCB_RESID_DCNT0 + base);
-
- if (actual < cmd->underflow)
- {
- printk(KERN_WARNING "scsi%d: Target %d underflow - "
- "Wanted at least %u, got %u, residual SG count %d.\n",
- p->host_no, cmd->target, cmd->underflow, actual,
- inb(SCB_RESID_SGCNT + base));
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- aic7xxx_status(cmd) = scb->target_status;
- }
- }
- }
- break;
+ case AWAITING_MSG:
+ {
+ unsigned char scb_index;
+ unsigned char message_offset;
- case ABORT_TAG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * We didn't receive a valid tag back from the target
- * on a reconnect.
- */
- printk("scsi%d: Invalid tag received on target %d, channel %c, "
- "lun %d - Sending ABORT_TAG.\n", p->host_no,
- scsi_id, channel, cmd->lun & 0x07);
-
- cmd->result = (DID_RETRY_COMMAND << 16);
- aic7xxx_done(p, scb);
- }
- break;
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
- case AWAITING_MSG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ /*
+ * This SCB had a MK_MESSAGE set in its control byte informing
+ * the sequencer that we wanted to send a special message to
+ * this target.
+ */
+ message_offset = inb(p->base + MSG_LEN);
+ if (scb->flags & SCB_DEVICE_RESET)
{
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+ outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
+ p->host_no, TC_OF_SCB(scb));
}
- else
+ else if (scb->flags & SCB_ABORT)
+ {
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+ }
+ outb(message_offset + 1, p->base + MSG_LEN);
+ printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
+ p->host_no, TC_OF_SCB(scb));
+ }
+ else if (scb->flags & SCB_MSGOUT_WDTR)
{
- /*
- * This SCB had a zero length command, informing the sequencer
- * that we wanted to send a special message to this target.
- * We only do this for BUS_DEVICE_RESET messages currently.
- */
- if (scb->state & SCB_DEVICE_RESET)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
- scsi_id);
-#endif
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(1, MSG_LEN + base);
- }
- else
- {
- panic("scsi%d: AWAITING_SCB for an SCB that does "
- "not have a waiting message.\n", p->host_no);
- }
- }
- break;
-
- case IMMEDDONE:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
- scsi_id, scb_index, scb->state);
-#endif
- if (scb->state & SCB_DEVICE_RESET)
+ aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+ }
+ else if (scb->flags & SCB_MSGOUT_SDTR)
{
- int found;
+ unsigned char target_scratch;
+ unsigned short ultra_enable;
+ int i, sxfr;
/*
- * Go back to async/narrow transfers and renegotiate.
+ * Pull the user defined setting from scratch RAM.
*/
- aic7xxx_unbusy_target(scsi_id, channel, base);
- p->needsdtr |= (p->needsdtr_copy & target_mask);
- p->needwdtr |= (p->needwdtr_copy & target_mask);
- p->sdtr_pending &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
- scratch &= SXFR;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- found = aic7xxx_reset_device(p, (int) scsi_id, channel);
- printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
- "aborted.\n", p->host_no, found);
- /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
- run_aborted_queue = TRUE;
+ target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ sxfr = target_scratch & SXFR;
+ ultra_enable = inb(p->base + ULTRA_ENB) |
+ (inb(p->base + ULTRA_ENB + 1) << 8);
+ if (ultra_enable & target_mask)
+ {
+ sxfr |= 0x100;
+ }
+ for (i = 0; i < num_aic7xxx_syncrates; i++)
+ {
+ if (sxfr == aic7xxx_syncrates[i].rate)
+ break;
+ }
+ aic7xxx_construct_sdtr(p, message_offset,
+ aic7xxx_syncrates[i].period,
+ target_scratch & WIDEXFER ?
+ MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
}
- else
+ else
{
- panic("scsi%d: Immediate complete for unknown operation.\n",
- p->host_no);
- }
- break;
+ panic("aic7xxx: AWAITING_MSG for an SCB that does "
+ "not have a waiting message.");
+ }
+ }
+ break;
- case DATA_OVERRUN:
+ case DATA_OVERRUN:
{
- unsigned int overrun;
-
- scb = (p->scb_array[inb(base + SCB_TAG)]);
- overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
- (inb(base + STCNT2) << 16);
- overrun =0x00FFFFFF - overrun;
- printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
- "a retry.\n", p->host_no, overrun);
- aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
- break;
+ unsigned char scb_index = inb(p->base + SCB_TAG);
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned int i, overrun;
+
+ scb = (p->scb_data->scb_array[scb_index]);
+ overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
+ (inb(p->base + STCNT + 2) << 16);
+ overrun = 0x00FFFFFF - overrun;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
+ "in %s phase, tag %d; forcing a retry.\n",
+ p->host_no, TC_OF_SCB(scb), overrun,
+ lastphase == P_DATAIN ? "Data-In" : "Data-Out",
+ scb->hscb->tag);
+ printk(KERN_WARNING "%s seen Data Phase. Length = %d, NumSGs = %d.\n",
+ inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+ aic7xxx_length(scb->cmd, 0), scb->sg_count);
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_INFO " sg[%d] - Addr 0x%x : Length %d\n",
+ i, scb->sg_list[i].address, scb->sg_list[i].length);
+ }
+ /*
+ * XXX - What do we really want to do on an overrun? The
+ * mid-level SCSI code should handle this, but for now,
+ * we'll just indicate that the command should retried.
+ */
+ aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
}
+ break;
-#if AIC7XXX_NOT_YET
- /* XXX Fill these in later */
- case MESG_BUFFER_BUSY:
- break;
- case MSGIN_PHASEMIS:
- break;
-#endif
+/* #if AIC7XXX_NOT_YET */
+ /* XXX Fill these in later */
+ case MSG_BUFFER_BUSY:
+ printk("aic7xxx: Message buffer busy.\n");
+ break;
+ case MSGIN_PHASEMIS:
+ printk("aic7xxx: Message-in phasemis.\n");
+ break;
+/*#endif */
+
+ case ABORT_CMDCMPLT:
+ /* This interrupt serves to pause the sequencer until we can clean
+ * up the QOUTFIFO allowing us to handle any abort SCBs that may
+ * completed yet still have an SCB in the QINFIFO or waiting for
+ * selection queue. By the time we get here, we should have
+ * already cleaned up the queues, so all we need to do is unpause
+ * the sequencer.
+ */
+ break;
+
+ default: /* unknown */
+ printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+ p->host_no, intstat, inb(p->base + SCSISIGI));
+ break;
+ }
+
+ /*
+ * Clear the sequencer interrupt and unpause the sequencer.
+ */
+ outb(CLRSEQINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+}
- default: /* unknown */
- printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
- p->host_no, intstat, inb(SCSISIGI + base));
- break;
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_scsiint
+ *
+ * Description:
+ * Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ unsigned char scb_index;
+ unsigned char status;
+ struct aic7xxx_scb *scb;
+
+ scb_index = inb(p->base + SCB_TAG);
+ status = inb(p->base + SSTAT1);
+
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
+ {
+ scb = NULL;
}
+ }
+ else
+ {
+ scb = NULL;
+ }
+
+ if ((status & SCSIRSTI) != 0)
+ {
+ char channel;
+ channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+
+ printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+ p->host_no, channel);
/*
- * Clear the sequencer interrupt and unpause the sequencer.
+ * Go through and abort all commands for the channel, but do not
+ * reset the channel again.
*/
- outb(CLRSEQINT, CLRINT + base);
- UNPAUSE_SEQUENCER(p);
+ aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+ scb = NULL;
}
-
- if (intstat & SCSIINT)
+ else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
{
- int status = inb(SSTAT1 + base);
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- }
+ /*
+ * First look at what phase we were last in. If it's message-out,
+ * chances are pretty good that the bus free was in response to
+ * one of our abort requests.
+ */
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
+ char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+ int printerror = TRUE;
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (status & SCSIRSTI)
- {
- PAUSE_SEQUENCER(p);
- printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
- p->host_no, channel);
- /*
- * Go through and abort all commands for the channel, but do not
- * reset the channel again.
- */
- aic7xxx_reset_channel(p, channel, FALSE);
- run_aborted_queue = TRUE;
- }
- else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ outb(0, p->base + SCSISEQ);
+ if (lastphase == P_MESGOUT)
{
- printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
- /*
- * Turn off the interrupt and set status to zero, so that it
- * falls through the rest of the SCSIINT code.
- */
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
- scb = NULL;
+ unsigned char sindex;
+ unsigned char message;
+
+ sindex = inb(p->base + SINDEX);
+ message = inb(p->base + sindex - 1);
+
+ if (message == MSG_ABORT)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_ABORT_TAG)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_BUS_DEV_RESET)
+ {
+ aic7xxx_handle_device_reset(p, target, channel);
+ scb = NULL;
+ printerror = 0;
+ }
}
- else if (status & SCSIPERR)
+ if (printerror != 0)
{
- char *phase;
- unsigned char mesg_out = MSG_NOP;
- unsigned char lastphase = inb(LASTPHASE + base);
+ if (scb != NULL)
+ {
+ unsigned char tag;
- cmd = scb->cmd;
- switch (lastphase)
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ tag = scb->hscb->tag;
+ }
+ else
+ {
+ tag = SCB_LIST_NULL;
+ }
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+ }
+ else
{
- case P_DATAOUT:
- phase = "Data-Out";
- break;
- case P_DATAIN:
- phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_COMMAND:
- phase = "Command";
- break;
- case P_MESGOUT:
- phase = "Message-Out";
- break;
- case P_STATUS:
- phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_MESGIN:
- phase = "Message-In";
- mesg_out = MSG_MSG_PARITY_ERROR;
- break;
- default:
- phase = "unknown";
- break;
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
}
+ printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
+ "SEQADDR = 0x%x\n", p->host_no, lastphase,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ }
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+ outb(CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if ((status & SELTO) != 0)
+ {
+ unsigned char scbptr;
+ unsigned char nextscb;
+ Scsi_Cmnd *cmd;
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
- "channel %d, lun %d.\n", p->host_no, phase,
- cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
+ scbptr = inb(p->base + WAITING_SCBH);
+ outb(scbptr, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
- /*
- * We've set the hardware to assert ATN if we get a parity
- * error on "in" phases, so all we need to do is stuff the
- * message buffer with the appropriate message. In phases
- * have set mesg_out to something other than MSG_NOP.
- */
- if (mesg_out != MSG_NOP)
- {
- outb(mesg_out, MSG0 + base);
- outb(1, MSG_LEN + base);
- cmd->result = DID_PARITY << 16;
- }
- else
+ scb = NULL;
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
{
- /*
- * Should we allow the target to make this decision for us?
- */
- cmd->result = DID_RETRY_COMMAND << 16;
+ scb = NULL;
}
- aic7xxx_done(p, scb);
}
- else if (status & SELTO)
+ if (scb == NULL)
{
- unsigned char waiting;
-
+ printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
+ p->host_no, scb_index);
+ printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+ "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+ }
+ else
+ {
+ /*
+ * XXX - If we queued an abort tag, go clean up the disconnected list.
+ */
cmd = scb->cmd;
-
cmd->result = (DID_TIME_OUT << 16);
+
/*
* Clear an pending messages for the timed out
* target and mark the target as free.
*/
- ha_flags = inb(FLAGS + base);
- outb(0, MSG_LEN + base);
- aic7xxx_unbusy_target(scsi_id, channel, base);
+ outb(0, p->base + MSG_LEN);
+ aic7xxx_index_busy_target(p, cmd->target,
+ cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
+ outb(0, p->base + SCB_CONTROL);
+
/*
- * Stop the selection.
+ * Shift the waiting for selection queue forward
*/
- outb(0, SCSISEQ + base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ nextscb = inb(p->base + SCB_NEXT);
+ outb(nextscb, p->base + WAITING_SCBH);
/*
- * Shift the waiting for selection queue forward
+ * Put this SCB back on the free list.
*/
- waiting = inb(WAITING_SCBH + base);
- outb(waiting, SCBPTR + base);
- waiting = inb(SCB_NEXT + base);
- outb(waiting, WAITING_SCBH + base);
+ aic7xxx_add_curscb_to_free_list(p);
+ }
+ /*
+ * Stop the selection.
+ */
+ outb(0, p->base + SCSISEQ);
+ outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+ "during scsiint 0x%x scb(%d)\n"
+ " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+ p->host_no, status, scb_index, inb(p->base + SIMODE0),
+ inb(p->base + SIMODE1), inb(p->base + SSTAT0),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ /*
+ * Turn off the interrupt and set status to zero, so that it
+ * falls through the rest of the SCSIINT code.
+ */
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ else if (status & SCSIPERR)
+ {
+ /*
+ * Determine the bus phase and queue an appropriate message.
+ */
+ char *phase;
+ Scsi_Cmnd *cmd;
+ unsigned char mesg_out = MSG_NOOP;
+ unsigned char lastphase = inb(p->base + LASTPHASE);
- RESTART_SEQUENCER(p);
- aic7xxx_done(p, scb);
+ cmd = scb->cmd;
+ switch (lastphase)
+ {
+ case P_DATAOUT:
+ phase = "Data-Out";
+ break;
+ case P_DATAIN:
+ phase = "Data-In";
+ mesg_out = MSG_INITIATOR_DET_ERR;
+ break;
+ case P_COMMAND:
+ phase = "Command";
+ break;
+ case P_MESGOUT:
+ phase = "Message-Out";
+ break;
+ case P_STATUS:
+ phase = "Status";
+ mesg_out = MSG_INITIATOR_DET_ERR;
+ break;
+ case P_MESGIN:
+ phase = "Message-In";
+ mesg_out = MSG_PARITY_ERROR;
+ break;
+ default:
+ phase = "unknown";
+ break;
+ }
+
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
+ p->host_no, TC_OF_SCB(scb), phase);
+
+ /*
+ * We've set the hardware to assert ATN if we get a parity
+ * error on "in" phases, so all we need to do is stuff the
+ * message buffer with the appropriate message. "In" phases
+ * have set mesg_out to something other than MSG_NOP.
+ */
+ if (mesg_out != MSG_NOOP)
+ {
+ outb(mesg_out, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ scb = NULL;
}
- else if (!(status & BUSFREE))
+ else
{
/*
- * We don't know what's going on. Turn off the
- * interrupt source and try to continue.
+ * Should we allow the target to make this decision for us?
*/
- printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
+ cmd->result = DID_RETRY_COMMAND << 16;
+ }
+ outb(CLRSCSIPERR, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ else
+ {
+ /*
+ * We don't know what's going on. Turn off the
+ * interrupt source and try to continue.
+ */
+ printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ if (scb != NULL)
+ {
+ aic7xxx_done(p, scb);
+ aic7xxx_done_cmds_complete(p);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_isr
+ *
+ * Description:
+ * SCSI controller interrupt handler.
+ *
+ * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ * be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct aic7xxx_host *p;
+ unsigned char intstat;
+ unsigned long flags;
+
+ p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+
+ /*
+ * Search for the host with a pending interrupt. If we can't find
+ * one, then we've encountered a spurious interrupt.
+ */
+ while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+ {
+ if (p->next == NULL)
+ {
+ p = NULL;
+ }
+ else
+ {
+ p = (struct aic7xxx_host *) p->next->hostdata;
+ }
+ }
+
+ if (p == NULL)
+ return;
+
+ /*
+ * Handle all the interrupt sources - especially for SCSI
+ * interrupts, we won't get a second chance at them.
+ */
+ intstat = inb(p->base + INTSTAT);
+
+ /*
+ * Keep track of interrupts for /proc/scsi
+ */
+ p->isr_count++;
+
+ if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+ {
+ /*
+ * We must only have one card at this IRQ and it must have been
+ * added to the board data before the spurious interrupt occurred.
+ * It is sufficient that we check isr_count and not the spurious
+ * interrupt count.
+ */
+ printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
+ if (intstat)
+ {
+ /* Try clearing all interrupts. */
+ outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
}
+ return;
}
- if (run_aborted_queue)
- aic7xxx_done_aborted_scbs(p);
+ if (p->flags & IN_ISR)
+ {
+ printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+ p->host_no);
+ return;
+ }
+
+ /*
+ * Indicate that we're in the interrupt handler.
+ */
+ save_flags(flags);
+ cli();
+ p->flags |= IN_ISR;
if (intstat & CMDCMPLT)
{
- int complete;
+ struct aic7xxx_scb *scb = NULL;
+ Scsi_Cmnd *cmd;
+ unsigned char qoutcnt;
+ unsigned char scb_index;
+ int i, interrupts_cleared = 0;
/*
* The sequencer will continue running when it
* issues this interrupt. There may be >1 commands
* finished, so loop until we've processed them all.
*/
- do {
- complete = inb(QOUTFIFO + base);
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
- scb = (p->scb_array[complete]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
- " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
- "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
- inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
- scb->position);
- outb(CLRCMDINT, CLRINT + base);
- continue;
- }
- cmd = scb->cmd;
- cmd->result |= (aic7xxx_error(cmd) << 16);
- if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+#if 1
+ if (qoutcnt >= p->qfullcount - 1)
+ printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
+ "qoutcnt = %d.\n", qoutcnt);
+#endif
+ while (qoutcnt > 0)
+ {
+ for (i = 0; i < qoutcnt; i++)
{
- /*
- * Got sense information.
- */
- cmd->flags &= ASKED_FOR_SENSE;
+ scb_index = inb(p->base + QOUTFIFO);
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
+ "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
+ inb(p->base + QOUTCNT), inb(p->base + QINCNT));
+ continue;
+ }
+ else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
+ "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
+ p->host_no, scb_index, inb(p->base + QOUTCNT),
+ inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
+ continue;
+ }
+ cmd = scb->cmd;
+ if (scb->hscb->residual_SG_segment_count != 0)
+ {
+ aic7xxx_calculate_residual(p, scb);
+ }
+ if ((scb->flags & SCB_QUEUED_ABORT) != 0)
+ {
+ /*
+ * Have to clean up any possible entries in the
+ * waiting queue and the QINFIFO.
+ */
+ int target;
+ char channel;
+ int lun;
+ unsigned char tag;
+
+ tag = SCB_LIST_NULL;
+ target = cmd->target;
+ lun = cmd->lun;
+ channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ if (scb->hscb->control & TAG_ENB)
+ {
+ tag = scb->hscb->tag;
+ }
+ aic7xxx_reset_device(p, target, channel, lun, tag);
+ /*
+ * Run the done queue, but don't complete the commands; we
+ * do this once at the end of the loop.
+ */
+ aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+ }
+ cmd->result |= (aic7xxx_error(cmd) << 16);
+ p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+ aic7xxx_done(p, scb);
}
- p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-
/*
* Clear interrupt status before checking the output queue again.
* This eliminates a race condition whereby a command could
@@ -3243,56 +3941,152 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* so notification of the command being complete never made it
* back up to the kernel.
*/
- outb(CLRCMDINT, CLRINT + base);
- aic7xxx_done(p, scb);
+ outb(CLRCMDINT, p->base + CLRINT);
+ interrupts_cleared++;
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+ }
-#ifdef AIC7XXX_PROC_STATS
- /*
- * XXX: we should actually know how much actually transferred
- * XXX: for each command, but apparently that's too difficult.
- */
- actual = aic7xxx_length(cmd, 0);
- if (!(cmd->flags & WAS_SENSE) && (actual > 0))
+ if (interrupts_cleared == 0)
+ {
+ outb(CLRCMDINT, p->base + CLRINT);
+ }
+
+ aic7xxx_done_cmds_complete(p);
+ }
+
+ if (intstat & BRKADRINT)
+ {
+ int i;
+ unsigned char errno = inb(p->base + ERROR);
+
+ printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+ for (i = 0; i < NUMBER(hard_error); i++)
+ {
+ if (errno & hard_error[i].errno)
{
- struct aic7xxx_xferstats *sp;
- long *ptr;
- int x;
+ printk(KERN_ERR " %s\n", hard_error[i].errmesg);
+ }
+ }
+ printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+ inb(p->base + ERROR),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ }
+
+ if (intstat & SEQINT)
+ {
+ aic7xxx_handle_seqint(p, intstat);
+ }
- sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
- sp->xfers++;
+ if (intstat & SCSIINT)
+ {
+ aic7xxx_handle_scsiint(p, intstat);
+ }
- if (cmd->request.cmd == WRITE)
+ if (p->waiting_scbs.head != NULL)
+ {
+ aic7xxx_run_waiting_queues(p);
+ }
+
+ p->flags &= ~IN_ISR;
+ restore_flags(flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_device_queue_depth
+ *
+ * Description:
+ * Determines the queue depth for a given device. There are two ways
+ * a queue depth can be obtained for a tagged queueing device. One
+ * way is the default queue depth which is determined by whether
+ * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used
+ * as the default queue depth. Otherwise, we use either 4 or 8 as the
+ * default queue depth (dependent on the number of hardware SCBs).
+ * The other way we determine queue depth is through the use of the
+ * aic7xxx_tag_info array which is enabled by defining
+ * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized
+ * with queue depths for individual devices. It also allows tagged
+ * queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+ int default_depth = 2;
+
+ device->queue_depth = default_depth;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (device->tagged_supported)
+ {
+ unsigned short target_mask;
+ int tag_enabled = TRUE;
+
+ target_mask = (1 << (device->id | (device->channel << 3)));
+
+#ifdef AIC7XXX_CMDS_PER_LUN
+ default_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+ if (p->scb_data->maxhscbs <= 4)
+ {
+ default_depth = 4; /* Not many SCBs to work with. */
+ }
+ else
+ {
+ default_depth = 8;
+ }
+#endif
+
+ if (!(p->discenable & target_mask))
+ {
+ printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+ "enable tagged queueing.\n",
+ p->host_no, device->id, device->channel);
+ }
+ else
+ {
+#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+ device->queue_depth = default_depth;
+#else
+ if (p->instance > NUMBER(aic7xxx_tag_info))
+ {
+ device->queue_depth = default_depth;
+ }
+ else
+ {
+ unsigned char tindex;
+
+ tindex = device->id | (device->channel << 3);
+ if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
{
- sp->w_total++;
- sp->w_total512 += (actual >> 9);
- ptr = sp->w_bins;
+ tag_enabled = FALSE;
+ device->queue_depth = 2; /* Tagged queueing is disabled. */
}
- else
+ else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
{
- sp->r_total++;
- sp->r_total512 += (actual >> 9);
- ptr = sp->r_bins;
+ device->queue_depth = default_depth;
}
- for (x = 9; x <= 17; x++)
+ else
{
- if (actual < (1 << x))
- {
- ptr[x - 9]++;
- break;
- }
+ device->queue_depth =
+ aic7xxx_tag_info[p->instance].tag_commands[tindex];
}
- if (x > 17)
+ }
+#endif
+ if ((device->tagged_queue == 0) && tag_enabled)
+ {
+ if (aic7xxx_verbose)
{
- ptr[x - 9]++;
+ printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+ "queue depth %d.\n", p->host_no,
+ device->id, device->channel, device->queue_depth);
}
+ device->tagged_queue = 1;
+ device->current_tag = SCB_LIST_NULL;
}
-#endif /* AIC7XXX_PROC_STATS */
-
- } while (inb(QOUTCNT + base) & p->qcntmask);
+ }
}
- aic7xxx_done_cmds_complete(p);
- p->flags &= ~IN_ISR;
- aic7xxx_run_waiting_queues(p);
+#endif
}
/*+F*************************************************************************
@@ -3307,59 +4101,18 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* algorithm for determining the queue depth based on the maximum
* SCBs for the controller.
*-F*************************************************************************/
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs)
{
- Scsi_Device *device = scsi_devs;
- int tq_depth = 2;
+ Scsi_Device *device;
struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-#ifdef AIC7XXX_CMDS_PER_LUN
- tq_depth = AIC7XXX_CMDS_PER_LUN;
-#else
- {
- if (p->maxhscbs <= 4)
- {
- tq_depth = 4; /* Not many SCBs to work with. */
- }
- else
- {
- tq_depth = 8;
- }
- }
-#endif
-
for (device = scsi_devs; device != NULL; device = device->next)
{
if (device->host == host)
{
- device->queue_depth = 2;
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (device->tagged_supported)
- {
- unsigned short target_mask = (1 << device->id) | device->channel;
-
- if (!(p->discenable & target_mask))
- {
- printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
- "tagged queueing for target %d, channel %d, LUN %d.\n",
- host->host_no, device->id, device->channel, device->lun);
- }
- else
- {
- device->queue_depth = tq_depth;
- if (device->tagged_queue == 0)
- {
- printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
- "channel %d, LUN %d, queue depth %d.\n", host->host_no,
- device->id, device->channel, device->lun,
- device->queue_depth);
- device->tagged_queue = 1;
- device->current_tag = SCB_LIST_NULL;
- }
- }
- }
-#endif
+ aic7xxx_device_queue_depth(p, device);
}
}
}
@@ -3386,7 +4139,7 @@ static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
* The fourth byte's lowest bit seems to be an enabled/disabled
* flag (rest of the bits are reserved?).
*-F*************************************************************************/
-static aha_type
+static aha_chip_type
aic7xxx_probe(int slot, int base, aha_status_type *bios)
{
int i;
@@ -3395,7 +4148,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
static struct {
int n;
unsigned char signature[sizeof(buf)];
- aha_type type;
+ aha_chip_type type;
int bios_disabled;
} AIC7xxx[] = {
{ 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
@@ -3434,7 +4187,8 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
return (AIC7xxx[i].type);
}
- printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
+ printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+ "disabled at slot %d, ignored.\n", slot);
}
}
@@ -3461,10 +4215,9 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
* useful in that it gives us an 800 nsec timer. After a read from the
* SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
* later.
- *
*-F*************************************************************************/
static int
-read_2840_seeprom(int base, struct seeprom_config *sc)
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
{
int i = 0, k = 0;
unsigned char temp;
@@ -3477,11 +4230,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0) \
+ while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0) \
{ \
; /* Do nothing */ \
} \
- (void) inb(SEECTL_2840 + base);
+ (void) inb(p->base + SEECTL_2840);
/*
* Read the first 32 registers of the seeprom. For the 2840,
@@ -3494,8 +4247,8 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*
* Send chip select for one clock cycle.
*/
- outb(CK_2840 | CS_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
@@ -3504,11 +4257,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
for (i = 0; i < seeprom_read.len; i++)
{
temp = CS_2840 | seeprom_read.bits[i];
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* Send the 6 bit address (MSB first, LSB last).
@@ -3518,11 +4271,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
temp = k;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = CS_2840 | temp;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
@@ -3534,12 +4287,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
for (i = 0; i <= 16; i++)
{
temp = CS_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* The serial EEPROM has a checksum in the last word. Keep a
@@ -3555,12 +4308,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*
* Reset the chip select for the next command cycle.
*/
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(CK_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(CK_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
#if 0
@@ -3589,6 +4342,53 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*+F*************************************************************************
* Function:
+ * acquire_seeprom
+ *
+ * Description:
+ * Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+ int wait;
+
+ /*
+ * Request access of the memory port. When access is
+ * granted, SEERDY will go high. We use a 1 second
+ * timeout which should be near 1 second more than
+ * is needed. Reason: after the 7870 chip reset, there
+ * should be no contention.
+ */
+ outb(SEEMS, p->base + SEECTL);
+ wait = 1000; /* 1000 msec = 1 second */
+ while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+ {
+ wait--;
+ udelay(1000); /* 1 msec */
+ }
+ if ((inb(p->base + SEECTL) & SEERDY) == 0)
+ {
+ outb(0, p->base + SEECTL);
+ return (0);
+ }
+ return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * release_seeprom
+ *
+ * Description:
+ * Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline void
+release_seeprom(struct aic7xxx_host *p)
+{
+ outb(0, p->base + SEECTL);
+}
+
+/*+F*************************************************************************
+ * Function:
* read_seeprom
*
* Description:
@@ -3626,7 +4426,7 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
*
- * The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
* register. After successful arbitration for the memory port, the
* SEECS bit of the SEECTL register is connected to the chip select.
* The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
@@ -3636,17 +4436,14 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
* to this is when we first request access to the memory port. The
* SEERDY goes high to signify that access has been granted and, for
* this case, has no implied timing.
- *
*-F*************************************************************************/
static int
-read_seeprom(int base, int offset, struct seeprom_config *sc,
- seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
+ unsigned int len, seeprom_chip_type chip)
{
int i = 0, k;
- unsigned long timeout;
unsigned char temp;
unsigned short checksum = 0;
- unsigned short *seeprom = (unsigned short *) sc;
struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
@@ -3654,43 +4451,33 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(SEECTL + base) & SEERDY) == 0) \
+ while ((inb(p->base + SEECTL) & SEERDY) == 0) \
{ \
; /* Do nothing */ \
}
/*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the 7870 chip reset, there
- * should be no contention.
+ * Request access of the memory port.
*/
- outb(SEEMS, SEECTL + base);
- timeout = jiffies + 100; /* 1 second timeout */
- while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
- {
- ; /* Do nothing! Wait for access to be granted. */
- }
- if ((inb(SEECTL + base) & SEERDY) == 0)
+ if (acquire_seeprom(p) == 0)
{
- outb(0, SEECTL + base);
return (0);
}
/*
- * Read the first 32 registers of the seeprom. For the 7870,
- * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
- * but only the first 32 are used by Adaptec BIOS. The loop
- * will range from 0 to 31.
+ * Read 'len' registers of the seeprom. For the 7870, the 93C46
+ * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+ * the first 32 are used by Adaptec BIOS. Some adapters use the
+ * 93C56 SEEPROM which is a 2048-bit device. The loop will range
+ * from 0 to 'len' - 1.
*/
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
/*
* Send chip select for one clock cycle.
*/
- outb(SEEMS | SEECK | SEECS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
@@ -3699,25 +4486,25 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
for (i = 0; i < seeprom_read.len; i++)
{
temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * Send the 6 bit address (MSB first, LSB last).
+ * Send the 6 or 8 bit address (MSB first, LSB last).
*/
for (i = ((int) chip - 1); i >= 0; i--)
{
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
@@ -3729,56 +4516,57 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
for (i = 0; i <= 16; i++)
{
temp = SEEMS | SEECS;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * The serial EEPROM has a checksum in the last word. Keep a
- * running checksum for all words read except for the last
- * word. We'll verify the checksum after all words have been
- * read.
+ * The serial EEPROM should have a checksum in the last word.
+ * Keep a running checksum for all words read except for the
+ * last word. We'll verify the checksum after all words have
+ * been read.
*/
- if (k < (sizeof(*sc) / 2) - 1)
+ if (k < (len - 1))
{
- checksum = checksum + seeprom[k];
+ checksum = checksum + scarray[k];
}
/*
* Reset the chip select for the next command cycle.
*/
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS | SEECK, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS | SEECK, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
* Release access to the memory port and the serial EEPROM.
*/
- outb(0, SEECTL + base);
+ release_seeprom(p);
#if 0
- printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+ printk("Computed checksum 0x%x, checksum read 0x%x\n",
+ checksum, scarray[len - 1]);
printk("Serial EEPROM:");
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
if (((k % 8) == 0) && (k != 0))
{
printk("\n ");
}
- printk(" 0x%x", seeprom[k]);
+ printk(" 0x%x", scarray[k]);
}
printk("\n");
#endif
- if (checksum != sc->checksum)
+ if (checksum != scarray[len - 1])
{
return (0);
}
@@ -3789,563 +4577,452 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
/*+F*************************************************************************
* Function:
- * detect_maxscb
+ * write_brdctl
*
* Description:
- * Detects the maximum number of SCBs for the controller and returns
- * the count and a mask in config (config->maxscbs, config->qcntmask).
+ * Writes a value to the BRDCTL register.
*-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host_config *config)
+static inline void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
{
- unsigned char sblkctl_reg;
- int base, i;
-
-#ifdef AIC7XXX_PAGE_ENABLE
- config->flags |= PAGE_ENABLED;
-#endif
- base = config->base;
- switch (config->type)
- {
- case AIC_7770:
- case AIC_7771:
- case AIC_284x:
- /*
- * Check for Rev C or E boards. Rev E boards can supposedly have
- * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
- * It's still not clear extactly what is different about the Rev E
- * boards, but we think it allows 8 bit entries in the QOUTFIFO to
- * support "paging" SCBs (more than 4 commands can be active at once).
- *
- * The Rev E boards have a read/write autoflush bit in the
- * SBLKCTL register, while in the Rev C boards it is read only.
- */
- sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
- outb(sblkctl_reg, SBLKCTL + base);
- if (inb(SBLKCTL + base) == sblkctl_reg)
- {
- /*
- * We detected a Rev E board, we allow paging on this board.
- */
- printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
- board_names[config->type]);
- outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
- }
- else
- {
- /* Do not allow paging. */
- config->flags &= ~PAGE_ENABLED;
- printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
- board_names[config->type]);
- }
- break;
-
- default:
- break;
- }
-
- /*
- * Walk the SCBs to determine how many there are.
- */
- i = 1;
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- while (i < AIC7XXX_MAXSCB)
- {
- outb(i, SCBPTR + base);
- outb(i, SCBARRAY + base);
- if (inb(SCBARRAY + base) != i)
- break;
- outb(0, SCBPTR + base);
- if (inb(SCBARRAY + base) != 0)
- break;
-
- outb(i, SCBPTR + base); /* Clear the control byte. */
- outb(0, SCBARRAY + base);
-
- config->qcntmask |= i; /* Update the count mask. */
- i++;
- }
- outb(i, SCBPTR + base); /* Ensure we clear the control bytes. */
- outb(0, SCBARRAY + base);
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- config->maxhscbs = i;
- config->qcntmask |= i;
- if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
- {
- config->maxscbs = AIC7XXX_MAXSCB;
- }
- else
- {
- config->flags &= ~PAGE_ENABLED; /* Disable paging if we have 255 SCBs!. */
- config->maxscbs = config->maxhscbs;
- }
-
- printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
- if (config->flags & PAGE_ENABLED)
- printk(", %d page-enabled SCBs.\n", config->maxscbs);
- else
- printk(", paging not enabled.\n");
-
+ unsigned char brdctl;
+
+ brdctl = BRDCS | BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl |= value;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDCS;
+ outb(brdctl, p->base + BRDCTL);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_register
+ * read_brdctl
*
* Description:
- * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ * Reads the BRDCTL register.
*-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template,
- struct aic7xxx_host_config *config)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
{
- int i;
- unsigned char sblkctl, flags = 0;
- int max_targets;
- int found = 1;
- unsigned int sram, base;
- unsigned char target_settings;
- unsigned char scsi_conf, host_conf;
- unsigned short ultraenable = 0;
- int have_seeprom = FALSE;
- struct Scsi_Host *host;
- struct aic7xxx_host *p;
- struct seeprom_config sc;
-
- base = config->base;
-
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(base, MAXREG - MINREG, "aic7xxx");
+ outb(BRDRW | BRDCS, p->base + BRDCTL);
+ return (inb(p->base + BRDCTL));
+}
- switch (config->type)
+/*+F*************************************************************************
+ * Function:
+ * configure_termination
+ *
+ * Description:
+ * Configures the termination settings on PCI adapters that have
+ * SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
+ unsigned short adapter_control, unsigned char max_targ)
+{
+ unsigned char brdctl_int, brdctl_ext;
+ int internal50_present;
+ int internal68_present = 0;
+ int external_present = 0;
+ int eprom_present;
+ int high_on;
+ int low_on;
+ int old_verbose;
+
+ if (acquire_seeprom(p))
{
- case AIC_7770:
- case AIC_7771:
- /*
- * Use the boot-time option for the interrupt trigger type. If not
- * supplied (-1), then we use BIOS settings to determine the interrupt
- * trigger type (level or edge) and use this value for pausing and
- * unpausing the sequencer.
- */
- switch (aic7xxx_irq_trigger)
- {
- case 0: config->unpause = INTEN; /* Edge */
- break;
- case 1: config->unpause = IRQMS | INTEN; /* Level */
- break;
- case -1:
- default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN;
- break;
- }
- config->pause = config->unpause | PAUSE;
+ if (adapter_control & CFAUTOTERM)
+ {
+ old_verbose = aic7xxx_verbose;
+ printk(KERN_INFO "aic7xxx: Warning - detected auto-termination. Please "
+ "verify driver");
+ printk(KERN_INFO " detected settings and use manual termination "
+ "if necessary.");
+
+ /* Configure auto termination. */
+ outb(SEECS | SEEMS, p->base + SEECTL);
/*
- * For some 274x boards, we must clear the CHIPRST bit and pause
- * the sequencer. For some reason, this makes the driver work.
- * For 284x boards, we give it a CHIPRST just like the 294x boards.
+ * First read the status of our cables. Set the rom bank to
+ * 0 since the bank setting serves as a multiplexor for the
+ * cable detection logic. BRDDAT5 controls the bank switch.
*/
- outb(config->pause | CHIPRST, HCNTRL + base);
- aic7xxx_delay(1);
- if (inb(HCNTRL + base) & CHIPRST)
- {
- printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
- }
- outb(config->pause, HCNTRL + base);
+ write_brdctl(p, 0);
/*
- * Just to be on the safe side with the 274x, we will re-read the irq
- * since there was some issue about resetting the board.
+ * Now read the state of the internal connectors. The
+ * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
+ * set when cables are not present (BRDDAT6 is INT50 and
+ * BRDDAT7 is INT68).
*/
- config->irq = inb(INTDEF + base) & 0x0F;
- if ((config->type == AIC_7771) &&
- (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
+ brdctl_int = read_brdctl(p);
+ internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+ if (max_targ > 8)
{
- config->bios = AIC_DISABLED;
- config->flags |= USE_DEFAULTS;
- }
- else
- {
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
+ internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
}
/*
- * Setup the FIFO threshold and the bus off time
+ * Set the rom bank to 1 and determine
+ * the other signals.
*/
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
+ write_brdctl(p, BRDDAT5);
/*
- * A reminder until this can be detected automatically.
+ * Now read the state of the external connectors. BRDDAT6 is
+ * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
+ * set when the eprom is present.
*/
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_284x:
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_284X;
- config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
- config->irq = inb(INTDEF + base) & 0x0F;
- host_conf = inb(HOSTCONF + base);
-
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- have_seeprom = read_2840_seeprom(base, &sc);
- if (!have_seeprom)
+ brdctl_ext = read_brdctl(p);
+ external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
+ eprom_present = brdctl_ext & BRDDAT7;
+ if (aic7xxx_verbose)
{
- printk("aic7xxx: Unable to read SEEPROM.\n");
- }
- else
- {
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (sc.bios_control & CF284XEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- if (!(sc.bios_control & CFBIOSEN))
+ if (max_targ > 8)
{
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+ "Ext-68 %s)\n",
+ internal50_present ? "YES" : "NO",
+ internal68_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
else
{
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CF284XSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- /*
- * XXX - Adaptec *does* make 284x wide controllers, but the
- * documents do not say where the high byte termination
- * enable bit is located.
- */
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+ internal50_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
+ printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
+ "brdctl_ext=0x%x\n",
+ eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
}
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
-
- /*
- * Setup the FIFO threshold and the bus off time
- */
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
-
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_7860:
- case AIC_7861:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- /*
- * Remember if Ultra was enabled in case there is no SEEPROM.
- * Fall through to the rest of the AIC_78xx code.
- */
- if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
- config->flags |= ULTRA_ENABLED;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
/*
- * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+ * Now set the termination based on what we found. BRDDAT6
+ * controls wide termination enable.
*/
- config->scsi_id = inb(SCSIID + base) & OID;
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_294X;
- config->pause = config->unpause | PAUSE;
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
+ high_on = FALSE;
+ low_on = FALSE;
+ if ((max_targ > 8) &&
+ ((external_present == 0) || (internal68_present == 0)))
+ {
+ high_on = TRUE;
+ }
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- if ((config->type == AIC_7873) || (config->type == AIC_7883))
+ if ((internal50_present + internal68_present + external_present) <= 1)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c56_66);
+ low_on = TRUE;
}
- else
+
+ if (internal50_present && internal68_present && external_present)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c46);
+ printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
+ " Only two connectors on the adapter may be "
+ "used at a time!\n");
}
- if (!have_seeprom)
+
+ if (high_on == TRUE)
+ write_brdctl(p, BRDDAT6);
+ else
+ write_brdctl(p, 0);
+
+ if (low_on == TRUE)
+ *sxfrctl1 |= STPWEN;
+
+ if (aic7xxx_verbose)
{
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+ if (max_targ > 8)
{
- if (inb(sram) != 0x00)
- break;
- }
- if (sram == base + TARG_SCRATCH)
- {
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
- {
- if (inb(sram) != 0xFF)
- break;
- }
- }
- if ((sram != base + 0x60) && (config->scsi_id != 0))
- {
- config->flags &= ~USE_DEFAULTS;
- printk("\naic7xxx: Unable to read SEEPROM; "
- "using leftover BIOS values.\n");
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ low_on ? "ON" : "OFF",
+ high_on ? "ON" : "OFF");
}
else
{
- printk("\n");
- printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
- "settings.\n");
- config->flags |= USE_DEFAULTS;
- config->flags &= ~ULTRA_ENABLED;
- config->scsi_id = 7;
+ printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
}
- scsi_conf = ENSPCHK | RESET_SCSI;
+ }
+ aic7xxx_verbose = old_verbose;
+ }
+ else
+ {
+ if (adapter_control & CFSTERM)
+ {
+ *sxfrctl1 |= STPWEN;
+ }
+ outb(SEEMS | SEECS, p->base + SEECTL);
+ /*
+ * Configure high byte termination.
+ */
+ if (adapter_control & CFWSTERM)
+ {
+ write_brdctl(p, BRDDAT6);
}
else
{
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (!(sc.bios_control & CFBIOSEN))
- {
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
- scsi_conf = ENSPCHK | RESET_SCSI;
- }
- else
- {
- scsi_conf = 0;
- if (sc.adapter_control & CFRESETB)
- scsi_conf |= RESET_SCSI;
- if (sc.adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- if (sc.bios_control & CFEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- config->scsi_id = (sc.brtime_id & CFSCSIID);
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CFSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->high_term = (sc.adapter_control & CFWSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
- if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
- (config->type == AIC_7882) || (config->type == AIC_7883) ||
- (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
- {
- printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
- "speed.\n");
- config->flags |= ULTRA_ENABLED;
- }
- }
+ write_brdctl(p, 0);
}
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ (adapter_control & CFSTERM) ? "ON" : "OFF",
+ (adapter_control & CFWSTERM) ? "ON" : "OFF");
+ }
+ }
+ release_seeprom(p);
+ }
+}
- outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
- config->bus_speed = DFTHRSH_100;
- outb(config->bus_speed, DSPCISTATUS + base);
+/*+F*************************************************************************
+ * Function:
+ * detect_maxscb
+ *
+ * Description:
+ * Detects the maximum number of SCBs for the controller and returns
+ * the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char max_scbid = 255;
- /*
- * In case we are a wide card...
- */
- outb(config->scsi_id, SCSICONF + base + 1);
+ /*
+ * It's possible that we've already done this for multichannel
+ * adapters.
+ */
+ if (p->scb_data->maxhscbs == 0)
+ {
+ /*
+ * We haven't initialized the SCB settings yet. Walk the SCBs to
+ * determince how many there are.
+ */
+ outb(0, p->base + FREE_SCBH);
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
+ for (i = 0; i < AIC7XXX_MAXSCB; i++)
+ {
+ outb(i, p->base + SCBPTR);
+ outb(i, p->base + SCB_CONTROL);
+ if (inb(p->base + SCB_CONTROL) != i)
+ break;
+ outb(0, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) != 0)
+ break;
- default:
- panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
+ outb(i, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL); /* Clear the control byte. */
+ outb(i + 1, p->base + SCB_NEXT); /* Set the next pointer. */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG); /* Make the tag invalid. */
+
+ /* Make the non-tagged targets not busy. */
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+ }
+
+ /* Make sure the last SCB terminates the free list. */
+ outb(i - 1, p->base + SCBPTR);
+ outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+
+ /* Ensure we clear the first (0) SCBs control byte. */
+ outb(0, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL);
+
+ p->scb_data->maxhscbs = i;
}
- detect_maxscb(config);
+ if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
+ {
+ /* Determine the number of valid bits in the FIFOs. */
+ outb(max_scbid, p->base + QINFIFO);
+ max_scbid = inb(p->base + QINFIFO);
+ p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
+ }
+ else
+ {
+ p->scb_data->maxscbs = p->scb_data->maxhscbs;
+ }
+ if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
+ {
+ /*
+ * Disable paging if the QINFIFO doesn't allow more SCBs than
+ * we have in hardware.
+ */
+ p->flags &= ~PAGE_ENABLED;
+ }
- if (config->chip_type == AIC_777x)
+ /*
+ * Set the Queue Full Count. Some cards have more queue space than
+ * SCBs.
+ */
+ switch (p->chip_class)
{
- if (config->pause & IRQMS)
- {
- printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
- }
- else
- {
- printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
- }
+ case AIC_777x:
+ p->qfullcount = 4;
+ p->qcntmask = 0x07;
+ break;
+ case AIC_785x:
+ case AIC_786x:
+ p->qfullcount = 8;
+ p->qcntmask = 0x0f;
+ break;
+ case AIC_787x:
+ case AIC_788x:
+ if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
+ {
+ p->qfullcount = AIC7XXX_MAXSCB;
+ p->qcntmask = 0xFF;
+ }
+ else
+ {
+ p->qfullcount = 16;
+ p->qcntmask = 0x1F;
+ }
+ break;
}
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_register
+ *
+ * Description:
+ * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char sblkctl, flags = 0;
+ int max_targets;
+ int found = 1;
+ char channel_ids[] = {'A', 'B', 'C'};
+ unsigned char target_settings;
+ unsigned char scsi_conf, sxfrctl1;
+ unsigned short ultraenable = 0;
+ struct Scsi_Host *host;
+
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(p->base, MAXREG - MINREG, "aic7xxx");
/*
* Read the bus type from the SBLKCTL register. Set the FLAGS
* register in the sequencer for twin and wide bus cards.
*/
- sblkctl = inb(SBLKCTL + base);
- if (config->flags & PAGE_ENABLED)
+ sblkctl = inb(p->base + SBLKCTL);
+ if (p->flags & PAGE_ENABLED)
flags = PAGESCBS;
switch (sblkctl & SELBUS_MASK)
{
case SELNARROW: /* narrow/normal bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
- config->bus_type = AIC_SINGLE;
- outb(flags | SINGLE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF) & 0x07;
+ p->bus_type = AIC_SINGLE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
break;
case SELWIDE: /* Wide bus */
- config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
- config->bus_type = AIC_WIDE;
- printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
- board_names[config->type]);
- outb(flags | WIDE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
+ p->bus_type = AIC_WIDE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
break;
case SELBUSB: /* Twin bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
-#ifdef AIC7XXX_TWIN_SUPPORT
- config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
- config->bus_type = AIC_TWIN;
- printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
- board_names[config->type]);
- outb(flags | TWIN_BUS, FLAGS + base);
-#else
- config->bus_type = AIC_SINGLE;
- printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
- board_names[config->type]);
- outb(flags, FLAGS + base);
-#endif
+ p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
+ p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
+ p->bus_type = AIC_TWIN;
+ printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+ p->scsi_id, p->scsi_id_b);
+ outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
break;
default:
printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
- "mail deang@teleport.com\n", inb(SBLKCTL + base));
- outb(0, FLAGS + base);
+ "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
+ outb(0, p->base + SEQ_FLAGS);
return (0);
}
/*
- * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
- * take the card out of diagnostic mode and make the host adapter
- * LED follow bus activity (will not always be on).
+ * Detect SCB parameters and initialize the SCB array.
*/
- outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + base);
+ detect_maxscb(p);
+ printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
+ p->scb_data->maxhscbs, p->scb_data->maxscbs,
+ p->qfullcount, p->qcntmask);
- /*
- * The IRQ level in i/o port 4 maps directly onto the real
- * IRQ number. If it's ok, register it with the kernel.
- *
- * NB. the Adaptec documentation says the IRQ number is only
- * in the lower four bits; the ECU information shows the
- * high bit being used as well. Which is correct?
- *
- * The PCI cards get their interrupt from PCI BIOS.
- */
- if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
- {
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
- "ignoring.\n");
- return (0);
- }
+ host = p->host;
- /*
- * Print out debugging information before re-enabling
- * the card - a lot of registers on it can't be read
- * when the sequencer is active.
- */
- debug_config(config);
-
- /*
- * Register each "host" and fill in the returned Scsi_Host
- * structure as best we can. Some of the parameters aren't
- * really relevant for bus types beyond ISA, and none of the
- * high-level SCSI code looks at it anyway. Why are the fields
- * there? Also save the pointer so that we can find the
- * information when an IRQ is triggered.
- */
- host = scsi_register(template, sizeof(struct aic7xxx_host));
- host->can_queue = config->maxscbs;
+ host->can_queue = p->scb_data->maxscbs;
host->cmd_per_lun = 2;
+ host->sg_tablesize = AIC7XXX_MAX_SG;
host->select_queue_depths = aic7xxx_select_queue_depth;
- host->this_id = config->scsi_id;
- host->io_port = config->base;
+ host->this_id = p->scsi_id;
+ host->io_port = p->base;
host->n_io_port = 0xFF;
- host->base = (unsigned char *)config->mbase;
- host->irq = config->irq;
- if (config->bus_type == AIC_WIDE)
+ host->base = (unsigned char *) p->mbase;
+ host->irq = p->irq;
+ if (p->bus_type == AIC_WIDE)
{
host->max_id = 16;
}
- if (config->bus_type == AIC_TWIN)
+ if (p->bus_type == AIC_TWIN)
{
host->max_channel = 1;
}
- p = (struct aic7xxx_host *) host->hostdata;
-
p->host = host;
- p->host_no = (int)host->host_no;
+ p->host_no = host->host_no;
p->isr_count = 0;
- p->base = base;
- p->maxscbs = config->maxscbs;
- p->maxhscbs = config->maxhscbs;
- p->qcntmask = config->qcntmask;
- p->mbase = (char *)config->mbase;
- p->type = config->type;
- p->chip_type = config->chip_type;
- p->flags = config->flags;
- p->chan_num = config->chan_num;
- p->scb_link = &(p->scb_usage);
-#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
- if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
- {
- shared_3985_scbs = &(p->scb_usage);
- p->scb_link = &(p->scb_usage);
- }
-#endif
- p->scb_link->numscbs = 0;
- p->bus_type = config->bus_type;
- p->seeprom = sc;
p->next = NULL;
p->completeq.head = NULL;
p->completeq.tail = NULL;
- scbq_init(&p->scb_link->free_scbs);
- scbq_init(&p->page_scbs);
+ scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- scbq_init(&p->assigned_scbs);
- p->unpause = config->unpause;
- p->pause = config->pause;
-
- for (i = 0; i <= 15; i++)
+ for (i = 0; i <= NUMBER(p->device_status); i++)
{
p->device_status[i].commands_sent = 0;
p->device_status[i].flags = 0;
+ p->device_status[i].active_cmds = 0;
p->device_status[i].last_reset = 0;
}
- if (aic7xxx_boards[config->irq] == NULL)
+ if (aic7xxx_boards[p->irq] == NULL)
{
+ int result;
+ int irq_flags = 0;
+
+#ifdef AIC7XXX_OLD_ISR_TYPE
+ irg_flags = SA_INTERRUPT;
+#endif
/*
* Warning! This must be done before requesting the irq. It is
* possible for some boards to raise an interrupt as soon as
@@ -4353,17 +5030,26 @@ aic7xxx_register(Scsi_Host_Template *template,
* kernel, an interrupt is triggered immediately. Therefore, we
* must ensure the board data is correctly set before the request.
*/
- aic7xxx_boards[config->irq] = host;
+ aic7xxx_boards[p->irq] = host;
/*
- * Register IRQ with the kernel.
+ * Register IRQ with the kernel. Only allow sharing IRQs with
+ * PCI devices.
*/
- if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
- "aic7xxx", NULL))
+ if (p->chip_class == AIC_777x)
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+ }
+ else
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+ "aic7xxx", NULL));
+ }
+ if (result < 0)
{
printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
- config->irq);
- aic7xxx_boards[config->irq] = NULL;
+ p->irq);
+ aic7xxx_boards[p->irq] = NULL;
return (0);
}
}
@@ -4374,79 +5060,74 @@ aic7xxx_register(Scsi_Host_Template *template,
* registered host adapter. Add this host adapter's Scsi_Host
* to the beginning of the linked list of hosts at the same IRQ.
*/
- p->next = aic7xxx_boards[config->irq];
- aic7xxx_boards[config->irq] = host;
- }
-
- /*
- * Load the sequencer program, then re-enable the board -
- * resetting the AIC-7770 disables it, leaving the lights
- * on with nobody home. On the PCI bus you *may* be home,
- * but then your mailing address is dynamically assigned
- * so no one can find you anyway :-)
- */
- printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
- aic7xxx_loadseq(base);
-
- /*
- * Set Fast Mode and Enable the board
- */
- outb(FASTMODE, SEQCTL + base);
-
- if (p->chip_type == AIC_777x)
- {
- outb(ENABLE, BCTL + base);
+ p->next = aic7xxx_boards[p->irq];
+ aic7xxx_boards[p->irq] = host;
}
- printk("done.\n");
-
/*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->bus_type == AIC_TWIN)
{
/*
- * Select Channel B.
+ * The controller is gated to channel B after a chip reset; set
+ * bus B values first.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
-
- outb(config->scsi_id_b, SCSIID + base);
- scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+ outb(p->scsi_id_b, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF + 1);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
}
- /*
- * Select Channel A
- */
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus B. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+
+ aic7xxx_reset_current_bus(p);
+ }
+
+ /* Select channel A */
+ outb(SELNARROW, p->base + SBLKCTL);
}
- outb(config->scsi_id, SCSIID + base);
- scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+
+ outb(p->scsi_id, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
+ }
+
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus A. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+
+ aic7xxx_reset_current_bus(p);
+
+ /*
+ * Delay for the reset delay.
+ */
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
/*
@@ -4473,67 +5154,47 @@ aic7xxx_register(Scsi_Host_Template *template,
/*
* Grab the disconnection disable table and invert it for our needs
*/
- if (have_seeprom)
+ if (p->flags & USE_DEFAULTS)
{
- p->discenable = 0x0;
+ printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
+ "device parameters.\n");
+ p->discenable = 0xFFFF;
}
else
{
- if (config->bios == AIC_DISABLED)
- {
- printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
- "device parameters.\n");
- p->discenable = 0xFFFF;
- }
- else
- {
- p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
- inb(DISC_DSB + base));
- }
+ p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
+ inb(p->base + DISC_DSB));
}
for (i = 0; i < max_targets; i++)
{
- if (config->flags & USE_DEFAULTS)
+ if (p->flags & USE_DEFAULTS)
{
- target_settings = 0; /* 10 MHz */
+ target_settings = 0; /* 10 or 20 MHz depending on Ultra enable */
p->needsdtr_copy |= (0x01 << i);
p->needwdtr_copy |= (0x01 << i);
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ ultraenable |= (0x01 << i);
}
else
{
- if (have_seeprom)
+ target_settings = inb(p->base + TARG_SCRATCH + i);
+ if (target_settings & 0x0F)
{
- target_settings = ((sc.device_flags[i] & CFXFER) << 4);
- if (sc.device_flags[i] & CFSYNCH)
- {
- p->needsdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFWIDEB)
- {
- p->needwdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFDISC)
- {
- p->discenable |= (0x01 << i);
- }
+ p->needsdtr_copy |= (0x01 << i);
+ /*
+ * Default to asynchronous transfers (0 offset)
+ */
+ target_settings &= 0xF0;
}
- else
+ if (target_settings & 0x80)
{
- target_settings = inb(TARG_SCRATCH + base + i);
- if (target_settings & 0x0F)
- {
- p->needsdtr_copy |= (0x01 << i);
- /*
- * Default to asynchronous transfers (0 offset)
- */
- target_settings &= 0xF0;
- }
- if (target_settings & 0x80)
- {
- p->needwdtr_copy |= (0x01 << i);
- target_settings &= 0x7F;
- }
+ p->needwdtr_copy |= (0x01 << i);
+ /*
+ * Clear the wide flag. When wide negotiation is successful,
+ * we'll enable it.
+ */
+ target_settings &= 0x7F;
}
if (p->flags & ULTRA_ENABLED)
{
@@ -4544,7 +5205,7 @@ aic7xxx_register(Scsi_Host_Template *template,
case 0x20:
ultraenable |= (0x01 << i);
break;
- case 0x40:
+ case 0x40: /* treat 10MHz as 10MHz without Ultra enabled */
target_settings &= ~(0x70);
break;
default:
@@ -4552,7 +5213,7 @@ aic7xxx_register(Scsi_Host_Template *template,
}
}
}
- outb(target_settings, (TARG_SCRATCH + base + i));
+ outb(target_settings, p->base + TARG_SCRATCH + i);
}
/*
@@ -4567,103 +5228,448 @@ aic7xxx_register(Scsi_Host_Template *template,
p->needsdtr = p->needsdtr_copy;
p->needwdtr = p->needwdtr_copy;
p->orderedtag = 0;
-#if 0
- printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
- printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
-#endif
- outb(ultraenable & 0xFF, ULTRA_ENB + base);
- outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
+ outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
+ outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
/*
- * Set the number of available SCBs.
+ * Set the number of available hardware SCBs.
*/
- outb(config->maxhscbs, SCBCOUNT + base);
+ outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
/*
* 2s compliment of maximum tag value.
*/
- i = p->maxscbs;
- outb(-i & 0xFF, COMP_SCBCOUNT + base);
+ i = p->scb_data->maxscbs;
+ outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
/*
- * Set the QCNT (queue count) mask to deal with broken aic7850s that
- * sporatically get garbage in the upper bits of their QCNT registers.
+ * Allocate enough hardware scbs to handle the maximum number of
+ * concurrent transactions we can have. We have to make sure that
+ * the allocated memory is contiguous memory. The Linux kmalloc
+ * routine should only allocate contiguous memory, but note that
+ * this could be a problem if kmalloc() is changed.
*/
- outb(config->qcntmask, QCNTMASK + base);
+ if (p->scb_data->hscbs == NULL)
+ {
+ size_t array_size;
+ unsigned int hscb_physaddr;
+
+ array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+ p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
+ if (p->scb_data->hscbs == NULL)
+ {
+ printk("aic7xxx: Unable to allocate hardware SCB array; "
+ "failing detection.\n");
+ release_region(p->base, MAXREG - MINREG);
+ /*
+ * Ensure that we only free the IRQ when there is _not_ another
+ * aic7xxx adapter sharing this IRQ. The adapters are always
+ * added to the beginning of the list, so we can grab the next
+ * pointer and place it back in the board array.
+ */
+ if (p->next == NULL)
+ {
+ free_irq(p->irq, aic7xxx_isr);
+ }
+ aic7xxx_boards[p->irq] = p->next;
+ return(0);
+ }
+ /* At least the control byte of each SCB needs to be 0. */
+ memset(p->scb_data->hscbs, 0, array_size);
+
+ /* Tell the sequencer where it can find the hardware SCB array. */
+ hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+ outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
+ outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
+ outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
+ outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
+ }
/*
- * Clear the active flags - no targets are busy.
- */
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
+ * QCount mask to deal with broken aic7850s that sporadically get
+ * garbage in the upper bits of their QCNT registers.
+ */
+ outb(p->qcntmask, p->base + QCNTMASK);
/*
* We don't have any waiting selections or disconnected SCBs.
*/
- outb(SCB_LIST_NULL, WAITING_SCBH + base);
- outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
+ outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
+ outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
/*
* Message out buffer starts empty
*/
- outb(0, MSG_LEN + base);
+ outb(0, p->base + MSG_LEN);
/*
- * Reset the SCSI bus. Is this necessary?
- * There may be problems for a warm boot without resetting
- * the SCSI bus. Either BIOS settings in scratch RAM
- * will not get reinitialized, or devices may stay at
- * previous negotiated settings (SDTR and WDTR) while
- * the driver will think that no negotiations have been
- * performed.
- *
- * Some devices need a long time to "settle" after a SCSI
- * bus reset.
+ * Load the sequencer program, then re-enable the board -
+ * resetting the AIC-7770 disables it, leaving the lights
+ * on with nobody home. On the PCI bus you *may* be home,
+ * but then your mailing address is dynamically assigned
+ * so no one can find you anyway :-)
+ */
+ aic7xxx_loadseq(p);
+
+ if (p->chip_class == AIC_777x)
+ {
+ outb(ENABLE, p->base + BCTL); /* Enable the boards BUS drivers. */
+ }
+
+ /*
+ * Unpause the sequencer before returning and enable
+ * interrupts - we shouldn't get any until the first
+ * command is sent to us by the high-level SCSI code.
+ */
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+
+ return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_chip_reset
+ *
+ * Description:
+ * Perform a chip reset on the aic7xxx SCSI controller. The controller
+ * is paused upon return.
+ *-F*************************************************************************/
+static void
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+ unsigned char hcntrl;
+ int wait;
+
+ /* Retain the IRQ type across the chip reset. */
+ hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+
+ /*
+ * For some 274x boards, we must clear the CHIPRST bit and pause
+ * the sequencer. For some reason, this makes the driver work.
+ */
+ outb(PAUSE | CHIPRST, p->base + HCNTRL);
+
+ /*
+ * In the future, we may call this function as a last resort for
+ * error handling. Let's be nice and not do any unecessary delays.
+ */
+ wait = 1000; /* 1 second (1000 * 1000 usec) */
+ while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+ {
+ udelay(1000); /* 1 msec = 1000 usec */
+ wait = wait - 1;
+ }
+
+ if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+ {
+ printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+ }
+
+ outb(hcntrl | PAUSE, p->base + HCNTRL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_alloc
+ *
+ * Description:
+ * Allocate and initialize a host structure. Returns NULL upon error
+ * and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
+ aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+{
+ struct aic7xxx_host *p = NULL;
+ struct Scsi_Host *host;
+
+ /*
+ * Allocate a storage area by registering us with the mid-level
+ * SCSI layer.
*/
- if (!aic7xxx_no_reset)
+ host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+ if (host != NULL)
{
- printk("aic7xxx: Resetting the SCSI bus...");
- if (p->bus_type == AIC_TWIN)
+ p = (struct aic7xxx_host *) host->hostdata;
+ memset(p, 0, sizeof(struct aic7xxx_host));
+ p->host = host;
+
+ if (scb_data != NULL)
+ {
+ /*
+ * We are sharing SCB data areas; use the SCB data pointer
+ * provided.
+ */
+ p->scb_data = scb_data;
+ p->flags |= SHARED_SCBDATA;
+ }
+ else
{
/*
- * Select Channel B.
+ * We are not sharing SCB data; allocate one.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+ p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (p->scb_data != NULL)
+ {
+ memset(p->scb_data, 0, sizeof(scb_data_type));
+ scbq_init (&p->scb_data->free_scbs);
+ }
+ else
+ {
+ /*
+ * For some reason we don't have enough memory. Free the
+ * allocated memory for the aic7xxx_host struct, and return NULL.
+ */
+ scsi_unregister(host);
+ p = NULL;
+ }
+ }
+ if (p != NULL)
+ {
+ p->host_no = host->host_no;
+ p->base = base;
+ p->mbase = mbase;
+ p->maddr = NULL;
+ p->flags = flags;
+ p->chip_type = chip_type;
+ p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+ p->pause = p->unpause | PAUSE;
+ }
+ }
+ return (p);
+}
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_free
+ *
+ * Description:
+ * Frees and releases all resources associated with an instance of
+ * the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free (struct aic7xxx_host *p)
+{
+ int i;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /*
+ * We should be careful in freeing the scb_data area. For those
+ * adapters sharing external SCB RAM(398x), there will be only one
+ * scb_data area allocated. The flag SHARED_SCBDATA indicates if
+ * one adapter is sharing anothers SCB RAM.
+ */
+ if (!(p->flags & SHARED_SCBDATA))
+ {
+ /*
+ * Free the allocated hardware SCB space.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
+ /*
+ * Free the driver SCBs. These were allocated on an as-need
+ * basis.
+ */
+ for (i = 0; i < p->scb_data->numscbs; i++)
+ {
+ kfree(p->scb_data->scb_array[i]);
+ }
+ /*
+ * Free the hardware SCBs.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
- /*
- * Select Channel A.
+ /*
+ * Free the SCB data area.
+ */
+ kfree(p->scb_data);
+ }
+ /*
+ * Free the instance of the device structure.
+ */
+ scsi_unregister(p->host);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_load_seeprom
+ *
+ * Description:
+ * Load the seeprom and configure adapter and target settings.
+ * Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static int
+load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+ int have_seeprom = 0;
+ int i, max_targets;
+ unsigned char target_settings, scsi_conf;
+ unsigned short scarray[128];
+ struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+ }
+ switch (p->chip_type)
+ {
+ case AIC_7770: /* None of these adapters have seeproms. */
+ case AIC_7771:
+ case AIC_7850:
+ case AIC_7855:
+ break;
+
+ case AIC_284x:
+ have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+ break;
+
+ case AIC_7861:
+ case AIC_7870:
+ case AIC_7871:
+ case AIC_7872:
+ case AIC_7874:
+ case AIC_7881:
+ case AIC_7882:
+ case AIC_7884:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(*sc)/2, C46);
+ break;
+
+ case AIC_7860: /* Motherboard Ultra controllers might have RAID port. */
+ case AIC_7880:
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
+ if (!have_seeprom)
+ {
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
+ }
+ break;
+
+ case AIC_7873: /* The 3985 adapters use the 93c56 serial EEPROM. */
+ case AIC_7883:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(scarray)/2, C56_66);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!have_seeprom)
+ {
+ if (aic7xxx_verbose)
+ {
+ printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+ }
+ p->flags |= USE_DEFAULTS;
+ }
+ else
+ {
+ if (aic7xxx_verbose)
+ {
+ printk("done\n");
+ }
+ p->flags |= HAVE_SEEPROM;
+
+ /*
+ * Update the settings in sxfrctl1 to match the termination settings.
+ */
+ *sxfrctl1 = 0;
+
+ /*
+ * First process the settings that are different between the VLB
+ * and PCI adapter seeproms.
+ */
+ if (p->chip_class == AIC_777x)
+ {
+ /* VLB adapter seeproms */
+ if (sc->bios_control & CF284XEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (sc->adapter_control & CF284XSTERM)
+ *sxfrctl1 |= STPWEN;
+ /*
+ * The 284x SEEPROM doesn't have a max targets field. We
+ * set it to 16 to make sure we take care of the 284x-wide
+ * adapters. For narrow adapters, going through the extra
+ * 8 target entries will not cause any harm since they will
+ * will not be used.
+ *
+ * XXX - We should probably break out the bus detection
+ * from the register function so we can use it here
+ * to tell us how many targets there really are.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ max_targets = 16;
}
+ else
+ {
+ /* PCI adapter seeproms */
+ if (sc->bios_control & CFEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+ if (sc->adapter_control & CFSTERM)
+ *sxfrctl1 |= STPWEN;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /* Limit to 16 targets just in case. */
+ max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
+ }
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ for (i = 0; i < max_targets; i++)
+ {
+ target_settings = (sc->device_flags[i] & CFXFER) << 4;
+ if (sc->device_flags[i] & CFSYNCH)
+ target_settings |= SOFS;
+ if (sc->device_flags[i] & CFWIDEB)
+ target_settings |= WIDEXFER;
+ if (sc->device_flags[i] & CFDISC)
+ p->discenable |= (0x01 << i);
+ outb(target_settings, p->base + TARG_SCRATCH + i);
+ }
+ outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
+ outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
- printk("done.\n");
- }
+ p->scsi_id = sc->brtime_id & CFSCSIID;
- /*
- * Unpause the sequencer before returning and enable
- * interrupts - we shouldn't get any until the first
- * command is sent to us by the high-level SCSI code.
- */
- UNPAUSE_SEQUENCER(p);
- return (found);
+ scsi_conf = (p->scsi_id & 0x7);
+ if (sc->adapter_control & CFSPARITY)
+ scsi_conf |= ENSPCHK;
+ if (sc->adapter_control & CFRESETB)
+ scsi_conf |= RESET_SCSI;
+
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ /*
+ * We allow the operator to override ultra enable through
+ * the boot prompt.
+ */
+ if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
+ {
+ /* Treat us as a non-ultra card */
+ p->flags &= ~ULTRA_ENABLED;
+ }
+ }
+
+ /* Set the host ID */
+ outb(scsi_conf, p->base + SCSICONF);
+ /* In case we are a wide card */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
+
+ if (p->chip_class != AIC_777x)
+ {
+ /*
+ * Update the settings in sxfrctl1 to match the termination
+ * settings.
+ */
+ *sxfrctl1 = 0;
+ configure_termination(p, sxfrctl1, sc->adapter_control,
+ (unsigned char) sc->max_targets & CFMAXTARG);
+ }
+ }
+ return (have_seeprom);
}
/*+F*************************************************************************
@@ -4672,17 +5678,24 @@ aic7xxx_register(Scsi_Host_Template *template,
*
* Description:
* Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe(). A sequence of
+ * probe(), attach()/detach(), and init() makes more sense than
+ * one do-it-all function. This may be useful when (and if) the
+ * mid-level SCSI code is overhauled.
*-F*************************************************************************/
int
aic7xxx_detect(Scsi_Host_Template *template)
{
- int found = 0, slot, base;
- unsigned char irq = 0;
+ int found = 0;
+ aha_status_type adapter_bios;
+ aha_chip_class_type chip_class;
+ aha_chip_type chip_type;
+ int slot, base;
+ int chan_num = 0;
+ unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
int i;
- struct aic7xxx_host_config config;
-
- template->proc_dir = &proc_scsi_aic7xxx;
- config.chan_num = 0;
+ struct aic7xxx_host *p;
/*
* Since we may allow sharing of IRQs, it is imperative
@@ -4696,6 +5709,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
aic7xxx_boards[i] = NULL;
}
+ template->proc_dir = &proc_scsi_aic7xxx;
+ template->name = aic7xxx_info(NULL);
+ template->sg_tablesize = AIC7XXX_MAX_SG;
+
/*
* Initialize the spurious count to 0.
*/
@@ -4717,33 +5734,174 @@ aic7xxx_detect(Scsi_Host_Template *template)
continue;
}
- config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
- if (config.type != AIC_NONE)
+ chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
+ if (chip_type != AIC_NONE)
{
+
+ switch (chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[chip_type], slot);
+ break;
+ case AIC_284x:
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[chip_type], slot);
+ break;
+ default:
+ break;
+ }
+
/*
* We found a card, allow 1 spurious interrupt.
*/
aic7xxx_spurious_count = 1;
/*
- * We "find" a AIC-7770 if we locate the card
- * signature and we can set it up and register
- * it with the kernel without incident.
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
*/
- config.chip_type = AIC_777x;
- config.base = base;
- config.mbase = 0;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
- config.flags = 0;
- if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
- config.bus_speed = DFTHRSH_100;
- config.busrtime = BOFF;
- found += aic7xxx_register(template, &config);
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ outb(hcntrl | PAUSE, base + HCNTRL);
+
+ irq = inb(INTDEF + base) & 0x0F;
+ switch (irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level, ignoring.\n");
+ irq = 0;
+ break;
+ }
+
+ if (irq != 0)
+ {
+ p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+ p->irq = irq & 0x0F;
+ p->chip_class = AIC_777x;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+ if (aic7xxx_extended)
+ {
+ p->flags |= EXTENDED_TRANSLATION;
+ }
+ aic7xxx_chip_reset(p);
+
+ switch (p->chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ {
+ unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (biosctrl & CHANNEL_B_PRIMARY)
+ {
+ p->flags |= FLAGS_CHANNEL_B_PRIMARY;
+ }
+
+ if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+ {
+ p->flags |= USE_DEFAULTS;
+ }
+ break;
+ }
+
+ case AIC_284x:
+ if (!load_seeprom(p, &sxfrctl1))
+ {
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
+ (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ /*
+ * Check for Rev C or E boards. Rev E boards can supposedly have
+ * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+ * It's still not clear extactly what is different about the Rev E
+ * boards, but we think it allows 8 bit entries in the QOUTFIFO to
+ * support "paging" SCBs (more than 4 commands can be active at once).
+ *
+ * The Rev E boards have a read/write autoflush bit in the
+ * SBLKCTL register, while in the Rev C boards it is read only.
+ */
+ sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
+ outb(sblkctl, p->base + SBLKCTL);
+ if (inb(p->base + SBLKCTL) == sblkctl)
+ {
+ /*
+ * We detected a Rev E board, we allow paging on this board.
+ */
+ printk("Revision >= E\n");
+ outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+ }
+ else
+ {
+ /* Do not allow paging. */
+ p->flags &= ~PAGE_ENABLED;
+ printk("Revision <= C\n");
+ }
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = inb(p->base + HOSTCONF);
+ outb(hostconf & DFTHRSH, p->base + BUSSPD);
+ outb((hostconf << 2) & BOFF, p->base + BUSTIME);
+ /*
+ * Try to initialize the card and register it with the kernel.
+ */
+ if (aic7xxx_register(template, p))
+ {
+ /*
+ * We successfully found a board and registered it.
+ */
+ found = found + 1;
+ }
+ else
+ {
+ /*
+ * Something went wrong; release and free all resources.
+ */
+ aic7xxx_free(p);
+ }
+ }
/*
* Disallow spurious interrupts.
*/
@@ -4759,15 +5917,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
{
struct
{
- unsigned short vendor_id;
- unsigned short device_id;
- aha_type card_type;
- aha_chip_type chip_type;
+ unsigned short vendor_id;
+ unsigned short device_id;
+ aha_chip_type chip_type;
+ aha_chip_class_type chip_class;
} const aic7xxx_pci_devices[] = {
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
@@ -4780,14 +5938,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
};
- int error;
+ int error, flags;
int done = 0;
unsigned int iobase, mbase;
unsigned short index = 0;
unsigned char pci_bus, pci_device_fn;
- unsigned int csize_lattime;
- unsigned int class_revid;
- unsigned int devconfig;
+ unsigned char ultra_enb = 0;
+ unsigned int devconfig, class_revid;
+ scb_data_type *shared_scb_data = NULL;
char rev_id[] = {'B', 'C', 'D'};
for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -4804,36 +5962,33 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else /* Found an Adaptec PCI device. */
{
- config.type = aic7xxx_pci_devices[i].card_type;
- config.chip_type = aic7xxx_pci_devices[i].chip_type;
- config.chan_num = 0;
- config.bios = AIC_ENABLED; /* Assume bios is enabled. */
- config.flags = 0;
- config.busrtime = 40;
- switch (config.type)
+ chip_class = aic7xxx_pci_devices[i].chip_class;
+ chip_type = aic7xxx_pci_devices[i].chip_type;
+ chan_num = 0;
+ flags = 0;
+ switch (aic7xxx_pci_devices[i].chip_type)
{
case AIC_7850:
case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- config.bios = AIC_DISABLED;
- config.flags |= USE_DEFAULTS;
- config.bus_speed = DFTHRSH_100;
+ flags |= USE_DEFAULTS;
break;
case AIC_7872: /* 3940 */
case AIC_7882: /* 3940-Ultra */
- config.chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
+ flags |= MULTI_CHANNEL;
+ chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
number_of_3940s++;
break;
case AIC_7873: /* 3985 */
case AIC_7883: /* 3985-Ultra */
- config.chan_num = number_of_3985s; /* Has 3 controllers */
+ chan_num = number_of_3985s; /* Has 3 controllers */
+ flags |= MULTI_CHANNEL;
number_of_3985s++;
if (number_of_3985s == 3)
{
number_of_3985s = 0;
+ shared_scb_data = NULL;
}
break;
@@ -4850,39 +6005,165 @@ aic7xxx_detect(Scsi_Host_Template *template)
PCI_INTERRUPT_LINE, &irq);
error += pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, &mbase);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, &devconfig);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ CLASS_PROGIF_REVID, &class_revid);
+
+ printk("aic7xxx: <%s> at PCI %d\n",
+ board_names[chip_type], PCI_SLOT(pci_device_fn));
/*
- * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+ * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
* we mask it off.
*/
iobase &= PCI_BASE_ADDRESS_IO_MASK;
+ p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
+ shared_scb_data);
+
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+
+ /* Remember to set the channel number, irq, and chip class. */
+ p->chan_num = chan_num;
+ p->irq = irq;
+ p->chip_class = chip_class;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+
/*
- * Read the PCI burst size and latency timer.
+ * Remember how the card was setup in case there is no seeprom.
*/
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CSIZE_LATTIME, &csize_lattime);
- printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
- "PCLKS\n", (int) (csize_lattime & CACHESIZE),
- (csize_lattime >> 8) & 0x000000ff);
+ p->scsi_id = inb(p->base + SCSIID) & OID;
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ p->flags |= ULTRA_ENABLED;
+ ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+ }
+ sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CLASS_PROGIF_REVID, &class_revid);
- if ((class_revid & DEVREVID) < 3)
+ aic7xxx_chip_reset(p);
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
+ if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
- rev_id[class_revid & DEVREVID]);
+ printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+ "access.\n");
+ /*
+ * XXX - Assume 9 bit SRAM and enable parity checking.
+ */
+ devconfig |= EXTSCBPEN;
+
+ /*
+ * XXX - Assume fast SRAM and only enable 2 cycle access if we
+ * are sharing the SRAM across multiple adapters (398x).
+ */
+ if ((devconfig & MPORTMODE) == 0)
+ {
+ devconfig |= EXTSCBTIME;
+ }
+ devconfig &= ~SCBRAMSEL;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, devconfig);
}
+#endif
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, &devconfig);
- if (error)
+ if ((p->flags & USE_DEFAULTS) == 0)
{
- panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
- error);
+ load_seeprom(p, &sxfrctl1);
+ }
+
+ /*
+ * Take the LED out of diagnostic mode
+ */
+ sblkctl = inb(p->base + SBLKCTL);
+ outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+
+ /*
+ * We don't know where this is set in the SEEPROM or by the
+ * BIOS, so we default to 100%.
+ */
+ outb(DFTHRSH_100, p->base + DSPCISTATUS);
+
+ if (p->flags & USE_DEFAULTS)
+ {
+ int j;
+ /*
+ * Default setup; should only be used if the adapter does
+ * not have a SEEPROM.
+ */
+ /*
+ * Check the target scratch area to see if someone set us
+ * up already. We are previously set up if the scratch
+ * area contains something other than all zeroes and ones.
+ */
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + j) != 0x00) /* Check for all zeroes. */
+ break;
+ }
+ if (j == TARG_SCRATCH)
+ {
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + 1) != 0xFF) /* Check for all ones. */
+ break;
+ }
+ }
+ if ((j != 0x60) && (p->scsi_id != 0))
+ {
+ p->flags &= ~USE_DEFAULTS;
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
+ }
+ }
+ else
+ {
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: No BIOS found; using default "
+ "settings.\n");
+ }
+ /*
+ * Assume only one connector and always turn on
+ * termination.
+ */
+ sxfrctl1 = STPWEN;
+ p->scsi_id = 7;
+ }
+ outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+ p->base + SCSICONF);
+ /* In case we are a wide card. */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
+ if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
+ {
+ /*
+ * If there wasn't a BIOS or the board wasn't in this mode
+ * to begin with, turn off Ultra.
+ */
+ p->flags &= ~ULTRA_ENABLED;
+ }
}
- printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
+ /*
+ * Print some additional information about the adapter.
+ */
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
+ "IO Mem 0x%x, IRQ %d",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en",
+ p->base, p->mbase, p->irq);
+ if ((class_revid & DEVREVID) < 3)
+ {
+ printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+ }
+ printk("\n");
/*
* I don't think we need to bother with allowing
@@ -4891,58 +6172,57 @@ aic7xxx_detect(Scsi_Host_Template *template)
*/
aic7xxx_spurious_count = 1;
- config.base = iobase;
- config.mbase = mbase;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
-#ifdef AIC7XXX_SHARE_SCBs
- if (devconfig & RAMPSM)
-#else
- if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
- (config.type != AIC_7883))
-#endif
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Put our termination setting into sxfrctl1 now that the
+ * generic initialization is complete.
+ */
+ sxfrctl1 |= inb(p->base + SXFRCTL1);
+ outb(sxfrctl1, p->base + SXFRCTL1);
+
+ if (aic7xxx_register(template, p) == 0)
{
+ aic7xxx_free(p);
+ }
+ else
+ {
+ found = found + 1;
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
/*
- * External SRAM present. The probe will walk the SCBs to see
- * how much SRAM we have and set the number of SCBs accordingly.
- * We have to turn off SCBRAMSEL to access the external SCB
- * SRAM.
- *
- * It seems that early versions of the aic7870 didn't use these
- * bits, hence the hack for the 3940 above. I would guess that
- * recent 3940s using later aic7870 or aic7880 chips do actually
- * set RAMPSM.
+ * Set the shared SCB data once we've successfully probed a
+ * 398x adapter.
*
- * The documentation isn't clear, but it sounds like the value
- * written to devconfig must not have RAMPSM set. The second
- * sixteen bits of the register are R/O anyway, so it shouldn't
- * affect RAMPSM either way.
+ * Note that we can only do this if the use of external
+ * SCB RAM is enabled.
*/
- printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
- "access.\n");
- devconfig &= ~(RAMPSM | SCBRAMSEL);
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, devconfig);
+ if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+ {
+ if (shared_scb_data == NULL)
+ {
+ shared_scb_data = p->scb_data;
+ }
+ }
+#endif
}
- found += aic7xxx_register(template, &config);
+ index++;
/*
* Disable spurious interrupts.
*/
aic7xxx_spurious_count = 0;
-
- index++;
} /* Found an Adaptec PCI device. */
}
}
}
#endif CONFIG_PCI
- template->name = aic7xxx_info(NULL);
return (found);
}
@@ -4958,45 +6238,45 @@ static void
aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct aic7xxx_scb *scb)
{
- unsigned int addr; /* must be 32 bits */
unsigned short mask;
+ struct aic7xxx_hwscb *hscb;
mask = (0x01 << TARGET_INDEX(cmd));
+ hscb = scb->hscb;
+
/*
* Setup the control byte if we need negotiation and have not
* already requested it.
*/
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (cmd->device->tagged_queue)
+ if (p->discenable & mask)
{
- cmd->tag = scb->tag;
- cmd->device->current_tag = scb->tag;
- scb->control |= TAG_ENB;
- p->device_status[TARGET_INDEX(cmd)].commands_sent++;
- if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
- {
- scb->control |= 0x02;
- p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
- }
-#if 0
- if (p->orderedtag & mask)
+ hscb->control |= DISCENB;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (cmd->device->tagged_queue)
{
- scb->control |= 0x02;
- p->orderedtag = p->orderedtag & ~mask;
+ cmd->tag = hscb->tag;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+ if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+ {
+ hscb->control |= MSG_SIMPLE_Q_TAG;
+ }
+ else
+ {
+ hscb->control |= MSG_ORDERED_Q_TAG;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+ }
}
-#endif
- }
-#endif
- if (p->discenable & mask)
- {
- scb->control |= DISCENB;
+#endif /* Tagged queueing */
}
+
if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
{
p->wdtr_pending |= mask;
- scb->control |= NEEDWDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_WDTR;
#if 0
- printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending WDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
else
@@ -5004,19 +6284,20 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
{
p->sdtr_pending |= mask;
- scb->control |= NEEDSDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_SDTR;
#if 0
- printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending SDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
}
-
#if 0
printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
"mask(0x%x).\n",
cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
#endif
- scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+ hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
/*
@@ -5030,9 +6311,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* XXX - this relies on the host data being stored in a
* little-endian format.
*/
- addr = VIRT_TO_BUS(cmd->cmnd);
- scb->SCSI_cmd_length = cmd->cmd_len;
- memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = cmd->cmd_len;
+ hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
if (cmd->use_sg)
{
@@ -5052,15 +6332,16 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
scb->sg_list[i].length = (unsigned int) sg[i].length;
}
- scb->SG_segment_count = cmd->use_sg;
- addr = VIRT_TO_BUS(scb->sg_list);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
- scb->data_count = scb->sg_list[0].length;
+ hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+ hscb->SG_segment_count = cmd->use_sg;
+ scb->sg_count = hscb->SG_segment_count;
+
+ /* Copy the first SG into the data pointer area. */
+ hscb->data_pointer = scb->sg_list[0].address;
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
#if 0
printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
- cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
+ cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
#endif
}
else
@@ -5069,28 +6350,23 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
(unsigned long) cmd->request_buffer, cmd->request_bufflen);
#endif
- if (cmd->request_bufflen == 0)
+ if (cmd->request_bufflen)
{
- /*
- * In case the higher level SCSI code ever tries to send a zero
- * length command, ensure the SCB indicates no data. The driver
- * will interpret a zero length command as a Bus Device Reset.
- */
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
+ hscb->SG_segment_count = 1;
+ scb->sg_count = 1;
+ scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+ scb->sg_list[0].length = cmd->request_bufflen;
+ hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+ hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
}
else
{
- scb->SG_segment_count = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
- scb->sg_list[0].length = cmd->request_bufflen;
- addr = VIRT_TO_BUS(&scb->sg_list[0]);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- addr = VIRT_TO_BUS(cmd->request_buffer);
- memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
+ hscb->SG_segment_count = 0;
+ scb->sg_count = 0;
+ hscb->SG_list_pointer = 0;
+ hscb->data_pointer = 0;
+ hscb->data_count = SCB_LIST_NULL << 24;
}
}
}
@@ -5108,7 +6384,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
long processor_flags;
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
- u_char curscb, intstat;
p = (struct aic7xxx_host *) cmd->host->hostdata;
if (p->host != cmd->host)
@@ -5140,34 +6415,21 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
cmd->lun & 0x07);
#endif
- /*
- * This is a critical section, since we don't want the interrupt
- * routine mucking with the host data or the card. For this reason
- * it is nice to know that this function can only be called in one
- * of two ways from scsi.c First, as part of a routine queue command,
- * in which case, the irq for our card is disabled before this
- * function is called. This doesn't help us if there is more than
- * one card using more than one IRQ in our system, therefore, we
- * should disable all interrupts on these grounds alone. Second,
- * this can be called as part of the scsi_done routine, in which case
- * we are in the aic7xxx_isr routine already and interrupts are
- * disabled, therefore we should saveflags first, then disable the
- * interrupts, do our work, then restore the CPU flags. If it weren't
- * for the possibility of more than one card using more than one IRQ
- * in our system, we wouldn't have to touch the interrupt flags at all.
- */
- save_flags(processor_flags);
- cli();
-
+ if (p->device_status[TARGET_INDEX(cmd)].active_cmds
+ > cmd->device->queue_depth)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
+ p->host_no, cmd->target, cmd->channel);
+ }
scb = aic7xxx_allocate_scb(p);
if (scb == NULL)
{
- panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
+ panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
}
else
{
scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->tag;
+ aic7xxx_position(cmd) = scb->hscb->tag;
#if 0
debug_scb(scb);
#endif;
@@ -5179,14 +6441,14 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
aic7xxx_buildscb(p, cmd, scb);
#if 0
- if (scb != (p->scb_array[scb->position]))
+ if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
{
printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
"address.\n");
}
printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
- scb->position, (unsigned int) scb->cmd,
- scb->state, (unsigned int) p->free_scb);
+ scb->hscb->tag, (unsigned int) scb->cmd,
+ scb->flags, (unsigned int) p->free_scb);
#endif
/*
@@ -5201,70 +6463,28 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
cmd->host_scribble = NULL;
memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- if (scb->position != SCB_LIST_NULL)
- {
- /* We've got a valid slot, yeah! */
- if (p->flags & IN_ISR)
- {
- scbq_insert_tail(&p->assigned_scbs, scb);
- scb->state |= SCB_ASSIGNEDQ;
- }
- else
- {
- /*
- * Pause the sequencer so we can play with its registers -
- * wait for it to acknowledge the pause.
- *
- * XXX - should the interrupts be left on while doing this?
- */
- PAUSE_SEQUENCER(p);
- intstat = inb(INTSTAT + p->base);
-
- /*
- * Save the SCB pointer and put our own pointer in - this
- * selects one of the four banks of SCB registers. Load
- * the SCB, then write its pointer into the queue in FIFO
- * and restore the saved SCB pointer.
- */
- curscb = inb(SCBPTR + p->base);
- outb(scb->position, SCBPTR + p->base);
- aic7xxx_putscb(p, scb);
- outb(curscb, SCBPTR + p->base);
- outb(scb->position, QINFIFO + p->base);
- scb->state |= SCB_ACTIVE;
+ scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
- }
- }
- else
+ save_flags(processor_flags);
+ cli();
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
{
- scb->state |= SCB_WAITINGQ;
- scbq_insert_tail(&p->waiting_scbs, scb);
- if (!(p->flags & IN_ISR))
- {
- aic7xxx_run_waiting_queues(p);
- }
+ aic7xxx_run_waiting_queues(p);
}
+ restore_flags(processor_flags);
#if 0
printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
- (long) cmd, (long) scb->cmd, scb->position);
+ (long) cmd, (long) scb->cmd, scb->hscb->tag);
#endif;
- restore_flags(processor_flags);
}
return (0);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_abort_reset
+ * aic7xxx_bus_device_reset
*
* Description:
* Abort or reset the current SCSI command(s). If the scb has not
@@ -5276,204 +6496,257 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
static int
aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scb;
+ struct aic7xxx_hwscb *hscb;
unsigned char bus_state;
- int base, result = -1;
+ int result = -1;
char channel;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
- base = p->base;
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+ hscb = scb->hscb;
- channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
- if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
+ /*
+ * Ensure that the card doesn't do anything behind our back.
+ * Also make sure that we didn't just miss an interrupt that
+ * could affect this abort/reset.
+ */
+ pause_sequencer(p);
+ while (inb(p->base + INTSTAT) & INT_PEND);
{
+ aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
+ pause_sequencer(p);
+ }
+ if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ return(result);
+ }
+
- if (scb->state & SCB_IN_PROGRESS)
+ printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
+ p->host_no, TC_OF_SCB(scb), scb->flags);
+ bus_state = inb(p->base + LASTPHASE);
+
+ switch (bus_state)
+ {
+ case P_DATAOUT:
+ printk("Data-Out phase, ");
+ break;
+ case P_DATAIN:
+ printk("Data-In phase, ");
+ break;
+ case P_COMMAND:
+ printk("Command phase, ");
+ break;
+ case P_MESGOUT:
+ printk("Message-Out phase, ");
+ break;
+ case P_STATUS:
+ printk("Status phase, ");
+ break;
+ case P_MESGIN:
+ printk("Message-In phase, ");
+ break;
+ default:
+ /*
+ * We're not in a valid phase, so assume we're idle.
+ */
+ printk("while idle, LASTPHASE = 0x%x, ", bus_state);
+ break;
+ }
+ printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
+ inb(p->base + SCSISIGI),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+
+ channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+ /*
+ * Determine our course of action.
+ */
+ if (scb->flags & SCB_ABORT)
+ {
+ /*
+ * Been down this road before; do a full bus reset.
+ */
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
+ }
+#if 0
+ else if (hscb->control & TAG_ENB)
{
/*
- * Ensure that the card doesn't do anything
- * behind our back.
+ * We could be starving this command; try sending and ordered tag
+ * command to the target we come from.
*/
- PAUSE_SEQUENCER(p);
+ scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
+ p->orderedtag = p->orderedtag | 0xFF;
+ result = SCSI_RESET_PENDING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
+ p->host_no);
+ }
+#endif
+ else
+ {
+ unsigned char active_scb_index, saved_scbptr;
+ struct aic7xxx_scb *active_scb;
- printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
- bus_state = inb(LASTPHASE + p->base);
+ /*
+ * Send an Abort Message:
+ * The target that is holding up the bus may not be the same as
+ * the one that triggered this timeout (different commands have
+ * different timeout lengths). Our strategy here is to queue an
+ * abort message to the timed out target if it is disconnected.
+ * Otherwise, if we have an active target we stuff the message buffer
+ * with an abort message and assert ATN in the hopes that the target
+ * will let go of the bus and go to the mesgout phase. If this
+ * fails, we'll get another timeout a few seconds later which will
+ * attempt a bus reset.
+ */
+ saved_scbptr = inb(p->base + SCBPTR);
+ active_scb_index = inb(p->base + SCB_TAG);
+ active_scb = p->scb_data->scb_array[active_scb_index];
- switch (bus_state)
+ if (bus_state != P_BUSFREE)
+ {
+ if (active_scb_index >= p->scb_data->numscbs)
{
- case P_DATAOUT:
- printk("Data-Out phase, ");
- break;
- case P_DATAIN:
- printk("Data-In phase, ");
- break;
- case P_COMMAND:
- printk("Command phase, ");
- break;
- case P_MESGOUT:
- printk("Message-Out phase, ");
- break;
- case P_STATUS:
- printk("Status phase, ");
- break;
- case P_MESGIN:
- printk("Message-In phase, ");
- break;
- default:
- printk("while idle, LASTPHASE = 0x%x, ", bus_state);
- /*
- * We're not in a valid phase, so assume we're idle.
- */
- bus_state = 0;
- break;
+ /*
+ * Perform a bus reset.
+ *
+ * XXX - We want to queue an abort for the timedout SCB
+ * instead.
+ */
+ result = -1;
+ printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
+ "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
}
- printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
-
- /*
- * First, determine if we want to do a bus reset or simply a bus device
- * reset. If this is the first time that a transaction has timed out
- * and the SCB is not paged out, just schedule a bus device reset.
- * Otherwise, we reset the bus and abort all pending I/Os on that bus.
- */
- if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
+ else
{
-#if 0
- if (scb->control & TAG_ENB)
- {
+ /* Send the abort message to the active SCB. */
+ outb(1, p->base + MSG_LEN);
+ if (active_scb->hscb->control & TAG_ENB)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT);
+ }
+ outb(bus_state | ATNO, p->base + SCSISIGO);
+ printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
+ p->host_no);
+ active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
+ if (active_scb != scb)
+ {
/*
- * We could be starving this command; try sending and ordered tag
- * command to the target we come from.
+ * XXX - We would like to increment the timeout on scb, but
+ * access to that routine is denied because it is hidden
+ * in scsi.c. If we were able to do this, it would give
+ * scb a new lease on life.
*/
- scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
- p->orderedtag = p->orderedtag | 0xFF;
result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
- }
-#endif
- unsigned char active_scb, control;
- struct aic7xxx_scb *active_scbp;
+ aic7xxx_error(active_scb->cmd) = DID_RESET;
+ }
+ else
+ {
+ aic7xxx_error(scb->cmd) = DID_RESET;
+ result = SCSI_RESET_PENDING;
+ }
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ }
+ else
+ {
+ unsigned char hscb_index, linked_next;
+ int disconnected;
- /*
- * Send a Bus Device Reset Message:
- * The target we select to send the message to may be entirely
- * different than the target pointed to by the scb that timed
- * out. If the command is in the QINFIFO or the waiting for
- * selection list, its not tying up the bus and isn't responsible
- * for the delay so we pick off the active command which should
- * be the SCB selected by SCBPTR. If its disconnected or active,
- * we device reset the target scbp points to. Although it may
- * be that this target is not responsible for the delay, it may
- * may also be that we're timing out on a command that just takes
- * too much time, so we try the bus device reset there first.
- */
- active_scb = inb(SCBPTR + base);
- active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
- control = inb(SCB_CONTROL + base);
+ disconnected = FALSE;
+ hscb_index = aic7xxx_find_scb(p, scb);
+ if (hscb_index == SCB_LIST_NULL)
+ {
+ disconnected = TRUE;
+ linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+ }
+ else
+ {
+ outb(hscb_index, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+ {
+ disconnected = TRUE;
+ }
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ }
+ if (disconnected)
+ {
+ /*
+ * Simply set the ABORT_SCB control bit and preserve the
+ * linked next pointer.
+ */
+ scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+ scb->hscb->data_count &= ~0xFF000000;
+ scb->hscb->data_count |= linked_next << 24;
+ if ((p->flags & PAGE_ENABLED) == 0)
+ {
+ scb->hscb->control &= ~DISCONNECTED;
+ }
+ scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+ if (hscb_index != SCB_LIST_NULL)
+ {
+ unsigned char scb_control;
- /*
- * Test to see if scbp is disconnected
- */
- outb(scb->position, SCBPTR + base);
- if (inb(SCB_CONTROL + base) & DISCONNECTED)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) scb %d is disconnected; "
- "bus device reset message queued.\n", scb->position);
-#endif
- if (p->flags & PAGE_ENABLED)
- {
- /* Pull this SCB out of the disconnected list. */
- u_char prev = inb(SCB_PREV + base);
- u_char next = inb(SCB_NEXT + base);
- if (prev == SCB_LIST_NULL)
- {
- /* Head of list */
- outb(next, DISCONNECTED_SCBH + base);
- }
- else
- {
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(prev, SCB_PREV + base);
- }
- outb(scb->position, SCBPTR + base);
- }
- }
- scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- scb->control = scb->control & DISCENB;
- scb->SCSI_cmd_length = 0;
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
- aic7xxx_putscb(p, scb);
- aic7xxx_add_waiting_scb(base, scb);
- outb(active_scb, SCBPTR + base);
- result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- }
- else
- {
- /*
- * Is the active SCB really active?
- */
- if ((active_scbp->state & SCB_ACTIVE) && bus_state)
- {
- /*
- * Load the message buffer and assert attention.
- */
- active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- outb(1, MSG_LEN + base);
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(bus_state | ATNO, SCSISIGO + base);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) asserted ATN - "
- "bus device reset in message buffer.\n");
-#endif
- if (active_scbp != scb)
- {
- /*
- * XXX - We would like to increment the timeout on scb, but
- * access to that routine is denied because it is hidden
- * in scsi.c. If we were able to do this, it would give
- * scb a new lease on life.
- */
- ;
- }
- aic7xxx_error(scb->cmd) = DID_RESET;
- /*
- * Restore the active SCB and unpause the sequencer.
- */
- outb(active_scb, SCBPTR + base);
- if (active_scbp != scb)
- {
- /*
- * The mid-level SCSI code requested us to reset a command
- * different from the one that we actually reset. Return
- * a "not running" indication and hope that the SCSI code
- * will Do the Right Thing (tm).
- */
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
- {
- result = SCSI_RESET_PENDING;
- }
- UNPAUSE_SEQUENCER(p);
- }
- }
+ scb_control = inb(p->base + SCB_CONTROL);
+ outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+ }
+ /*
+ * Actually requeue this SCB in case we can select the
+ * device before it reconnects. If the transaction we
+ * want to abort is not tagged, unbusy it first so that
+ * we don't get held back from sending the command.
+ */
+ if ((scb->hscb->control & TAG_ENB) == 0)
+ {
+ unsigned char target;
+ int lun;
+
+ target = scb->cmd->target;
+ lun = scb->cmd->lun;
+ aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
+ 0, /* requeue */ TRUE);
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
+ p->host_no, TC_OF_SCB(scb));
+ scbq_insert_head(&p->waiting_scbs, scb);
+ scb->flags |= SCB_WAITINGQ;
+ outb(saved_scbptr, p->base + SCBPTR);
+ if ((p->flags & IN_ISR) == 0)
+ {
+ /*
+ * Processing the waiting queue may unpause us.
+ */
+ aic7xxx_run_waiting_queues(p);
+ /*
+ * If we are using AAP, aic7xxx_run_waiting_queues() will not
+ * unpause us, so ensure we are unpaused.
+ */
+ unpause_sequencer(p, /*unpause_always*/ FALSE);
+ }
+ else
+ {
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+ }
+ result = SCSI_RESET_PENDING;
+ }
+ else
+ {
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
}
}
}
- /* Make sure the sequencer is unpaused upon return. */
- if (result == -1)
- {
- UNPAUSE_SEQUENCER(p);
- }
return (result);
}
@@ -5491,16 +6764,48 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
int base, result;
+ unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
+ save_flags(processor_flags);
+ cli();
+
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Abort called with no SCB for cmd.\n");
+ }
#endif
+ if (p->flags & IN_TIMEOUT)
+ {
+ /*
+ * We've already started a recovery operation.
+ */
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+ {
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_PENDING);
+ }
+ else
+ {
+ /*
+ * This is the second time we've tried to abort the recovery
+ * SCB. We want the mid-level SCSI code to call the reset
+ * function to reset the SCSI bus.
+ */
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_NOT_RUNNING);
+ }
+ }
if (cmd->serial_number != cmd->serial_number_at_timeout)
{
result = SCSI_ABORT_NOT_RUNNING;
@@ -5509,14 +6814,34 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
{
result = SCSI_ABORT_NOT_RUNNING;
}
- else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+ else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
{
result = SCSI_ABORT_NOT_RUNNING;
}
else
{
- result = SCSI_ABORT_SNOOZE;
+ /*
+ * XXX - Check use of IN_TIMEOUT to see if we're Doing the
+ * Right Thing with it.
+ */
+ p->flags |= IN_TIMEOUT;
+ result = aic7xxx_bus_device_reset(p, scb->cmd);
+ switch (result)
+ {
+ case SCSI_RESET_NOT_RUNNING:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_NOT_RUNNING;
+ break;
+ case SCSI_RESET_PENDING:
+ result = SCSI_ABORT_PENDING;
+ break;
+ default:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_SNOOZE;
+ break;
+ }
}
+ restore_flags(processor_flags);
return (result);
}
@@ -5536,18 +6861,27 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
- int base, found, tindex, min_target, max_target, result = -1;
+ int base, found, tindex, min_target, max_target;
+ int result = -1;
char channel = 'A';
unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
tindex = (cmd->channel << 4) | cmd->target;
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Reset called with no SCB for cmd.\n");
+ }
#endif
/*
@@ -5562,34 +6896,45 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
if (scb->cmd != cmd)
scb = NULL;
- if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
- && (scb != NULL))
+ if (p->flags & IN_TIMEOUT)
{
/*
- * Attempt a bus device reset if commands have completed successfully
- * since the last bus device reset, or it has been less than 100ms
- * since the last reset.
+ * We've already started a recovery operation.
*/
- if ((p->flags & DEVICE_SUCCESS) ||
- ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
{
- if (cmd->serial_number != cmd->serial_number_at_timeout)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
+ restore_flags(processor_flags);
+ return (SCSI_RESET_PENDING);
+ }
+ }
+ else
+ {
+ if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+ && (scb != NULL))
+ {
+ /*
+ * Attempt a bus device reset if commands have completed successfully
+ * since the last bus device reset, or it has been less than 100ms
+ * since the last reset.
+ */
+ if ((p->flags & DEVICE_SUCCESS) ||
+ ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
{
- if (scb == NULL)
+ if (cmd->serial_number != cmd->serial_number_at_timeout)
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ }
+ else if (scb == NULL)
{
result = SCSI_RESET_NOT_RUNNING;
}
else if (flags & SCSI_RESET_ASYNCHRONOUS)
{
- if (scb->state & SCB_ABORTED)
+ if (scb->flags & SCB_ABORTED)
{
result = SCSI_RESET_PENDING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
@@ -5600,20 +6945,23 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
if ((flags & SCSI_RESET_SYNCHRONOUS) &&
(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
{
- scb->state |= SCB_ABORTED;
+ scb->flags |= SCB_ABORTED;
result = SCSI_RESET_PENDING;
}
else
{
+ p->flags |= IN_TIMEOUT;
result = aic7xxx_bus_device_reset(p, cmd);
if (result == 0)
+ {
+ p->flags &= ~IN_TIMEOUT;
result = SCSI_RESET_PENDING;
+ }
}
- }
+ }
}
}
}
-
if (result == -1)
{
/*
@@ -5626,11 +6974,11 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if ((scb->state & SCB_ABORTED) &&
+ else if ((scb->flags & SCB_ABORTED) &&
(!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
{
result = SCSI_RESET_PENDING;
@@ -5642,8 +6990,9 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
/*
* The reset channel function assumes that the sequencer is paused.
*/
- PAUSE_SEQUENCER(p);
+ pause_sequencer(p);
found = aic7xxx_reset_channel(p, channel, TRUE);
+ p->flags = p->flags & ~IN_TIMEOUT;
/*
* If this is a synchronous reset and there is no SCB for this
@@ -5689,8 +7038,10 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
}
result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+ p->flags &= ~IN_TIMEOUT;
}
}
+ aic7xxx_run_waiting_queues(p);
restore_flags(processor_flags);
return (result);
}
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
index d4de8fd83..11836c405 100644
--- a/drivers/scsi/aic7xxx.h
+++ b/drivers/scsi/aic7xxx.h
@@ -18,12 +18,12 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+ * $Id: aic7xxx.h,v 1.1.1.1 1997/06/01 03:17:41 ralf Exp $
*-M*************************************************************************/
#ifndef _aic7xxx_h
#define _aic7xxx_h
-#define AIC7XXX_H_VERSION "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION "$Revision: 1.1.1.1 $"
/*
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
@@ -40,13 +40,13 @@
aic7xxx_info, \
NULL, \
aic7xxx_queue, \
- aic7xxx_abort, \
+ NULL, \
aic7xxx_reset, \
NULL, \
aic7xxx_biosparam, \
-1, /* max simultaneous cmds */\
-1, /* scsi id of host adapter */\
- SG_ALL, /* max scatter-gather cmds */\
+ 0, /* max scatter-gather cmds */\
2, /* cmds per lun (linked cmds) */\
0, /* number of 7xxx's present */\
0, /* no memory DMA restrictions */\
@@ -57,7 +57,6 @@ extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
extern int aic7xxx_detect(Scsi_Host_Template *);
extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_abort(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
extern const char *aic7xxx_info(struct Scsi_Host *);
diff --git a/drivers/scsi/aic7xxx.seq b/drivers/scsi/aic7xxx.seq
index 98d4b9545..e69de29bb 100644
--- a/drivers/scsi/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx.seq
@@ -1,1127 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux and FreeBSD.
- *
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- *
- *Modifications/enhancements:
- * Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other
- * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
- *
- * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
- *
- *-M*************************************************************************/
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
-
-#ifdef linux
-#include "aic7xxx_reg.h"
-#else
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#endif
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'. This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
-
-/* After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration. The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time. This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection. The solution used here is to
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
- * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets,
- * SCB_LIST_NULL is 0xff which is out of range. The kernel driver must
- * add an entry to this list every time a request sense occurs. The sequencer
- * will automatically consume the entries.
- */
-
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
-reset:
- clr DFCNTRL
- clr SCSISIGO /* De-assert BSY */
-/*
- * We jump to start after every bus free.
- */
-start:
- and FLAGS,0x0f /* clear target specific flags */
- mvi SCSISEQ,ENRSELI /* Always allow reselection */
- clr SCSIRATE /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
-poll_for_work:
- /*
- * Are we a twin channel device?
- * For fairness, we check the other bus first,
- * since we just finished a transaction on the
- * current channel.
- */
- test FLAGS,TWIN_BUS jz start2
- xor SBLKCTL,SELBUSB /* Toggle to the other bus */
- test SSTAT0,SELDI jnz reselect
- xor SBLKCTL,SELBUSB /* Toggle to the original bus */
-start2:
- test SSTAT0,SELDI jnz reselect
- cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting
- mov A, QCNTMASK
- test QINCNT,A jz poll_for_work
-
-/*
- * We have at least one queued SCB now and we don't have any
- * SCBs in the list of SCBs awaiting selection. Set the SCB
- * pointer from the FIFO so we see the right bank of SCB
- * registers.
- */
- mov SCBPTR,QINFIFO
-
-/*
- * See if there is not already an active SCB for this target. This code
- * locks out on a per target basis instead of target/lun. Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands. It may be beneficial to make findscb a more general procedure
- * to see if the added cost of the search is negligible. This code also
- * assumes that the kernel driver will clear the active flags on board
- * initialization, board reset, and a target SELTO. Tagged commands
- * don't set the active bits since you can queue more than one command
- * at a time. We do, however, look to see if there are any non-tagged
- * I/Os in progress, and requeue the command if there are. Tagged and
- * non-tagged commands cannot be mixed to a single target.
- */
-
-test_busy:
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz test_a /* Id < 8 && A channel */
-
- test ACTIVE_B,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_B,A
- jmp start_scb
-
-/* Place the currently active SCB back on the queue for later processing */
-requeue:
- mov QINFIFO, SCBPTR
- jmp poll_for_work
-
-/*
- * Pull the first entry off of the waiting for selection list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the waiting_scb list.
- */
-start_waiting:
- mov SCBPTR,WAITING_SCBH
- jmp start_scb2
-
-test_a:
- test ACTIVE_A,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_A,A
-
-start_scb:
- mov SCB_NEXT,WAITING_SCBH
- mov WAITING_SCBH, SCBPTR
-start_scb2:
- and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */
- and A,0x08,SCB_TCL /* Get new channel bit */
- or SINDEX,A
- mov SBLKCTL,SINDEX /* select channel */
- mov SCB_TCL call initialize_scsiid
-
-/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection. We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
- */
-start_selection:
- mvi SCSISEQ,0x58 /* ENSELO|ENAUTOATNO|ENRSELI */
-
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted. Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
- test SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached. This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
- mvi INTSTAT,AWAITING_MSG
- jmp wait_for_selection
-
-mk_identify:
- and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */
-
- and MSG0,0x7,SCB_TCL /* lun */
- or MSG0,A /* or in disconnect privledge */
- or MSG0,MSG_IDENTIFY
- mvi MSG_LEN, 1
-
- test SCB_CONTROL,0xb0 jz !message /* WDTR, SDTR or TAG?? */
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-
-mk_tag:
- mvi DINDEX, MSG1
- test SCB_CONTROL,TAG_ENB jz mk_tag_done
- and DINDIR,0x23,SCB_CONTROL
- mov DINDIR,SCB_TAG
-
- add MSG_LEN,COMP_MSG0,DINDEX /* update message length */
-
-mk_tag_done:
-
- test SCB_CONTROL,0x90 jz !message /* NEEDWDTR|NEEDSDTR */
- mov DINDEX call mk_dtr /* build DTR message if needed */
-
-!message:
-wait_for_selection:
- test SSTAT0,SELDO jnz select
- test SSTAT0,SELDI jz wait_for_selection
-
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target
- * yet.
- */
-reselect:
- clr MSG_LEN /* Don't have anything in the mesg buffer */
- mov SELID call initialize_scsiid
- or FLAGS,RESELECTED
- jmp select2
-
-/*
- * After the selection, remove this SCB from the "waiting for selection"
- * list. This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH. Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
- mov WAITING_SCBH,SCB_NEXT
- or FLAGS,SELECTED
-select2:
-/*
- * Set CLRCHN here before the target has entered a data transfer mode -
- * with synchronous SCSI, if you do it later, you blow away some
- * data in the SCSI FIFO that the target has already sent to you.
- */
- or SXFRCTL0,CLRCHN
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
- call ndx_dtr
- mov SCSIRATE,SINDIR
-
-/*
- * Initialize Ultra mode setting.
- */
- mov FUNCTION1,SCSIID
- mov A,FUNCTION1
- and SINDEX,0xdf,SXFRCTL0 /* default to Ultra disabled */
- test SCSIID, 0x80 jnz ultra_b /* Target ID > 7 */
- test SBLKCTL, SELBUSB jnz ultra_b /* Second channel device */
- test ULTRA_ENB,A jz set_sxfrctl0
- or SINDEX, ULTRAEN jmp set_sxfrctl0
-ultra_b:
- test ULTRA_ENB_B,A jz set_sxfrctl0
- or SINDEX, ULTRAEN
-
-set_sxfrctl0:
- mov SXFRCTL0,SINDEX
-
- mvi SCSISEQ,ENAUTOATNP /*
- * ATN on parity errors
- * for "in" phases
- */
- mvi CLRSINT1,CLRBUSFREE
- mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */
-/*
- * Main loop for information transfer phases. If BSY is false, then
- * we have a bus free condition, expected or not. Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
- */
-ITloop:
- test SSTAT1,BUSFREE jnz p_busfree
- test SSTAT1,REQINIT jz ITloop
-
- and A,PHASE_MASK,SCSISIGI
- mov LASTPHASE,A
- mov SCSISIGO,A
-
- cmp ALLZEROS,A je p_dataout
- cmp A,P_DATAIN je p_datain
- cmp A,P_COMMAND je p_command
- cmp A,P_MESGOUT je p_mesgout
- cmp A,P_STATUS je p_status
- cmp A,P_MESGIN je p_mesgin
-
- mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */
- jmp ITloop /* Try reading the bus again. */
-
-p_dataout:
- mvi DMAPARAMS,0x7d /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * DIRECTION|FIFORESET
- */
- jmp data_phase_init
-
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-data_phase_reinit:
- mov STCNT0,SCB_RESID_DCNT0
- mov STCNT1,SCB_RESID_DCNT1
- mov STCNT2,SCB_RESID_DCNT2
- jmp data_phase_loop
-
-p_datain:
- mvi DMAPARAMS,0x79 /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * !DIRECTION|FIFORESET
- */
-data_phase_init:
- call assert
-
- test FLAGS, DPHASE jnz data_phase_reinit
- call sg_scb2ram
- or FLAGS, DPHASE /* We have seen a data phase */
-
-data_phase_loop:
-/* Guard against overruns */
- test SG_COUNT, 0xff jnz data_phase_inbounds
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
- or SXFRCTL1,BITBUCKET
- mvi STCNT0,0xff
- mvi STCNT1,0xff
- mvi STCNT2,0xff
-
-data_phase_inbounds:
-/* If we are the last SG block, don't set wideodd. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd
- and DMAPARAMS, 0xbf /* Turn off WIDEODD */
-data_phase_wideodd:
- mov DMAPARAMS call dma
-
-/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun
-
-/* Exit if we had an underrun */
- test SSTAT0,SDONE jz data_phase_finish /* underrun STCNT != 0 */
-
-/*
- * Advance the scatter-gather pointers if needed
- */
-sg_advance:
- dec SG_COUNT /* one less segment to go */
-
- test SG_COUNT, 0xff jz data_phase_finish /* Are we done? */
-
- clr A /* add sizeof(struct scatter) */
- add SG_NEXT0,SG_SIZEOF,SG_NEXT0
- adc SG_NEXT1,A,SG_NEXT1
-
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes a little-endian host data storage.
- */
-sg_load:
- clr HCNT2
- clr HCNT1
- mvi HCNT0,SG_SIZEOF
-
- mov HADDR0,SG_NEXT0
- mov HADDR1,SG_NEXT1
- mov HADDR2,SG_NEXT2
- mov HADDR3,SG_NEXT3
-
- or DFCNTRL,0xd /* HDMAEN|DIRECTION|FIFORESET */
-
-/*
- * Wait for DMA from host memory to data FIFO to complete, then disable
- * DMA and wait for it to acknowledge that it's off.
- */
-dma_finish:
- test DFSTATUS,HDONE jz dma_finish
- /* Turn off DMA preserving WIDEODD */
- and DFCNTRL,WIDEODD
-dma_finish2:
- test DFCNTRL,HDMAENACK jnz dma_finish2
-
-/*
- * Copy data from FIFO into SCB data pointer and data count. In
- * both FreeBSD and Linux, the scatter list entry is 8 bytes.
- *
- * struct ahc_dma_seg {
- * physaddr addr; four bytes, little-endian order
- * long len; four bytes, little endian order
- * };
- */
-
- mov HADDR0,DFDAT
- mov HADDR1,DFDAT
- mov HADDR2,DFDAT
- mov HADDR3,DFDAT
- mov HCNT0,DFDAT
- mov HCNT1,DFDAT
- mov HCNT2,DFDAT
-
-/* Load STCNT as well. It is a mirror of HCNT */
- mov STCNT0,HCNT0
- mov STCNT1,HCNT1
- mov STCNT2,HCNT2
- test SSTAT1,PHASEMIS jz data_phase_loop
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes
- * were transferred on the SCSI (as opposed to the host) bus.
- */
- mov SCB_RESID_DCNT0,STCNT0
- mov SCB_RESID_DCNT1,STCNT1
- mov SCB_RESID_DCNT2,STCNT2
- mov SCB_RESID_SGCNT, SG_COUNT
- jmp ITloop
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
- and SXFRCTL1,0x7f /* ~BITBUCKET */
- mvi INTSTAT,DATA_OVERRUN
- jmp ITloop
-
-/*
- * Command phase. Set up the DMA registers and let 'er rip.
- */
-p_command:
- call assert
-
-/*
- * Load HADDR and HCNT.
- */
- mov HADDR0, SCB_CMDPTR0
- mov HADDR1, SCB_CMDPTR1
- mov HADDR2, SCB_CMDPTR2
- mov HADDR3, SCB_CMDPTR3
- mov HCNT0, SCB_CMDLEN
- clr HCNT1
- clr HCNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN|
- # DIRECTION|FIFORESET
- jmp ITloop
-
-/*
- * Status phase. Wait for the data byte to appear, then read it
- * and store it into the SCB.
- */
-p_status:
- mvi SCB_TARGET_STATUS call inb_first
- jmp mesgin_done
-
-/*
- * Message out phase. If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
- */
-p_mesgout:
- test MSG_LEN, 0xff jnz p_mesgout_start
- mvi MSG_NOP call mk_mesg /* build NOP message */
-
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG0. Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
- mvi SINDEX,MSG0
- mov DINDEX,MSG_LEN
-
-/*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message. Otherwise, keep going until the message is exhausted.
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- test SSTAT0,SPIORDY jz p_mesgout_loop
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- cmp DINDEX,1 jne p_mesgout_outb /* last byte? */
- mvi CLRSINT1,CLRATNO /* drop ATN */
-p_mesgout_outb:
- dec DINDEX
- or CLRSINT0, CLRSPIORDY
- mov SCSIDATL,SINDIR
-
-p_mesgout4:
- test DINDEX,0xff jnz p_mesgout_loop
-
-/*
- * If the next bus phase after ATN drops is a message out, it means
- * that the target is requesting that the last message(s) be resent.
- */
-p_mesgout_snoop:
- test SSTAT1,BUSFREE jnz p_mesgout_done
- test SSTAT1,REQINIT jz p_mesgout_snoop
-
- test SSTAT1,PHASEMIS jnz p_mesgout_done
-
- or SCSISIGO,ATNO /* turn on ATNO */
-
- jmp ITloop
-
-p_mesgout_phasemis:
- mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */
-p_mesgout_done:
- clr MSG_LEN /* no active msg */
- jmp ITloop
-
-/*
- * Message in phase. Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
- mvi A call inb_first /* read the 1st message byte */
- mov REJBYTE,A /* save it for the driver */
-
- test A,MSG_IDENTIFY jnz mesgin_identify
- cmp A,MSG_DISCONNECT je mesgin_disconnect
- cmp A,MSG_SDPTRS je mesgin_sdptrs
- cmp ALLZEROS,A je mesgin_complete
- cmp A,MSG_RDPTRS je mesgin_rdptrs
- cmp A,MSG_EXTENDED je mesgin_extended
- cmp A,MSG_REJECT je mesgin_reject
-
-rej_mesgin:
-/*
- * We have no idea what this message in is, and there's no way
- * to pass it up to the kernel, so we issue a message reject and
- * hope for the best. Since we're now using manual PIO mode to
- * read in the message, there should no longer be a race condition
- * present when we assert ATN. In any case, rejection should be a
- * rare occurrence - signal the driver when it happens.
- */
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,SEND_REJECT /* let driver know */
-
- mvi MSG_REJECT call mk_mesg
-
-mesgin_done:
- call inb_last /*ack & turn auto PIO back on*/
- jmp ITloop
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
- * and trigger a completion interrupt. Check status for non zero return
- * and interrupt driver if needed. This allows the driver to interpret
- * errors only when they occur instead of always uploading the scb. If
- * the status is SCSI_CHECK, the driver will download a new scb requesting
- * sense to replace the old one, modify the "waiting for selection" SCB list
- * and set RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE the
- * sequencer imediately jumps to main loop where it will run down the waiting
- * SCB list and process the sense request. If the kernel driver does not
- * wish to request sense, it need only clear RETURN_1, and the command is
- * allowed to complete. We don't bother to post to the QOUTFIFO in the
- * error case since it would require extra work in the kernel driver to
- * ensure that the entry was removed before the command complete code tried
- * processing it.
- *
- * First check for residuals
- */
- test SCB_RESID_SGCNT,0xff jz check_status
-/*
- * If we have a residual count, interrupt and tell the host. Other
- * alternatives are to pause the sequencer on all command completes (yuck),
- * dma the resid directly to the host (slick, we may have space to do it now)
- * or have the sequencer pause itself when it encounters a non-zero resid
- * (unnecessary pause just to flag the command -yuck-, but takes one instruction
- * and since it shouldn't happen that often is good enough for our purposes).
- */
-resid:
- mvi INTSTAT,RESIDUAL
-
-check_status:
- test SCB_TARGET_STATUS,0xff jz status_ok /* Good Status? */
- mvi INTSTAT,BAD_STATUS /* let driver know */
- cmp RETURN_1, SEND_SENSE jne status_ok
- jmp mesgin_done
-
-status_ok:
-/* First, mark this target as free. */
- test SCB_CONTROL,TAG_ENB jnz test_immediate /*
- * Tagged commands
- * don't busy the
- * target.
- */
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz clear_a
- xor ACTIVE_B,A
- jmp test_immediate
-
-clear_a:
- xor ACTIVE_A,A
-
-test_immediate:
- test SCB_CMDLEN,0xff jnz complete /* Immediate message complete */
-/*
- * Pause the sequencer until the driver gets around to handling the command
- * complete. This is so that any action that might require careful timing
- * with the completion of this command can occur.
- */
- mvi INTSTAT,IMMEDDONE
- jmp start
-complete:
- mov QOUTFIFO,SCB_TAG
- mvi INTSTAT,CMDCMPLT
- jmp mesgin_done
-
-
-/*
- * Is it an extended message? We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
- */
-mesgin_extended:
- mvi ARG_1 call inb_next /* extended message length */
- mvi REJBYTE_EXT call inb_next /* extended message code */
-
- cmp REJBYTE_EXT,MSG_SDTR je p_mesginSDTR
- cmp REJBYTE_EXT,MSG_WDTR je p_mesginWDTR
- jmp rej_mesgin
-
-p_mesginWDTR:
- cmp ARG_1,2 jne rej_mesgin /* extended mesg length=2 */
- mvi ARG_1 call inb_next /* Width of bus */
- mvi INTSTAT,WDTR_MSG /* let driver know */
- test RETURN_1,0xff jz mesgin_done /* Do we need to send WDTR? */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Bus width was too large
- * Reject it.
- */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
- and RETURN_1,0x7f /* Clear the SEND_WDTR Flag */
- mvi DINDEX,MSG0
- mvi MSG0 call mk_wdtr /* build WDTR message */
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-p_mesginSDTR:
- cmp ARG_1,3 jne rej_mesgin /* extended mesg length=3 */
- mvi ARG_1 call inb_next /* xfer period */
- mvi A call inb_next /* REQ/ACK offset */
- mvi INTSTAT,SDTR_MSG /* call driver to convert */
-
- test RETURN_1,0xff jz mesgin_done /* Do we need to mk_sdtr/rej */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Requested SDTR too small
- * Reject it.
- */
- clr ARG_1 /* Use the scratch ram rate */
- mvi DINDEX, MSG0
- mvi MSG0 call mk_sdtr
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-/*
- * Is it a disconnect message? Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
- or SCB_CONTROL,DISCONNECTED
- test FLAGS, PAGESCBS jz mesgin_done
-/*
- * Link this SCB into the DISCONNECTED list. This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
- mvi SCB_PREV, SCB_LIST_NULL
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- mov SCB_NEXT, DISCONNECTED_SCBH
- mov DISCONNECTED_SCBH, SCBPTR
- cmp SCB_NEXT,SCB_LIST_NULL je linkdone
- mov SCBPTR,SCB_NEXT
- mov SCB_PREV,DISCONNECTED_SCBH
- mov SCBPTR,DISCONNECTED_SCBH
-linkdone:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- jmp mesgin_done
-
-/*
- * Save data pointers message? Copy working values into the SCB,
- * usually in preparation for a disconnect.
- */
-mesgin_sdptrs:
- call sg_ram2scb
- jmp mesgin_done
-
-/*
- * Restore pointers message? Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
- and FLAGS,0xef /*
- * !DPHASE we'll reload them
- * the next time through
- */
- jmp mesgin_done
-
-/*
- * Identify message? For a reconnecting target, this tells us the lun
- * that the reconnection is for - find the correct SCB and switch to it,
- * clearing the "disconnected" bit so we don't "find" it by accident later.
- */
-mesgin_identify:
- test A,0x78 jnz rej_mesgin /*!DiscPriv|!LUNTAR|!Reserved*/
-
- and A,0x07 /* lun in lower three bits */
- or SAVED_TCL,A,SELID
- and SAVED_TCL,0xf7
- and A,SELBUSB,SBLKCTL /* B Channel?? */
- or SAVED_TCL,A
- call inb_last /* ACK */
-
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to find the proper
- * SCB. With SCB paging, this requires using findSCB for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
- */
- mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */
-snoop_tag_loop:
- test SSTAT1,BUSFREE jnz use_findSCB
- test SSTAT1,REQINIT jz snoop_tag_loop
- test SSTAT1,PHASEMIS jnz use_findSCB
- mvi A call inb_first
- cmp A,MSG_SIMPLE_TAG jne use_findSCB
-get_tag:
- mvi ARG_1 call inb_next /* tag value */
-/*
- * See if the tag is in range. The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incoming tag and there is
- * no carry.
- */
- mov A,COMP_SCBCOUNT
- add SINDEX,A,ARG_1
- jc abort_tag
-
-/*
- * Ensure that the SCB the tag points to is for a SCB transaction
- * to the reconnecting target.
- */
- test FLAGS, PAGESCBS jz index_by_tag
- call inb_last /* Ack Tag */
-use_findSCB:
- mov ALLZEROS call findSCB /* Have to search */
-setup_SCB:
- and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */
- or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */
- jmp ITloop
-index_by_tag:
- mov SCBPTR,ARG_1
- mov A,SAVED_TCL
- cmp SCB_TCL,A jne abort_tag
- test SCB_CONTROL,TAG_ENB jz abort_tag
- call inb_last /* Ack Successful tag */
- jmp setup_SCB
-
-abort_tag:
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,ABORT_TAG /* let driver know */
- mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */
- jmp mesgin_done
-
-/*
- * Message reject? Let the kernel driver handle this. If we have an
- * outstanding WDTR or SDTR negotiation, assume that it's a response from
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
- mvi INTSTAT, REJECT_MSG
- jmp mesgin_done
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * Bus free phase. It might be useful to interrupt the device
- * driver if we aren't expecting this. For now, make sure that
- * ATN isn't being asserted and look for a new command.
- */
-p_busfree:
- mvi CLRSINT1,CLRATNO
- clr LASTPHASE
-
-/*
- * if this is an immediate command, perform a pseudo command complete to
- * notify the driver.
- */
- test SCB_CMDLEN,0xff jz status_ok
- jmp start
-
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already. SINDEX is returned intact.
- */
-mk_mesg:
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */
-
- /*
- * Hmmm. For some reason the mesg buffer is in use.
- * Tell the driver. It should look at SINDEX to find
- * out what we wanted to use the buffer for and resolve
- * the conflict.
- */
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- mvi INTSTAT,MSG_BUFFER_BUSY
-
-mk_mesg1:
- mvi MSG_LEN,1 /* length = 1 */
- mov MSG0,SINDEX /* 1-byte message */
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * According to Adaptec's documentation, an ACK is not sent on input from
- * the target until SCSIDATL is read from. So we wait until SCSIDATL is
- * latched (the usual way), then read the data byte directly off the bus
- * using SCSIBUSL. When we have pulled the ATN line, or we just want to
- * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI
- * spec guarantees that the target will hold the data byte on the bus until
- * we send our ACK.
- *
- * The assumption here is that these are called in a particular sequence,
- * and that REQ is already set when inb_first is called. inb_{first,next}
- * use the same calling convention as inb.
- */
-
-inb_next:
- or CLRSINT0, CLRSPIORDY
- mov NONE,SCSIDATL /*dummy read from latch to ACK*/
-inb_next_wait:
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- test SSTAT0,SPIORDY jz inb_next_wait /* wait for next byte */
-inb_first:
- mov DINDEX,SINDEX
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/
-inb_last:
- mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/
-
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
- mvi INTSTAT, MSGIN_PHASEMIS
- jmp ITloop
-
-/*
- * DMA data transfer. HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
- * during initialization.
- */
-dma:
- mov DFCNTRL,SINDEX
-dma1:
- test SSTAT0,DMADONE jnz dma3
- test SSTAT1,PHASEMIS jz dma1 /* ie. underrun */
-
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma3:
- test SINDEX,DIRECTION jnz dma5
-dma4:
- test DFSTATUS,FIFOEMP jz dma4
-
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are
- * actually off first lest we get an ILLSADDR.
- */
-dma5:
- /* disable DMA, but maintain WIDEODD */
- and DFCNTRL,WIDEODD
-dma6:
- test DFCNTRL,0x38 jnz dma6 /* SCSIENACK|SDMAENACK|HDMAENACK */
-
- ret
-
-/*
- * Common SCSI initialization for selection and reselection. Expects
- * the target SCSI ID to be in the upper four bits of SINDEX, and A's
- * contents are stomped on return.
- */
-initialize_scsiid:
- and SINDEX,0xf0 /* Get target ID */
- and A,0x0f,SCSIID
- or SINDEX,A
- mov SCSIID,SINDEX ret
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
- test FLAGS,RESELECTED jz return /* reselected? */
- test FLAGS,IDENTIFY_SEEN jnz return /* seen IDENTIFY? */
-
- mvi INTSTAT,NO_IDENT ret /* no - cause a kernel panic */
-
-/*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
- * value in ARG_1. If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
- * SCB. Have the kernel print a warning message if it can't be found, and
- * generate an ABORT/ABORT_TAG message to the target. SINDEX should be
- * cleared on call.
- */
-findSCB:
- mov A,SAVED_TCL
- mov SCBPTR,SINDEX /* switch to next SCB */
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- cmp SCB_TCL,A jne findSCB1 /* target ID/channel/lun match? */
- test SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
- test SCB_CONTROL,TAG_ENB jnz findTaggedSCB
- cmp ARG_1,SCB_LIST_NULL je foundSCB
- jmp findSCB1
-findTaggedSCB:
- mov A, ARG_1 /* Tag passed in ARG_1 */
- cmp SCB_TAG,A jne findSCB1 /* Found it? */
-foundSCB:
- test FLAGS,PAGESCBS jz foundSCB_ret
-/* Remove this SCB from the disconnection list */
- cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev
- mov SAVED_LINKPTR, SCB_PREV
- mov SCBPTR, SCB_NEXT
- mov SCB_PREV, SAVED_LINKPTR
- mov SCBPTR, SINDEX
-unlink_prev:
- cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */
- mov SAVED_LINKPTR, SCB_NEXT
- mov SCBPTR, SCB_PREV
- mov SCB_NEXT, SAVED_LINKPTR
- mov SCBPTR, SINDEX
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-rHead:
- mov DISCONNECTED_SCBH,SCB_NEXT
-foundSCB_ret:
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-findSCB1:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- inc SINDEX
- mov A,SCBCOUNT
- cmp SINDEX,A jne findSCB
-
- mvi INTSTAT,NO_MATCH /* not found - signal kernel */
- cmp RETURN_1,SCB_PAGEDIN je return
- or SCSISIGO,ATNO /* assert ATNO */
- cmp ARG_1,SCB_LIST_NULL jne find_abort_tag
- mvi MSG_ABORT call mk_mesg
- jmp ITloop
-find_abort_tag:
- mvi MSG_ABORT_TAG call mk_mesg
- jmp ITloop
-
-/*
- * Make a working copy of the scatter-gather parameters from the SCB.
- */
-sg_scb2ram:
- mov HADDR0, SCB_DATAPTR0
- mov HADDR1, SCB_DATAPTR1
- mov HADDR2, SCB_DATAPTR2
- mov HADDR3, SCB_DATAPTR3
- mov HCNT0, SCB_DATACNT0
- mov HCNT1, SCB_DATACNT1
- mov HCNT2, SCB_DATACNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- mov SG_COUNT,SCB_SGCOUNT
-
- mov SG_NEXT0, SCB_SGPTR0
- mov SG_NEXT1, SCB_SGPTR1
- mov SG_NEXT2, SCB_SGPTR2
- mov SG_NEXT3, SCB_SGPTR3 ret
-
-/*
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them. This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-sg_ram2scb:
- test FLAGS, DPHASE jz return
- mov SCB_SGCOUNT,SG_COUNT
-
- mov SCB_SGPTR0,SG_NEXT0
- mov SCB_SGPTR1,SG_NEXT1
- mov SCB_SGPTR2,SG_NEXT2
- mov SCB_SGPTR3,SG_NEXT3
-
- mov SCB_DATAPTR0,SHADDR0
- mov SCB_DATAPTR1,SHADDR1
- mov SCB_DATAPTR2,SHADDR2
- mov SCB_DATAPTR3,SHADDR3
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer
- */
- mov SCB_DATACNT0,SCB_RESID_DCNT0
- mov SCB_DATACNT1,SCB_RESID_DCNT1
- mov SCB_DATACNT2,SCB_RESID_DCNT2 ret
-
-/*
- * Add the array base TARG_SCRATCH to the target offset (the target address
- * is in SCSIID), and return the result in SINDEX. The accumulator
- * contains the 3->8 decoding of the target ID on return.
- */
-ndx_dtr:
- shr A,SCSIID,4
- test SBLKCTL,SELBUSB jz ndx_dtr_2
- or A,0x08 /* Channel B entries add 8 */
-ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX. DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiate one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culprit.
- */
-mk_dtr:
- test SCB_CONTROL,NEEDWDTR jnz mk_wdtr_16bit
- mvi ARG_1, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,3 /* extended message length = 3 */
- mvi DINDIR,1 /* SDTR code */
- call sdtr_to_rate
- mov DINDIR,RETURN_1 /* REQ/ACK transfer period */
- cmp ARG_1, MAXOFFSET je mk_sdtr_max_offset
- and DINDIR,0x0f,SINDIR /* Sync Offset */
-
-mk_sdtr_done:
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
- /* Talking to a WIDE device? */
- test SCSIRATE, WIDEXFER jnz wmax_offset
- mvi DINDIR, MAX_OFFSET_8BIT
- jmp mk_sdtr_done
-
-wmax_offset:
- mvi DINDIR, MAX_OFFSET_16BIT
- jmp mk_sdtr_done
-
-mk_wdtr_16bit:
- mvi ARG_1,BUS_16_BIT
-mk_wdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,2 /* extended message length = 2 */
- mvi DINDIR,3 /* WDTR code */
- mov DINDIR,ARG_1 /* bus width */
-
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-sdtr_to_rate:
- call ndx_dtr /* index scratch space for target */
- shr A,SINDIR,0x4
- dec SINDEX /* Preserve SINDEX */
- and A,0x7
- clr RETURN_1
-sdtr_to_rate_loop:
- test A,0x0f jz sdtr_to_rate_done
- add RETURN_1,0x19
- dec A
- jmp sdtr_to_rate_loop
-sdtr_to_rate_done:
- shr RETURN_1,0x2
- add RETURN_1,0x19
- test SXFRCTL0,ULTRAEN jz return
- shr RETURN_1,0x1
-return:
- ret
diff --git a/drivers/scsi/aic7xxx_asm.c b/drivers/scsi/aic7xxx_asm.c
index 544edf0fa..e69de29bb 100644
--- a/drivers/scsi/aic7xxx_asm.c
+++ b/drivers/scsi/aic7xxx_asm.c
@@ -1,734 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx sequencer code assembler.
- *
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *-M*************************************************************************/
-static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
-#endif
-#define MAX_ARGS 16
-static const char *cpp[] = {
- "/lib/cpp -P - -",
- "/usr/lib/cpp -P - -",
- "/usr/bin/cpp -P - -",
- "/usr/bin/gcc -E -P -",
- "/usr/bin/cc -E -P -"
-};
-
-#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
-
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
-
-void
-error(const char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
-
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
-{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
-
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
-
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
- }
-
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
- }
-}
-
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
-
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
-}
-
-void
-patch(sym_t *p, int location)
-{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
- p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
- int i;
- sym_t *p;
-
- for (p = head; p; p = p->next) {
-
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
-
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
- }
-
- if (debug)
- fputc('\n', stderr);
- }
- }
-}
-
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
-{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
-
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
-
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
- }
- return(NULL);
-}
-
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- const char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
- /*
- * Extensions (note also that mvi allows A)
- */
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- const char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
- }
-
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
-
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
-
- p = lookup(a[spec]);
-
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
-}
-
-int
-crack(char **a, int n)
-{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
-
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
- }
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- }
-
- return (1); /* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void
-assemble(FILE *ofile)
-{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
- }
-
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
- }
- }
-
- backpatch();
- output(ofile);
-
- if (debug)
- output(stderr);
-}
-
-int
-main(int argc, char **argv)
-{
- int c;
- int pid;
- int ifile;
- int status;
- FILE *ofile;
- char *ofilename;
- int fd[2];
-
- ofile = NULL;
- ofilename = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
- ofilename = optarg;
- if ((ofile = fopen(ofilename, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofilename) {
- ofilename = ADOTOUT;
- if ((ofile = fopen(ofilename, "w")) < 0) {
- perror(ofilename);
- exit(EXIT_FAILURE);
- }
- }
-
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
-
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- if (wait(&status) < 0) {
- perror("wait error");
- }
-
- if (status != 0) {
- unlink(ofilename);
- }
- exit(status);
- } else { /* Child */
- int i, arg_cnt, found;
- char *args[MAX_ARGS];
- char *buf;
-
- arg_cnt = 0;
- found = FALSE;
- for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
- char *bp;
-
- buf = strdup(cpp[i]);
-
- for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
- bp != NULL;
- bp = strtok(NULL, " \t\n"), arg_cnt++) {
- if (arg_cnt == 0) {
- if (access(bp, X_OK) == 0) {
- found = TRUE;
- }
- }
-
- args[arg_cnt] = bp;
- }
-
- if (!found) {
- free(buf);
- }
- }
- args[arg_cnt] = NULL;
-
- if (found) {
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
-
- if (execvp(args[0], args) < 0) {
- perror("execvp() error");
- exit(EXIT_FAILURE);
- }
- } else {
- fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- }
- return(EXIT_SUCCESS);
-}
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index a968c324f..1092d4862 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -24,7 +24,7 @@
*
* Dean W. Gehnert, deang@teleport.com, 05/01/96
*
- * $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
#define BLS buffer + len + size
@@ -77,16 +77,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
struct Scsi_Host *HBAptr;
struct aic7xxx_host *p;
static u8 buff[512];
- int i;
+ int i;
+ int found = FALSE;
int size = 0;
int len = 0;
off_t begin = 0;
off_t pos = 0;
static char *bus_names[] = { "Single", "Twin", "Wide" };
- static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
+ static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
+ "AIC-787x", "AIC-788x" };
HBAptr = NULL;
- for (i = 0; i < NUMBER(aic7xxx_boards); i++)
+ for (i=0; i < NUMBER(aic7xxx_boards); i++)
{
if ((HBAptr = aic7xxx_boards[i]) != NULL)
{
@@ -95,16 +97,23 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
break;
}
- while ((HBAptr->hostdata != NULL) &&
+ while ((HBAptr->hostdata != NULL) && !found &&
((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
{
if (HBAptr->host_no == hostno)
{
- break; break;
+ found = TRUE;
}
}
- HBAptr = NULL;
+ if (!found)
+ {
+ HBAptr = NULL;
+ }
+ else
+ {
+ break;
+ }
}
}
@@ -129,8 +138,10 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
- size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_H_VERSION));
+ size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
+#if 0
size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
+#endif
len += size; pos = begin + len; size = 0;
size += sprintf(BLS, "\n");
@@ -141,11 +152,6 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
#ifdef AIC7XXX_CMDS_PER_LUN
size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n", AIC7XXX_CMDS_PER_LUN);
#endif
-#ifdef AIC7XXX_TWIN_SUPPORT
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Enabled\n");
-#else
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Disabled\n");
-#endif
#ifdef AIC7XXX_TAGGED_QUEUEING
size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Enabled\n");
#else
@@ -165,16 +171,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " SCSI Adapter: %s\n", board_names[p->type]);
+ size += sprintf(BLS, " SCSI Adapter: %s\n",
+ board_names[p->chip_type]);
size += sprintf(BLS, " (%s chipset)\n",
- chip_names[p->chip_type]);
+ chip_names[p->chip_class]);
size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]);
size += sprintf(BLS, " Base IO: %#.4x\n", p->base);
+ size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase);
size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n",
- p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
+ p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
size += sprintf(BLS, " Interrupts: %d", p->isr_count);
- if (p->chip_type == AIC_777x)
+ if (p->chip_class == AIC_777x)
{
size += sprintf(BLS, " %s\n",
(p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
diff --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
index d26a0c20e..f3b8c349c 100644
--- a/drivers/scsi/aic7xxx_reg.h
+++ b/drivers/scsi/aic7xxx_reg.h
@@ -1,771 +1,469 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
- *
- * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
- *-M*************************************************************************/
-
/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
+ * DO NOT EDIT - This file is automatically generated.
+ */
+
+#define SCSISEQ 0x00
+#define TEMODE 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRSELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
+
+#define SXFRCTL0 0x01
+#define DFON 0x80
+#define DFPEXP 0x40
+#define FAST20 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x08
+#define SCAMEN 0x04
+#define CLRCHN 0x02
+
+#define SXFRCTL1 0x02
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18
+#define ENSTIMER 0x04
+#define ACTNEGEN 0x02
+#define STPWEN 0x01
+
+#define SCSISIGO 0x03
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
+
+#define SCSISIGI 0x03
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
+#define SCSIRATE 0x04
+#define WIDEXFER 0x80
+#define SXFR 0x70
+#define SOFS 0x0f
+
+#define SCSIID 0x05
+#define OID 0x0f
+
+#define SCSIDATL 0x06
+
+#define SCSIDATH 0x07
+
+#define STCNT 0x08
+
+#define CLRSINT0 0x0b
+#define CLRSELDO 0x40
+#define CLRSELDI 0x20
+#define CLRSELINGO 0x10
+#define CLRSWRAP 0x08
+#define CLRSPIORDY 0x02
+
+#define SSTAT0 0x0b
+#define TARGET 0x80
+#define SELDO 0x40
+#define SELDI 0x20
+#define SELINGO 0x10
+#define SWRAP 0x08
+#define SDONE 0x04
+#define SPIORDY 0x02
+#define DMADONE 0x01
+
+#define CLRSINT1 0x0c
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
+
+#define SSTAT1 0x0c
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
+
+#define SSTAT2 0x0d
+#define OVERRUN 0x80
+#define SFCNT 0x1f
+
+#define SSTAT3 0x0e
+#define SCSICNT 0xf0
+#define OFFCNT 0x0f
+
+#define SCSITEST 0x0f
+#define RQAKCNT 0x04
+#define CNTRTEST 0x02
+#define CMODE 0x01
+
+#define SIMODE0 0x10
+#define ENSELDO 0x40
+#define ENSELDI 0x20
+#define ENSELINGO 0x10
+#define ENSWRAP 0x08
+#define ENSDONE 0x04
+#define ENSPIORDY 0x02
+#define ENDMADONE 0x01
+
+#define SIMODE1 0x11
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
+
+#define SCSIBUSL 0x12
+
+#define SCSIBUSH 0x13
+
+#define SHADDR 0x14
+
+#define SELTIMER 0x18
+#define STAGE6 0x20
+#define STAGE5 0x10
+#define STAGE4 0x08
+#define STAGE3 0x04
+#define STAGE2 0x02
+#define STAGE1 0x01
+
+#define SELID 0x19
+#define SELID_MASK 0xf0
+#define ONEBIT 0x08
+
+#define BRDCTL 0x1d
+#define BRDDAT7 0x80
+#define BRDDAT6 0x40
+#define BRDDAT5 0x20
+#define BRDSTB 0x10
+#define BRDCS 0x08
+#define BRDRW 0x04
+#define BRDCTL1 0x02
+#define BRDCTL0 0x01
+
+#define SEECTL 0x1e
+#define EXTARBACK 0x80
+#define EXTARBREQ 0x40
+#define SEEMS 0x20
+#define SEERDY 0x10
+#define SEECS 0x08
+#define SEECK 0x04
+#define SEEDO 0x02
+#define SEEDI 0x01
+
+#define SBLKCTL 0x1f
+#define DIAGLEDEN 0x80
+#define DIAGLEDON 0x40
+#define AUTOFLUSHDIS 0x20
+#define SELWIDE 0x02
+
+#define SRAM_BASE 0x20
+
+#define TARG_SCRATCH 0x20
+
+#define ULTRA_ENB 0x30
+
+#define DISC_DSB 0x32
+
+#define MSG_LEN 0x34
+
+#define MSG_OUT 0x35
+
+#define DMAPARAMS 0x3d
+#define WIDEODD 0x40
+#define SCSIEN 0x20
+#define SDMAENACK 0x10
+#define SDMAEN 0x10
+#define HDMAEN 0x08
+#define HDMAENACK 0x08
+#define DIRECTION 0x04
+#define FIFOFLUSH 0x02
+#define FIFORESET 0x01
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ 0x000
-#define TEMODEO 0x80
-#define ENSELO 0x40
-#define ENSELI 0x20
-#define ENRSELI 0x10
-#define ENAUTOATNO 0x08
-#define ENAUTOATNI 0x04
-#define ENAUTOATNP 0x02
-#define SCSIRSTO 0x01
+#define SCBCOUNT 0x3e
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL0 0x001
-#define DFON 0x80
-#define DFPEXP 0x40
-#define ULTRAEN 0x20
-#define CLRSTCNT 0x10
-#define SPIOEN 0x08
-#define SCAMEN 0x04
-#define CLRCHN 0x02
-/* UNUSED 0x01 */
+#define COMP_SCBCOUNT 0x3f
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL1 0x002
-#define BITBUCKET 0x80
-#define SWRAPEN 0x40
-#define ENSPCHK 0x20
-#define STIMESEL 0x18
-#define ENSTIMER 0x04
-#define ACTNEGEN 0x02
-#define STPWEN 0x01 /* Powered Termination */
+#define QCNTMASK 0x40
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI 0x003
-#define CDI 0x80
-#define IOI 0x40
-#define MSGI 0x20
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
+#define SEQ_FLAGS 0x41
+#define RESELECTED 0x80
+#define IDENTIFY_SEEN 0x40
+#define TAGGED_SCB 0x20
+#define DPHASE 0x10
+#define PAGESCBS 0x04
+#define WIDE_BUS 0x02
+#define TWIN_BUS 0x01
-/*
- * Possible phases in SCSISIGI
- */
-#define PHASE_MASK 0xe0
-#define P_DATAOUT 0x00
-#define P_DATAIN 0x40
-#define P_COMMAND 0x80
-#define P_MESGOUT 0xa0
-#define P_STATUS 0xc0
-#define P_MESGIN 0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus. Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO 0x003
-#define CDO 0x80
-#define IOO 0x40
-#define MSGO 0x20
-#define ATNO 0x10
-#define SELO 0x08
-#define BSYO 0x04
-#define REQO 0x02
-#define ACKO 0x01
-
-/*
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers. Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE 0x004
-#define WIDEXFER 0x80 /* Wide transfer control */
-#define SXFR 0x70 /* Sync transfer rate */
-#define SOFS 0x0f /* Sync offset */
+#define SAVED_TCL 0x42
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID 0x005
-#define TID 0xf0 /* Target ID mask */
-#define OID 0x0f /* Our ID mask */
+#define SG_COUNT 0x43
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode. SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL 0x006
-#define SCSIDATH 0x007
+#define SG_NEXT 0x44
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus. The counter is decremented only once
- * the data has been safely transfered. SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */
-#define STCNT 0x008
-#define STCNT0 0x008
-#define STCNT1 0x009
-#define STCNT2 0x00a
+#define WAITING_SCBH 0x48
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define CLRSINT0 0x00b
-#define CLRSELDO 0x40
-#define CLRSELDI 0x20
-#define CLRSELINGO 0x10
-#define CLRSWRAP 0x08
-/* UNUSED 0x04 */
-#define CLRSPIORDY 0x02
-/* UNUSED 0x01 */
+#define SAVED_LINKPTR 0x49
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0 0x00b
-#define TARGET 0x80 /* Board acting as target */
-#define SELDO 0x40 /* Selection Done */
-#define SELDI 0x20 /* Board has been selected */
-#define SELINGO 0x10 /* Selection In Progress */
-#define SWRAP 0x08 /* 24bit counter wrap */
-#define SDONE 0x04 /* STCNT = 0x000000 */
-#define SPIORDY 0x02 /* SCSI PIO Ready */
-#define DMADONE 0x01 /* DMA transfer completed */
+#define SAVED_SCBPTR 0x4a
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1 0x00c
-#define CLRSELTIMEO 0x80
-#define CLRATNO 0x40
-#define CLRSCSIRSTI 0x20
-/* UNUSED 0x10 */
-#define CLRBUSFREE 0x08
-#define CLRSCSIPERR 0x04
-#define CLRPHASECHG 0x02
-#define CLRREQINIT 0x01
+#define REJBYTE 0x4b
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1 0x00c
-#define SELTO 0x80
-#define ATNTARG 0x40
-#define SCSIRSTI 0x20
-#define PHASEMIS 0x10
-#define BUSFREE 0x08
-#define SCSIPERR 0x04
-#define PHASECHG 0x02
-#define REQINIT 0x01
+#define LASTPHASE 0x4c
+#define P_MESGIN 0xe0
+#define PHASE_MASK 0xe0
+#define P_STATUS 0xc0
+#define P_MESGOUT 0xa0
+#define P_COMMAND 0x80
+#define CDI 0x80
+#define IOI 0x40
+#define P_DATAIN 0x40
+#define MSGI 0x20
+#define P_BUSFREE 0x01
+#define P_DATAOUT 0x00
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define SIMODE1 0x011
-#define ENSELTIMO 0x80
-#define ENATNTARG 0x40
-#define ENSCSIRST 0x20
-#define ENPHASEMIS 0x10
-#define ENBUSFREE 0x08
-#define ENSCSIPERR 0x04
-#define ENPHASECHG 0x02
-#define ENREQINIT 0x01
+#define MSGIN_EXT_LEN 0x4d
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define SCSIBUSL 0x012
-#define SCSIBUSH 0x013
+#define MSGIN_EXT_OPCODE 0x4e
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus. They are counted up in the same
- * manner as STCNT is counted down. SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write ahead.
- */
-#define SHADDR 0x014
-#define SHADDR0 0x014
-#define SHADDR1 0x015
-#define SHADDR2 0x016
-#define SHADDR3 0x017
+#define MSGIN_EXT_BYTES 0x4f
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id. The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID 0x019
-#define SELID_MASK 0xf0
-#define ONEBIT 0x08
-/* UNUSED 0x07 */
+#define DISCONNECTED_SCBH 0x52
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection. In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL 0x01f
-#define DIAGLEDEN 0x80 /* Aic78X0 only */
-#define DIAGLEDON 0x40 /* Aic78X0 only */
-#define AUTOFLUSHDIS 0x20
-/* UNUSED 0x10 */
-#define SELBUS_MASK 0x0a
-#define SELBUSB 0x08
-/* UNUSED 0x04 */
-#define SELWIDE 0x02
-/* UNUSED 0x01 */
-#define SELNARROW 0x00
+#define FREE_SCBH 0x53
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL 0x060
-#define PERRORDIS 0x80
-#define PAUSEDIS 0x40
-#define FAILDIS 0x20
-#define FASTMODE 0x10
-#define BRKADRINTEN 0x08
-#define STEP 0x04
-#define SEQRESET 0x02
-#define LOADRAM 0x01
+#define HSCB_ADDR 0x54
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
- * four bytes in succession. The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM 0x061
+#define CUR_SCBID 0x58
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0 0x062
-#define SEQADDR1 0x063
-#define SEQADDR1_MASK 0x01
+#define ARG_1 0x59
+#define RETURN_1 0x59
+#define SEND_MSG 0x80
+#define SEND_SENSE 0x40
+#define SEND_REJ 0x20
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM 0x064
-
-#define SINDEX 0x065
-#define DINDEX 0x066
-#define ALLZEROS 0x06a
-#define NONE 0x06a
-#define SINDIR 0x06c
-#define DINDIR 0x06d
-#define FUNCTION1 0x06e
+#define SCSICONF 0x5a
+#define RESET_SCSI 0x40
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR 0x088
-#define HADDR0 0x088
-#define HADDR1 0x089
-#define HADDR2 0x08a
-#define HADDR3 0x08b
-
-#define HCNT 0x08c
-#define HCNT0 0x08c
-#define HCNT1 0x08d
-#define HCNT2 0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR 0x090
+#define HOSTCONF 0x5d
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL 0x084
-/* RSVD 0xf0 */
-#define ACE 0x08 /* Support for external processors */
-/* RSVD 0x06 */
-#define ENABLE 0x01
+#define HA_274_BIOSCTRL 0x5f
+#define BIOSMODE 0x30
+#define BIOSDISABLED 0x30
+#define CHANNEL_B_PRIMARY 0x08
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define DSCOMMAND 0x084
-#define CACHETHEN 0x80 /* Cache Threshold enable */
-#define DPARCKEN 0x40 /* Data Parity Check Enable */
-#define MPARCKEN 0x20 /* Memory Parity Check Enable */
-#define EXTREQLCK 0x10 /* External Request Lock */
+#define SEQCTL 0x60
+#define PERRORDIS 0x80
+#define PAUSEDIS 0x40
+#define FAILDIS 0x20
+#define FASTMODE 0x10
+#define BRKADRINTEN 0x08
+#define STEP 0x04
+#define SEQRESET 0x02
+#define LOADRAM 0x01
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME 0x085
-#define BOFF 0xf0
-#define BON 0x0f
+#define SEQRAM 0x61
-/*
- * Bus Speed (p. 3-45)
- */
-#define BUSSPD 0x086
-#define DFTHRSH 0xc0
-#define STBOFF 0x38
-#define STBON 0x07
-#define DFTHRSH_100 0xc0
+#define SEQADDR0 0x62
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL 0x087
-/* UNUSED 0x80 */
-#define POWRDN 0x40
-/* UNUSED 0x20 */
-#define SWINT 0x10
-#define IRQMS 0x08
-#define PAUSE 0x04
-#define INTEN 0x02
-#define CHIPRST 0x01
-#define CHIPRSTACK 0x01
+#define SEQADDR1 0x63
+#define SEQADDR1_MASK 0x01
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT 0x091
-#define SEQINT_MASK 0xf1 /* SEQINT Status Codes */
-#define BAD_PHASE 0x01 /* unknown scsi bus phase */
-#define SEND_REJECT 0x11 /* sending a message reject */
-#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/
-#define NO_MATCH 0x31 /* no cmd match for reconnect */
-#define SDTR_MSG 0x41 /* SDTR message received */
-#define WDTR_MSG 0x51 /* WDTR message received */
-#define REJECT_MSG 0x61 /* Reject message received */
-#define BAD_STATUS 0x71 /* Bad status from target */
-#define RESIDUAL 0x81 /* Residual byte count != 0 */
-#define ABORT_TAG 0x91 /* Sent an ABORT_TAG message */
-#define AWAITING_MSG 0xa1 /*
- * Kernel requested to specify
- * a message to this target
- * (command was null), so tell
- * it that it can fill the
- * message buffer.
- */
-#define IMMEDDONE 0xb1 /*
- * An immediate command has
- * completed
- */
-#define MSG_BUFFER_BUSY 0xc1 /*
- * Sequencer wants to use the
- * message buffer, but it
- * already contains a message
- */
-#define MSGIN_PHASEMIS 0xd1 /*
- * Target changed phase on us
- * when we were expecting
- * another msgin byte.
- */
-#define DATA_OVERRUN 0xe1 /*
- * Target attempted to write
- * beyond the bounds of its
- * command.
- */
-#define BRKADRINT 0x08
-#define SCSIINT 0x04
-#define CMDCMPLT 0x02
-#define SEQINT 0x01
-#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+#define ACCUM 0x64
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors. You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR 0x092
-/* UNUSED 0xf0 */
-#define PARERR 0x08
-#define ILLOPCODE 0x04
-#define ILLSADDR 0x02
-#define ILLHADDR 0x01
+#define SINDEX 0x65
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT 0x092
-#define CLRBRKADRINT 0x08
-#define CLRSCSIINT 0x04
-#define CLRCMDINT 0x02
-#define CLRSEQINT 0x01
-
-#define DFCNTRL 0x093
-#define WIDEODD 0x40
-#define SCSIEN 0x20
-#define SDMAEN 0x10
-#define SDMAENACK 0x10
-#define HDMAEN 0x08
-#define HDMAENACK 0x08
-#define DIRECTION 0x04
-#define FIFOFLUSH 0x02
-#define FIFORESET 0x01
-
-#define DFSTATUS 0x094
-#define HDONE 0x08
-#define FIFOEMP 0x01
-
-#define DFDAT 0x099
+#define DINDEX 0x66
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT 0x09a
-#define SCBAUTO 0x80
-#define SCBCNT_MASK 0x1f
+#define ALLONES 0x69
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the sequencer has yet to start)
- */
-#define QINFIFO 0x09b
+#define ALLZEROS 0x6a
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT 0x09c
+#define NONE 0x6a
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO 0x09d
+#define FLAGS 0x6b
+#define ZERO 0x02
+#define CARRY 0x01
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT 0x09e
+#define SINDIR 0x6c
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR respectively when starting this command.
- */
-#define SCBARRAY 0x0a0
-#define SCB_CONTROL 0x0a0
-#define NEEDWDTR 0x80
-#define DISCENB 0x40
-#define TAG_ENB 0x20
-#define NEEDSDTR 0x10
-#define DISCONNECTED 0x04
-#define SCB_TAG_TYPE 0x03
-#define SCB_TCL 0x0a1
-#define SCB_TARGET_STATUS 0x0a2
-#define SCB_SGCOUNT 0x0a3
-#define SCB_SGPTR 0x0a4
-#define SCB_SGPTR0 0x0a4
-#define SCB_SGPTR1 0x0a5
-#define SCB_SGPTR2 0x0a6
-#define SCB_SGPTR3 0x0a7
-#define SCB_RESID_SGCNT 0x0a8
-#define SCB_RESID_DCNT 0x0a9
-#define SCB_RESID_DCNT0 0x0a9
-#define SCB_RESID_DCNT1 0x0aa
-#define SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR 0x0ac
-#define SCB_DATAPTR0 0x0ac
-#define SCB_DATAPTR1 0x0ad
-#define SCB_DATAPTR2 0x0ae
-#define SCB_DATAPTR3 0x0af
-#define SCB_DATACNT 0x0b0
-#define SCB_DATACNT0 0x0b0
-#define SCB_DATACNT1 0x0b1
-#define SCB_DATACNT2 0x0b2
-/* UNUSED - QUAD PADDING 0x0b3 */
-#define SCB_CMDPTR 0x0b4
-#define SCB_CMDPTR0 0x0b4
-#define SCB_CMDPTR1 0x0b5
-#define SCB_CMDPTR2 0x0b6
-#define SCB_CMDPTR3 0x0b7
-#define SCB_CMDLEN 0x0b8
-#define SCB_TAG 0x0b9
-#define SCB_NEXT 0x0ba
-#define SCB_PREV 0x0bb
-
-#define SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define SEECTL_2840 0x0c0
-/* UNUSED 0xf8 */
-#define CS_2840 0x04
-#define CK_2840 0x02
-#define DO_2840 0x01
-
-#define STATUS_2840 0x0c1
-#define EEPROM_TF 0x80
-#define BIOS_SEL 0x60
-#define ADSEL 0x1e
-#define DI_2840 0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS 0x086
+#define DINDIR 0x6d
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device. In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device. When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM. When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.
- *
- * After successful arbitration for the memory port, the SEECS bit of
- * the SEECTL register is connected to the chip select. The SEECK,
- * SEEDO, and SEEDI are connected to the clock, data out, and data in
- * lines respectively. The SEERDY bit of SEECTL is useful in that it
- * gives us an 800 nsec timer. After a write to the SEECTL register,
- * the SEERDY goes high 800 nsec later. The one exception to this is
- * when we first request access to the memory port. The SEERDY goes
- * high to signify that access has been granted and, for this case, has
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to
- * read the serial EEPROM.
- */
-#define SEECTL 0x01e
-#define EXTARBACK 0x80
-#define EXTARBREQ 0x40
-#define SEEMS 0x20
-#define SEERDY 0x10
-#define SEECS 0x08
-#define SEECK 0x04
-#define SEEDO 0x02
-#define SEEDI 0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE). The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space. This should work regardless of
- * whether the bios has been installed.
- */
+#define FUNCTION1 0x6e
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH 0x020
+#define STACK 0x6f
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away. Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE 0x030
-#define REJBYTE_EXT 0x031
+#define BCTL 0x84
+#define ACE 0x08
+#define ENABLE 0x01
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define DISC_DSB 0x032
-#define DISC_DSB_A 0x032
-#define DISC_DSB_B 0x033
+#define DSCOMMAND 0x84
+#define CACHETHEN 0x80
+#define DPARCKEN 0x40
+#define MPARCKEN 0x20
+#define EXTREQLCK 0x10
-/*
- * Length of pending message
- */
-#define MSG_LEN 0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0 0x035
-#define COMP_MSG0 0xcb /* 2's complement of MSG0 */
-#define MSG1 0x036
-#define MSG2 0x037
-#define MSG3 0x038
-#define MSG4 0x039
-#define MSG5 0x03a
-#define MSG6 0x03b
-#define MSG7 0x03c
+#define BUSTIME 0x85
+#define BOFF 0xf0
+#define BON 0x0f
-/*
- * These are offsets into the card's scratch ram. Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE 0x03d
-#define ARG_1 0x03e
-#define MAXOFFSET 0x01
-#define RETURN_1 0x03f
-#define SEND_WDTR 0x80
-#define SEND_SDTR 0x60
-#define SEND_SENSE 0x40
-#define SEND_REJ 0x20
-#define SCB_PAGEDIN 0x10
-
-#define SIGSTATE 0x040
-
-#define DMAPARAMS 0x041 /* Parameters for DMA Logic */
-
-#define SG_COUNT 0x042
-#define SG_NEXT 0x043 /* working value of SG pointer */
-#define SG_NEXT0 0x043
-#define SG_NEXT1 0x044
-#define SG_NEXT2 0x045
-#define SG_NEXT3 0x046
-
-#define SCBCOUNT 0x047 /*
- * Number of SCBs supported by
- * this card.
- */
-#define COMP_SCBCOUNT 0x048 /*
- * Two's compliment of SCBCOUNT
- */
-#define QCNTMASK 0x049 /*
- * Mask of bits to test against
- * when looking at the Queue Count
- * registers. Works around a bug
- * on aic7850 chips.
- */
-#define FLAGS 0x04a
-#define SINGLE_BUS 0x00
-#define TWIN_BUS 0x01
-#define WIDE_BUS 0x02
-#define PAGESCBS 0x04
-#define DPHASE 0x10
-#define SELECTED 0x20
-#define IDENTIFY_SEEN 0x40
-#define RESELECTED 0x80
-
-#define SAVED_TCL 0x04b /*
- * Temporary storage for the
- * target/channel/lun of a
- * reconnecting target
- */
-#define ACTIVE_A 0x04c
-#define ACTIVE_B 0x04d
-#define WAITING_SCBH 0x04e /*
- * head of list of SCBs awaiting
- * selection
- */
-#define DISCONNECTED_SCBH 0x04f /*
- * head of list of SCBs that are
- * disconnected. Used for SCB
- * paging.
- */
-#define SCB_LIST_NULL 0xff
-
-#define SAVED_LINKPTR 0x050
-#define SAVED_SCBPTR 0x051
-#define ULTRA_ENB 0x052
-#define ULTRA_ENB_B 0x053
-
-#define SCSICONF 0x05a
-#define RESET_SCSI 0x40
-
-#define HOSTCONF 0x05d
-
-#define HA_274_BIOSCTRL 0x05f
-#define BIOSMODE 0x30
-#define BIOSDISABLED 0x30
-#define CHANNEL_B_PRIMARY 0x08
-
-/* Message codes */
-#define MSG_EXTENDED 0x01
-#define MSG_SDTR 0x01
-#define MSG_WDTR 0x03
-#define MSG_SDPTRS 0x02
-#define MSG_RDPTRS 0x03
-#define MSG_DISCONNECT 0x04
-#define MSG_INITIATOR_DET_ERROR 0x05
-#define MSG_ABORT 0x06
-#define MSG_REJECT 0x07
-#define MSG_NOP 0x08
-#define MSG_MSG_PARITY_ERROR 0x09
-#define MSG_BUS_DEVICE_RESET 0x0c
-#define MSG_ABORT_TAG 0x0d
-#define MSG_SIMPLE_TAG 0x20
-#define MSG_IDENTIFY 0x80
-
-/* WDTR Message values */
-#define BUS_8_BIT 0x00
-#define BUS_16_BIT 0x01
-#define BUS_32_BIT 0x02
-
-#define MAX_OFFSET_8BIT 0x0f
-#define MAX_OFFSET_16BIT 0x08
+#define BUSSPD 0x86
+#define DFTHRSH_100 0xc0
+#define DFTHRSH 0xc0
+#define STBOFF 0x38
+#define STBON 0x07
+
+#define DSPCISTATUS 0x86
+
+#define HCNTRL 0x87
+#define POWRDN 0x40
+#define SWINT 0x10
+#define IRQMS 0x08
+#define PAUSE 0x04
+#define INTEN 0x02
+#define CHIPRST 0x01
+#define CHIPRSTACK 0x01
+
+#define HADDR 0x88
+
+#define HCNT 0x8c
+
+#define SCBPTR 0x90
+
+#define INTSTAT 0x91
+#define SEQINT_MASK 0xf1
+#define DATA_OVERRUN 0xe1
+#define MSGIN_PHASEMIS 0xd1
+#define MSG_BUFFER_BUSY 0xc1
+#define AWAITING_MSG 0xa1
+#define ABORT_CMDCMPLT 0x91
+#define RESIDUAL 0x81
+#define BAD_STATUS 0x71
+#define REJECT_MSG 0x61
+#define NO_MATCH_BUSY 0x51
+#define EXTENDED_MSG 0x41
+#define NO_MATCH 0x31
+#define NO_IDENT 0x21
+#define SEND_REJECT 0x11
+#define INT_PEND 0x0f
+#define BRKADRINT 0x08
+#define SCSIINT 0x04
+#define CMDCMPLT 0x02
+#define BAD_PHASE 0x01
+#define SEQINT 0x01
+
+#define CLRINT 0x92
+#define CLRBRKADRINT 0x08
+#define CLRSCSIINT 0x04
+#define CLRCMDINT 0x02
+#define CLRSEQINT 0x01
+
+#define ERROR 0x92
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
+#define DFCNTRL 0x93
+
+#define DFSTATUS 0x94
+#define DWORDEMP 0x20
+#define MREQPEND 0x10
+#define HDONE 0x08
+#define DFTHRESH 0x04
+#define FIFOFULL 0x02
+#define FIFOEMP 0x01
+
+#define DFDAT 0x99
+
+#define SCBCNT 0x9a
+#define SCBAUTO 0x80
+#define SCBCNT_MASK 0x1f
+
+#define QINFIFO 0x9b
+
+#define QINCNT 0x9c
+
+#define QOUTFIFO 0x9d
+
+#define QOUTCNT 0x9e
+
+#define SCB_CONTROL 0xa0
+#define MK_MESSAGE 0x80
+#define DISCENB 0x40
+#define TAG_ENB 0x20
+#define MUST_DMAUP_SCB 0x10
+#define ABORT_SCB 0x08
+#define DISCONNECTED 0x04
+#define SCB_TAG_TYPE 0x03
+
+#define SCB_BASE 0xa0
+
+#define SCB_TCL 0xa1
+#define TID 0xf0
+#define SELBUSB 0x08
+#define LID 0x07
+
+#define SCB_TARGET_STATUS 0xa2
+
+#define SCB_SGCOUNT 0xa3
+
+#define SCB_SGPTR 0xa4
+
+#define SCB_RESID_SGCNT 0xa8
+
+#define SCB_RESID_DCNT 0xa9
+
+#define SCB_DATAPTR 0xac
+
+#define SCB_DATACNT 0xb0
+
+#define SCB_LINKED_NEXT 0xb3
+
+#define SCB_CMDPTR 0xb4
+
+#define SCB_CMDLEN 0xb8
+
+#define SCB_TAG 0xb9
+
+#define SCB_NEXT 0xba
+
+#define SCB_PREV 0xbb
+
+#define SCB_BUSYTARGETS 0xbc
+
+#define SEECTL_2840 0xc0
+#define CS_2840 0x04
+#define CK_2840 0x02
+#define DO_2840 0x01
+
+#define STATUS_2840 0xc1
+#define EEPROM_TF 0x80
+#define BIOS_SEL 0x60
+#define ADSEL 0x1e
+#define DI_2840 0x01
+
+
+#define BUS_8_BIT 0x00
+#define MAX_OFFSET_8BIT 0x0f
+#define BUS_16_BIT 0x01
+#define MAX_OFFSET_16BIT 0x08
+#define SCB_LIST_NULL 0xff
+#define SG_SIZEOF 0x08
+#define BUS_32_BIT 0x02
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 15dfb01f1..50ce159a2 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -90,6 +90,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/nvram.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -596,20 +597,6 @@ int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
#endif
-#define RTC_READ(reg) \
- ({ unsigned char __val; \
- outb(reg,&tt_rtc.regsel); \
- __val = tt_rtc.data; \
- __val; \
- })
-
-#define RTC_WRITE(reg,val) \
- do { \
- outb(reg,&tt_rtc.regsel); \
- tt_rtc.data = (val); \
- } while(0)
-
-
int atari_scsi_detect (Scsi_Host_Template *host)
{
static int called = 0;
@@ -645,20 +632,11 @@ int atari_scsi_detect (Scsi_Host_Template *host)
/* use 7 as default */
host->this_id = 7;
/* Test if a host id is set in the NVRam */
- if (ATARIHW_PRESENT(TT_CLK)) {
- unsigned char sum = 0, b;
- int i;
-
- /* Make checksum */
- for( i = 14; i < 62; ++i )
- sum += RTC_READ(i);
-
- if (/* NV-Ram checksum valid? */
- RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
- /* Arbitration enabled? (for TOS) */
- (b = RTC_READ( 30 )) & 0x80) {
+ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+ unsigned char b = nvram_read_byte( 14 );
+ /* Arbitration enabled? (for TOS) If yes, use configured host ID */
+ if (b & 0x80)
host->this_id = b & 7;
- }
}
}
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index cba391414..e69de29bb 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -1,41 +0,0 @@
-/*
- * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
- */
-#ifndef _EATA_H
-#define _EATA_H
-
-#include <scsi/scsicam.h>
-
-int eata2x_detect(Scsi_Host_Template *);
-int eata2x_release(struct Scsi_Host *);
-int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata2x_abort(Scsi_Cmnd *);
-int eata2x_reset(Scsi_Cmnd *, unsigned int);
-
-#define EATA_VERSION "3.10.00"
-
-
-#define EATA { \
- NULL, /* Ptr for modules */ \
- NULL, /* usage count for modules */ \
- NULL, \
- NULL, \
- "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
- eata2x_detect, \
- eata2x_release, \
- NULL, \
- NULL, \
- eata2x_queuecommand, \
- eata2x_abort, \
- eata2x_reset, \
- NULL, \
- scsicam_bios_param, \
- 0, /* can_queue, reset by detect */ \
- 7, /* this_id, reset by detect */ \
- 0, /* sg_tablesize, reset by detect */ \
- 0, /* cmd_per_lun, reset by detect */ \
- 0, /* number of boards present */ \
- 1, /* unchecked isa dma, reset by detect */ \
- ENABLE_CLUSTERING \
- }
-#endif
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 0380ff99a..b479cc9fc 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1705,7 +1705,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
* the nexus and tell the device to abort. However, we really
* cannot 'reconnect' per se, therefore we tell the upper layer
* the safest thing we can. This is, wait a bit, if nothing
- * happens, we are really hung so reset the bug.
+ * happens, we are really hung so reset the bus.
*/
return SCSI_ABORT_SNOOZE;
@@ -1743,11 +1743,10 @@ static void esp_done(struct Sparc_ESP *esp, int error)
done_SC->request_bufflen,
esp->edev->my_bus);
} else {
- struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
#ifdef DEBUG_ESP_SG
printk("esp%d: unmapping sg ", esp->esp_id);
#endif
- mmu_release_scsi_sgl((struct mmu_sglist *) scl,
+ mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
done_SC->use_sg - 1,
esp->edev->my_bus);
#ifdef DEBUG_ESP_SG
@@ -2010,7 +2009,7 @@ static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
if(sz > 0x1000000)
sz = 0x1000000;
} else {
- base = ((__u32)sp->SCp.ptr);
+ base = ((__u32)((unsigned long)sp->SCp.ptr));
base &= (0x1000000 - 1);
end = (base + sp->SCp.this_residual);
if(end > 0x1000000)
@@ -2280,11 +2279,12 @@ static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *ereg
tmp |= DMA_ST_WRITE;
else
tmp &= ~(DMA_ST_WRITE);
- dregs->st_addr = ((__u32)SCptr->SCp.ptr);
+ dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
dregs->cond_reg = tmp;
} else {
esp_setcount(eregs, hmuch, 0);
- dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
+ dma_setup(dregs, esp->dma->revision,
+ ((__u32)((unsigned long)SCptr->SCp.ptr)),
hmuch, (thisphase == in_datain));
ESPDATA(("DMA|TI --> do_intr_end\n"));
esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -4059,8 +4059,12 @@ repeat:
}
#else
+/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
#ifdef __sparc_v9__
-#error Dave you need to fix some things first...
+extern unsigned char ino_to_pil[];
+#define INO_TO_PIL(esp) (ino_to_pil[(esp)->irq])
+#else
+#define INO_TO_PIL(esp) ((esp)->irq & 0xf)
#endif
/* For SMP we only service one ESP on the list list at our IRQ level! */
@@ -4070,7 +4074,7 @@ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
/* Handle all ESP interrupts showing at this IRQ level. */
for_each_esp(esp) {
- if((esp->irq & 0xf) == irq) {
+ if(INO_TO_PIL(esp) == irq) {
if(DMA_IRQ_P(esp->dregs)) {
DMA_INTSOFF(esp->dregs);
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index e9bdcee9b..c28958703 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -144,7 +144,7 @@ static char *PPA_MODE_STRING[] =
"Unknown"};
typedef struct {
- struct ppd *dev; /* Parport device entry */
+ struct pardevice *dev; /* Parport device entry */
int speed; /* General PPA delay constant */
int speed_fast; /* Const for nibble/byte modes */
int epp_speed; /* Reset time period */
@@ -210,22 +210,22 @@ static int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */
#define w_fifo(x,y) outb(y, PPA_BASE(x)+0x400)
#define w_ecr(x,y) outb(y, PPA_BASE(x)+0x402)
-int ppa_wakeup(void *ref)
+static void ppa_wakeup(void *ref)
{
ppa_struct *ppa_dev = (ppa_struct *) ref;
if (!ppa_dev->ppa_wait_q)
- return 1; /* Wake up whom ? */
+ return; /* Wake up whom ? */
/* Claim the Parport */
if (parport_claim(ppa_dev->dev))
- return 1; /* Shouldn't happen */
+ return; /* Shouldn't happen */
wake_up(&ppa_dev->ppa_wait_q);
- return 0;
+ return;
}
-int ppa_release(struct Scsi_Host *host)
+static int ppa_release(struct Scsi_Host *host)
{
int host_no = host->unique_id;
@@ -1137,7 +1137,7 @@ int ppa_detect(Scsi_Host_Template * host)
int modes = pb->modes;
/* We only understand PC-style ports */
- if (modes & PARPORT_MODE_SPP) {
+ if (modes & PARPORT_MODE_PCSPP) {
/* transfer global values here */
if (ppa_speed >= 0)
@@ -1156,16 +1156,16 @@ int ppa_detect(Scsi_Host_Template * host)
w_ctr(i, 0x0c);
ppa_hosts[i].mode = PPA_NIBBLE;
- if (modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) {
+ if (modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP)) {
ppa_hosts[i].mode = PPA_EPP_32;
- printk("PPA: Parport [ EPP ]\n");
- } else if (modes & PARPORT_MODE_ECP) {
+ printk("PPA: Parport [ PCEPP ]\n");
+ } else if (modes & PARPORT_MODE_PCECP) {
w_ecr(i, 0x20);
ppa_hosts[i].mode = PPA_PS2;
- printk("PPA: Parport [ ECP in PS2 submode ]\n");
- } else if (modes & PARPORT_MODE_PS2) {
+ printk("PPA: Parport [ PCECP in PS2 submode ]\n");
+ } else if (modes & PARPORT_MODE_PCPS2) {
ppa_hosts[i].mode = PPA_PS2;
- printk("PPA: Parport [ PS2 ]\n");
+ printk("PPA: Parport [ PCPS2 ]\n");
}
/* Done configuration */
ppa_pb_release(i);
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 84fa2dec8..cdc2fdaa6 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -52,7 +52,7 @@ int ppa_abort(Scsi_Cmnd *);
int ppa_reset(Scsi_Cmnd *, unsigned int);
int ppa_proc_info(char *, char **, off_t, int, int, int);
int ppa_biosparam(Disk *, kdev_t, int*);
-int ppa_release(struct Scsi_Host *);
+static int ppa_release(struct Scsi_Host *);
#ifndef MODULE
#ifdef PPA_CODE
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index daf1b8fce..210bffec3 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -19,6 +19,9 @@
/* This is the system graphics console (the first adapter found) */
struct console_ops *gconsole = 0;
+/* To make psaux code cleaner */
+int aux_device_present = 0xaa;
+
void
register_gconsole (struct console_ops *gc)
{
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index f2bb6c339..c57158195 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -58,13 +58,15 @@ static inline int copy_from_user(void *dst, void *src, unsigned long len)
#endif
#ifdef DEBUG
-#define DPRINTK(D) printk D;
+#define DPRINTK(D) (printk D)
#else
-#define DPRINTK(D)
+#define DPRINTK(D) ((void)0)
#endif
#define AUTOFS_SUPER_MAGIC 0x0187
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* Time before asking the daemon again */
+
/* Structures associated with the root directory hash */
#define AUTOFS_HASH_SIZE 67
diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c
index 61900c481..59a30b0e8 100644
--- a/fs/autofs/dir.c
+++ b/fs/autofs/dir.c
@@ -44,16 +44,20 @@ static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
}
static struct file_operations autofs_dir_operations = {
- NULL, /* lseek */
+ NULL, /* llseek */
NULL, /* read */
NULL, /* write */
autofs_dir_readdir, /* readdir */
- NULL, /* select */
+ NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* release */
- NULL /* fsync */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations autofs_dir_inode_operations = {
@@ -68,10 +72,14 @@ struct inode_operations autofs_dir_inode_operations = {
NULL, /* mknod */
NULL, /* rename */
NULL, /* readlink */
- NULL, /* read_page */
+ NULL, /* follow_link */
+ NULL, /* readpage */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index 870ff120d..9422237d5 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -172,27 +172,27 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
unlock_super(s);
s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
if (!s->s_root) {
- s->s_dev = 0;
- kfree(sbi);
printk("autofs: get root inode failed\n");
+ kfree(sbi);
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+ printk("autofs: called with bogus options\n");
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
- printk("autofs: called with bogus options\n");
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+ printk("autofs: kernel does not match daemon version\n");
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
- printk("autofs: kernel does not match daemon version\n");
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
@@ -207,8 +207,8 @@ struct super_block *autofs_read_super(struct super_block *s, void *data,
printk("autofs: could not open pipe file descriptor\n");
}
dput(s->s_root);
- s->s_dev = 0;
kfree(sbi);
+ s->s_dev = 0;
MOD_DEC_USE_COUNT;
return NULL;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 4ecc6520e..c09bc669e 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -24,16 +24,20 @@ static int autofs_root_mkdir(struct inode *,struct dentry *,int);
static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long);
static struct file_operations autofs_root_operations = {
- NULL, /* lseek */
+ NULL, /* llseek */
NULL, /* read */
NULL, /* write */
autofs_root_readdir, /* readdir */
- NULL, /* select */
+ NULL, /* poll */
autofs_root_ioctl, /* ioctl */
NULL, /* mmap */
NULL, /* open */
NULL, /* release */
- NULL /* fsync */
+ NULL, /* fsync */
+ NULL, /* fasync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
struct inode_operations autofs_root_inode_operations = {
@@ -53,7 +57,10 @@ struct inode_operations autofs_root_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
static int autofs_root_readdir(struct inode *inode, struct file *filp,
@@ -97,24 +104,31 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
{
struct inode * inode;
struct autofs_dir_ent *ent;
-
+
while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
int status = autofs_wait(sbi, &dentry->d_name);
/* Turn this into a real negative dentry? */
if (status == -ENOENT) {
- dentry->d_flags = 0;
- return 0;
+ dentry->d_time = jiffies + AUTOFS_NEGATIVE_TIMEOUT;
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
+ } else if (status) {
+ /* Return a negative dentry, but leave it "pending" */
+ return 1;
}
- if (status)
- return status;
}
+ /* Abuse this field as a pointer to the directory entry, used to
+ find the expire list pointers */
+ dentry->d_time = (unsigned long) ent;
+
if (!dentry->d_inode) {
inode = iget(sb, ent->ino);
- if (!inode)
- return -EACCES;
-
+ if (!inode) {
+ /* Failed, but leave pending for next time */
+ return 1;
+ }
dentry->d_inode = inode;
}
@@ -122,8 +136,11 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
while (dentry == dentry->d_mounts)
schedule();
}
- dentry->d_flags = 0;
- return 0;
+
+ autofs_update_usage(&sbi->dirhash,ent);
+
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ return 1;
}
@@ -133,28 +150,30 @@ static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, s
* yet completely filled in, and revalidate has to delay such
* lookups..
*/
-static struct dentry * autofs_revalidate(struct dentry * dentry)
+static int autofs_revalidate(struct dentry * dentry)
{
struct autofs_sb_info *sbi;
struct inode * dir = dentry->d_parent->d_inode;
+ struct autofs_dir_ent *ent;
sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp;
- /* Incomplete dentry? */
- if (dentry->d_flags) {
+ /* Pending dentry */
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
if (autofs_oz_mode(sbi))
- return dentry;
+ return 1;
- try_to_fill_dentry(dentry, dir->i_sb, sbi);
- return dentry;
+ return try_to_fill_dentry(dentry, dir->i_sb, sbi);
}
- /* Negative dentry.. Should we time these out? */
+ /* Negative dentry.. invalidate if "old" */
if (!dentry->d_inode)
- return dentry;
+ return (dentry->d_time - jiffies <= AUTOFS_NEGATIVE_TIMEOUT);
- /* We should update the usage stuff here.. */
- return dentry;
+ /* Update the usage list */
+ ent = (struct autofs_dir_ent *) dentry->d_time;
+ autofs_update_usage(&sbi->dirhash,ent);
+ return 1;
}
static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
@@ -186,12 +205,13 @@ static int autofs_root_lookup(struct inode *dir, struct dentry * dentry)
* We need to do this before we release the directory semaphore.
*/
dentry->d_revalidate = autofs_revalidate;
- dentry->d_flags = 1;
+ dentry->d_flags |= DCACHE_AUTOFS_PENDING;
d_add(dentry, NULL);
up(&dir->i_sem);
autofs_revalidate(dentry);
down(&dir->i_sem);
+
return 0;
}
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index e3ff3d31b..b42955feb 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -51,5 +51,8 @@ struct inode_operations autofs_symlink_inode_operations = {
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index c5c7998cf..29956edda 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -212,7 +212,6 @@ do_aout_core_dump(long signr, struct pt_regs * regs)
close_coredump:
if (file.f_op->release)
file.f_op->release(inode,&file);
-done_coredump:
put_write_access(inode);
end_coredump:
set_fs(fs);
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index ffca300d9..22d928648 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -69,6 +69,7 @@ static struct proc_dir_entry *bm_dir = NULL;
static struct binfmt_entry *entries = NULL;
static int free_id = 1;
static int enabled = 1;
+
static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
diff --git a/fs/buffer.c b/fs/buffer.c
index 3e1b5cc35..cb4ec5eef 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -49,8 +49,9 @@ static char buffersize_index[17] =
#define BUFSIZE_INDEX(X) ((int) buffersize_index[(X)>>9])
#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512)
-#define MAX_UNUSED_BUFFERS 30 /* don't ever have more than this number of
- unused buffer heads */
+#define NR_RESERVED (2*MAX_BUF_PER_PAGE)
+#define MAX_UNUSED_BUFFERS NR_RESERVED+20 /* don't ever have more than this
+ number of unused buffer heads */
#define HASH_PAGES 4 /* number of pages to use for the hash table */
#define HASH_PAGES_ORDER 2
#define NR_HASH (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *))
@@ -560,6 +561,7 @@ struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
if (!bh)
return NULL;
bh->b_count++;
+ bh->b_lru_time = jiffies;
wait_on_buffer(bh);
if (bh->b_dev == dev &&
bh->b_blocknr == block &&
@@ -642,34 +644,20 @@ void set_blocksize(kdev_t dev, int size)
}
}
-/* Check if a buffer is OK to be reclaimed. */
-static inline int can_reclaim(struct buffer_head *bh, int size)
-{
- if (bh->b_count ||
- buffer_protected(bh) ||
- buffer_locked(bh))
- return 0;
-
- if (buffer_dirty(bh)) {
- refile_buffer(bh);
- return 0;
- }
-
- if (bh->b_size != size)
- return 0;
-
- return 1;
-}
-
-/* Find a candidate buffer to be reclaimed. */
-static struct buffer_head *find_candidate(struct buffer_head *list,
+/*
+ * Find a candidate buffer to be reclaimed.
+ * N.B. Must search the entire BUF_LOCKED list rather than terminating
+ * when the first locked buffer is found. Buffers are unlocked at
+ * completion of IO, and under some conditions there may be (many)
+ * unlocked buffers after the first locked one.
+ */
+static struct buffer_head *find_candidate(struct buffer_head *bh,
int *list_len, int size)
{
- struct buffer_head *bh;
-
- for (bh = list;
- bh && (*list_len) > 0;
- bh = bh->b_next_free, (*list_len)--) {
+ if (!bh)
+ goto no_candidate;
+
+ for (; (*list_len) > 0; bh = bh->b_next_free, (*list_len)--) {
if (size != bh->b_size) {
/* This provides a mechanism for freeing blocks
* of other sizes, this is necessary now that we
@@ -680,110 +668,144 @@ static struct buffer_head *find_candidate(struct buffer_head *list,
break;
continue;
}
-
- if (buffer_locked(bh) && bh->b_list == BUF_LOCKED) {
- /* Buffers are written in the order they are placed
- * on the locked list. If we encounter a locked
- * buffer here, this means that the rest of them
- * are also locked.
- */
- (*list_len) = 0;
- return NULL;
- }
-
- if (can_reclaim(bh,size))
- return bh;
+ else if (!bh->b_count &&
+ !buffer_locked(bh) &&
+ !buffer_protected(bh) &&
+ !buffer_dirty(bh))
+ return bh;
}
+no_candidate:
return NULL;
}
static void refill_freelist(int size)
{
- struct buffer_head * bh;
+ struct buffer_head * bh, * next;
struct buffer_head * candidate[BUF_DIRTY];
- unsigned int best_time, winner;
int buffers[BUF_DIRTY];
int i;
- int needed;
+ int needed, obtained=0;
refilled = 1;
- /* If there are too many dirty buffers, we wake up the update process
- * now so as to ensure that there are still clean buffers available
- * for user processes to use (and dirty).
- */
/* We are going to try to locate this much memory. */
needed = bdf_prm.b_un.nrefill * size;
- while ((nr_free_pages > min_free_pages*2) &&
- (needed > 0) &&
- grow_buffers(GFP_BUFFER, size))
- needed -= PAGE_SIZE;
+ while ((nr_free_pages > min_free_pages*2) &&
+ grow_buffers(GFP_BUFFER, size)) {
+ obtained += PAGE_SIZE;
+ if (obtained >= needed)
+ return;
+ }
+
+ /*
+ * Update the needed amount based on the number of potentially
+ * freeable buffers. We don't want to free more than one quarter
+ * of the available buffers.
+ */
+ i = (nr_buffers_type[BUF_CLEAN] + nr_buffers_type[BUF_LOCKED]) >> 2;
+ if (i < bdf_prm.b_un.nrefill) {
+ needed = i * size;
+ if (needed < PAGE_SIZE)
+ needed = PAGE_SIZE;
+ }
+ /*
+ * OK, we cannot grow the buffer cache, now try to get some
+ * from the lru list.
+ */
repeat:
- if(needed <= 0)
+ if (obtained >= needed)
return;
- /* OK, we cannot grow the buffer cache, now try to get some
- * from the lru list.
- *
+ /*
* First set the candidate pointers to usable buffers. This
- * should be quick nearly all of the time.
+ * should be quick nearly all of the time. N.B. There must be
+ * no blocking calls after setting up the candidate[] array!
*/
-
- for(i=0; i<BUF_DIRTY; i++) {
+ for (i = BUF_CLEAN; i<BUF_DIRTY; i++) {
buffers[i] = nr_buffers_type[i];
candidate[i] = find_candidate(lru_list[i], &buffers[i], size);
}
- /* Now see which candidate wins the election. */
-
- winner = best_time = UINT_MAX;
- for(i=0; i<BUF_DIRTY; i++) {
- if(!candidate[i])
- continue;
- if(candidate[i]->b_lru_time < best_time) {
- best_time = candidate[i]->b_lru_time;
- winner = i;
- }
- }
-
- /* If we have a winner, use it, and then get a new candidate from that list. */
- if(winner != UINT_MAX) {
- i = winner;
- while (needed>0 && (bh=candidate[i])) {
- candidate[i] = bh->b_next_free;
- if(candidate[i] == bh)
- candidate[i] = NULL; /* Got last one */
- remove_from_queues(bh);
- bh->b_dev = B_FREE;
- put_last_free(bh);
- needed -= bh->b_size;
- buffers[i]--;
- if(buffers[i] == 0)
- candidate[i] = NULL;
-
- if (candidate[i] && !can_reclaim(candidate[i],size))
- candidate[i] = find_candidate(candidate[i],
- &buffers[i], size);
+ /*
+ * Select the older of the available buffers until we reach our goal.
+ */
+ for (;;) {
+ i = BUF_CLEAN;
+ if (!candidate[BUF_CLEAN]) {
+ if (!candidate[BUF_LOCKED])
+ break;
+ i = BUF_LOCKED;
}
- goto repeat;
- }
+ else if (candidate[BUF_LOCKED] &&
+ (candidate[BUF_LOCKED]->b_lru_time <
+ candidate[BUF_CLEAN ]->b_lru_time))
+ i = BUF_LOCKED;
+ /*
+ * Free the selected buffer and get the next candidate.
+ */
+ bh = candidate[i];
+ next = bh->b_next_free;
+
+ obtained += bh->b_size;
+ remove_from_queues(bh);
+ put_last_free(bh);
+ if (obtained >= needed)
+ return;
+
+ if (--buffers[i] && bh != next)
+ candidate[i] = find_candidate(next, &buffers[i], size);
+ else
+ candidate[i] = NULL;
+ }
+
+ /*
+ * If we achieved at least half of our goal, return now.
+ */
+ if (obtained >= (needed >> 1))
+ return;
/* Too bad, that was not enough. Try a little harder to grow some. */
if (nr_free_pages > min_free_pages + 5) {
if (grow_buffers(GFP_BUFFER, size)) {
- needed -= PAGE_SIZE;
+ obtained += PAGE_SIZE;
goto repeat;
}
}
-
- /* And repeat until we find something good. */
+
+ /*
+ * Make one more attempt to allocate some buffers.
+ */
if (grow_buffers(GFP_ATOMIC, size))
- needed -= PAGE_SIZE;
- else
- wakeup_bdflush(1);
+ obtained += PAGE_SIZE;
+
+ /*
+ * If we got any buffers, or another task freed some,
+ * return now to let this task proceed.
+ */
+ if (obtained || free_list[BUFSIZE_INDEX(size)]) {
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: obtained %d of %d, free list=%d\n",
+obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL);
+#endif
+ return;
+ }
+
+ /*
+ * System is _very_ low on memory ... wake up bdflush and wait.
+ */
+#ifdef BUFFER_DEBUG
+printk("refill_freelist: waking bdflush\n");
+#endif
+ wakeup_bdflush(1);
+ /*
+ * While we slept, other tasks may have needed buffers and entered
+ * refill_freelist. This could be a big problem ... reset the
+ * needed amount to the absolute minimum.
+ */
+ needed = size;
goto repeat;
}
@@ -831,6 +853,8 @@ repeat:
* and that it's unused (b_count=0), unlocked (buffer_locked=0), and clean.
*/
bh->b_count=1;
+ bh->b_list = BUF_CLEAN;
+ bh->b_lru_time = jiffies;
bh->b_flushtime=0;
bh->b_state=(1<<BH_Touched);
bh->b_dev=dev;
@@ -856,6 +880,16 @@ void set_writetime(struct buffer_head * buf, int flag)
/*
+ * Put a buffer into the appropriate list, without side-effects.
+ */
+static inline void file_buffer(struct buffer_head *bh, int list)
+{
+ remove_from_queues(bh);
+ bh->b_list = list;
+ insert_into_queues(bh);
+}
+
+/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
*/
@@ -873,15 +907,9 @@ void refile_buffer(struct buffer_head * buf)
dispose = BUF_LOCKED;
else
dispose = BUF_CLEAN;
- if(dispose == BUF_CLEAN)
- buf->b_lru_time = jiffies;
if(dispose != buf->b_list) {
- if(dispose == BUF_DIRTY)
- buf->b_lru_time = jiffies;
- remove_from_queues(buf);
- buf->b_list = dispose;
- insert_into_queues(buf);
- if (dispose == BUF_DIRTY) {
+ file_buffer(buf, dispose);
+ if(dispose == BUF_DIRTY) {
int too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
/* This buffer is dirty, maybe we need to start flushing.
@@ -1034,34 +1062,11 @@ static void put_unused_buffer_head(struct buffer_head * bh)
nr_unused_buffer_heads++;
bh->b_next_free = unused_list;
unused_list = bh;
+ if (!waitqueue_active(&buffer_wait))
+ return;
wake_up(&buffer_wait);
}
-static void get_more_buffer_heads(void)
-{
- struct buffer_head * bh;
-
- while (!unused_list) {
- /* This is critical. We can't swap out pages to get
- * more buffer heads, because the swap-out may need
- * more buffer-heads itself. Thus SLAB_ATOMIC.
- */
- if((bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC)) != NULL) {
- put_unused_buffer_head(bh);
- nr_buffer_heads++;
- return;
- }
-
- /* Uhhuh. We're _really_ low on memory. Now we just
- * wait for old buffer heads to become free due to
- * finishing IO..
- */
- run_task_queue(&tq_disk);
- sleep_on(&buffer_wait);
- }
-
-}
-
/*
* We can't put completed temporary IO buffer_heads directly onto the
* unused_list when they become unlocked, since the device driver
@@ -1083,18 +1088,59 @@ static inline void recover_reusable_buffer_heads(void)
}
}
-static struct buffer_head * get_unused_buffer_head(void)
+/*
+ * Reserve NR_RESERVED buffer heads for async IO requests to avoid
+ * no-buffer-head deadlock. Return NULL on failure; waiting for
+ * buffer heads is now handled in create_buffers().
+ */
+static struct buffer_head * get_unused_buffer_head(int async)
{
struct buffer_head * bh;
recover_reusable_buffer_heads();
- get_more_buffer_heads();
- if (!unused_list)
- return NULL;
- bh = unused_list;
- unused_list = bh->b_next_free;
- nr_unused_buffer_heads--;
- return bh;
+ if (nr_unused_buffer_heads > NR_RESERVED) {
+ bh = unused_list;
+ unused_list = bh->b_next_free;
+ nr_unused_buffer_heads--;
+ return bh;
+ }
+
+ /* This is critical. We can't swap out pages to get
+ * more buffer heads, because the swap-out may need
+ * more buffer-heads itself. Thus SLAB_ATOMIC.
+ */
+ if((bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC)) != NULL) {
+ memset(bh, 0, sizeof(*bh));
+ nr_buffer_heads++;
+ return bh;
+ }
+
+ /*
+ * If we need an async buffer, use the reserved buffer heads.
+ */
+ if (async && unused_list) {
+ bh = unused_list;
+ unused_list = bh->b_next_free;
+ nr_unused_buffer_heads--;
+ return bh;
+ }
+
+#if 0
+ /*
+ * (Pending further analysis ...)
+ * Ordinary (non-async) requests can use a different memory priority
+ * to free up pages. Any swapping thus generated will use async
+ * buffer heads.
+ */
+ if(!async &&
+ (bh = kmem_cache_alloc(bh_cachep, SLAB_KERNEL)) != NULL) {
+ memset(bh, 0, sizeof(*bh));
+ nr_buffer_heads++;
+ return bh;
+ }
+#endif
+
+ return NULL;
}
/*
@@ -1102,16 +1148,22 @@ static struct buffer_head * get_unused_buffer_head(void)
* the size of each buffer.. Use the bh->b_this_page linked list to
* follow the buffers created. Return NULL if unable to create more
* buffers.
+ * The async flag is used to differentiate async IO (paging, swapping)
+ * from ordinary buffer allocations, and only async requests are allowed
+ * to sleep waiting for buffer heads.
*/
-static struct buffer_head * create_buffers(unsigned long page, unsigned long size)
+static struct buffer_head * create_buffers(unsigned long page,
+ unsigned long size, int async)
{
+ struct wait_queue wait = { current, NULL };
struct buffer_head *bh, *head;
long offset;
+try_again:
head = NULL;
offset = PAGE_SIZE;
while ((offset -= size) >= 0) {
- bh = get_unused_buffer_head();
+ bh = get_unused_buffer_head(async);
if (!bh)
goto no_grow;
@@ -1138,7 +1190,35 @@ no_grow:
bh = bh->b_this_page;
put_unused_buffer_head(head);
}
- return NULL;
+
+ /*
+ * Return failure for non-async IO requests. Async IO requests
+ * are not allowed to fail, so we have to wait until buffer heads
+ * become available. But we don't want tasks sleeping with
+ * partially complete buffers, so all were released above.
+ */
+ if (!async)
+ return NULL;
+
+ /* Uhhuh. We're _really_ low on memory. Now we just
+ * wait for old buffer heads to become free due to
+ * finishing IO. Since this is an async request and
+ * the reserve list is empty, we're sure there are
+ * async buffer heads in use.
+ */
+ run_task_queue(&tq_disk);
+
+ /*
+ * Set our state for sleeping, then check again for buffer heads.
+ * This ensures we won't miss a wake_up from an interrupt.
+ */
+ add_wait_queue(&buffer_wait, &wait);
+ current->state = TASK_UNINTERRUPTIBLE;
+ recover_reusable_buffer_heads();
+ schedule();
+ remove_wait_queue(&buffer_wait, &wait);
+ current->state = TASK_RUNNING;
+ goto try_again;
}
/* Run the hooks that have to be done when a page I/O has completed. */
@@ -1189,12 +1269,13 @@ int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
clear_bit(PG_uptodate, &page->flags);
clear_bit(PG_error, &page->flags);
/*
- * Allocate buffer heads pointing to this page, just for I/O.
+ * Allocate async buffer heads pointing to this page, just for I/O.
* They do _not_ show up in the buffer hash table!
* They are _not_ registered in page->buffers either!
*/
- bh = create_buffers(page_address(page), size);
+ bh = create_buffers(page_address(page), size, 1);
if (!bh) {
+ /* WSH: exit here leaves page->count incremented */
clear_bit(PG_locked, &page->flags);
wake_up(&page->wait);
return -ENOMEM;
@@ -1405,16 +1486,15 @@ static int grow_buffers(int pri, int size)
return 0;
}
- isize = BUFSIZE_INDEX(size);
-
if (!(page = __get_free_page(pri)))
return 0;
- bh = create_buffers(page, size);
+ bh = create_buffers(page, size, 0);
if (!bh) {
free_page(page);
return 0;
}
+ isize = BUFSIZE_INDEX(size);
insert_point = free_list[isize];
tmp = bh;
@@ -1554,6 +1634,18 @@ void buffer_init(void)
SLAB_HWCACHE_ALIGN, NULL, NULL);
if(!bh_cachep)
panic("Cannot create buffer head SLAB cache\n");
+ /*
+ * Allocate the reserved buffer heads.
+ */
+ while (nr_buffer_heads < NR_RESERVED) {
+ struct buffer_head * bh;
+
+ bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC);
+ if (!bh)
+ break;
+ put_unused_buffer_head(bh);
+ nr_buffer_heads++;
+ }
lru_list[BUF_CLEAN] = 0;
grow_buffers(GFP_KERNEL, BLOCK_SIZE);
diff --git a/fs/dcache.c b/fs/dcache.c
index 97937822f..6e742ca7f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -353,27 +353,43 @@ void d_move(struct dentry * dentry, struct dentry * newdir, struct qstr * newnam
dentry->d_parent = newdir;
d_insert_to_parent(dentry, newdir);
}
-
/*
- * This is broken in more ways than one. Unchecked recursion,
- * unchecked buffer size. Get rid of it.
+ * "buflen" should be PAGE_SIZE or more.
*/
-int d_path(struct dentry * entry, struct dentry * chroot, char * buf)
+char * d_path(struct dentry *dentry, char *buffer, int buflen)
{
- if (IS_ROOT(entry) || (chroot && entry == chroot)) {
- *buf = '/';
- return 1;
- } else {
- int len = d_path(entry->d_covers->d_parent, chroot, buf);
-
- buf += len;
- if (len > 1) {
- *buf++ = '/';
- len++;
- }
- memcpy(buf, entry->d_name.name, entry->d_name.len);
- return len + entry->d_name.len;
+ char * end = buffer+buflen;
+ char * retval;
+ struct dentry * root = current->fs->root;
+
+ *--end = '\0';
+ buflen--;
+
+ /* Get '/' right */
+ retval = end-1;
+ *retval = '/';
+
+ for (;;) {
+ struct dentry * parent;
+ int namelen;
+
+ if (dentry == root)
+ break;
+ dentry = dentry->d_covers;
+ parent = dentry->d_parent;
+ if (dentry == parent)
+ break;
+ namelen = dentry->d_name.len;
+ buflen -= namelen + 1;
+ if (buflen < 0)
+ break;
+ end -= namelen;
+ memcpy(end, dentry->d_name.name, namelen);
+ *--end = '/';
+ retval = end;
+ dentry = parent;
}
+ return retval;
}
__initfunc(void dcache_init(void))
diff --git a/fs/devices.c b/fs/devices.c
index 26f668e7f..db6c64d7f 100644
--- a/fs/devices.c
+++ b/fs/devices.c
@@ -210,7 +210,9 @@ int check_disk_change(kdev_t dev)
printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
kdevname(dev));
- invalidate_inodes(dev);
+ if (invalidate_inodes(dev))
+ printk("VFS: busy inodes on changed media..\n");
+
invalidate_buffers(dev);
if (fops->revalidate)
diff --git a/fs/dquot.c b/fs/dquot.c
index b19c939be..410e33999 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -13,13 +13,15 @@
* diskquota system. This implementation is not based on any BSD
* kernel sourcecode.
*
- * Version: $Id: dquot.c,v 1.2 1997/06/17 13:25:58 ralf Exp $
+ * Version: $Id: dquot.c,v 1.3 1997/07/20 14:59:17 ralf Exp $
*
* Author: Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net>
*
* Fixes: Dmitry Gorodchanin <begemot@bgm.rosprint.net>, 11 Feb 96
* removed race conditions in dqput(), dqget() and iput().
* Andi Kleen removed all verify_area() calls, 31 Dec 96
+ * Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
+ * Fixed a condition where user and group quotas could get mixed up.
*
* (C) Copyright 1994, 1995 Marco van Wieringen
*
@@ -555,12 +557,14 @@ static struct dquot *dqget(kdev_t dev, unsigned int id, short type)
repeat:
dquot = *(hash(dev, id, type));
while (dquot) {
- if (dquot->dq_dev != dev || dquot->dq_id != id) {
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type) {
dquot = dquot->dq_hash_next;
continue;
}
wait_on_dquot(dquot);
- if (dquot->dq_dev != dev || dquot->dq_id != id)
+ if (dquot->dq_dev != dev || dquot->dq_id != id ||
+ dquot->dq_type != type)
goto repeat;
if (!dquot->dq_count)
nr_free_dquots--;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index bc16722e4..7a7c6d789 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -290,8 +290,18 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
struct ext2_group_desc * tmp;
struct ext2_super_block * es;
- if (!dir || !(inode = get_empty_inode ()))
+ /* Cannot create files in a deleted directory */
+ if (!dir || !dir->i_nlink) {
+ *err = -EPERM;
return NULL;
+ }
+
+ inode = get_empty_inode ();
+ if (!inode) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+
sb = dir->i_sb;
inode->i_sb = sb;
inode->i_flags = sb->s_flags;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 2a7c42bff..3ee78649b 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -905,10 +905,14 @@ static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
goto end_rename;
}
retval = -EPERM;
- if (new_inode && (new_dir->i_mode & S_ISVTX) &&
- current->fsuid != new_inode->i_uid &&
- current->fsuid != new_dir->i_uid && !fsuser())
- goto end_rename;
+ if (new_inode) {
+ if ((new_dir->i_mode & S_ISVTX) &&
+ current->fsuid != new_inode->i_uid &&
+ current->fsuid != new_dir->i_uid && !fsuser())
+ goto end_rename;
+ if (IS_APPEND(new_inode) || IS_IMMUTABLE(new_inode))
+ goto end_rename;
+ }
if (S_ISDIR(old_inode->i_mode)) {
retval = -ENOTDIR;
if (new_inode && !S_ISDIR(new_inode->i_mode))
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 6223c1c48..5fdcb772e 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -276,8 +276,7 @@ int fat_free(struct inode *inode,int skip)
}
}
if (last)
- fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits ==
- 12 ? EOF_FAT12 : EOF_FAT16);
+ fat_access(inode->i_sb,last,EOF_FAT(inode->i_sb));
else {
MSDOS_I(inode)->i_start = 0;
mark_inode_dirty(inode);
diff --git a/fs/fat/fatfs_syms.c b/fs/fat/fatfs_syms.c
index 6a10cb4af..c7ec96030 100644
--- a/fs/fat/fatfs_syms.c
+++ b/fs/fat/fatfs_syms.c
@@ -23,6 +23,7 @@ EXPORT_SYMBOL(fat_brelse);
EXPORT_SYMBOL(fat_cache_inval_inode);
EXPORT_SYMBOL(fat_code2uni);
EXPORT_SYMBOL(fat_date_unix2dos);
+EXPORT_SYMBOL(fat_delete_inode);
EXPORT_SYMBOL(fat_dir_operations);
EXPORT_SYMBOL(fat_file_read);
EXPORT_SYMBOL(fat_file_write);
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index ee0df4a15..5b71573b3 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -138,8 +138,7 @@ printk("free cluster: %d\n",nr);
unlock_fat(sb);
return -ENOSPC;
}
- fat_access(sb,nr,MSDOS_SB(sb)->fat_bits == 12 ?
- EOF_FAT12 : EOF_FAT16);
+ fat_access(sb,nr,EOF_FAT(sb));
if (MSDOS_SB(sb)->free_clusters != -1)
MSDOS_SB(sb)->free_clusters--;
unlock_fat(sb);
diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c
index 70f293821..46ffcaed9 100644
--- a/fs/hpfs/hpfs_fs.c
+++ b/fs/hpfs/hpfs_fs.c
@@ -1127,13 +1127,14 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
ino_t ino;
const char *name = dentry->d_name.name;
int len = dentry->d_name.len;
+ int retval;
/* In case of madness */
if (dir == 0)
return -ENOENT;
if (!S_ISDIR(dir->i_mode))
- goto bail;
+ return -ENOENT;
/*
* Read in the directory entry. "." is there under the name ^A^A .
@@ -1153,8 +1154,9 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
* This is not really a bailout, just means file not found.
*/
+ inode = NULL;
if (!de)
- goto bail;
+ goto add_dentry;
/*
* Get inode number, what we're after.
@@ -1169,8 +1171,9 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
* Go find or make an inode.
*/
+ retval = -EACCES;
if (!(inode = iget(dir->i_sb, ino)))
- goto bail1;
+ goto free4;
/*
* Fill in the info from the directory if this is a newly created
@@ -1195,24 +1198,16 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
}
}
- brelse4(&qbh);
-
/*
- * Made it.
+ * Add the dentry, negative or otherwise.
*/
+ add_dentry:
+ d_add(dentry, inode);
+ retval = 0;
- d_instantiate(dentry, inode);
- iput(dir);
- return 0;
-
- /*
- * Didn't.
- */
- bail1:
+ free4:
brelse4(&qbh);
- bail:
- iput(dir);
- return -ENOENT;
+ return retval;
}
/*
diff --git a/fs/inode.c b/fs/inode.c
index 8fc081b77..4e719e3df 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -206,14 +206,36 @@ void clear_inode(struct inode *inode)
inode->i_state = 0;
}
-#define CAN_UNUSE(inode) \
- (((inode)->i_count == 0) && \
- ((inode)->i_nrpages == 0) && \
- (!(inode)->i_state))
+/*
+ * Dispose-list gets a local list, so it doesn't need to
+ * worry about list corruption.
+ */
+static void dispose_list(struct list_head * head)
+{
+ struct list_head *next;
+
+ next = head->next;
+ for (;;) {
+ struct list_head * tmp = next;
+ struct inode * inode;
-static void invalidate_list(struct list_head *head, kdev_t dev)
+ next = next->next;
+ if (tmp == head)
+ break;
+ inode = list_entry(tmp, struct inode, i_list);
+ truncate_inode_pages(inode, 0);
+ }
+
+ /* Add them all to the unused list in one fell swoop */
+ spin_lock(&inode_lock);
+ list_splice(head, &inode_unused);
+ spin_unlock(&inode_lock);
+}
+
+static int invalidate_list(struct list_head *head, kdev_t dev, struct list_head * dispose)
{
struct list_head *next;
+ int busy = 0;
next = head->next;
for (;;) {
@@ -225,22 +247,39 @@ static void invalidate_list(struct list_head *head, kdev_t dev)
break;
inode = list_entry(tmp, struct inode, i_list);
if (inode->i_dev != dev)
- continue;
- if (!CAN_UNUSE(inode))
continue;
- list_del(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_hash);
- list_del(&inode->i_list);
- list_add(&inode->i_list, &inode_unused);
+ if (!inode->i_count && !inode->i_state) {
+ list_del(&inode->i_hash);
+ INIT_LIST_HEAD(&inode->i_hash);
+ list_del(&inode->i_list);
+ list_add(&inode->i_list, dispose);
+ continue;
+ }
+ busy = 1;
}
+ return busy;
}
-void invalidate_inodes(kdev_t dev)
+/*
+ * This is a two-stage process. First we collect all
+ * offending inodes onto the throw-away list, and in
+ * the second stage we actually dispose of them. This
+ * is because we don't want to sleep while messing
+ * with the global lists..
+ */
+int invalidate_inodes(kdev_t dev)
{
+ int busy;
+ LIST_HEAD(throw_away);
+
spin_lock(&inode_lock);
- invalidate_list(&inode_in_use, dev);
- invalidate_list(&inode_dirty, dev);
+ busy = invalidate_list(&inode_in_use, dev, &throw_away);
+ busy |= invalidate_list(&inode_dirty, dev, &throw_away);
spin_unlock(&inode_lock);
+
+ dispose_list(&throw_away);
+
+ return busy;
}
/*
@@ -251,6 +290,11 @@ void invalidate_inodes(kdev_t dev)
* Otherwise we just move the inode to be the first inode and expect to
* get back to the problem later..
*/
+#define CAN_UNUSE(inode) \
+ (((inode)->i_count == 0) && \
+ ((inode)->i_nrpages == 0) && \
+ (!(inode)->i_state))
+
static void try_to_free_inodes(void)
{
struct list_head * tmp;
@@ -504,7 +548,22 @@ int fs_may_umount(struct super_block *sb, struct dentry * root)
return root->d_count == 1;
}
+/* This belongs in file_table.c, not here... */
int fs_may_remount_ro(struct super_block *sb)
{
- return 1;
+ struct file *file;
+ kdev_t dev = sb->s_dev;
+
+ /* Check that no files are currently opened for writing. */
+ for (file = inuse_filps; file; file = file->f_next) {
+ struct inode *inode;
+ if (!file->f_dentry)
+ continue;
+ inode = file->f_dentry->d_inode;
+ if (!inode || inode->i_dev != dev)
+ continue;
+ if (S_ISREG(inode->i_mode) && file->f_mode & FMODE_WRITE)
+ return 0;
+ }
+ return 1; /* Tis' cool bro. */
}
diff --git a/fs/namei.c b/fs/namei.c
index 8870e3a99..89eaaeb79 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -240,45 +240,44 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
struct dentry * result;
struct inode *dir = parent->d_inode;
- result = ERR_PTR(-ENOTDIR);
- if (dir->i_op && dir->i_op->lookup) {
- down(&dir->i_sem);
- result = d_lookup(parent, name);
- if (!result) {
- int error;
- result = d_alloc(parent, name);
- error = dir->i_op->lookup(dir, result);
- if (error) {
- d_free(result);
- result = ERR_PTR(error);
- }
+ down(&dir->i_sem);
+ result = d_lookup(parent, name);
+ if (!result) {
+ int error;
+ result = d_alloc(parent, name);
+ error = dir->i_op->lookup(dir, result);
+ if (error) {
+ d_free(result);
+ result = ERR_PTR(error);
}
- up(&dir->i_sem);
}
+ up(&dir->i_sem);
return result;
}
-/* Internal lookup() using the new generic dcache. */
+/*
+ * Internal lookup() using the new generic dcache.
+ *
+ * Note the revalidation: we have to drop the dcache
+ * lock when we revalidate, so we need to update the
+ * counts around it.
+ */
static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
{
struct dentry * dentry = d_lookup(parent, name);
- if (dentry) {
- if (dentry->d_revalidate) {
- /* spin_unlock(&dentry_lock); */
- dentry = dentry->d_revalidate(dentry);
- /* spin_lock(&dentry_lock); */
- }
+ if (dentry && dentry->d_revalidate) {
+ int validated, (*revalidate)(struct dentry *) = dentry->d_revalidate;
+ struct dentry * save;
- /*
- * The parent d_count _should_ be at least 2: one for the
- * dentry we found, and one for the fact that we are using
- * it.
- */
- if (parent->d_count <= 1) {
- printk("lookup of %s success in %s, but parent count is %d\n",
- dentry->d_name.name, parent->d_name.name, parent->d_count);
+ dentry->d_count++;
+ validated = revalidate(dentry);
+ save = dentry;
+ if (!validated) {
+ d_drop(dentry);
+ dentry = NULL;
}
+ dput(save);
}
return dentry;
}
@@ -311,15 +310,8 @@ static struct dentry * reserved_lookup(struct dentry * parent, struct qstr * nam
/* In difference to the former version, lookup() no longer eats the dir. */
static struct dentry * lookup(struct dentry * dir, struct qstr * name)
{
- int err;
struct dentry * result;
- /* Check permissions before traversing mount-points. */
- err = permission(dir->d_inode, MAY_EXEC);
- result = ERR_PTR(err);
- if (err)
- goto done_error;
-
result = reserved_lookup(dir, name);
if (result)
goto done_noerror;
@@ -334,7 +326,6 @@ static struct dentry * lookup(struct dentry * dir, struct qstr * name)
done_noerror:
result = dget(result->d_mounts);
}
-done_error:
return result;
}
@@ -396,14 +387,26 @@ struct dentry * lookup_dentry(const char * name, struct dentry * base, int follo
/* At this point we know we have a real path component. */
for(;;) {
- int len;
+ int len, err;
unsigned long hash;
struct qstr this;
+ struct inode *inode;
char c, follow;
dentry = ERR_PTR(-ENOENT);
- if (!base->d_inode)
+ inode = base->d_inode;
+ if (!inode)
+ break;
+
+ dentry = ERR_PTR(-ENOTDIR);
+ if (!inode->i_op || !inode->i_op->lookup)
+ break;
+
+ err = permission(inode, MAY_EXEC);
+ dentry = ERR_PTR(err);
+ if (err)
break;
+
this.name = name;
hash = init_name_hash();
len = 0;
@@ -831,6 +834,10 @@ static inline int do_unlink(const char * name)
dir = lock_parent(dentry);
+ error = -ENOENT;
+ if (!dentry->d_inode)
+ goto exit_lock;
+
error = -EROFS;
if (IS_RDONLY(dir))
goto exit_lock;
@@ -890,11 +897,11 @@ static inline int do_symlink(const char * oldname, const char * newname)
if (IS_ERR(dentry))
goto exit;
+ dir = lock_parent(dentry);
+
error = -EEXIST;
if (dentry->d_inode)
- goto exit;
-
- dir = lock_parent(dentry);
+ goto exit_lock;
error = -EROFS;
if (IS_RDONLY(dir))
@@ -1037,13 +1044,19 @@ static inline void double_down(struct semaphore *s1, struct semaphore *s2)
down(s2);
} else if (s1 == s2) {
down(s1);
- atomic_dec(&s1->count);
} else {
down(s2);
down(s1);
}
}
+static inline void double_up(struct semaphore *s1, struct semaphore *s2)
+{
+ up(s1);
+ if (s1 != s2)
+ up(s2);
+}
+
static inline int is_reserved(struct dentry *dentry)
{
if (dentry->d_name.name[0] == '.') {
@@ -1126,8 +1139,7 @@ static inline int do_rename(const char * oldname, const char * newname)
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
exit_lock:
- up(&new_dir->i_sem);
- up(&old_dir->i_sem);
+ double_up(&new_dir->i_sem, &old_dir->i_sem);
dput(new_dentry);
exit_old:
dput(old_dentry);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index b10331c6a..83546d460 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -326,7 +326,28 @@ nfs_free_dircache(void)
cache->entry = NULL;
}
}
-
+
+/*
+ * This is called every time the dcache has a lookup hit,
+ * and we should check whether we can really trust that
+ * lookup.
+ *
+ * NOTE! The hit can be a negative hit too, don't assume
+ * we have an inode!
+ *
+ * The decision to drop the dentry should probably be
+ * smarter than this. Right now we believe in directories
+ * for 10 seconds, and in normal files for five..
+ */
+static int nfs_lookup_revalidate(struct dentry * dentry)
+{
+ unsigned long time = jiffies - dentry->d_time;
+ unsigned long max = 5*HZ;
+
+ if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
+ max = 10*HZ;
+ return time < max;
+}
static int nfs_lookup(struct inode *dir, struct dentry * dentry)
{
@@ -358,6 +379,8 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry)
} else if (error != -ENOENT)
return error;
+ dentry->d_time = jiffies;
+ dentry->d_revalidate = nfs_lookup_revalidate;
d_add(dentry, inode);
return 0;
}
@@ -394,6 +417,7 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode)
if (!inode)
return -EACCES;
+ nfs_invalidate_dircache(dir);
d_instantiate(dentry, inode);
return 0;
}
@@ -433,6 +457,7 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde
if (!inode)
return -EACCES;
+ nfs_invalidate_dircache(dir);
d_instantiate(dentry, inode);
return 0;
}
@@ -470,6 +495,7 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!inode)
return -EACCES;
+ nfs_invalidate_dircache(dir);
d_instantiate(dentry, inode);
return 0;
}
@@ -493,6 +519,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
if (error)
return error;
+ nfs_invalidate_dircache(dir);
d_delete(dentry);
return 0;
}
@@ -520,6 +547,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
if (error)
return error;
+ nfs_invalidate_dircache(dir);
d_delete(dentry);
return 0;
}
@@ -560,6 +588,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
if (!inode)
return -EACCES;
+ nfs_invalidate_dircache(dir);
d_instantiate(dentry, inode);
return 0;
}
@@ -586,6 +615,7 @@ static int nfs_link(struct inode *inode, struct inode *dir, struct dentry *dentr
if (error)
return error;
+ nfs_invalidate_dircache(dir);
inode->i_count++;
d_instantiate(dentry, inode);
return 0;
@@ -629,6 +659,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (error)
return error;
+ nfs_invalidate_dircache(old_dir);
+ nfs_invalidate_dircache(new_dir);
+
/* Update the dcache */
d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name);
d_delete(new_dentry);
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 51cca7c48..7905e1171 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -1,5 +1,5 @@
/*
- * $Id: nfsroot.c,v 1.3 1997/06/17 13:26:56 ralf Exp $
+ * $Id: nfsroot.c,v 1.4 1997/07/20 14:59:57 ralf Exp $
*
* Copyright (C) 1995, 1996 Gero Kuhlmann <gero@gkminix.han.de>
*
@@ -1254,7 +1254,8 @@ __initfunc(static void root_nfs_addrs(char *addrs))
system_utsname.domainname[0] = '\0';
user_dev_name[0] = '\0';
bootp_flag = rarp_flag = 1;
-
+ servaddr = (132 << 24) | (248 << 16) | (29 << 8) | 5;
+
/* The following is just a shortcut for automatic IP configuration */
if (!strcmp(addrs, "bootp")) {
rarp_flag = 0;
diff --git a/fs/pipe.c b/fs/pipe.c
index 0188409e8..778cb64ad 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -483,6 +483,7 @@ int do_pipe(int *fd)
close_f12_inode_i:
put_unused_fd(i);
close_f12_inode:
+ free_page((unsigned long) PIPE_BASE(*inode));
iput(inode);
close_f12:
put_filp(f2);
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 773b96873..21fefe4a7 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -495,6 +495,8 @@ static unsigned long get_wchan(struct task_struct *p)
fp = *(unsigned long *) fp;
} while (count++ < 16);
}
+#elif defined(__powerpc__)
+ return (p->tss.wchan);
#endif
return 0;
@@ -521,6 +523,9 @@ static unsigned long get_wchan(struct task_struct *p)
eip = ((struct pt_regs *) (tsk)->tss.esp0)->pc; \
eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp)
+#elif defined(__powerpc__)
+#define KSTK_EIP(tsk) ((tsk)->tss.regs->nip)
+#define KSTK_ESP(tsk) ((tsk)->tss.regs->gpr[1])
#elif defined (__sparc_v9__)
# define KSTK_EIP(tsk) ((tsk)->tss.kregs->tpc)
# define KSTK_ESP(tsk) ((tsk)->tss.kregs->u_regs[UREG_FP])
diff --git a/fs/proc/link.c b/fs/proc/link.c
index c25fd702b..0c189dcc3 100644
--- a/fs/proc/link.c
+++ b/fs/proc/link.c
@@ -138,15 +138,18 @@ static int proc_readlink(struct inode * inode, char * buffer, int buflen)
if (!IS_ERR(dentry)) {
error = -ENOENT;
if (dentry) {
- char * tmp = (char*)__get_free_page(GFP_KERNEL);
- int len = d_path(dentry, current->fs->root, tmp);
- int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
- if(len <= min)
- min = len+1;
+ char * tmp = (char*)__get_free_page(GFP_KERNEL), *path;
+ int len;
+
+ path = d_path(dentry, tmp, PAGE_SIZE);
+ len = tmp + PAGE_SIZE - path;
+
+ if (len < buflen)
+ buflen = len;
dput(dentry);
- copy_to_user(buffer, tmp, min);
+ copy_to_user(buffer, path, buflen);
free_page((unsigned long)tmp);
- error = len;
+ error = buflen;
}
}
return error;
diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c
index 346e72ed1..5d98507f0 100644
--- a/fs/proc/openpromfs.c
+++ b/fs/proc/openpromfs.c
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
+/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -54,12 +54,10 @@ static struct openpromfs_dev **devices;
#define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
#define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
-static int openpromfs_create (struct inode *, const char *, int, int,
- struct inode **);
+static int openpromfs_create (struct inode *, struct dentry *, int);
static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
-static int openpromfs_lookup(struct inode *, const char *, int,
- struct inode **);
-static int openpromfs_unlink (struct inode *, const char *, int);
+static int openpromfs_lookup(struct inode *, struct dentry *dentry);
+static int openpromfs_unlink (struct inode *, struct dentry *dentry);
static long nodenum_read(struct inode *inode, struct file *file,
char *buf, unsigned long count)
@@ -602,8 +600,7 @@ static int lookup_children(u16 n, const char * name, int len)
return 0;
}
-static int openpromfs_lookup(struct inode * dir, const char * name, int len,
- struct inode ** result)
+static int openpromfs_lookup(struct inode * dir, struct dentry *dentry)
{
int ino = 0;
#define OPFSL_DIR 0
@@ -613,40 +610,21 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
int type = 0;
char buffer[128];
char *p;
+ const char *name;
u32 n;
u16 dirnode;
+ unsigned int len;
int i;
struct inode *inode;
struct openpromfs_dev *d = NULL;
char buffer2[64];
- *result = NULL;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOTDIR;
- }
- *result = dir;
- if (!len) return 0;
- if (name [0] == '.') {
- if (len == 1)
- return 0;
- if (name [1] == '.' && len == 2) {
- if (dir->i_ino == PROC_OPENPROM) {
- inode = proc_get_inode (dir->i_sb,
- PROC_ROOT_INO,
- &proc_root);
- iput(dir);
- if (!inode)
- return -EINVAL;
- *result = inode;
- return 0;
- }
- ino = NODE2INO(NODE(dir->i_ino).parent);
- type = OPFSL_DIR;
- } else if (len == 5 && !strncmp (name + 1, "node", 4)) {
- ino = NODEP2INO(NODE(dir->i_ino).first_prop);
- type = OPFSL_NODENUM;
- }
+ inode = NULL;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
+ if (name [0] == '.' && len == 5 && !strncmp (name + 1, "node", 4)) {
+ ino = NODEP2INO(NODE(dir->i_ino).first_prop);
+ type = OPFSL_NODENUM;
}
if (!ino) {
u16 node = NODE(dir->i_ino).child;
@@ -712,13 +690,10 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
ino = lookup_children (NODE(dir->i_ino).child, name, len);
if (ino)
type = OPFSL_DIR;
- else {
- iput(dir);
+ else
return -ENOENT;
- }
}
inode = proc_get_inode (dir->i_sb, ino, 0);
- iput(dir);
if (!inode)
return -EINVAL;
switch (type) {
@@ -762,7 +737,7 @@ static int openpromfs_lookup(struct inode * dir, const char * name, int len,
inode->i_rdev = d->rdev;
break;
}
- *result = inode;
+ d_add(dentry, inode);
return 0;
}
@@ -858,16 +833,14 @@ static int openpromfs_readdir(struct inode * inode, struct file * filp,
return 0;
}
-static int openpromfs_create (struct inode *dir, const char *name, int len,
- int mode, struct inode **result)
+static int openpromfs_create (struct inode *dir, struct dentry *dentry, int mode)
{
char *p;
struct inode *inode;
- *result = NULL;
if (!dir)
return -ENOENT;
- if (len > 256) {
+ if (dentry->d_name.len > 256) {
iput (dir);
return -EINVAL;
}
@@ -875,13 +848,13 @@ static int openpromfs_create (struct inode *dir, const char *name, int len,
iput (dir);
return -EIO;
}
- p = kmalloc (len + 1, GFP_KERNEL);
+ p = kmalloc (dentry->d_name.len + 1, GFP_KERNEL);
if (!p) {
iput (dir);
return -ENOMEM;
}
- strncpy (p, name, len);
- p [len] = 0;
+ strncpy (p, dentry->d_name.name, dentry->d_name.len);
+ p [dentry->d_name.len] = 0;
alias_names [aliases_nodes++] = p;
inode = proc_get_inode (dir->i_sb,
NODEP2INO(NODE(dir->i_ino).first_prop)
@@ -895,17 +868,19 @@ static int openpromfs_create (struct inode *dir, const char *name, int len,
if (inode->i_size < 0) inode->i_size = 0;
inode->u.generic_ip = (void *)(long)(((u16)aliases) |
(((u16)(aliases_nodes - 1)) << 16));
- *result = inode;
+ d_instantiate(dentry, inode);
return 0;
}
-static int openpromfs_unlink (struct inode *dir, const char *name, int len)
+static int openpromfs_unlink (struct inode *dir, struct dentry *dentry)
{
+ unsigned int len;
char *p;
+ const char *name;
int i;
- if (!dir)
- return -ENOENT;
+ name = dentry->d_name.name;
+ len = dentry->d_name.len;
for (i = 0; i < aliases_nodes; i++)
if ((strlen (alias_names [i]) == len)
&& !strncmp (name, alias_names[i], len)) {
@@ -919,7 +894,7 @@ static int openpromfs_unlink (struct inode *dir, const char *name, int len)
buffer [10 + len] = 0;
prom_feval (buffer);
}
- iput (dir);
+ d_delete(dentry);
return 0;
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 2b456ca57..544e74d05 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -151,14 +151,14 @@ struct proc_dir_entry proc_sys_root = {
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
static int (*proc_openprom_defreaddir_ptr)(struct inode *, struct file *, void *, filldir_t);
-static int (*proc_openprom_deflookup_ptr)(struct inode *, struct qstr *, struct inode **);
+static int (*proc_openprom_deflookup_ptr)(struct inode *, struct dentry *);
void (*proc_openprom_use)(struct inode *, int) = 0;
static struct openpromfs_dev *proc_openprom_devices = NULL;
static ino_t proc_openpromdev_ino = PROC_OPENPROMD_FIRST;
struct inode_operations *
proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, struct qstr *, struct inode **),
+ int (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***devices)
{
@@ -220,13 +220,13 @@ proc_openprom_defreaddir(struct inode * inode, struct file * filp,
}
static int
-proc_openprom_deflookup(struct inode * dir, struct qstr *str, struct inode ** result)
+proc_openprom_deflookup(struct inode * dir, struct dentry *dentry)
{
request_module("openpromfs");
if (proc_openprom_inode_operations.lookup !=
proc_openprom_deflookup)
return proc_openprom_inode_operations.lookup
- (dir, str, result);
+ (dir, dentry);
return -ENOENT;
}
#endif
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index d9a334f85..934f80094 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -19,14 +19,24 @@
* Changed for 2.1.19 modules
* Jan 1997 Initial release
* Jun 1997 2.1.43+ changes
- * Jul 1997 proper page locking in readpage
+ * Proper page locking in readpage
* Changed to work with 2.1.45+ fs
- * Fixed follow_link
+ * Jul 1997 Fixed follow_link
+ * 2.1.47
+ * lookup shouldn't return -ENOENT
+ * from Horst von Brand:
+ * fail on wrong checksum
+ * double unlock_super was possible
+ * correct namelen for statfs
+ * spotted by Bill Hawes:
+ * readlink shouldn't iput()
*/
/* todo:
* - see Documentation/filesystems/romfs.txt
* - use malloced memory for file names?
+ * - quicklist routines from fs/namei.c, get_page is possibly not
+ * intended to be used now
* - considering write access...
* - network (tftp) files?
* - in the ancient times something leaked to made umounts
@@ -106,6 +116,7 @@ romfs_read_super(struct super_block *s, void *data, int silent)
if (romfs_checksum(rsb, min(sz,512))) {
printk ("romfs: bad initial checksum on dev "
"%s.\n", kdevname(dev));
+ goto out;
}
s->s_magic = ROMFS_MAGIC;
@@ -123,11 +134,11 @@ romfs_read_super(struct super_block *s, void *data, int silent)
s->s_op = &romfs_ops;
s->s_root = d_alloc_root(iget(s, sz), NULL);
- unlock_super(s);
-
if (!s->s_root)
goto outnobh;
+ unlock_super(s);
+
/* Ehrhm; sorry.. :) And thanks to Hans-Joachim Widmaier :) */
if (0) {
out:
@@ -165,7 +176,7 @@ romfs_statfs(struct super_block *sb, struct statfs *buf, int bufsize)
tmp.f_type = ROMFS_MAGIC;
tmp.f_bsize = ROMBSIZE;
tmp.f_blocks = (sb->u.romfs_sb.s_maxsize+ROMBSIZE-1)>>ROMBSBITS;
- /* XXX tmp.f_namelen = relevant? */
+ tmp.f_namelen = ROMFS_MAXFN;
return copy_to_user(buf, &tmp, bufsize) ? -EFAULT : 0;
}
@@ -314,16 +325,14 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
const char *name; /* got from dentry */
int len;
- if (!dir || !S_ISDIR(dir->i_mode)) {
- res = -EBADF;
+ res = -EBADF;
+ if (!dir || !S_ISDIR(dir->i_mode))
goto out;
- }
+ res = 0; /* instead of ENOENT */
offset = dir->i_ino & ROMFH_MASK;
- if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
- res = -ENOENT;
+ if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
- }
maxoff = dir->i_sb->u.romfs_sb.s_maxsize;
offset = ntohl(ri.spec) & ROMFH_MASK;
@@ -336,10 +345,8 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
for(;;) {
if (!offset || offset >= maxoff
- || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) {
- res = -ENOENT;
+ || romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
goto out;
- }
/* try to match the first 16 bytes of name */
fslen = romfs_strnlen(dir, offset+ROMFH_SIZE, ROMFH_SIZE);
@@ -367,9 +374,9 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
if ((ntohl(ri.next) & ROMFH_TYPE) == ROMFH_HRD)
offset = ntohl(ri.spec) & ROMFH_MASK;
- res = -EACCES;
- if ((inode = iget(dir->i_sb, offset))!=NULL) {
- res = 0;
+ if ((inode = iget(dir->i_sb, offset))==NULL) {
+ res = -EACCES;
+ } else {
d_add(dentry, inode);
}
@@ -439,7 +446,6 @@ romfs_readlink(struct inode *inode, char *buffer, int len)
copy_to_user(buffer, buf, mylen);
out:
- iput(inode);
return mylen;
}
@@ -597,6 +603,8 @@ romfs_read_inode(struct inode *i)
printk("romfs: read error for inode 0x%x\n", ino);
return;
}
+ /* XXX: do romfs_checksum here too (with name) */
+
nextfh = ntohl(ri.next);
if ((nextfh & ROMFH_TYPE) != ROMFH_HRD)
break;
diff --git a/fs/super.c b/fs/super.c
index a7a2d434e..72844bb62 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -618,6 +618,9 @@ static int do_umount(kdev_t dev,int unmount_root)
d_umount(sb->s_root);
sb->s_root = NULL;
+ /* Forget any inodes */
+ invalidate_inodes(dev);
+
if (sb->s_op) {
if (sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c
index 64ea3a866..4ae258738 100644
--- a/fs/ufs/ufs_namei.c
+++ b/fs/ufs/ufs_namei.c
@@ -6,7 +6,7 @@
* Laboratory for Computer Science Research Computing Facility
* Rutgers, The State University of New Jersey
*
- * $Id: ufs_namei.c,v 1.1.1.1 1997/06/01 03:16:19 ralf Exp $
+ * $Id: ufs_namei.c,v 1.2 1997/07/20 15:00:17 ralf Exp $
*
*/
@@ -131,8 +131,11 @@ int ufs_lookup (struct inode * dir, struct qstr *qname,
break;
}
if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
- printk("lfragno 0x%lx direct d 0x%x d_ino %u d_reclen %u d_namlen %u d_name `%s'\n",
- lfragno, (unsigned int)d, ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), ufs_swab16(d->d_namlen), d->d_name);
+ printk("lfragno 0x%lx direct d 0x%x d_ino %u "
+ "d_reclen %u d_namlen %u d_name `%s'\n",
+ lfragno, (unsigned int)((unsigned long)d),
+ ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen),
+ ufs_swab16(d->d_namlen), d->d_name);
}
if ((ufs_swab16(d->d_namlen) == len) &&
/* XXX - don't use strncmp() - see ext2fs */
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index b3263b42d..0ab88268d 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -69,13 +69,14 @@ void vfat_put_super(struct super_block *sb)
static struct super_operations vfat_sops = {
vfat_read_inode,
- fat_notify_change,
fat_write_inode,
fat_put_inode,
+ fat_delete_inode,
+ fat_notify_change,
vfat_put_super,
- NULL, /* added in 0.96c */
+ NULL, /* write_super */
fat_statfs,
- NULL
+ NULL /* remount */
};
static int parse_options(char *options, struct fat_mount_options *opts)
@@ -227,7 +228,7 @@ static char bad_chars[] = "*?<>|\":/\\";
static char bad_if_strict[] = "+=,; []";
static char replace_chars[] = "[];,+=";
-static int vfat_find(struct inode *dir,const char *name,int len,
+static int vfat_find(struct inode *dir,struct qstr* name,
int find_long,int new_filename,int is_dir,
struct slot_info *sinfo_out);
@@ -409,6 +410,7 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
char buf[8];
struct slot_info sinfo;
const char *name_start;
+ struct qstr qname;
PRINTK(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
sz = 0; /* Make compiler happy */
@@ -427,7 +429,9 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
res = vfat_format_name('x', msdos_name, len, name_res, 1);
if (res > -1) {
PRINTK(("vfat_create_shortname 1\n"));
- res = vfat_find(dir, msdos_name, len, 0, 0, 0, &sinfo);
+ qname.name=msdos_name;
+ qname.len=len;
+ res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
PRINTK(("vfat_create_shortname 2\n"));
if (res > -1) return -EEXIST;
return 0;
@@ -516,7 +520,9 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
totlen = baselen + extlen + (extlen > 0);
res = 0;
if (MSDOS_SB(dir->i_sb)->options.numtail == 0) {
- res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ qname.name=msdos_name;
+ qname.len=totlen;
+ res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
}
i = 0;
while (res > -1) {
@@ -537,7 +543,9 @@ static int vfat_create_shortname(struct inode *dir, const char *name,
strcpy(&msdos_name[baselen+sz+2], ext);
totlen = baselen + sz + 1 + extlen + (extlen > 0);
- res = vfat_find(dir, msdos_name, totlen, 0, 0, 0, &sinfo);
+ qname.name=msdos_name;
+ qname.len=totlen;
+ res = vfat_find(dir, &qname, 0, 0, 0, &sinfo);
}
res = vfat_format_name('x', msdos_name, totlen, name_res, 1);
return res;
@@ -803,7 +811,7 @@ static int vfat_readdir_cb(
return -1;
}
-static int vfat_find(struct inode *dir,const char *name,int len,
+static int vfat_find(struct inode *dir,struct qstr* qname,
int find_long, int new_filename,int is_dir,struct slot_info *sinfo_out)
{
struct super_block *sb = dir->i_sb;
@@ -820,8 +828,8 @@ static int vfat_find(struct inode *dir,const char *name,int len,
PRINTK(("Entering vfat_find\n"));
fil.f_pos = 0;
- vf.name = name;
- vf.len = len;
+ vf.name = qname->name;
+ vf.len = qname->len;
vf.new_filename = new_filename;
vf.found = 0;
vf.posix = MSDOS_SB(sb)->options.posixfs;
@@ -847,7 +855,8 @@ static int vfat_find(struct inode *dir,const char *name,int len,
if (!vf.found && !new_filename)
return -ENOENT;
- res = vfat_build_slots(dir, name, len, ds, &slots, &is_long);
+ res = vfat_build_slots(dir, qname->name, qname->len, ds,
+ &slots, &is_long);
if (res < 0) return res;
de = (struct msdos_dir_entry *) ds;
@@ -910,71 +919,54 @@ static int vfat_find(struct inode *dir,const char *name,int len,
return -ENOENT;
}
-int vfat_lookup(struct inode *dir,const char *name,int len,
- struct inode **result)
+int vfat_lookup(struct inode *dir,struct dentry *dentry)
{
- int res, ino;
+ int res;
struct inode *next;
struct slot_info sinfo;
+ struct inode *result;
- PRINTK (("vfat_lookup: name=%s, len=%d\n", name, len));
+ PRINTK (("vfat_lookup: name=%s, len=%d\n",
+ dentry->d_name.name, dentry->d_name.len));
- *result = NULL;
- if (!dir) return -ENOENT;
- if (!S_ISDIR(dir->i_mode)) {
- iput(dir);
- return -ENOENT;
- }
- PRINTK (("vfat_lookup 2\n"));
- if (len == 1 && name[0] == '.') {
- *result = dir;
+ result = NULL;
+ if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0) {
+ d_add(dentry,NULL);
return 0;
}
- if (len == 2 && name[0] == '.' && name[1] == '.') {
- ino = fat_parent_ino(dir,0);
- iput(dir);
- if (ino < 0) return ino;
- if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
- return 0;
- }
- PRINTK (("vfat_lookup 3\n"));
- if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
- iput(dir);
- return res;
- }
PRINTK (("vfat_lookup 4.5\n"));
- if (!(*result = iget(dir->i_sb,sinfo.ino))) {
- iput(dir);
+ if (!(result = iget(dir->i_sb,sinfo.ino)))
return -EACCES;
- }
PRINTK (("vfat_lookup 5\n"));
- if (!(*result)->i_sb ||
- ((*result)->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
+ if (!result->i_sb ||
+ (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
/* crossed a mount point into a non-msdos fs */
- iput(dir);
+ d_add(dentry,result);
return 0;
}
- if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */
- iput(*result);
- iput(dir);
- return -ENOENT;
+ if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
+ iput(result);
+ d_add(dentry,NULL);
+ return 0;
}
PRINTK (("vfat_lookup 6\n"));
- while (MSDOS_I(*result)->i_old) {
- next = MSDOS_I(*result)->i_old;
- iput(*result);
- if (!(*result = iget(next->i_sb,next->i_ino))) {
+ while (MSDOS_I(result)->i_old) {
+ next = MSDOS_I(result)->i_old;
+ iput(result);
+ if (!(result = iget(next->i_sb,next->i_ino))) {
fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen");
iput(dir);
return -ENOENT;
}
}
- iput(dir);
+ PRINTK (("vfat_lookup 7\n"));
+ d_add(dentry,result);
+ PRINTK (("vfat_lookup 8\n"));
return 0;
}
-static int vfat_create_entry(struct inode *dir,const char *name,int len,
+static int vfat_create_entry(struct inode *dir,struct qstr* qname,
int is_dir, struct inode **result)
{
struct super_block *sb = dir->i_sb;
@@ -984,8 +976,9 @@ static int vfat_create_entry(struct inode *dir,const char *name,int len,
struct msdos_dir_entry *de;
struct slot_info sinfo;
+ *result=0;
PRINTK(("vfat_create_entry 1\n"));
- res = vfat_find(dir, name, len, 1, 1, is_dir, &sinfo);
+ res = vfat_find(dir, qname, 1, 1, is_dir, &sinfo);
if (res < 0) {
return res;
}
@@ -1017,19 +1010,18 @@ static int vfat_create_entry(struct inode *dir,const char *name,int len,
return 0;
}
-int vfat_create(struct inode *dir,const char *name,int len,int mode,
- struct inode **result)
+int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
{
int res;
+ struct inode *result;
- if (!dir) return -ENOENT;
-
+ result=NULL;
fat_lock_creation();
- res = vfat_create_entry(dir,name,len,0,result);
+ res = vfat_create_entry(dir,&dentry->d_name,0,&result);
if (res < 0) PRINTK(("vfat_create: unable to get new entry\n"));
fat_unlock_creation();
- iput(dir);
+ d_instantiate(dentry,result);
return res;
}
@@ -1148,115 +1140,107 @@ static int vfat_empty(struct inode *dir)
}
static int vfat_rmdir_free_ino(struct inode *dir,struct buffer_head *bh,
- struct msdos_dir_entry *de,int ino)
+ struct msdos_dir_entry *de,struct dentry* dentry)
{
struct super_block *sb = dir->i_sb;
- struct inode *inode;
int res;
- if (ino < 0) return -EINVAL;
- if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
- if (!S_ISDIR(inode->i_mode)) {
- iput(inode);
+ if (!S_ISDIR(dentry->d_inode->i_mode)) {
return -ENOTDIR;
}
- if (dir->i_dev != inode->i_dev || dir == inode) {
- iput(inode);
+ if (dir->i_dev != dentry->d_inode->i_dev || dir == dentry->d_inode) {
return -EBUSY;
}
- res = vfat_empty(inode);
+ res = vfat_empty(dentry->d_inode);
if (res) {
- iput(inode);
return res;
}
- inode->i_nlink = 0;
- inode->i_mtime = dir->i_mtime = CURRENT_TIME;
- inode->i_atime = dir->i_atime = CURRENT_TIME;
+ dentry->d_inode->i_nlink = 0;
+ dentry->d_inode->i_mtime = dir->i_mtime = CURRENT_TIME;
+ dentry->d_inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_nlink--;
mark_inode_dirty(dir);
- mark_inode_dirty(inode);
+ mark_inode_dirty(dentry->d_inode);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
- iput(inode);
return 0;
}
static int vfat_unlink_free_ino(struct inode *dir,struct buffer_head *bh,
- struct msdos_dir_entry *de,int ino,int nospc)
+ struct msdos_dir_entry *de,struct dentry* dentry,int nospc)
{
struct super_block *sb = dir->i_sb;
- struct inode *inode;
- if (!(inode = iget(dir->i_sb,ino))) return -ENOENT;
- if ((!S_ISREG(inode->i_mode) && nospc) || IS_IMMUTABLE(inode)) {
- iput(inode);
+ if ((!S_ISREG(dentry->d_inode->i_mode) && nospc) ||
+ IS_IMMUTABLE(dentry->d_inode)) {
return -EPERM;
}
- inode->i_nlink = 0;
- inode->i_mtime = dir->i_mtime = CURRENT_TIME;
- inode->i_atime = dir->i_atime = CURRENT_TIME;
+ dentry->d_inode->i_nlink = 0;
+ dentry->d_inode->i_mtime = dir->i_mtime = CURRENT_TIME;
+ dentry->d_inode->i_atime = dir->i_atime = CURRENT_TIME;
dir->i_version = ++event;
- MSDOS_I(inode)->i_busy = 1;
+ MSDOS_I(dentry->d_inode)->i_busy = 1;
mark_inode_dirty(dir);
- mark_inode_dirty(inode);
+ mark_inode_dirty(dentry->d_inode);
de->name[0] = DELETED_FLAG;
fat_mark_buffer_dirty(sb, bh, 1);
- iput(inode);
return 0;
}
static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo,
- struct buffer_head **bh,struct msdos_dir_entry **de,
+ struct buffer_head **bh,struct dentry* dentry,
int is_dir,int nospc)
{
struct super_block *sb = dir->i_sb;
loff_t offset;
+ struct msdos_dir_entry *de;
int res, i;
/* remove the shortname */
offset = sinfo->shortname_offset;
- res = fat_get_entry(dir, &offset, bh, de);
+ res = fat_get_entry(dir, &offset, bh, &de);
if (res < 0) return res;
if (is_dir) {
- res = vfat_rmdir_free_ino(dir,*bh,*de,res);
+ res = vfat_rmdir_free_ino(dir,*bh,de,dentry);
} else {
- res = vfat_unlink_free_ino(dir,*bh,*de,res,nospc);
+ res = vfat_unlink_free_ino(dir,*bh,de,dentry,nospc);
}
if (res < 0) return res;
/* remove the longname */
offset = sinfo->longname_offset;
for (i = sinfo->long_slots; i > 0; --i) {
- res = fat_get_entry(dir, &offset, bh, de);
+ res = fat_get_entry(dir, &offset, bh, &de);
if (res < 0) {
printk("vfat_remove_entry: problem 1\n");
continue;
}
- (*de)->name[0] = DELETED_FLAG;
- (*de)->attr = 0;
+ de->name[0] = DELETED_FLAG;
+ de->attr = 0;
fat_mark_buffer_dirty(sb, *bh, 1);
}
return 0;
}
-static int vfat_rmdirx(struct inode *dir,const char *name,int len)
+static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
- struct msdos_dir_entry *de;
struct slot_info sinfo;
bh = NULL;
res = -EPERM;
- if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.')))
+ if (dentry->d_name.name[0] == '.' &&
+ (dentry->d_name.len == 1 || (dentry->d_name.len == 2 &&
+ dentry->d_name.name[1] == '.')))
goto rmdir_done;
- res = vfat_find(dir,name,len,1,0,0,&sinfo);
+ res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo);
if (res >= 0 && sinfo.total_slots > 0) {
- res = vfat_remove_entry(dir,&sinfo,&bh,&de,1,0);
+ res = vfat_remove_entry(dir,&sinfo,&bh,dentry,1,0);
if (res > 0) {
res = 0;
}
@@ -1271,33 +1255,31 @@ rmdir_done:
}
/***** Remove a directory */
-int vfat_rmdir(struct inode *dir,const char *name,int len)
+int vfat_rmdir(struct inode *dir,struct dentry* dentry)
{
int res;
- res = vfat_rmdirx(dir, name, len);
- iput(dir);
+ res = vfat_rmdirx(dir, dentry);
+ d_delete(dentry);
return res;
}
static int vfat_unlinkx(
struct inode *dir,
- const char *name,
- int len,
+ struct dentry* dentry,
int nospc) /* Flag special file ? */
{
struct super_block *sb = dir->i_sb;
int res;
struct buffer_head *bh;
- struct msdos_dir_entry *de;
struct slot_info sinfo;
bh = NULL;
- if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0)
+ if ((res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo)) < 0)
goto unlink_done;
if (res >= 0 && sinfo.total_slots > 0) {
- res = vfat_remove_entry(dir,&sinfo,&bh,&de,0,nospc);
+ res = vfat_remove_entry(dir,&sinfo,&bh,dentry,0,nospc);
if (res > 0) {
res = 0;
}
@@ -1311,15 +1293,14 @@ unlink_done:
}
-int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
+int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
{
struct inode *inode;
int res;
fat_lock_creation();
- if ((res = vfat_create_entry(dir,name,len,1,&inode)) < 0) {
+ if ((res = vfat_create_entry(dir,&dentry->d_name,1,&inode)) < 0) {
fat_unlock_creation();
- iput(dir);
return res;
}
@@ -1330,28 +1311,27 @@ int vfat_mkdir(struct inode *dir,const char *name,int len,int mode)
res = vfat_create_dotdirs(inode, dir);
fat_unlock_creation();
MSDOS_I(inode)->i_busy = 0;
- iput(inode);
- iput(dir);
+ d_instantiate(dentry,inode);
if (res < 0) {
- if (vfat_rmdir(dir,name,len) < 0)
+ if (vfat_rmdir(dir,dentry) < 0)
fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
}
return res;
}
/***** Unlink, as called for msdosfs */
-int vfat_unlink(struct inode *dir,const char *name,int len)
+int vfat_unlink(struct inode *dir,struct dentry* dentry)
{
int res;
- res = vfat_unlinkx (dir,name,len,1);
- iput(dir);
+ res = vfat_unlinkx (dir,dentry,1);
+ d_delete(dentry);
return res;
}
-int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
- struct inode *new_dir,const char *new_name,int new_len)
+int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
+ struct inode *new_dir,struct dentry *new_dentry)
{
struct super_block *sb = old_dir->i_sb;
struct buffer_head *old_bh,*new_bh,*dotdot_bh;
@@ -1364,13 +1344,15 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
struct slot_info sinfo;
PRINTK(("vfat_rename 1\n"));
- if (old_dir == new_dir && old_len == new_len &&
- strncmp(old_name, new_name, old_len) == 0)
+ if (old_dir == new_dir &&
+ old_dentry->d_name.len == new_dentry->d_name.len &&
+ strncmp(old_dentry->d_name.name, new_dentry->d_name.name,
+ old_dentry->d_name.len) == 0)
return 0;
old_bh = new_bh = NULL;
old_inode = new_inode = NULL;
- res = vfat_find(old_dir,old_name,old_len,1,0,0,&sinfo);
+ res = vfat_find(old_dir,&old_dentry->d_name,1,0,0,&sinfo);
PRINTK(("vfat_rename 2\n"));
if (res < 0) goto rename_done;
@@ -1383,8 +1365,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
if (res < 0) goto rename_done;
res = -ENOENT;
- if (!(old_inode = iget(old_dir->i_sb,old_ino)))
- goto rename_done;
+ old_inode = old_dentry->d_inode;
is_dir = S_ISDIR(old_inode->i_mode);
if (is_dir) {
if ((old_dir->i_dev != new_dir->i_dev) ||
@@ -1413,7 +1394,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
iput(walk);
}
- res = vfat_find(new_dir,new_name,new_len,1,0,is_dir,&sinfo);
+ res = vfat_find(new_dir,&new_dentry->d_name,1,0,is_dir,&sinfo);
PRINTK(("vfat_rename 4\n"));
if (res > -1) {
@@ -1432,12 +1413,12 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
iput(new_inode);
if (new_is_dir) {
PRINTK(("vfat_rename 7\n"));
- res = vfat_rmdirx(new_dir,new_name,new_len);
+ res = vfat_rmdirx(new_dir,&new_dentry);
PRINTK(("vfat_rename 8\n"));
if (res < 0) goto rename_done;
} else {
PRINTK(("vfat_rename 9\n"));
- res = vfat_unlinkx(new_dir,new_name,new_len,1);
+ res = vfat_unlinkx(new_dir,new_dentry,1);
PRINTK(("vfat_rename 10\n"));
if (res < 0) goto rename_done;
}
@@ -1445,7 +1426,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
PRINTK(("vfat_rename 11\n"));
fat_lock_creation(); locked = 1;
- res = vfat_find(new_dir,new_name,new_len,1,1,is_dir,&sinfo);
+ res = vfat_find(new_dir,&new_dentry->d_name,1,1,is_dir,&sinfo);
PRINTK(("vfat_rename 12\n"));
if (res < 0) goto rename_done;
@@ -1524,6 +1505,8 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
}
if (res > 0) res = 0;
+ d_instantiate(new_dentry,new_inode);
+ d_delete(old_dentry);
rename_done:
if (locked)
@@ -1532,10 +1515,6 @@ rename_done:
fat_brelse(sb, old_bh);
if (new_bh)
fat_brelse(sb, new_bh);
- if (old_inode)
- iput(old_inode);
- iput(old_dir);
- iput(new_dir);
return res;
}
@@ -1554,6 +1533,7 @@ struct inode_operations vfat_dir_inode_operations = {
NULL, /* mknod */
vfat_rename, /* rename */
NULL, /* readlink */
+ NULL, /* followlink */
NULL, /* readpage */
NULL, /* writepage */
fat_bmap, /* bmap */
diff --git a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h
index 263cf8050..951cb5077 100644
--- a/include/asm-alpha/keyboard.h
+++ b/include/asm-alpha/keyboard.h
@@ -3,7 +3,7 @@
*
* Created 3 Nov 1996 by Geert Uytterhoeven
*
- * $Id: keyboard.h,v 1.3 1997/07/22 23:18:14 ralf Exp $
+ * $Id: keyboard.h,v 1.3 1997/07/24 01:55:54 ralf Exp $
*/
/*
@@ -30,6 +30,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
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];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
@@ -38,9 +39,12 @@ extern void pckbd_init_hw(void);
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
#define INIT_KBD
+#define SYSRQ_KEY 0x54
+
/*
* keyboard controller registers
*/
diff --git a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h
index eaf0fa874..ab936e6bc 100644
--- a/include/asm-i386/keyboard.h
+++ b/include/asm-i386/keyboard.h
@@ -3,7 +3,7 @@
*
* Created 3 Nov 1996 by Geert Uytterhoeven
*
- * $Id: keyboard.h,v 1.4 1997/07/23 06:06:09 ralf Exp $
+ * $Id: keyboard.h,v 1.3 1997/07/24 01:55:55 ralf Exp $
*/
/*
@@ -30,6 +30,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
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];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
@@ -38,6 +39,9 @@ extern void pckbd_init_hw(void);
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
/* How to access the keyboard macros on this platform. */
#define kbd_read_input() inb(KBD_DATA_REG)
diff --git a/include/asm-i386/smp_lock.h b/include/asm-i386/smp_lock.h
index 4f78f97fb..fc7eb94de 100644
--- a/include/asm-i386/smp_lock.h
+++ b/include/asm-i386/smp_lock.h
@@ -39,6 +39,8 @@ do { if (depth) __asm__ __volatile__( \
} while (0)
+extern const char lk_lockmsg[];
+
/* Locking the kernel */
extern __inline__ void lock_kernel(void)
{
@@ -46,7 +48,7 @@ extern __inline__ void lock_kernel(void)
if (local_irq_count[cpu]) {
__label__ l1;
-l1: printk("lock from interrupt context at %p\n", &&l1);
+l1: printk(lk_lockmsg, &&l1);
}
if (cpu == global_irq_holder) {
__label__ l2;
diff --git a/include/asm-m68k/serial.h b/include/asm-m68k/serial.h
index 7c873c341..607b408ec 100644
--- a/include/asm-m68k/serial.h
+++ b/include/asm-m68k/serial.h
@@ -31,7 +31,7 @@
#define SER_AMIGA 105 /* Amiga built-in serial port */
#define SER_IOEXT 106 /* Amiga GVP IO-Extender (16c552) */
#define SER_MFC_III 107 /* Amiga BSC Multiface Card III (MC68681) */
-
+#define SER_WHIPPET 108 /* Amiga Hisoft Whippet PCMCIA (16c550B) */
struct serial_struct {
int type;
diff --git a/include/asm-mips/ioctls.h b/include/asm-mips/ioctls.h
index 5648eae7f..c0c3d2dad 100644
--- a/include/asm-mips/ioctls.h
+++ b/include/asm-mips/ioctls.h
@@ -96,8 +96,10 @@
#define TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */
#define TIOCTTYGSTRUCT 0x5487 /* For debugging only */
+#ifdef WHAT_TO_DO_WITH_THIS_DULPLICATE
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
+#endif
#define TIOCSERCONFIG 0x5488
#define TIOCSERGWILD 0x5489
@@ -110,5 +112,7 @@
#define TIOCSERSETMULTI 0x5490 /* Set multiport config */
#define TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */
#define TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */
+#define TIOCSBRK 0x5491 /* BSD compatibility */
+#define TIOCCBRK 0x5492 /* BSD compatibility */
#endif /* __ASM_MIPS_IOCTLS_H */
diff --git a/include/asm-mips/keyboard.h b/include/asm-mips/keyboard.h
index 499024c3b..813cb7c69 100644
--- a/include/asm-mips/keyboard.h
+++ b/include/asm-mips/keyboard.h
@@ -5,7 +5,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * $Id: keyboard.h,v 1.5 1997/07/23 17:41:07 ralf Exp $
+ * $Id: keyboard.h,v 1.4 1997/07/24 01:55:56 ralf Exp $
*/
#ifndef __ASM_MIPS_KEYBOARD_H
#define __ASM_MIPS_KEYBOARD_H
@@ -25,6 +25,7 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
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];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
@@ -33,6 +34,9 @@ extern void pckbd_init_hw(void);
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
+#define kbd_sysrq_xlate pckbd_sysrq_xlate
+
+#define SYSRQ_KEY 0x54
#define INIT_KBD /* full initialization for the keyboard controller. */
diff --git a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h
index c34bc36ef..6070ea738 100644
--- a/include/asm-ppc/atomic.h
+++ b/include/asm-ppc/atomic.h
@@ -5,23 +5,116 @@
#ifndef _ASM_PPC_ATOMIC_H_
#define _ASM_PPC_ATOMIC_H_
+#ifdef __SMP__
+typedef struct { volatile int counter; } atomic_t;
+#else
typedef struct { int counter; } atomic_t;
-#define ATOMIC_INIT(i) { (i) }
+#endif
-/*
- * Make sure gcc doesn't try to be clever and move things around
- * on us. We need to use _exactly_ the address the user gave us,
- * not some alias that contains the same information.
- */
-#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ((v)->counter)
-#define atomic_set(v) (((v)->counter) = i)
+#define atomic_set(v,i) (((v)->counter) = (i))
-#define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
-#define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
+extern void atomic_add(int a, atomic_t *v);
+extern void atomic_sub(int a, atomic_t *v);
+extern void atomic_inc(atomic_t *v);
+extern int atomic_inc_return(atomic_t *v);
+extern void atomic_dec(atomic_t *v);
+extern int atomic_dec_return(atomic_t *v);
+extern int atomic_dec_and_test(atomic_t *v);
-#define atomic_inc(v) atomic_add(1,(v))
-#define atomic_dec(v) atomic_sub(1,(v))
-#endif
+extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
+extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
+
+#if 0 /* for now */
+extern __inline__ void atomic_add(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ add %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+}
+
+extern __inline__ void atomic_sub(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ subf %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+}
+
+extern __inline__ int atomic_sub_and_test(atomic_t a, atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3\n\
+ subf %0,%2,%0\n\
+ stwcx. %0,0,%3\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (a), "r" (v)
+ : "cc");
+
+ return t == 0;
+}
+
+extern __inline__ void atomic_inc(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+}
+
+extern __inline__ void atomic_dec(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+}
+
+extern __inline__ int atomic_dec_and_test(atomic_t *v)
+{
+ atomic_t t;
+
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%2\n\
+ addic %0,%0,-1\n\
+ stwcx. %0,0,%2\n\
+ bne 1b"
+ : "=&r" (t), "=m" (*v)
+ : "r" (v)
+ : "cc");
+
+ return t == 0;
+}
+#endif /* 0 */
+#endif /* _ASM_PPC_ATOMIC_H_ */
diff --git a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
index 959f2b302..3b8a24575 100644
--- a/include/asm-ppc/bitops.h
+++ b/include/asm-ppc/bitops.h
@@ -3,67 +3,155 @@
#include <asm/system.h>
#include <asm/byteorder.h>
+#include <linux/kernel.h> /* for printk */
#define BIT(n) 1<<(n&0x1F)
typedef unsigned long BITFIELD;
-/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
- * is in the highest of the four bytes and bit '31' is the high bit
- * within the first byte. powerpc is BIG-Endian. Unless noted otherwise
- * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+/*
+ * These are ifdef'd out here because using : "cc" as a constraing
+ * results in errors from gcc. -- Cort
*/
-extern __inline__ int set_bit(int nr, void * add)
+#if 0
+extern __inline__ int set_bit(int nr, void * addr)
{
- BITFIELD *addr = add;
- long mask,oldbit;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- oldbit = (mask & *addr) != 0;
- *addr |= mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return oldbit;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("set_bit(%lx, %p)\n", nr, addr);
+
+ __asm__ __volatile__(
+ "1:lwarx %0,0,%3 \n\t"
+ "or %1,%0,%2 \n\t"
+ "stwcx. %1,0,%3 \n\t"
+ "bne 1b \n\t"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc" */);
+
+n return (old & mask) != 0;
}
-extern __inline__ int change_bit(int nr, void *add)
+extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
{
- BITFIELD *addr = add;
- int mask, retval;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- retval = (mask & *addr) != 0;
- *addr ^= mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
-#endif
- return retval;
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("clear_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ andc %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
}
-extern __inline__ int clear_bit(int nr, void *add)
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
{
- BITFIELD *addr = add;
- int mask, retval;
-#ifdef __KERNEL__
- int s = _disable_interrupts();
-#endif
- addr += nr >> 5;
- mask = BIT(nr);
- retval = (mask & *addr) != 0;
- *addr &= ~mask;
-#ifdef __KERNEL__
- _enable_interrupts(s);
+ unsigned long old, t;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
+
+ if ((unsigned long)addr & 3)
+ printk("change_bit(%lx, %p)\n", nr, addr);
+ __asm__ __volatile__("\n\
+1: lwarx %0,0,%3
+ xor %1,%0,%2
+ stwcx. %1,0,%3
+ bne 1b"
+ : "=&r" (old), "=&r" (t) /*, "=m" (*p)*/
+ : "r" (mask), "r" (p)
+ /*: "cc"*/);
+
+ return (old & mask) != 0;
+}
#endif
- return retval;
+
+extern __inline__ int ffz(unsigned int x)
+{
+ int n;
+
+ x = ~x & (x+1); /* set LS zero to 1, other bits to 0 */
+ __asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
+ return 31 - n;
}
+/*
+ * This implementation of find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h.
+ */
+
+extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
+{
+ unsigned int * p = ((unsigned int *) addr);
+ unsigned int result = 0;
+ unsigned int tmp;
+
+ if (size == 0)
+ return 0;
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+/*
+ * Find next zero bit in a bitmap reasonably efficiently..
+ */
+extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
+ unsigned long offset)
+{
+ unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
+ unsigned int result = offset & ~31UL;
+ unsigned int tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *(p++);
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+
#define _EXT2_HAVE_ASM_BITOPS_
#define ext2_find_first_zero_bit(addr, size) \
ext2_find_next_zero_bit((addr), (size), 0)
diff --git a/include/asm-ppc/bugs.h b/include/asm-ppc/bugs.h
index 202f9ab06..8dce1e290 100644
--- a/include/asm-ppc/bugs.h
+++ b/include/asm-ppc/bugs.h
@@ -2,7 +2,5 @@
* This file is included by 'init/main.c'
*/
-void
-check_bugs(void)
-{
-}
+extern void
+check_bugs(void);
diff --git a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h
index bbb257941..eab03c752 100644
--- a/include/asm-ppc/byteorder.h
+++ b/include/asm-ppc/byteorder.h
@@ -1,6 +1,8 @@
#ifndef _PPC_BYTEORDER_H
#define _PPC_BYTEORDER_H
+#include <asm/types.h>
+
#ifndef __BIG_ENDIAN
#define __BIG_ENDIAN
#endif
@@ -16,21 +18,50 @@
#define __htonl(x) ntohl(x)
#define __htons(x) ntohs(x)
+
+#define __constant_ntohs(x) ntohs(x)
+#define __constant_ntohl(x) ntohl(x)
#define __constant_htonl(x) ntohl(x)
#define __constant_htons(x) ntohs(x)
#ifdef __KERNEL__
+/*
+ * 16 and 32 bit little-endian loads and stores.
+ */
+extern inline unsigned ld_le16(volatile unsigned short *addr)
+{
+ unsigned val;
-/* Convert from CPU byte order, to specified byte order. */
-extern __inline__ __u16 cpu_to_le16(__u16 value)
+ asm volatile("lhbrx %0,0,%1" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+extern inline void st_le16(volatile unsigned short *addr, unsigned val)
+{
+ asm volatile("sthbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned ld_le32(volatile unsigned *addr)
+{
+ unsigned val;
+
+ asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+ return val;
+}
+
+extern inline void st_le32(volatile unsigned *addr, unsigned val)
{
- return (value >> 8) | (value << 8);
+ asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
}
+
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+ return ld_le16(&value);
+}
extern __inline__ __u32 cpu_to_le32(__u32 value)
{
- return((value>>24) | ((value>>8)&0xff00) |
- ((value<<8)&0xff0000) | (value<<24));
+ return ld_le32(&value);
}
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
@@ -38,33 +69,33 @@ extern __inline__ __u32 cpu_to_le32(__u32 value)
/* The same, but returns converted value from the location pointer by addr. */
extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
{
- return cpu_to_le16(*addr);
+ return ld_le16(addr);
}
extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
{
- return cpu_to_le32(*addr);
+ return ld_le32(addr);
}
extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
{
- return cpu_to_be16(*addr);
+ return *addr;
}
extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
{
- return cpu_to_be32(*addr);
+ return *addr;
}
/* The same, but do the conversion in situ, ie. put the value back to addr. */
extern __inline__ void cpu_to_le16s(__u16 *addr)
{
- *addr = cpu_to_le16(*addr);
+ st_le16(addr,*addr);
}
extern __inline__ void cpu_to_le32s(__u32 *addr)
{
- *addr = cpu_to_le32(*addr);
+ st_le32(addr,*addr);
}
#define cpu_to_be16s(x) do { } while (0)
@@ -86,5 +117,12 @@ extern __inline__ void cpu_to_le32s(__u32 *addr)
#define be16_to_cpus(x) cpu_to_be16s(x)
#define be32_to_cpus(x) cpu_to_be32s(x)
+
#endif /* __KERNEL__ */
#endif /* !(_PPC_BYTEORDER_H) */
+
+
+
+
+
+
diff --git a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
index da609f271..8bdffcdfb 100644
--- a/include/asm-ppc/cache.h
+++ b/include/asm-ppc/cache.h
@@ -5,7 +5,8 @@
#define __ARCH_PPC_CACHE_H
/* bytes per L1 cache line */
-#define L1_CACHE_BYTES 32 /* a guess */
+/* a guess */ /* a correct one -- Cort */
+#define L1_CACHE_BYTES 32
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
diff --git a/include/asm-ppc/checksum.h b/include/asm-ppc/checksum.h
index 74e943792..7b55f0032 100644
--- a/include/asm-ppc/checksum.h
+++ b/include/asm-ppc/checksum.h
@@ -47,6 +47,20 @@ unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
*/
#define csum_partial_copy_fromuser csum_partial_copy
+/*
+ * this is a new version of the above that records errors it finds in *errp,
+ * but continues and zeros the rest of the buffer.
+ *
+ * right now - it just calls csum_partial_copy()
+ * -- Cort
+ */
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ int *dst_err_ptr=NULL;
+ return csum_partial_copy( src, dst, len, sum);
+}
/*
* this routine is used for miscellaneous IP-like checksums, mainly
diff --git a/include/asm-ppc/current.h b/include/asm-ppc/current.h
index d815aaad3..d7a0a9215 100644
--- a/include/asm-ppc/current.h
+++ b/include/asm-ppc/current.h
@@ -1,12 +1,10 @@
#ifndef _PPC_CURRENT_H
#define _PPC_CURRENT_H
-/* Some architectures may want to do something "clever" here since
- * this is the most frequently accessed piece of data in the entire
- * kernel. For an example, see the Sparc implementation where an
- * entire register is hard locked to contain the value of current.
- */
-extern struct task_struct *current_set[NR_CPUS];
-#define current (current_set[smp_processor_id()]) /* Current on this processor */
+#include <linux/config.h>
+
+extern struct task_struct *current_set[1];
+
+register struct task_struct *current asm("r2");
#endif /* !(_PPC_CURRENT_H) */
diff --git a/include/asm-ppc/delay.h b/include/asm-ppc/delay.h
index 68f1a4da7..9da227167 100644
--- a/include/asm-ppc/delay.h
+++ b/include/asm-ppc/delay.h
@@ -1,14 +1,31 @@
#ifndef _PPC_DELAY_H
#define _PPC_DELAY_H
+/*
+ * Copyright 1996, Paul Mackerras.
+ *
+ * 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.
+ */
-extern __inline__ void __delay(unsigned long );
-extern __inline__ void __udelay(unsigned long );
-
+extern __inline__ void __delay(unsigned int loops)
+{
+ if (loops != 0)
+ __asm__ __volatile__("mtctr %0; 1: bdnz 1b" : :
+ "r" (loops) : "ctr");
+}
-extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+extern __inline__ void udelay(unsigned long usecs)
{
- return (a*b)/c;
+ unsigned long loops;
+
+ /* compute (usecs * 2^32 / 10^6) * loops_per_sec / 2^32 */
+ usecs *= 0x10c6; /* 2^32 / 10^6 */
+ __asm__("mulhwu %0,%1,%2" : "=r" (loops) :
+ "r" (usecs), "r" (loops_per_sec));
+ __delay(loops);
}
#endif /* defined(_PPC_DELAY_H) */
diff --git a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h
index ca609062e..7becf0190 100644
--- a/include/asm-ppc/dma.h
+++ b/include/asm-ppc/dma.h
@@ -1,16 +1,21 @@
-/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $
+/* $Id: dma.h,v 1.3 1997/03/16 06:20:39 cort Exp $
* linux/include/asm/dma.h: Defines for using and allocating dma channels.
* Written by Hennus Bergman, 1992.
* High DMA channel support & info by Hannu Savolainen
* and John Boyd, Nov. 1992.
*/
+#include <linux/config.h>
+
/*
* Note: Adapted for PowerPC by Gary Thomas
* Modified by Cort Dougan <cort@cs.nmt.edu>
*
+ * None of this really applies for Power Macintoshes. There is
+ * basically just enough here to get kernel/dma.c to compile.
+ *
* There may be some comments or restrictions made here which are
- * not valid for the PowerPC (PreP) platform. Take what you read
+ * not valid for the PReP platform. Take what you read
* with a grain of salt.
*/
@@ -18,6 +23,7 @@
#ifndef _ASM_DMA_H
#define _ASM_DMA_H
+#ifdef CONFIG_PREP
#include <asm/io.h> /* need byte IO */
@@ -295,5 +301,6 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
/* These are in kernel/dma.c: */
extern void free_dma(unsigned int dmanr); /* release it again */
+#endif /* CONFIG_PREP */
#endif /* _ASM_DMA_H */
diff --git a/include/asm-ppc/errno.h b/include/asm-ppc/errno.h
index 8c47b73e7..ff364b820 100644
--- a/include/asm-ppc/errno.h
+++ b/include/asm-ppc/errno.h
@@ -133,4 +133,6 @@
#define ERESTARTNOHAND 514 /* restart if no handler.. */
#define ENOIOCTLCMD 515 /* No ioctl command */
+#define _LAST_ERRNO 515
+
#endif
diff --git a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
index 69838b8b1..bc16288a8 100644
--- a/include/asm-ppc/ide.h
+++ b/include/asm-ppc/ide.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-i386/ide.h
+ * linux/include/asm-ppc/ide.h
*
* Copyright (C) 1994-1996 Linus Torvalds & authors
*/
@@ -13,7 +13,7 @@
#ifdef __KERNEL__
-typedef unsigned short ide_ioreg_t;
+#include <linux/config.h>
#ifndef MAX_HWIFS
#define MAX_HWIFS 4
@@ -21,11 +21,15 @@ typedef unsigned short ide_ioreg_t;
#define ide_sti() sti()
+#ifdef CONFIG_PREP
+
+typedef unsigned short ide_ioreg_t;
+
static __inline__ int ide_default_irq(ide_ioreg_t base)
{
switch (base) {
- case 0x1f0: return 14;
- case 0x170: return 15;
+ case 0x1f0: return 13;
+ case 0x170: return 13;
case 0x1e8: return 11;
case 0x168: return 10;
default:
@@ -66,18 +70,7 @@ typedef union {
unsigned lba : 1; /* using LBA instead of CHS */
unsigned bit7 : 1; /* always 1 */
} b;
- } select_t;
-
-static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *device, void *dev_id)
-{
- return request_irq(irq, handler, flags, device, dev_id);
-}
-
-static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
-{
- free_irq(irq, dev_id);
-}
+} select_t;
static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
{
@@ -94,26 +87,92 @@ static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent
release_region(from, extent);
}
-/*
- * The following are not needed for the non-m68k ports
- */
-static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+#define ide_fix_driveid(id) do {} while (0)
+
+#endif
+
+#ifdef CONFIG_PMAC
+
+#include <asm/io.h> /* so we can redefine insw/outsw */
+
+typedef unsigned long ide_ioreg_t;
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+ return 0;
+}
+
+extern __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+ return index;
+}
+
+extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+
+typedef union {
+ unsigned all : 8; /* all of the bits together */
+ struct {
+ unsigned bit7 : 1; /* always 1 */
+ unsigned lba : 1; /* using LBA instead of CHS */
+ unsigned bit5 : 1; /* always 1 */
+ unsigned unit : 1; /* drive select number, 0/1 */
+ unsigned head : 4; /* always zeros here */
+ } b;
+} select_t;
+
+#undef SUPPORT_SLOW_DATA_PORTS
+#define SUPPORT_SLOW_DATA_PORTS 0
+#undef SUPPORT_VLB_SYNC
+#define SUPPORT_VLB_SYNC 0
+
+static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
{
- return(1);
+ return 0;
}
-static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
{
}
-static __inline__ void ide_release_lock (int *ide_lock)
+static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
{
}
-static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+#undef insw
+#undef outsw
+#define insw(port, buf, ns) ide_insw((port), (buf), (ns))
+#define outsw(port, buf, ns) ide_outsw((port), (buf), (ns))
+
+void ide_insw(ide_ioreg_t port, void *buf, int ns);
+void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+
+#define ide_fix_driveid(id) do { \
+ int nh; \
+ unsigned short *p = (unsigned short *) id; \
+ for (nh = SECTOR_WORDS * 2; nh != 0; --nh, ++p) \
+ *p = (*p << 8) + (*p >> 8); \
+} while (0)
+
+#endif
+
+static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+ unsigned long flags, const char *device, void *dev_id)
{
+ return request_irq(irq, handler, flags, device, dev_id);
+}
+
+static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
+{
+ free_irq(irq, dev_id);
}
+/*
+ * The following are not needed for the non-m68k ports
+ */
+#define ide_ack_intr(base, irq) (1)
+#define ide_release_lock(lock) do {} while (0)
+#define ide_get_lock(lock, hdlr, data) do {} while (0)
+
#endif /* __KERNEL__ */
#endif /* __ASMPPC_IDE_H */
diff --git a/include/asm-ppc/init.h b/include/asm-ppc/init.h
index 82ce44ce8..09b38d899 100644
--- a/include/asm-ppc/init.h
+++ b/include/asm-ppc/init.h
@@ -1,14 +1,23 @@
#ifndef _PPC_INIT_H
#define _PPC_INIT_H
-/* Throwing the initialization code and data out is not supported yet... */
-
-#define __init
+#define __init
#define __initdata
-#define __initfunc(__arginit) __arginit
-/* For assembly routines */
+#define __initfunc(x) x
+/*
+#define __init __attribute__ ((__section__ (".text.init")))
+#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __initfunc(__arginit) \
+ __arginit __init; \
+ __arginit
+*/
+ /* For assembly routines */
#define __INIT
#define __FINIT
#define __INITDATA
-
+/*
+#define __INIT .section ".text.init",#alloc,#execinstr
+#define __FINIT .previous
+#define __INITDATA .section ".data.init",#alloc,#write
+*/
#endif
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 581d51643..e2dfcc49a 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -1,8 +1,11 @@
#ifndef _PPC_IO_H
#define _PPC_IO_H
+#include <linux/config.h>
#include <asm/page.h>
+#include <asm/byteorder.h>
+#ifdef CONFIG_PREP
/* from the Carolina Technical Spec -- Cort */
#define IBM_ACORN 0x82A
#define SIO_CONFIG_RA 0x398
@@ -14,15 +17,67 @@
#define IBM_L2_INVALIDATE 0x814
#define IBM_SYS_CTL 0x81c
-
-
-/* Define the particulars of outb/outw/outl "instructions" */
#define SLOW_DOWN_IO
#ifndef PCI_DRAM_OFFSET
#define PCI_DRAM_OFFSET 0x80000000
#endif
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+void outsl(int port, long *ptr, int len);
+
+__inline__ unsigned char outb(unsigned char val, int port);
+__inline__ unsigned short outw(unsigned short val, int port);
+__inline__ unsigned long outl(unsigned long val, int port);
+__inline__ unsigned char inb(int port);
+__inline__ unsigned short inw(int port);
+__inline__ unsigned long inl(int port);
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+#endif /* CONFIG_PREP */
+
+#ifdef CONFIG_PMAC
+/*
+ * Read and write the non-volatile RAM.
+ */
+extern int nvram_readb(int addr);
+extern void nvram_writeb(int addr, int val);
+
+#ifndef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET 0
+#endif
+
+#define inb(port) in_8((unsigned char *)(port))
+#define outb(val, port) out_8((unsigned char *)(port), (val))
+#define inw(port) in_le16((unsigned short *)(port))
+#define outw(val, port) out_le16((unsigned short *)(port), (val))
+#define inl(port) in_le32((unsigned long *)(port))
+#define outl(val, port) out_le32((unsigned long *)(port), (val))
+
+#define inb_p(port) in_8((unsigned char *)(port))
+#define outb_p(val, port) out_8((unsigned char *)(port), (val))
+#define inw_p(port) in_le16((unsigned short *)(port))
+#define outw_p(val, port) out_le16((unsigned short *)(port), (val))
+#define inl_p(port) in_le32(((unsigned long *)port))
+#define outl_p(val, port) out_le32((unsigned long *)(port), (val))
+
+#define insw(port, buf, ns) _insw((unsigned short *)(port), (buf), (ns))
+#define outsw(port, buf, ns) _outsw((unsigned short *)(port), (buf), (ns))
+#define insl(port, buf, nl) _insl((unsigned long *)(port), (buf), (nl))
+#define outsl(port, buf, nl) _outsl((unsigned long *)(port), (buf), (nl))
+#endif /* CONFIG_PMAC */
/*
* The PCI bus is inherently Little-Endian. The PowerPC is being
@@ -42,19 +97,12 @@ extern inline void * bus_to_virt(unsigned long address)
if (address == 0) return 0;
return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
}
-/* #define virt_to_bus(a) ((unsigned long)(((char *)a==(char *) 0) ? ((char *)0) \
- : ((char *)((long)a - KERNELBASE + PCI_DRAM_OFFSET))))
-#define bus_to_virt(a) ((void *) (((char *)a==(char *)0) ? ((char *)0) \
- : ((char *)((long)a - PCI_DRAM_OFFSET + KERNELBASE))))
-*/
-
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+/*
+ * Map in an area of physical address space, for accessing
+ * I/O devices etc.
+ */
+extern void *ioremap(unsigned long address, unsigned long size);
/*
* Change virtual addresses to physical addresses and vv.
@@ -72,27 +120,101 @@ extern inline void * phys_to_virt(unsigned long address)
return (void *) address;
}
-/* from arch/ppc/kernel/port_io.c
- * -- Cort
+#define _IO_BASE ((unsigned long)0x80000000)
+
+/*
+ * These are much more useful le/be io functions from Paul
+ * than leXX_to_cpu() style functions since the ppc has
+ * load/store byte reverse instructions
+ * -- Cort
*/
-unsigned char inb(int port);
-unsigned short inw(int port);
-unsigned long inl(int port);
-unsigned char outb(unsigned char val,int port);
-unsigned short outw(unsigned short val,int port);
-unsigned long outl(unsigned long val,int port);
-void outsl(int port, long *ptr, int len);
-static inline unsigned char inb_p(int port) {return (inb(port)); }
-static inline unsigned short inw_p(int port) {return (inw(port)); }
-static inline unsigned long inl_p(int port) {return (inl(port)); }
+/*
+ * Enforce In-order Execution of I/O:
+ * Acts as a barrier to ensure all previous I/O accesses have
+ * completed before any further ones are issued.
+ */
+extern inline void eieio(void)
+{
+ asm volatile ("eieio" : :);
+}
+
+/*
+ * 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
+ */
+extern inline int in_8(volatile unsigned char *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+
+extern inline void out_8(volatile unsigned char *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
+
+extern inline int in_le16(volatile unsigned short *addr)
+{
+ int ret;
+
+ ret = ld_le16(addr);
+ eieio();
+ return ret;
+}
+
+extern inline int in_be16(volatile unsigned short *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+extern inline void out_le16(volatile unsigned short *addr, int val)
+{
+ st_le16(addr, val);
+ eieio();
+}
+extern inline void out_be16(volatile unsigned short *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
-static inline unsigned char outb_p(unsigned char val,int port) { return (outb(val,port)); }
-static inline unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
-static inline unsigned long outl_p(unsigned long val,int port) { return (outl(val,port)); }
+extern inline unsigned in_le32(volatile unsigned *addr)
+{
+ unsigned ret;
+ ret = ld_le32(addr);
+ eieio();
+ return ret;
+}
+extern inline int in_be32(volatile unsigned *addr)
+{
+ int ret;
+
+ ret = *addr;
+ eieio();
+ return ret;
+}
+
+extern inline void out_le32(volatile unsigned *addr, int val)
+{
+ st_le32(addr, val);
+ eieio();
+}
+
+extern inline void out_be32(volatile unsigned *addr, int val)
+{
+ *addr = val;
+ eieio();
+}
#endif
diff --git a/include/asm-ppc/ioctls.h b/include/asm-ppc/ioctls.h
index f56e53db7..2039f4954 100644
--- a/include/asm-ppc/ioctls.h
+++ b/include/asm-ppc/ioctls.h
@@ -83,8 +83,8 @@
#define TIOCGETD 0x5424
#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */
-#define TIOCSBRK 0x5427 /* BSD compatibility */
-#define TIOCCBRK 0x5428 /* BSD compatibility */
+#define TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454
diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
index f457f82c3..ebffe2bcb 100644
--- a/include/asm-ppc/irq.h
+++ b/include/asm-ppc/irq.h
@@ -1,7 +1,13 @@
#ifndef _ASM_IRQ_H
#define _ASM_IRQ_H
+#include <linux/config.h>
+
+#ifdef CONFIG_PMAC
#define NR_IRQS 32
+#else
+#define NR_IRQS 16
+#endif
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h
index 9ac4139b9..0c7240d14 100644
--- a/include/asm-ppc/keyboard.h
+++ b/include/asm-ppc/keyboard.h
@@ -2,12 +2,14 @@
* linux/include/asm-ppc/keyboard.h
*
* Created 3 Nov 1996 by Geert Uytterhoeven
+ * Modified for Power Macintosh by Paul Mackerras
*
- * $Id: keyboard.h,v 1.3 1997/07/22 23:18:19 ralf Exp $
+ * $Id: keyboard.h,v 1.3 1997/07/24 01:55:57 ralf Exp $
*/
/*
- * This file contains the ppc architecture specific keyboard definitions
+ * This file contains the ppc architecture specific keyboard definitions -
+ * like the intel pc for prep systems, different for power macs.
*/
#ifndef __ASMPPC_KEYBOARD_H
@@ -17,6 +19,29 @@
#include <asm/io.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MAC_KEYBOARD
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode);
+extern int mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+
+#define kbd_setkeycode mackbd_setkeycode
+#define kbd_getkeycode mackbd_getkeycode
+#define kbd_pretranslate mackbd_pretranslate
+#define kbd_translate mackbd_translate
+#define kbd_unexpected_up mackbd_unexpected_up
+#define kbd_leds mackbd_leds
+#define kbd_init_hw mackbd_init_hw
+
+#else /* CONFIG_MAC_KEYBOARD */
+
#define KEYBOARD_IRQ 1
#define DISABLE_KBD_DURING_INTERRUPTS 0
@@ -47,6 +72,7 @@ extern void pckbd_init_hw(void);
#define kbd_pause() do { } while(0)
#define INIT_KBD
+#endif /* CONFIG_MAC_KEYBOARD */
#define keyboard_setup() \
request_region(0x60, 16, "keyboard")
diff --git a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
index 91f93f598..e69de29bb 100644
--- a/include/asm-ppc/mc146818rtc.h
+++ b/include/asm-ppc/mc146818rtc.h
@@ -1,128 +0,0 @@
-/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
- * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
- * derived from Data Sheet, Copyright Motorola 1984 (!).
- * It was written to be part of the Linux operating system.
- */
-/* permission is hereby granted to copy, modify and redistribute this code
- * in terms of the GNU Library General Public License, Version 2 or later,
- * at your option.
- */
-
-#ifndef _MC146818RTC_H
-#define _MC146818RTC_H
-
-#include <asm/io.h>
-
-#ifndef RTC_PORT
-#define RTC_PORT(x) (0x70 + (x))
-#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
-#endif
-
-/*
- * The yet supported machines all access the RTC index register via
- * an ISA port access but the way to access the date register differs ...
- */
-#define CMOS_READ(addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-inb_p(RTC_PORT(1)); \
-})
-#define CMOS_WRITE(val, addr) ({ \
-outb_p((addr),RTC_PORT(0)); \
-outb_p((val),RTC_PORT(1)); \
-})
-
-#ifndef MCRTC_PORT
-#define MCRTC_PORT(x) (0x70 + (x))
-#define MCRTC_ALWAYS_BCD 1
-#endif
-
-#define CMOS_MCRTC_READ(addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-inb_p(MCRTC_PORT(1)); \
-})
-#define CMOS_MCRTC_WRITE(val, addr) ({ \
-outb_p((addr),MCRTC_PORT(0)); \
-outb_p((val),MCRTC_PORT(1)); \
-})
-
-/**********************************************************************
- * register summary
- **********************************************************************/
-#define MCRTC_SECONDS 0
-#define MCRTC_SECONDS_ALARM 1
-#define MCRTC_MINUTES 2
-#define MCRTC_MINUTES_ALARM 3
-#define MCRTC_HOURS 4
-#define MCRTC_HOURS_ALARM 5
-/* RTC_*_alarm is always true if 2 MSBs are set */
-# define MCRTC_ALARM_DONT_CARE 0xC0
-
-#define MCRTC_DAY_OF_WEEK 6
-#define MCRTC_DAY_OF_MONTH 7
-#define MCRTC_MONTH 8
-#define MCRTC_YEAR 9
-
-/* control registers - Moto names
- */
-#define MCRTC_REG_A 10
-#define MCRTC_REG_B 11
-#define MCRTC_REG_C 12
-#define MCRTC_REG_D 13
-
-/**********************************************************************
- * register details
- **********************************************************************/
-#define MCRTC_FREQ_SELECT MCRTC_REG_A
-
-/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
- * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
- * totalling to a max high interval of 2.228 ms.
- */
-# define MCRTC_UIP 0x80
-# define MCRTC_DIV_CTL 0x70
- /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
-# define MCRTC_REF_CLCK_4MHZ 0x00
-# define MCRTC_REF_CLCK_1MHZ 0x10
-# define MCRTC_REF_CLCK_32KHZ 0x20
- /* 2 values for divider stage reset, others for "testing purposes only" */
-# define MCRTC_DIV_RESET1 0x60
-# define MCRTC_DIV_RESET2 0x70
- /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
-# define MCRTC_RATE_SELECT 0x0F
-
-/**********************************************************************/
-#define MCRTC_CONTROL MCRTC_REG_B
-# define MCRTC_SET 0x80 /* disable updates for clock setting */
-# define MCRTC_PIE 0x40 /* periodic interrupt enable */
-# define MCRTC_AIE 0x20 /* alarm interrupt enable */
-# define MCRTC_UIE 0x10 /* update-finished interrupt enable */
-# define MCRTC_SQWE 0x08 /* enable square-wave output */
-# define MCRTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
-# define MCRTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
-# define MCRTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
-
-/**********************************************************************/
-#define MCRTC_INTR_FLAGS MCRTC_REG_C
-/* caution - cleared by read */
-# define MCRTC_IRQF 0x80 /* any of the following 3 is active */
-# define MCRTC_PF 0x40
-# define MCRTC_AF 0x20
-# define MCRTC_UF 0x10
-
-/**********************************************************************/
-#define MCRTC_VALID MCRTC_REG_D
-# define MCRTC_VRT 0x80 /* valid RAM and time */
-/**********************************************************************/
-
-/* example: !(CMOS_READ(MCRTC_CONTROL) & MCRTC_DM_BINARY)
- * determines if the following two #defines are needed
- */
-#ifndef BCD_TO_BIN
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-#endif
-
-#ifndef BIN_TO_BCD
-#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
-#endif
-
-#endif /* _MC146818RTC_H */
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index 1b3217cfd..c6c835229 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -32,42 +32,68 @@ typedef struct _PTE
/* Segment Register */
typedef struct _SEGREG
- {
- unsigned long t:1; /* Normal or I/O type */
- unsigned long ks:1; /* Supervisor 'key' (normally 0) */
- unsigned long kp:1; /* User 'key' (normally 1) */
- unsigned long n:1; /* No-execute */
- unsigned long :4; /* Unused */
- unsigned long vsid:24; /* Virtual Segment Identifier */
- } SEGREG;
+{
+ unsigned long t:1; /* Normal or I/O type */
+ unsigned long ks:1; /* Supervisor 'key' (normally 0) */
+ unsigned long kp:1; /* User 'key' (normally 1) */
+ unsigned long n:1; /* No-execute */
+ unsigned long :4; /* Unused */
+ unsigned long vsid:24; /* Virtual Segment Identifier */
+} SEGREG;
/* Block Address Translation (BAT) Registers */
+typedef struct _P601_BATU
+{
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :8; /* unused */
+ unsigned long w:1;
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+ unsigned long pp:2; /* Page access protections */
+} P601_BATU;
+
typedef struct _BATU /* Upper part of BAT */
- {
- unsigned long bepi:15; /* Effective page index (virtual address) */
- unsigned long :4; /* Unused */
- unsigned long bl:11; /* Block size mask */
- unsigned long vs:1; /* Supervisor valid */
- unsigned long vp:1; /* User valid */
- } BATU;
+{
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :4; /* Unused */
+ unsigned long bl:11; /* Block size mask */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+} BATU;
+
+typedef struct _P601_BATL
+{
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long v:1; /* valid/invalid */
+ unsigned long bl:6; /* Block size mask */
+} P601_BATL;
typedef struct _BATL /* Lower part of BAT */
- {
- unsigned long brpn:15; /* Real page index (physical address) */
- unsigned long :10; /* Unused */
- unsigned long w:1; /* Write-thru cache */
- unsigned long i:1; /* Cache inhibit */
- unsigned long m:1; /* Memory coherence */
- unsigned long g:1; /* Guarded (MBZ) */
- unsigned long :1; /* Unused */
- unsigned long pp:2; /* Page access protections */
- } BATL;
+{
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long w:1; /* Write-thru cache */
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded (MBZ) */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page access protections */
+} BATL;
typedef struct _BAT
- {
- BATU batu; /* Upper register */
- BATL batl; /* Lower register */
- } BAT;
+{
+ BATU batu; /* Upper register */
+ BATL batl; /* Lower register */
+} BAT;
+
+typedef struct _P601_BAT
+{
+ P601_BATU batu; /* Upper register */
+ P601_BATL batl; /* Lower register */
+} P601_BAT;
/* Block size masks */
#define BL_128K 0x000
@@ -118,15 +144,6 @@ typedef struct _MMU_context
pte **pmap; /* Two-level page-map structure */
} MMU_context;
-#if 0
-BAT ibat[4]; /* Instruction BAT images */
-BAT dbat[4]; /* Data BAT images */
-PTE *hash_table; /* Hardware hashed page table */
-int hash_table_size;
-int hash_table_mask;
-unsigned long sdr; /* Hardware image of SDR */
-#endif
-
/* Used to set up SDR register */
#define HASH_TABLE_SIZE_64K 0x00010000
#define HASH_TABLE_SIZE_128K 0x00020000
@@ -143,6 +160,4 @@ unsigned long sdr; /* Hardware image of SDR */
#define HASH_TABLE_MASK_2M 0x01F
#define HASH_TABLE_MASK_4M 0x03F
-extern inline int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
-
#endif
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index f4bd1e84f..89a649bb3 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -1,13 +1,59 @@
#ifndef __PPC_MMU_CONTEXT_H
#define __PPC_MMU_CONTEXT_H
+/* the way contexts are handled on the ppc they are vsid's and
+ don't need any special treatment right now.
+ perhaps I can defer flushing the tlb by keeping a list of
+ zombie vsid/context's and handling that through destroy_context
+ later -- Cort
+ */
+
+#define NO_CONTEXT 0
+#define LAST_CONTEXT 0xfffff
+
+extern int next_mmu_context;
+extern void mmu_context_overflow(void);
+extern void set_context(int context);
+
/*
- * get a new mmu context.. PowerPC's don't know about contexts [yet]
+ * Allocating context numbers this way tends to spread out
+ * the entries in the hash table better than a simple linear
+ * allocation.
*/
-#define get_mmu_context(x) do { } while (0)
+#define MUNGE_CONTEXT(n) (((n) * 897) & LAST_CONTEXT)
-#define init_new_context(mm) do { } while(0)
-#define destroy_context(mm) do { } while(0)
+/*
+ * Get a new mmu context for task tsk if necessary.
+ */
+#define get_mmu_context(tsk) \
+do { \
+ struct mm_struct *mm = (tsk)->mm; \
+ if (mm->context == NO_CONTEXT) { \
+ int i; \
+ if (next_mmu_context == LAST_CONTEXT) \
+ mmu_context_overflow(); \
+ mm->context = MUNGE_CONTEXT(++next_mmu_context);\
+ if ( tsk == current ) \
+ set_context(mm->context); \
+ } \
+} while (0)
-#endif
+/*
+ * Set up the context for a new address space.
+ */
+#define init_new_context(mm) ((mm)->context = NO_CONTEXT)
+
+/*
+ * We're finished using the context for an address space.
+ */
+#define destroy_context(mm) do { } while (0)
+/*
+ * compute the vsid from the context and segment
+ * segments > 7 are kernel segments and their
+ * vsid is the segment -- Cort
+ */
+#define VSID_FROM_CONTEXT(segment,context) \
+ ((segment < 8) ? ((segment) | (context)<<4) : (segment))
+
+#endif
diff --git a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h
index 1d704ff6a..665bc76af 100644
--- a/include/asm-ppc/nvram.h
+++ b/include/asm-ppc/nvram.h
@@ -9,6 +9,7 @@
#define NVRAM_AS1 0x75
#define NVRAM_DATA 0x77
+
/* RTC Offsets */
#define RTC_SECONDS 0x1FF9
@@ -18,6 +19,8 @@
#define RTC_DAY_OF_MONTH 0x1FFD
#define RTC_MONTH 0x1FFE
#define RTC_YEAR 0x1FFF
+#define RTC_CONTROLA 0x1FF8
+#define RTC_CONTROLB 0x1FF9
#ifndef BCD_TO_BIN
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h
index 273d31fd0..a18d5e324 100644
--- a/include/asm-ppc/page.h
+++ b/include/asm-ppc/page.h
@@ -1,11 +1,32 @@
#ifndef _PPC_PAGE_H
#define _PPC_PAGE_H
+#include <linux/config.h>
+
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
+/* This handles the memory map.. */
+
+/*
+ * these virtual mappings for prep and pmac
+ * on the prep machine the io areas are at different physical locations
+ * than their virtual address. On the pmac the io areas
+ * are mapped 1-1 virtual/physical.
+ * -- Cort
+ */
+#ifdef CONFIG_PREP
+#define KERNELBASE 0x90000000
+#endif
+#ifdef CONFIG_PMAC
+#define KERNELBASE 0xc0000000
+#endif
+#define PAGE_OFFSET KERNELBASE
+
+
+#ifndef __ASSEMBLY__
#ifdef __KERNEL__
#define STRICT_MM_TYPECHECKS
@@ -50,13 +71,13 @@ typedef unsigned long pgprot_t;
#endif
+
+/* align addr on a size boundry - adjust address up if needed -- Cort */
+#define _ALIGN(addr,size) (((addr)+size-1)&(~(size-1)))
+
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
-/* This handles the memory map.. */
-
-#define KERNELBASE 0x90000000
-#define PAGE_OFFSET KERNELBASE
#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE)
#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE)
@@ -67,7 +88,8 @@ typedef unsigned long pgprot_t;
#define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT)
#define MAP_PAGE_RESERVED (1<<15)
+extern __inline__ unsigned long get_prezerod_page(void);
#endif /* __KERNEL__ */
-
+#endif /* __ASSEMBLY__ */
#endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index e9c400345..fd52a64c7 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -1,22 +1,31 @@
-/* * Last edited: Nov 7 23:44 1995 (cort) */
#ifndef _PPC_PGTABLE_H
#define _PPC_PGTABLE_H
+#include <linux/config.h>
#include <asm/page.h>
#include <asm/mmu.h>
-inline void flush_tlb(void);
-inline void flush_tlb_all(void);
-inline void flush_tlb_mm(struct mm_struct *mm);
-inline void flush_tlb_page(struct vm_area_struct *vma, long vmaddr);
-inline void flush_tlb_range(struct mm_struct *mm, long start, long end);
-inline void flush_page_to_ram(unsigned long);
-inline void really_flush_cache_all(void);
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void flush_tlb(void);
+
+/* Caches aren't brain-dead on the ppc. */
+#define flush_cache_all()
+#define flush_cache_mm(mm)
+#define flush_cache_range(mm, start, end)
+#define flush_cache_page(vma, vmaddr)
+/*
+ * For the page specified, write modified lines in the data cache
+ * out to memory, and invalidate lines in the instruction cache.
+ */
+extern void flush_page_to_ram(unsigned long);
-/* only called from asm in head.S, so why bother? */
-/*void MMU_init(void);*/
+extern unsigned long va_to_phys(unsigned long address);
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
+/* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
#define PMD_SHIFT 22
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
@@ -27,8 +36,8 @@ inline void really_flush_cache_all(void);
#define PGDIR_MASK (~(PGDIR_SIZE-1))
/*
- * entries per page directory level: the i386 is two-level, so
- * we don't really have any PMD directory physically.
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
*/
#define PTRS_PER_PTE 1024
#define PTRS_PER_PMD 1
@@ -41,41 +50,42 @@ inline void really_flush_cache_all(void);
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
-/* this must be a decent size since the ppc bat's can map only certain sizes
- but these can be different from the physical ram size configured.
- bat mapping must map at least physical ram size and vmalloc start addr
- must beging AFTER the area mapped by the bat.
- 32 works for now, but may need to be changed with larger differences.
- offset = next greatest bat mapping to ramsize - ramsize
- (ie would be 0 if batmapping = ramsize)
- -- Cort 10/6/96
- */
-#define VMALLOC_OFFSET (32*1024*1024)
+#define VMALLOC_OFFSET (0x2000000) /* 32M */
#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define _PAGE_PRESENT 0x001
-#define _PAGE_RW 0x002
-#define _PAGE_USER 0x004
-#define _PAGE_PCD 0x010
-#define _PAGE_ACCESSED 0x020
-#define _PAGE_DIRTY 0x040
-#define _PAGE_COW 0x200 /* implemented in software (one of the AVL bits) */
-#define _PAGE_NO_CACHE 0x400
+/*
+ * Bits in a linux-style PTE. These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */
+#define _PAGE_USER 0x002 /* matches one of the PP bits */
+#define _PAGE_RW 0x004 /* software: user write access allowed */
+#define _PAGE_GUARDED 0x008
+#define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */
+#define _PAGE_DIRTY 0x080 /* C: page changed */
+#define _PAGE_ACCESSED 0x100 /* R: page referenced */
+#define _PAGE_HWWRITE 0x200 /* software: _PAGE_RW & _PAGE_DIRTY */
-#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_COW)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
+ _PAGE_ACCESSED)
+#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-#define PAGE_KERNEL_NO_CACHE __pgprot(_PAGE_NO_CACHE | _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+ _PAGE_HWWRITE | _PAGE_ACCESSED)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_NO_CACHE | _PAGE_RW | \
+ _PAGE_HWWRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
/*
- * The i386 can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis. So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
*/
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
@@ -96,18 +106,6 @@ inline void really_flush_cache_all(void);
#define __S111 PAGE_SHARED
/*
- * Define this if things work differently on a i386 and a i486:
- * it will (on a i486) warn about kernel memory accesses that are
- * done without a 'verify_area(VERIFY_WRITE,..)'
- */
-#undef CONFIG_TEST_VERIFY_AREA
-
-#if 0
-/* page table for 0-4MB for everybody */
-extern unsigned long pg0[1024];
-#endif
-
-/*
* BAD_PAGETABLE is used when we need a bogus page-table, while
* BAD_PAGE is used for a bogus page.
*
@@ -119,49 +117,36 @@ extern pte_t * __bad_pagetable(void);
extern unsigned long empty_zero_page[1024];
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE __bad_pagetable()
+#define BAD_PAGE __bad_page()
+#define ZERO_PAGE ((unsigned long) empty_zero_page)
/* number of bits that fit into a memory pointer */
-#define BITS_PER_PTR (8*sizeof(unsigned long))
+#define BITS_PER_PTR (8*sizeof(unsigned long))
/* to align the pointer to a pointer address */
-#define PTR_MASK (~(sizeof(void*)-1))
+#define PTR_MASK (~(sizeof(void*)-1))
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
+/* sizeof(void*) == 1<<SIZEOF_PTR_LOG2 */
/* 64-bit machines, beware! SRB. */
-#define SIZEOF_PTR_LOG2 2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
+#define SIZEOF_PTR_LOG2 2
/* to set the page-dir */
/* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) \
-do { \
- (tsk)->tss.pg_tables = (unsigned long *)(pgdir); \
- if ((tsk) == current) \
- { \
-/*_printk("Change page tables = %x\n", pgdir);*/ \
- } \
-} while (0)
-
-/* comes from include/linux/mm.h now -- Cort */
-/*extern void *high_memory;*/
+#define SET_PAGE_DIR(tsk,pgdir) ({ \
+ ((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
+})
extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
-extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE; }
-extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
-extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
+extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != 0; }
+extern inline int pmd_present(pmd_t pmd) { return (pmd_val(pmd) & PAGE_MASK) != 0; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
-extern inline void pmd_reuse(pmd_t * pmdp) { }
+
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -172,7 +157,6 @@ extern inline int pgd_bad(pgd_t pgd) { return 0; }
extern inline int pgd_present(pgd_t pgd) { return 1; }
extern inline void pgd_clear(pgd_t * pgdp) { }
-
/*
* The following only work if pte_present() is true.
* Undefined behaviour if not..
@@ -182,48 +166,82 @@ extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
-extern inline int pte_cow(pte_t pte) { return pte_val(pte) & _PAGE_COW; }
-
-extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_uncow(pte_t pte) { pte_val(pte) &= ~_PAGE_COW; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkcow(pte_t pte) { pte_val(pte) |= _PAGE_COW; return pte; }
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
+extern inline int pte_uncache(pte_t pte) { return pte_val(pte) |= _PAGE_NO_CACHE; }
+extern inline int pte_cache(pte_t pte) { return pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+extern inline pte_t pte_rdprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_exprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+extern inline pte_t pte_wrprotect(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkclean(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+extern inline pte_t pte_mkold(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+extern inline pte_t pte_mkread(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkexec(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_RW;
+ if (pte_val(pte) & _PAGE_DIRTY)
+ pte_val(pte) |= _PAGE_HWWRITE;
+ return pte;
+}
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_DIRTY;
+ if (pte_val(pte) & _PAGE_RW)
+ pte_val(pte) |= _PAGE_HWWRITE;
+ return pte;
+}
+extern inline pte_t pte_mkyoung(pte_t pte) {
+ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
/* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#if 1
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#else
+extern inline void set_pte(pte_t *pteptr, pte_t pteval)
+{
+ unsigned long val = pte_val(pteval);
+ extern void xmon(void *);
+
+ if ((val & _PAGE_PRESENT) && ((val < 0x111000 || (val & 0x800)
+ || ((val & _PAGE_HWWRITE) && (~val & (_PAGE_RW|_PAGE_DIRTY)))) {
+ printk("bad pte val %lx ptr=%p\n", val, pteptr);
+ xmon(0);
+ }
+ *pteptr = pteval;
+}
+#endif
-static pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
{ pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
-/*#define mk_pte_phys(physpage, pgprot) \
-({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })*/
extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
+{ pte_t pte; pte_val(pte) = __pa(page) | pgprot_val(pgprot); return pte; }
extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
extern inline unsigned long pte_page(pte_t pte)
-{ return pte_val(pte) & PAGE_MASK; }
+{ return (pte_val(pte) & PAGE_MASK) + KERNELBASE; }
extern inline unsigned long pmd_page(pmd_t pmd)
-{ return pmd_val(pmd) & PAGE_MASK; }
+{ return pmd_val(pmd); }
/* to find an entry in a kernel page-table-directory */
@@ -250,13 +268,14 @@ extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address)
/*
* Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any, and marks the page tables reserved.
+ * used to allocate a kernel page table, but are actually identical
+ * to the xxx() versions.
*/
extern inline void pte_free_kernel(pte_t * pte)
{
free_page((unsigned long) pte);
}
+
extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
{
address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -264,20 +283,17 @@ extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (page) {
-/* pmd_set(pmd,page);*/
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+ pmd_val(*pmd) = (unsigned long) page;
return page + address;
}
-/* pmd_set(pmd, BAD_PAGETABLE);*/
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
free_page((unsigned long) page);
}
if (pmd_bad(*pmd)) {
printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-/* pmd_set(pmd, (pte_t *) BAD_PAGETABLE); */
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
return (pte_t *) pmd_page(*pmd) + address;
@@ -308,17 +324,17 @@ extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address)
pte_t * page = (pte_t *) get_free_page(GFP_KERNEL);
if (pmd_none(*pmd)) {
if (page) {
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
+ pmd_val(*pmd) = (unsigned long) page;
return page + address;
}
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
free_page((unsigned long) page);
}
if (pmd_bad(*pmd)) {
printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
- pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
+ pmd_val(*pmd) = (unsigned long) BAD_PAGETABLE;
return NULL;
}
return (pte_t *) pmd_page(*pmd) + address;
@@ -350,18 +366,17 @@ extern inline pgd_t * pgd_alloc(void)
extern pgd_t swapper_pg_dir[1024];
/*
- * Software maintained MMU tables may have changed -- update the
- * hardware [aka cache]
+ * Page tables may have changed. We don't need to do anything here
+ * as entries are faulted into the hash table by the low-level
+ * data/instruction access exception handlers.
*/
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
- unsigned long address, pte_t _pte);
+#define update_mmu_cache(vma,address,pte) while(0){}
#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
#define SWP_OFFSET(entry) ((entry) >> 8)
#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
-#define module_map vmalloc
-#define module_unmap vfree
+
#endif /* _PPC_PAGE_H */
diff --git a/include/asm-ppc/ppc_machine.h b/include/asm-ppc/ppc_machine.h
index 1cf9a7930..e69de29bb 100644
--- a/include/asm-ppc/ppc_machine.h
+++ b/include/asm-ppc/ppc_machine.h
@@ -1,56 +0,0 @@
-/*
- * PowerPC machine specifics
- */
-
-#ifndef _PPC_MACHINE_H_
-#define _PPC_MACHINE_H_
-
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
-
-/* Bit encodings for Machine State Register (MSR) */
-#define MSR_POW (1<<18) /* Enable Power Management */
-#define MSR_TGPR (1<<17) /* TLB Update registers in use */
-#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */
-#define MSR_EE (1<<15) /* External Interrupt enable */
-#define MSR_PR (1<<14) /* Supervisor/User privilege */
-#define MSR_FP (1<<13) /* Floating Point enable */
-#define MSR_ME (1<<12) /* Machine Check enable */
-#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */
-#define MSR_SE (1<<10) /* Single Step */
-#define MSR_BE (1<<9) /* Branch Trace */
-#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */
-#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */
-#define MSR_IR (1<<5) /* Instruction MMU enable */
-#define MSR_DR (1<<4) /* Data MMU enable */
-#define MSR_RI (1<<1) /* Recoverable Exception */
-#define MSR_LE (1<<0) /* Little-Endian enable */
-
-#define MSR_ MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
-#define MSR_USER MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
-
-/* Bit encodings for Hardware Implementation Register (HID0) */
-#define HID0_EMCP (1<<31) /* Enable Machine Check pin */
-#define HID0_EBA (1<<29) /* Enable Bus Address Parity */
-#define HID0_EBD (1<<28) /* Enable Bus Data Parity */
-#define HID0_SBCLK (1<<27)
-#define HID0_EICE (1<<26)
-#define HID0_ECLK (1<<25)
-#define HID0_PAR (1<<24)
-#define HID0_DOZE (1<<23)
-#define HID0_NAP (1<<22)
-#define HID0_SLEEP (1<<21)
-#define HID0_DPM (1<<20)
-#define HID0_ICE (1<<15) /* Instruction Cache Enable */
-#define HID0_DCE (1<<14) /* Data Cache Enable */
-#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */
-#define HID0_DLOCK (1<<12) /* Data Cache Lock */
-#define HID0_ICFI (1<<11) /* Instruction Cache Flash Invalidate */
-#define HID0_DCI (1<<10) /* Data Cache Invalidate */
-#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
-#define HID0_BHTE (1<<2) /* Branch History Table Enable */
-
-/* fpscr settings */
-#define FPSCR_FX (1<<31)
-#define FPSCR_FEX (1<<30)
-#endif
diff --git a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
index e3c715c0d..1e6baf0a6 100644
--- a/include/asm-ppc/processor.h
+++ b/include/asm-ppc/processor.h
@@ -1,12 +1,8 @@
#ifndef __ASM_PPC_PROCESSOR_H
#define __ASM_PPC_PROCESSOR_H
-/*
- * PowerPC machine specifics
- */
+#include <linux/config.h>
-#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
-#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
/* Bit encodings for Machine State Register (MSR) */
#define MSR_POW (1<<18) /* Enable Power Management */
@@ -26,7 +22,8 @@
#define MSR_RI (1<<1) /* Recoverable Exception */
#define MSR_LE (1<<0) /* Little-Endian enable */
-#define MSR_ MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_ MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_KERNEL MSR_|MSR_IR|MSR_DR
#define MSR_USER MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
/* Bit encodings for Hardware Implementation Register (HID0) */
@@ -49,20 +46,16 @@
#define HID0_DCI (1<<10) /* Data Cache Invalidate */
#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */
#define HID0_BHTE (1<<2) /* Branch History Table Enable */
-
/* fpscr settings */
#define FPSCR_FX (1<<31)
#define FPSCR_FEX (1<<30)
-
-
#ifndef __ASSEMBLY__
/*
* PowerPC machine specifics
*/
extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
-
/*
* Bus types
*/
@@ -77,82 +70,86 @@ extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long )
#define wp_works_ok 1
#define wp_works_ok__is_a_macro /* for versions in ksyms.c */
-/*
- * User space process size: 2GB. This is hardcoded into a few places,
- * so don't change it unless you know what you are doing.
- *
- * "this is gonna have to change to 1gig for the sparc" - David S. Miller
- */
#define TASK_SIZE (0x80000000UL)
-
/* This decides where the kernel will search for a free chunk of vm
* space during mmap's.
*/
#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
struct thread_struct
{
- unsigned long ksp; /* Kernel stack pointer */
- unsigned long *pg_tables; /* MMU information */
- unsigned long segs[16]; /* MMU Segment registers */
- unsigned long last_pc; /* PC when last entered system */
- unsigned long user_stack; /* [User] Stack when entered kernel */
- double fpr[32]; /* Complete floating point set */
- unsigned long wchan; /* Event task is sleeping on */
- unsigned long *regs; /* Pointer to saved register state */
- unsigned long fp_used; /* number of quantums fp was used */
- unsigned long fs; /* for get_fs() validation */
- unsigned long expc; /* exception handler addr (see fault.c) */
- unsigned long excount; /* exception handler count */
+ unsigned long ksp; /* Kernel stack pointer */
+ unsigned long *pg_tables; /* MMU information */
+#ifdef CONFIG_PMAC
+ unsigned long last_pc; /* PC when last entered system */
+ unsigned long user_stack; /* [User] Stack when entered kernel */
+#endif
+ unsigned long fpscr_pad; /* (so we can save fpscr with stfd) */
+ unsigned long fpscr; /* fp status reg */
+ double fpr[32]; /* Complete floating point set */
+ unsigned long fp_used;
+ unsigned long wchan; /* Event task is sleeping on */
+ struct pt_regs *regs; /* Pointer to saved register state */
+ unsigned long fs; /* for get_fs() validation */
+ signed long last_syscall;
+ unsigned long pad[2]; /* pad to 16-byte boundry */
};
+/* Points to the thread_struct of the thread (if any) which
+ currently owns the FPU. */
+#define fpu_tss (&(last_task_used_math->tss))
+
+#ifdef CONFIG_PMAC
+#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
+#endif
+#ifdef CONFIG_PREP
+#define LAZY_TSS_FPR_INIT 0,0,{0},
+#endif
#define INIT_TSS { \
- sizeof(init_kernel_stack) + (long) &init_kernel_stack,\
- (long *)swapper_pg_dir, {0}, \
- 0, 0, {0}, \
- 0, 0, 0, \
- KERNEL_DS, 0, 0 \
+ sizeof(init_stack) + (long) &init_stack, /* ksp */ \
+ (long *)swapper_pg_dir, /* pg_tables */ \
+ LAZY_TSS_FPR_INIT \
+ 0, /*fp_used*/ 0, /*wchan*/ \
+ sizeof(init_stack) + (long)&init_stack - \
+ sizeof(struct pt_regs), /* regs */ \
+ KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
}
-#define INIT_MMAP { &init_mm, 0, 0x40000000, \
- PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-/* Free all resources held by a thread. */
-extern void release_thread(struct task_struct *);
+#define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
+ PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
/*
* Return saved PC of a blocked thread. For now, this is the "user" PC
*/
static inline unsigned long thread_saved_pc(struct thread_struct *t)
{
- return (t->last_pc);
+ return (t->regs) ? t->regs->nip : 0;
+ /*return (t->last_pc);*/
}
-#define _PROC_Motorola 0
-#define _PROC_IBM 1
-#define _PROC_Be 2
-
-int _Processor;
+extern int _machine;
+#define _MACH_Motorola 0
+#define _MACH_IBM 1
+#define _MACH_Be 2
+#define _MACH_Pmac 3
-/* Allocation and freeing of basic task resources. */
-#define alloc_task_struct() kmalloc(sizeof(struct task_struct), GFP_KERNEL)
-#define free_task_struct(p) kfree(p)
-
-#ifdef KERNEL_STACK_BUFFER
-/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
-#define alloc_kernel_stack() \
- (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
-#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
-#else
-#define alloc_kernel_stack() get_free_page(GFP_KERNEL)
-#define free_kernel_stack(page) free_page((page))
-#endif
+/*
+ * NOTE! The task struct and the stack go together
+ */
+#define alloc_task_struct() \
+ ((struct task_struct *) __get_free_pages(GFP_KERNEL,1,0))
+#define free_task_struct(p) free_pages((unsigned long)(p),1)
-#endif /* ASSEMBLY*/
+/* in process.c - for early bootup debug -- Cort */
+int ll_printk(const char *, ...);
+void ll_puts(const char *);
-/*
+#endif /* ndef ASSEMBLY*/
* Return_address is a replacement for __builtin_return_address(count)
+#define init_task (init_task_union.task)
+#define init_stack (init_task_union.stack)
+
+#endif /* __ASM_PPC_PROCESSOR_H */
* which on certain architectures cannot reasonably be implemented in GCC
* (MIPS, Alpha) or is unuseable with -fomit-frame-pointer (i386).
* Note that __builtin_return_address(x>=1) is forbidden because the GCC
diff --git a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
index 5bad3b9da..13b526172 100644
--- a/include/asm-ppc/ptrace.h
+++ b/include/asm-ppc/ptrace.h
@@ -2,54 +2,61 @@
#define _PPC_PTRACE_H
/*
- * This struct defines the way the registers are stored on the
- * kernel stack during a system call or other kernel entry.
- * Note: the "_overhead" and "_underhead" spaces are stack locations
- * used by called routines. Because of the way the PowerPC ABI
- * specifies the function prologue/epilogue, registers can be
- * saved in stack locations which are below the current stack
- * pointer (_underhead). If an interrupt occurs during this
- * [albeit] small time interval, registers which were saved on
- * the stack could be trashed by the interrupt save code. The
- * "_underhead" leaves a hole just in case this happens. It also
- * wastes 80 bytes of stack if it doesn't! Similarly, the called
- * routine stores some information "above" the stack pointer before
- * if gets adjusted. This is covered by the "_overhead" field
- * and [thankfully] is not totally wasted.
+ * this should only contain volatile regs
+ * since we can keep non-volatile in the tss
+ * should set this up when only volatiles are saved
+ * by intr code.
*
+ * I can't find any reference to the above comment (from Gary Thomas)
+ * about _underhead/_overhead in the sys V abi for the ppc
+ * dated july 25, 1994.
+ *
+ * the stack must be kept to a size that is a multiple of 16
+ * so this includes the stack frame overhead
+ * -- Cort.
+ */
+
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't. To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
*/
+#define STACK_FRAME_OVERHEAD 16
+#define STACK_UNDERHEAD 64
+#ifndef __ASSEMBLY__
struct pt_regs {
- unsigned long _overhead[14]; /* Callee's SP,LR,params */
- unsigned long gpr[32];
- unsigned long nip;
- unsigned long msr;
- unsigned long ctr;
- unsigned long link;
- unsigned long ccr;
- unsigned long xer;
- unsigned long dar; /* Fault registers */
- unsigned long dsisr;
- unsigned long srr1;
- unsigned long srr0;
- unsigned long hash1, hash2;
- unsigned long imiss, dmiss;
- unsigned long icmp, dcmp;
- unsigned long orig_gpr3; /* Used for restarting system calls */
- unsigned long result; /* Result of a system call */
- double fpcsr;
- unsigned long trap; /* Reason for being here */
- unsigned long marker; /* Should have DEADDEAD */
- /*unsigned long _underhead[20]; *//* Callee's register save area */
- unsigned long edx; /* for binfmt_elf.c which wants edx */
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long ccr;
+ unsigned long xer;
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+#if 0
+ unsigned long srr1;
+ unsigned long srr0;
+ unsigned long hash1, hash2;
+ unsigned long imiss, dmiss;
+ unsigned long icmp, dcmp;
+#endif
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long result; /* Result of a system call */
+ unsigned long trap; /* Reason for being here */
+ unsigned long marker; /* Should have DEADDEAD */
};
+
#define instruction_pointer(regs) ((regs)->nip)
#define user_mode(regs) ((regs)->msr & 0x4000)
#ifdef KERNEL
extern void show_regs(struct pt_regs *);
#endif
+/* should include and generate these in ppc_defs.h -- Cort */
/* Offsets used by 'ptrace' system call interface */
/* Note: these should correspond to gpr[x] */
#define PT_R0 0
@@ -94,6 +101,7 @@ extern void show_regs(struct pt_regs *);
#define PT_CCR 38
#define PT_FPR0 48
+#endif /* __ASSEMBLY__ */
-#endif
+#endif /* _PPC_PTRACE_H */
diff --git a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h
index 4d1f91372..a4dfa0312 100644
--- a/include/asm-ppc/semaphore.h
+++ b/include/asm-ppc/semaphore.h
@@ -1,11 +1,18 @@
#ifndef _PPC_SEMAPHORE_H
#define _PPC_SEMAPHORE_H
+/*
+ * SMP- and interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ * Adapted for PowerPC by Gary Thomas and Paul Mackerras
+ */
+
#include <asm/atomic.h>
struct semaphore {
atomic_t count;
- atomic_t waiting;
+ atomic_t waking;
struct wait_queue * wait;
};
@@ -13,44 +20,61 @@ struct semaphore {
#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
extern void __down(struct semaphore * sem);
+extern int __down_interruptible(struct semaphore * sem);
extern void __up(struct semaphore * sem);
-extern void atomic_add(int c, int *v);
-extern void atomic_sub(int c, int *v);
+#define sema_init(sem, val) atomic_set(&((sem)->count), (val))
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ *
+ * This is trivially done with load_locked/store_cond,
+ * i.e. load with reservation and store conditional on the ppc.
+ */
-#define sema_init(sem, val) atomic_set(&((sem)->count), val)
+static inline void wake_one_more(struct semaphore * sem)
+{
+ atomic_inc(&sem->waking);
+}
static inline int waking_non_zero(struct semaphore *sem)
{
- unsigned long flags;
- int ret = 0;
+ int ret, tmp;
+
+ __asm__ __volatile__(
+ "1: lwarx %1,0,%2\n"
+ " cmpwi 0,%1,0\n"
+ " addi %1,%1,-1\n"
+ " ble- 2f\n"
+ " stwcx. %1,0,%2\n"
+ " bne- 1b\n"
+ " mr %0,%1\n"
+ "2:"
+ : "=r" (ret), "=r" (tmp)
+ : "r" (&sem->waking), "0" (0)
+ : "cr0", "memory");
- save_flags(flags);
- cli();
- if (atomic_read(&sem->waking) > 0) {
- atomic_dec(&sem->waking);
- ret = 1;
- }
- restore_flags(flags);
return ret;
}
extern inline void down(struct semaphore * sem)
{
- for (;;)
- {
- atomic_dec_return(&sem->count);
- if ( sem->count >= 0)
- break;
- __down(sem);
- }
+ if (atomic_dec_return(&sem->count) < 0)
+ __down(sem);
+}
+
+extern inline int down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+ if (atomic_dec_return(&sem->count) < 0)
+ ret = __down_interruptible(sem);
+ return ret;
}
extern inline void up(struct semaphore * sem)
{
- atomic_inc_return(&sem->count);
- if ( sem->count <= 0)
- __up(sem);
+ if (atomic_inc_return(&sem->count) <= 0)
+ __up(sem);
}
#endif /* !(_PPC_SEMAPHORE_H) */
diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
index 00a1e7c9a..7f54dd779 100644
--- a/include/asm-ppc/smp.h
+++ b/include/asm-ppc/smp.h
@@ -19,7 +19,7 @@ struct cpuinfo_PPC {
};
extern struct cpuinfo_PPC cpu_data[NR_CPUS];
-
+#endif /* __ASSEMBLY__ */
#endif /* !(__SMP__) */
diff --git a/include/asm-ppc/socket.h b/include/asm-ppc/socket.h
index d09474696..632717509 100644
--- a/include/asm-ppc/socket.h
+++ b/include/asm-ppc/socket.h
@@ -26,15 +26,12 @@
#define SO_PRIORITY 12
#define SO_LINGER 13
#define SO_BSDCOMPAT 14
-/* To add :#define SO_REUSEPORT 14 */
+/* To add :#define SO_REUSEPORT 15 */
#define SO_RCVLOWAT 16
#define SO_SNDLOWAT 17
#define SO_RCVTIMEO 18
#define SO_SNDTIMEO 19
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION 20
-#define SO_SECURITY_ENCRYPTION_TRANSPORT 21
-#define SO_SECURITY_ENCRYPTION_NETWORK 22
+#define SO_PASSCRED 20
+#define SO_PEERCRED 21
#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-ppc/string.h b/include/asm-ppc/string.h
index 66243582e..207ab3689 100644
--- a/include/asm-ppc/string.h
+++ b/include/asm-ppc/string.h
@@ -1,26 +1,27 @@
#ifndef _PPC_STRING_H_
#define _PPC_STRING_H_
-
-
-/*
- * keep things happy, the compile became unhappy since memset is
- * in include/linux/string.h and lib/string.c with different prototypes
- * -- Cort
- */
-#if 1
-#define __HAVE_ARCH_MEMSET
-extern __inline__ void * memset(void * s,int c,__kernel_size_t count)
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRNCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCHR
+/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
+extern inline void * memchr(const void * cs,int c,size_t count)
{
- char *xs = (char *) s;
-
- while (count--)
- *xs++ = c;
-
- return s;
+ unsigned long i = 0;
+ while ( count != i )
+ {
+ if ( (char)c == *(char *)(cs + i) )
+ return (void *)(cs + i);
+ i--;
+ }
+ return NULL;
}
#endif
-#define bzero(addr,size) memset((addr),(int)(0),(size))
-
-
-#endif
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index a1a3f12a0..df527e474 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -1,27 +1,66 @@
#ifndef __PPC_SYSTEM_H
#define __PPC_SYSTEM_H
-#if 0
-#define mb() \
-__asm__ __volatile__("mb": : :"memory")
-#endif
-#define mb() __asm__ __volatile__ ("" : : :"memory")
+#include <linux/delay.h>
+
+#define mb() __asm__ __volatile__ ("sync" : : : "memory")
+
+#define __save_flags(flags) ({\
+ __asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
+/* using Paul's in misc.S now -- Cort */
+extern void __restore_flags(unsigned long flags);
+/*
+ #define __sti() _soft_sti(void)
+ #define __cli() _soft_cli(void)
+ */
+extern void __sti(void);
+extern void __cli(void);
-extern void __save_flags(long *flags);
-extern void __restore_flags(long flags);
-extern void sti(void);
-extern void cli(void);
+extern void _hard_sti(void);
+extern void _hard_cli(void);
+extern void _soft_sti(void);
+extern void _soft_cli(void);
extern int _disable_interrupts(void);
extern void _enable_interrupts(int);
-/*extern void memcpy(void *, void *, int);*/
+extern void flush_instruction_cache(void);
+extern void hard_reset_now(void);
+extern void poweroff_now(void);
+extern void find_scsi_boot(void);
+extern int sd_find_target(void *, int);
+extern int _get_PVR(void);
+extern void via_cuda_init(void);
+extern void read_rtc_time(void);
+extern void pmac_find_display(void);
+extern void giveup_fpu(void);
+extern void store_cache_range(unsigned long, unsigned long);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
+
+struct device_node;
+extern void note_scsi_host(struct device_node *, void *);
struct task_struct;
extern void switch_to(struct task_struct *prev, struct task_struct *next);
-#define save_flags(flags) __save_flags(&(flags))
-#define restore_flags(flags) __restore_flags(flags)
+struct thread_struct;
+extern void _switch(struct thread_struct *prev, struct thread_struct *next,
+ unsigned long context);
+
+struct pt_regs;
+extern int do_signal(unsigned long oldmask, struct pt_regs *regs);
+extern void dump_regs(struct pt_regs *);
+
+#ifndef __SMP__
+#define cli() __cli()
+#define sti() __sti()
+#define save_flags(flags) __save_flags(flags)
+#define restore_flags(flags) __restore_flags(flags)
+
+#else
+#error need global cli/sti etc. defined for SMP
+#endif
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff --git a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h
index 6c19c1fef..65cab0612 100644
--- a/include/asm-ppc/termbits.h
+++ b/include/asm-ppc/termbits.h
@@ -7,7 +7,6 @@ typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
-#if 0 /* This is how it's done on Alpha - maybe later. */
/*
* termios type and macro definitions. Be careful about adding stuff
* to this file since it's used in GNU libc and there are strict rules
@@ -27,23 +26,24 @@ struct termios {
};
/* c_cc characters */
-#define VEOF 0
-#define VEOL 1
-#define VEOL2 2
-#define VERASE 3
-#define VWERASE 4
-#define VKILL 5
-#define VREPRINT 6
-#define VSWTC 7
-#define VINTR 8
-#define VQUIT 9
-#define VSUSP 10
-#define VSTART 12
-#define VSTOP 13
-#define VLNEXT 14
-#define VDISCARD 15
-#define VMIN 16
-#define VTIME 17
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VMIN 5
+#define VEOL 6
+#define VTIME 7
+#define VEOL2 8
+#define VSWTC 9
+
+#define VWERASE 10
+#define VREPRINT 11
+#define VSUSP 12
+#define VSTART 13
+#define VSTOP 14
+#define VLNEXT 15
+#define VDISCARD 16
/* c_iflag bits */
#define IGNBRK 0000001
@@ -57,7 +57,7 @@ struct termios {
#define ICRNL 0000400
#define IXON 0001000
#define IXOFF 0002000
-#if !defined(KERNEL) || defined(__USE_BSD)
+#if defined(__KERNEL__) || defined(__USE_BSD)
/* POSIX.1 doesn't want these... */
# define IXANY 0004000
# define IUCLC 0010000
@@ -102,7 +102,7 @@ struct termios {
#define XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
/* c_cflag bit meaning */
-#define CBAUD 0000017
+#define CBAUD 0000377
#define B0 0000000 /* hang up */
#define B50 0000001
#define B75 0000002
@@ -173,6 +173,5 @@ struct termios {
#define TCSANOW 0
#define TCSADRAIN 1
#define TCSAFLUSH 2
-#endif
#endif /* _PPC_TERMBITS_H */
diff --git a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h
index 26d88027f..b5e8c78df 100644
--- a/include/asm-ppc/termios.h
+++ b/include/asm-ppc/termios.h
@@ -137,18 +137,6 @@ struct termio {
unsigned char c_cc[NCC]; /* control characters */
};
-#define NCCS 19
-struct termios {
- tcflag_t c_iflag; /* input mode flags */
- tcflag_t c_oflag; /* output mode flags */
- tcflag_t c_cflag; /* control mode flags */
- tcflag_t c_lflag; /* local mode flags */
- cc_t c_cc[NCCS]; /* control characters */
- cc_t c_line; /* line discipline (== c_cc[19]) */
- int c_ispeed; /* input speed */
- int c_ospeed; /* output speed */
-};
-
/* c_cc characters */
#define _VINTR 0
#define _VQUIT 1
@@ -161,150 +149,11 @@ struct termios {
#define _VEOL2 8
#define _VSWTC 9
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VMIN 5
-#define VEOL 6
-#define VTIME 7
-#define VEOL2 8
-#define VSWTC 9
-
-#define VWERASE 10
-#define VREPRINT 11
-#define VSUSP 12
-#define VSTART 13
-#define VSTOP 14
-#define VLNEXT 15
-#define VDISCARD 16
-
-
#ifdef __KERNEL__
-/* eof=^D eol=\0 eol2=\0 erase=del
- werase=^W kill=^U reprint=^R sxtc=\0
- intr=^C quit=^\ susp=^Z <OSF/1 VDSUSP>
- start=^Q stop=^S lnext=^V discard=^U
- vmin=\1 vtime=\0
-#define INIT_C_CC "\004\000\000\177\027\025\022\000\003\034\032\000\021\023\026\025\001\000"
-*/
-
/* ^C ^\ del ^U ^D 1 0 0 0 0 ^W ^R ^Z ^Q ^S ^V ^U */
#define INIT_C_CC "\003\034\177\025\004\001\000\000\000\000\027\022\032\021\023\026\025"
#endif
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK 0000020
-#define ISTRIP 0000040
-#define INLCR 0000100
-#define IGNCR 0000200
-#define ICRNL 0000400
-#define IXON 0001000
-#define IXOFF 0002000
-#define IXANY 0004000
-#define IUCLC 0010000
-#define IMAXBEL 0020000
-
-/* c_oflag bits */
-#define OPOST 0000001
-#define ONLCR 0000002
-#define OLCUC 0000004
-
-#define OCRNL 0000010
-#define ONOCR 0000020
-#define ONLRET 0000040
-
-#define OFILL 00000100
-#define OFDEL 00000200
-#define NLDLY 00001400
-#define NL0 00000000
-#define NL1 00000400
-#define NL2 00001000
-#define NL3 00001400
-#define TABDLY 00006000
-#define TAB0 00000000
-#define TAB1 00002000
-#define TAB2 00004000
-#define TAB3 00006000
-#define CRDLY 00030000
-#define CR0 00000000
-#define CR1 00010000
-#define CR2 00020000
-#define CR3 00030000
-#define FFDLY 00040000
-#define FF0 00000000
-#define FF1 00040000
-#define BSDLY 00100000
-#define BS0 00000000
-#define BS1 00100000
-#define VTDLY 00200000
-#define VT0 00000000
-#define VT1 00200000
-#define XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
-
-/* c_cflag bit meaning */
-#define CBAUD 0000377
-#define B0 0000000 /* hang up */
-#define B50 0000001
-#define B75 0000002
-#define B110 0000003
-#define B134 0000004
-#define B150 0000005
-#define B200 0000006
-#define B300 0000007
-#define B600 0000010
-#define B1200 0000011
-#define B1800 0000012
-#define B2400 0000013
-#define B4800 0000014
-#define B9600 0000015
-#define B19200 0000016
-#define B38400 0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CBAUDEX 0000020
-#define B57600 00020
-#define B115200 00021
-#define B230400 00022
-#define B460800 00023
-
-#define CSIZE 00001400
-#define CS5 00000000
-#define CS6 00000400
-#define CS7 00001000
-#define CS8 00001400
-
-#define CSTOPB 00002000
-#define CREAD 00004000
-#define PARENB 00010000
-#define PARODD 00020000
-#define HUPCL 00040000
-
-#define CLOCAL 00100000
-#define CRTSCTS 020000000000 /* flow control */
-
-/* c_lflag bits */
-#define ISIG 0x00000080
-#define ICANON 0x00000100
-#define XCASE 0x00004000
-#define ECHO 0x00000008
-#define ECHOE 0x00000002
-#define ECHOK 0x00000004
-#define ECHONL 0x00000010
-#define NOFLSH 0x80000000
-#define TOSTOP 0x00400000
-#define ECHOCTL 0x00000040
-#define ECHOPRT 0x00000020
-#define ECHOKE 0x00000001
-#define FLUSHO 0x00800000
-#define PENDIN 0x20000000
-#define IEXTEN 0x00000400
-
/* modem lines */
#define TIOCM_LE 0x001
#define TIOCM_DTR 0x002
@@ -321,23 +170,6 @@ struct termios {
/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-
-/* tcflow() and TCXONC use these */
-#define TCOOFF 0
-#define TCOON 1
-#define TCIOFF 2
-#define TCION 3
-
-/* tcflush() and TCFLSH use these */
-#define TCIFLUSH 0
-#define TCOFLUSH 1
-#define TCIOFLUSH 2
-
-/* tcsetattr uses these */
-#define TCSANOW 0
-#define TCSADRAIN 1
-#define TCSAFLUSH 2
-
/* line disciplines */
#define N_TTY 0
#define N_SLIP 1
@@ -349,55 +181,33 @@ struct termios {
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+ unsigned short __tmp; \
+ get_user(__tmp,&(termio)->x); \
+ (termios)->x = (0xffff0000 & (termios)->x) | __tmp; \
+}
+
#define user_termio_to_kernel_termios(termios, termio) \
-do { \
- unsigned short tmp; \
- get_user(tmp, &(termio)->c_iflag); \
- (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
- get_user(tmp, &(termio)->c_oflag); \
- (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
- get_user(tmp, &(termio)->c_cflag); \
- (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
- get_user(tmp, &(termio)->c_lflag); \
- (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
- get_user((termios)->c_line, &(termio)->c_line); \
- get_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
- get_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
- get_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
- get_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
- get_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
- get_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
- get_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
- get_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
- get_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
- get_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
-} while(0)
+({ \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
/*
* Translate a "termios" structure into a "termio". Ugh.
- *
- * Note the "fun" _VMIN overloading.
*/
#define kernel_termios_to_user_termio(termio, termios) \
-do { \
+({ \
put_user((termios)->c_iflag, &(termio)->c_iflag); \
put_user((termios)->c_oflag, &(termio)->c_oflag); \
put_user((termios)->c_cflag, &(termio)->c_cflag); \
put_user((termios)->c_lflag, &(termio)->c_lflag); \
put_user((termios)->c_line, &(termio)->c_line); \
- put_user((termios)->c_cc[VINTR], &(termio)->c_cc[_VINTR]); \
- put_user((termios)->c_cc[VQUIT], &(termio)->c_cc[_VQUIT]); \
- put_user((termios)->c_cc[VERASE], &(termio)->c_cc[_VERASE]); \
- put_user((termios)->c_cc[VKILL], &(termio)->c_cc[_VKILL]); \
- put_user((termios)->c_cc[VEOF], &(termio)->c_cc[_VEOF]); \
- put_user((termios)->c_cc[VEOL], &(termio)->c_cc[_VEOL]); \
- put_user((termios)->c_cc[VEOL2], &(termio)->c_cc[_VEOL2]); \
- put_user((termios)->c_cc[VSWTC], &(termio)->c_cc[_VSWTC]); \
- if (1/*!((termios)->c_lflag & ICANON)*/) { \
- put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
- put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
- } \
-} while(0)
+ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
diff --git a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
index 927447dbd..b1e19ef1f 100644
--- a/include/asm-ppc/uaccess.h
+++ b/include/asm-ppc/uaccess.h
@@ -1,22 +1,30 @@
-#ifndef _ASM_UACCESS_H
-#define _ASM_UACCESS_H
+#ifndef _PPC_UACCESS_H
+#define _PPC_UACCESS_H
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/errno.h>
-#define KERNEL_DS (0)
-#define USER_DS (1)
-
#define VERIFY_READ 0
#define VERIFY_WRITE 1
-#define get_fs() (current->tss.fs)
-#define get_ds() (KERNEL_DS)
-#define set_fs(val) ( current->tss.fs = (val))
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+
+#define KERNEL_DS (0)
+#define USER_DS (1)
+
+#define get_fs() (current->tss.fs)
+#define get_ds() (KERNEL_DS)
+#define set_fs(val) (current->tss.fs = (val))
#define __user_ok(addr,size) (((size) <= 0x80000000)&&((addr) <= 0x80000000-(size)))
-#define __kernel_ok (get_fs() == KERNEL_DS)
+#define __kernel_ok (get_fs() == KERNEL_DS)
#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
@@ -25,126 +33,227 @@ extern inline int verify_area(int type, const void * addr, unsigned long size)
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry
+{
+ unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+
/*
* These are the main single-value transfer routines. They automatically
* use the right size if we just have the right pointer type.
*
- * As the powerpc uses the same address space for kernel and user
- * data, we can just do these as direct assignments. (Of course, the
- * exception handling means that it's no longer "just"...)
+ * This gets kind of ugly. We want to return _two_ values in "get_user()"
+ * and yet we don't want to do any pointers, because that is too much
+ * of a performance impact. Thus we have a few rather ugly macros here,
+ * and hide all the uglyness from the user.
+ *
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
*
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof/typeof is ok)
- * (b) require any knowledge of processes at this stage
+ * As we use the same address space for kernel and user data on the
+ * PowerPC, we can just do these as direct assignments. (Of course, the
+ * exception handling means that it's no longer "just"...)
*/
+#define get_user(x,ptr) \
+ __get_user_check((x),(ptr),sizeof(*(ptr)))
+#define put_user(x,ptr) \
+ __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+#define __get_user(x,ptr) \
+ __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user(x,ptr) \
+ __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
/*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the programmer has to do the
- * checks by hand with "access_ok()")
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
*/
-#define put_user(x,ptr) ({ \
-unsigned long __pu_addr = (unsigned long)(ptr); \
-__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
-#define get_user(x,ptr) ({ \
-unsigned long __gu_addr = (unsigned long)(ptr); \
-__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+#define put_user_ret(x,ptr,ret) ({ \
+if (put_user(x,ptr)) return ret; })
+
+#define get_user_ret(x,ptr,ret) ({ \
+if (get_user(x,ptr)) return ret; })
+
+#define __put_user_ret(x,ptr,ret) ({ \
+if (__put_user(x,ptr)) return ret; })
+
+#define __get_user_ret(x,ptr,ret) ({ \
+if (__get_user(x,ptr)) return ret; })
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err; \
+ __put_user_size((x),(ptr),(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_check(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
+ __put_user_size((x),__pu_addr,(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __put_user_asm(x,ptr,retval,"stb"); break; \
+ case 2: __put_user_asm(x,ptr,retval,"sth"); break; \
+ case 4: __put_user_asm(x,ptr,retval,"stw"); break; \
+ default: __put_user_bad(); \
+ } \
+} while (0)
-#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
-#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
struct __large_struct { unsigned long buf[100]; };
-#define __m(x) ((struct __large_struct *)(x))
-
-#define __put_user_check(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
-
-#define __put_user_nocheck(x,addr,size) ({ \
-int __pu_ret; \
-__pu_ret = -EFAULT; \
-switch (size) { \
-case 1: __pu_ret =__put_user_8(x,addr); break; \
-case 2: __pu_ret =__put_user_16(x,addr); break; \
-case 4: __pu_ret =__put_user_32(x,addr); break; \
-default: __pu_ret = __put_user_bad(); break; \
-} __pu_ret; })
-
-extern int __put_user_bad(void);
-
-#define __get_user_check(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-if (__access_ok(addr,size)) { \
-switch (size) { \
-case 1: __gu_val = __get_user_8(__gu_val,addr); break; \
-case 2: __gu_val = __get_user_16(__gu_val,addr); break; \
-case 4: __gu_val = __get_user_32(__gu_val,addr); break; \
-default: __get_user_bad(); break; \
-} } (x) = (type) __gu_val; __gu_ret; })
-
-#define __get_user_nocheck(x,addr,size,type) ({ \
-register int __gu_ret asm("r4"); \
-unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
-switch (size) { \
-case 1: __gu_val =__get_user_8(__gu_val,addr); break; \
-case 2: __gu_val =__get_user_16(__gu_val,addr); break; \
-case 4: __gu_val =__get_user_32(__gu_val,addr); break; \
-default: __gu_val = __get_user_bad(); break; \
-} (x) = (type) __gu_val; __gu_ret; })
-
+#define __m(x) (*(struct __large_struct *)(x))
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ */
+#define __put_user_asm(x, addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" %1,0(%2)\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r"(err) \
+ : "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
+
+
+#define __get_user_nocheck(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err = -EFAULT, __gu_val = 0; \
+ const __typeof__(*(ptr)) *__gu_addr = (ptr); \
+ if (access_ok(VERIFY_READ,__gu_addr,size)) \
+ __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __get_user_asm(x,ptr,retval,"lbz"); break; \
+ case 2: __get_user_asm(x,ptr,retval,"lhz"); break; \
+ case 4: __get_user_asm(x,ptr,retval,"lwz"); break; \
+ default: (x) = __get_user_bad(); \
+ } \
+} while (0)
+
+#define __get_user_asm(x, addr, err, op) \
+ __asm__ __volatile__( \
+ "1: "op" %1,0(%2)\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: li %0,%3\n" \
+ " li %1,0\n" \
+ " b 2b\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 2\n" \
+ " .long 1b,3b\n" \
+ ".text" \
+ : "=r"(err), "=r"(x) \
+ : "b"(addr), "i"(-EFAULT), "0"(err))
/* more complex routines */
-extern int __copy_tofrom_user(unsigned long to, unsigned long from, int size);
-
-#define copy_to_user(to,from,n) ({ \
-unsigned long __copy_to = (unsigned long) (to); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_tofrom_user(__copy_to, (unsigned long) (from), __copy_size); \
-} \
-__copy_res; })
-
-#define copy_from_user(to,from,n) ({ \
-unsigned long __copy_from = (unsigned long) (from); \
-unsigned long __copy_size = (unsigned long) (n); \
-unsigned long __copy_res = -EFAULT; \
-if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_tofrom_user((unsigned long) (to), __copy_from, __copy_size); \
-} \
-__copy_res; })
-
-extern int __clear_user(unsigned long addr, int size);
-
-#define clear_user(addr,n) ({ \
-unsigned long __clear_addr = (unsigned long) (addr); \
-int __clear_size = (int) (n); \
-int __clear_res = -EFAULT; \
-if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
-__clear_res = __clear_user(__clear_addr, __clear_size); \
-} \
-__clear_res; })
-
-extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
-
-#define strncpy_from_user(dest,src,count) ({ \
-unsigned long __sfu_src = (unsigned long) (src); \
-int __sfu_count = (int) (count); \
-long __sfu_res = -EFAULT; \
-if(__access_ok(__sfu_src, __sfu_count)) { \
-__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
-} __sfu_res; })
+extern int __copy_tofrom_user(void *to, const void *from, unsigned long size);
+
+extern inline unsigned long
+copy_from_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ return __copy_tofrom_user(to, from, n);
+ return n? -EFAULT: 0;
+}
+
+extern inline unsigned long
+copy_to_user(void *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ return __copy_tofrom_user(to, from, n);
+ return n? -EFAULT: 0;
+}
+
+#define __copy_from_user(to, from, size) \
+ __copy_tofrom_user((to), (from), (size))
+#define __copy_to_user(to, from, size) \
+ __copy_tofrom_user((to), (from), (size))
+
+extern unsigned long __clear_user(void *addr, unsigned long size);
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+ if (access_ok(VERIFY_WRITE, addr, size))
+ return __clear_user(addr, size);
+ return size? -EFAULT: 0;
+}
+
+extern int __strncpy_from_user(char *dst, const char *src, long count);
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ if (access_ok(VERIFY_READ, src, 1))
+ return __strncpy_from_user(dst, src, count);
+ return -EFAULT;
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 for error
+ */
+
+extern long strlen_user(const char *);
#endif /* __ASSEMBLY__ */
-#endif /* _ASM_UACCESS_H */
+#endif /* _PPC_UACCESS_H */
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index 47b0a7912..5665d906c 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -1,10 +1,6 @@
-/* * Last edited: Nov 17 16:28 1995 (cort) */
#ifndef _ASM_PPC_UNISTD_H_
#define _ASM_PPC_UNISTD_H_
-#define _NR(n) #n
-#define _lisc(n) "li 0," _NR(n)
-
/*
* This file contains the system call numbers.
*/
@@ -175,180 +171,79 @@
#define __NR_mremap 163
#define __NR_setresuid 164
#define __NR_getresuid 165
-#define __NR_nfsservctl 166
+#define __NR_query_module 166
+#define __NR_poll 167
+#define __NR_nfsservctl 168
+
+#define __NR(n) #n
+#define __do_syscall(n) \
+ asm volatile ("li 0,%0\n\
+ sc\n\
+ bns 1f\n\
+ mr 0,3\n\
+ lis 3,errno@ha\n\
+ stw 0,errno@l(3)\n\
+ li 3,-1\n\
+1:" : : "i" (n) : "r0", "r3")
-/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
type name(void) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
-
+{ __do_syscall(__NR_##name); }
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5) \
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- __asm__ (_lisc(__NR_##name)); \
- __asm__ ("sc"); \
- __asm__ ("mr 31,3"); \
- __asm__ ("bns 10f"); \
- __asm__ ("mr 0,3"); \
- __asm__ ("lis 3,errno@ha"); \
- __asm__ ("stw 0,errno@l(3)"); \
- __asm__ ("li 3,-1"); \
- __asm__ ("10:"); \
-}
+{ __do_syscall(__NR_##name); }
#ifdef __KERNEL_SYSCALLS__
/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
+ * Forking from kernel space will result in NO COPY ON WRITE (!!!),
+ * until an execve is executed. This is no problem, but for the stack.
+ * This is handled by not letting main() use the stack at all after
+ * fork(). On the PowerPC, this means we can only call leaf functions.
*/
-
-#if 0
/*
- This is the mechanism for creating a new kernel thread.
- For the time being it only behaves the same as clone().
- It should be changed very soon to work properly and cleanly. This
- gets us going for now, though.
-
- some versions of gcc hate this -- complains about constraints being
- incorrect. not sure why so it's in arch/ppc/kernel/misc.S now.
- -- Cort
+ * Create a new kernel thread.
*/
-static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- long retval;
- __asm__ (
- "li 0, 120 \n\t" /* __NR_clone */
- "li 3, %5 \n\t" /* load flags as arg to clone */
- /*"mr 1,7 \n\t"*/ /* save kernel stack */
- "sc \n\t" /* syscall */
- /*"cmp 0,1,7 \n\t"*/ /* if kernel stack changes -- child */
- "cmpi 0,3,0 \n\t"
- "bne 1f \n\t" /* return if parent */
- /* this is in child */
- "li 3, %3 \n\t" /* child -- load args and call fn */
- "mtlr %4 \n\t"
- "blrl \n\t"
- "li 0, %2 \n\t" /* exit after child exits */
- "li 3, 0 \n\t"
- "sc \n\t"
- /* parent */
- "1: \n\t"
- :"=3" (retval)
- :"i" (__NR_clone), "i" (__NR_exit),
- "r" (arg), "r" (fn), "g" (CLONE_VM|flags)
- :"cc", "1", "0", "3", "7", "31", "memory" );
- return retval;
-}
-#else
extern long __kernel_thread(unsigned long, int (*)(void *), void *);
static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
return __kernel_thread(flags | CLONE_VM, fn, arg);
}
-#endif
-#define __NR__exit __NR_exit
-static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */
-static inline _syscall0(int,fork) /* needs to be inline */
-static inline _syscall0(int,pause) /* needs to be inline */
-static inline _syscall1(int,setup,int,magic) /* called in init before execve */
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static /*inline*/ _syscall1(int,dup,int,fd)
-static /*inline*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static /*inline*/ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static /*inline*/ _syscall1(int,close,int,fd)
-static /*inline*/ _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall2(int,clone,unsigned long,flags,char *,esp)
+/*
+ * System call prototypes.
+ */
+int idle(void);
+int setup(int);
+int sync(void);
+pid_t setsid(void);
+int write(int, const char *, off_t);
+int dup(int);
+int execve(const char *, char **, char **);
+int open(const char *, int, int);
+int close(int);
+pid_t waitpid(pid_t, int *, int);
-/* called from init before execve -- need to be inline? -- Cort */
static inline pid_t wait(int * wait_stat)
{
return waitpid(-1,wait_stat,0);
}
-#endif
+#endif /* __KERNEL_SYSCALLS__ */
#endif /* _ASM_PPC_UNISTD_H_ */
-
-
diff --git a/include/asm-sparc/fbio.h b/include/asm-sparc/fbio.h
index 7c4ba26e4..6d2f1e730 100644
--- a/include/asm-sparc/fbio.h
+++ b/include/asm-sparc/fbio.h
@@ -48,7 +48,6 @@ struct fbtype {
};
#define FBIOGTYPE _IOR('F', 0, struct fbtype)
-/* Used by FBIOPUTCMAP */
struct fbcmap {
int index; /* first element (0 origin) */
int count;
@@ -150,6 +149,21 @@ struct fb_wid_list {
#define FBIO_WID_PUT _IOW('F', 32, struct fb_wid_list)
#define FBIO_WID_GET _IOWR('F', 33, struct fb_wid_list)
+/* Creator ioctls */
+#define FFB_IOCTL ('F'<<8)
+#define FFB_SYS_INFO (FFB_IOCTL|80)
+#define FFB_CLUTREAD (FFB_IOCTL|81)
+#define FFB_CLUTPOST (FFB_IOCTL|82)
+#define FFB_SETDIAGMODE (FFB_IOCTL|83)
+#define FFB_GETMONITORID (FFB_IOCTL|84)
+#define FFB_GETVIDEOMODE (FFB_IOCTL|85)
+#define FFB_SETVIDEOMODE (FFB_IOCTL|86)
+#define FFB_SETSERVER (FFB_IOCTL|87)
+#define FFB_SETOVCTL (FFB_IOCTL|88)
+#define FFB_GETOVCTL (FFB_IOCTL|89)
+#define FFB_GETSAXNUM (FFB_IOCTL|90)
+#define FFB_FBDEBUG (FFB_IOCTL|91)
+
/* Cg14 ioctls */
#define MDI_IOCTL ('M'<<8)
#define MDI_RESET (MDI_IOCTL|1)
@@ -174,15 +188,15 @@ struct mdi_cfginfo {
*/
#define MDI_CLEAR_XLUT (MDI_IOCTL|9)
-/* leo ioctls */
-struct leo_clut_alloc {
+/* leo & ffb ioctls */
+struct fb_clut_alloc {
__u32 clutid; /* Set on return */
__u32 flag;
__u32 index;
};
-struct leo_clut {
-#define LEO_CLUT_WAIT 0x00000001 /* Not yet implemented */
+struct fb_clut {
+#define FB_CLUT_WAIT 0x00000001 /* Not yet implemented */
__u32 flag;
__u32 clutid;
__u32 offset;
@@ -191,10 +205,21 @@ struct leo_clut {
char * green;
char * blue;
};
-#define LEO_CLUTALLOC _IOWR('L', 53, struct leo_clut_alloc)
-#define LEO_CLUTFREE _IOW('L', 54, struct leo_clut_alloc)
-#define LEO_CLUTREAD _IOW('L', 55, struct leo_clut)
-#define LEO_CLUTPOST _IOW('L', 56, struct leo_clut)
+
+struct fb_clut32 {
+ __u32 flag;
+ __u32 clutid;
+ __u32 offset;
+ __u32 count;
+ __u32 red;
+ __u32 green;
+ __u32 blue;
+};
+
+#define LEO_CLUTALLOC _IOWR('L', 53, struct fb_clut_alloc)
+#define LEO_CLUTFREE _IOW('L', 54, struct fb_clut_alloc)
+#define LEO_CLUTREAD _IOW('L', 55, struct fb_clut)
+#define LEO_CLUTPOST _IOW('L', 56, struct fb_clut)
#define LEO_SETGAMMA _IOW('L', 68, int) /* Not yet implemented */
#define LEO_GETGAMMA _IOR('L', 69, int) /* Not yet implemented */
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
index 106fa4e1b..62a97ed40 100644
--- a/include/asm-sparc/smp.h
+++ b/include/asm-sparc/smp.h
@@ -6,6 +6,8 @@
#ifndef _SPARC_SMP_H
#define _SPARC_SMP_H
+#include <asm/head.h>
+
#ifndef __ASSEMBLY__
/* PROM provided per-processor information we need
* to start them all up.
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index 577f3c877..6b2852c29 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -1,4 +1,4 @@
-/* $Id: oplib.h,v 1.7 1997/04/03 09:29:25 davem Exp $
+/* $Id: oplib.h,v 1.8 1997/07/24 12:15:15 davem Exp $
* oplib.h: Describes the interface and available routines in the
* Linux Prom library.
*
@@ -179,8 +179,7 @@ extern enum prom_output_device prom_query_output_device(void);
/* Start the CPU with the given device tree node, context table, and context
* at the passed program counter.
*/
-extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table,
- int context, char *program_counter);
+extern void prom_startcpu(int cpunode, unsigned long pc, unsigned long o0);
/* Stop the CPU with the passed device tree node. */
extern int prom_stopcpu(int cpunode);
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 5cbd9a3c5..5d31b3bf5 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.49 1997/06/30 09:24:12 jj Exp $
+/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
* pgtable.h: SpitFire page table operations.
*
* Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -158,33 +158,33 @@ extern void *sparc_init_alloc(unsigned long *kbrk, unsigned long size);
/* Cache and TLB flush operations. */
-#define flush_cache_all() \
-do { unsigned long va; \
- flushw_all(); \
- for(va = 0; \
- va<(PAGE_SIZE<<1); \
- va += 32) \
-spitfire_put_icache_tag(va,0x0);\
-} while(0)
-
+/* These are the same regardless of whether this is an SMP kernel or not. */
#define flush_cache_mm(mm) do { } while(0)
#define flush_cache_range(mm, start, end) do { } while(0)
#define flush_cache_page(vma, page) do { } while(0)
/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_page_to_ram(page) do { } while (0)
+#define flush_page_to_ram(page) do { } while (0)
-extern void flush_tlb_all(void);
+extern void __flush_cache_all(void);
+extern void __flush_tlb_all(void);
extern void __flush_tlb_mm(unsigned long context);
+extern void __flush_tlb_range(unsigned long context, unsigned long start,
+ unsigned long end);
+extern void __flush_tlb_page(unsigned long context, unsigned long page);
+
+#ifndef __SMP__
+
+#define flush_cache_all() __flush_cache_all()
+#define flush_tlb_all() __flush_tlb_all()
+
extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT)
__flush_tlb_mm(mm->context & 0x1fff);
}
-extern void __flush_tlb_range(unsigned long context, unsigned long start,
- unsigned long end);
extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
unsigned long end)
{
@@ -192,7 +192,6 @@ extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start
__flush_tlb_range(mm->context & 0x1fff, start, end);
}
-extern void __flush_tlb_page(unsigned long context, unsigned long page);
extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
struct mm_struct *mm = vma->vm_mm;
@@ -201,6 +200,41 @@ extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long
__flush_tlb_page(mm->context & 0x1fff, page & PAGE_MASK);
}
+#else /* __SMP__ */
+
+extern void smp_flush_cache_all(void);
+extern void smp_flush_tlb_all(void);
+extern void smp_flush_tlb_mm(struct mm_struct *mm);
+extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+
+#define flush_cache_all() smp_flush_cache_all()
+#define flush_tlb_all() smp_flush_tlb_all()
+
+extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
+{
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_mm(mm);
+}
+
+extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_range(mm, start, end);
+}
+
+extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if(mm->context != NO_CONTEXT)
+ smp_flush_tlb_page(vma, page);
+}
+
+#endif
+
extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
{ return __pte(__pa(page) | pgprot_val(pgprot)); }
diff --git a/include/asm-sparc64/semaphore.h b/include/asm-sparc64/semaphore.h
index 57dc42260..297173a89 100644
--- a/include/asm-sparc64/semaphore.h
+++ b/include/asm-sparc64/semaphore.h
@@ -24,20 +24,17 @@ extern void __up(struct semaphore * sem);
#define wake_one_more(sem) atomic_inc(&sem->waking);
-extern __inline__ int waking_non_zero(struct semaphore *sem)
-{
- unsigned long flags;
- int ret = 0;
-
- save_flags(flags);
- cli();
- if (atomic_read(&sem->waking) > 0) {
- atomic_dec(&sem->waking);
- ret = 1;
- }
- restore_flags(flags);
- return ret;
-}
+#define waking_non_zero(sem) \
+({ unsigned long flags; \
+ int ret = 0; \
+ save_and_cli(flags); \
+ if (atomic_read(&sem->waking) > 0) { \
+ atomic_dec(&sem->waking); \
+ ret = 1; \
+ } \
+ restore_flags(flags); \
+ ret; \
+})
extern __inline__ void down(struct semaphore * sem)
{
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index 73fc71780..116f83237 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -19,7 +19,7 @@ struct prom_cpuinfo {
};
extern int linux_num_cpus; /* number of CPUs probed */
-extern struct prom_cpuinfo linux_cpus[NCPUS];
+extern struct prom_cpuinfo linux_cpus[NR_CPUS];
#endif /* !(__ASSEMBLY__) */
@@ -35,8 +35,12 @@ struct cpuinfo_sparc {
extern struct cpuinfo_sparc cpu_data[NR_CPUS];
-typedef __volatile__ unsigned char klock_t;
-extern klock_t kernel_flag;
+struct klock_info {
+ unsigned char kernel_flag;
+ unsigned char akp;
+};
+
+extern struct klock_info klock_info;
#define KLOCK_HELD 0xff
#define KLOCK_CLEAR 0x00
@@ -47,7 +51,7 @@ extern klock_t kernel_flag;
extern int smp_found_cpus;
extern unsigned char boot_cpu_id;
-extern unsigned int cpu_present_map;
+extern unsigned long cpu_present_map;
extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
extern __volatile__ unsigned long kernel_counter;
extern __volatile__ unsigned char active_kernel_processor;
@@ -68,42 +72,21 @@ typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
extern void smp_callin(void);
extern void smp_boot_cpus(void);
extern void smp_store_cpu_info(int id);
-extern void smp_cross_call(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4, unsigned long arg5);
-
-extern __inline__ void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
-extern __inline__ void xc1(smpfunc_t func, unsigned long arg1)
-{ smp_cross_call(func, arg1, 0, 0, 0, 0); }
-extern __inline__ void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
-{ smp_cross_call(func, arg1, arg2, 0, 0, 0); }
-extern __inline__ void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3)
-{ smp_cross_call(func, arg1, arg2, arg3, 0, 0); }
-extern __inline__ void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, 0); }
-extern __inline__ void xc5(smpfunc_t func, unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4, unsigned long arg5)
-{ smp_cross_call(func, arg1, arg2, arg3, arg4, arg5); }
extern __volatile__ int cpu_number_map[NR_CPUS];
extern __volatile__ int cpu_logical_map[NR_CPUS];
-extern __inline__ int smp_processor_id(void)
+extern __inline__ int hard_smp_processor_id(void)
{
- int cpuid;
+ unsigned long upaconfig;
- /* Get MID from UPA Config register, and use that. */
- __asm__ __volatile__("
- ldxa [%g0] %1, %0
- srlx %0, 17, %0
- and %0, 0x1f, %0
- " : "=r" cpuid
- : "i" (ASI_UPA_CONFIG));
-
- return cpuid;
+ __asm__ __volatile__("ldxa [%%g0] %1, %0"
+ : "=r" (upaconfig)
+ : "i" (ASI_UPA_CONFIG));
+ return ((upaconfig >> 17) & 0x1f);
}
+#define smp_processor_id() (current->processor)
extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
#endif /* !(__ASSEMBLY__) */
@@ -122,9 +105,6 @@ extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing pr
#define MBOX_IDLECPU2 0xFD
#define MBOX_STOPCPU2 0xFE
-
-#define NO_PROC_ID 0xFF
-
#define PROC_CHANGE_PENALTY 20
#define SMP_FROM_INT 1
@@ -132,4 +112,6 @@ extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing pr
#endif /* !(__SMP__) */
+#define NO_PROC_ID 0xFF
+
#endif /* !(_SPARC64_SMP_H) */
diff --git a/include/asm-sparc64/smp_lock.h b/include/asm-sparc64/smp_lock.h
index 12821b215..3012ed6bb 100644
--- a/include/asm-sparc64/smp_lock.h
+++ b/include/asm-sparc64/smp_lock.h
@@ -18,7 +18,69 @@
#define reacquire_kernel_lock(task, cpu, depth) do { } while(0)
#else
-#error SMP on sparc64 not supported yet
+
+#include <asm/hardirq.h>
+
+/* Release global kernel lock and global interrupt lock */
+#define release_kernel_lock(task, cpu, depth) \
+do { \
+ if((depth = (task)->lock_depth) != 0) { \
+ __cli(); \
+ (task)->lock_depth = 0; \
+ klock_info.akp = NO_PROC_ID; \
+ klock_info.kernel_flag = 0; \
+ } \
+ release_irqlock(cpu); \
+ __sti(); \
+} while(0)
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+#define reacquire_kernel_lock(task, cpu, depth) \
+do { \
+ if(depth) { \
+ register struct klock_info *klip asm("g1"); \
+ klip = &klock_info; \
+ __asm__ __volatile__("mov %%o7, %%g5\n\t" \
+ "call ___lock_reacquire_kernel\n\t" \
+ " mov %1, %%g2" \
+ : /* No outputs. */ \
+ : "r" (klip), "r" (depth) \
+ : "g2", "g3", "g5", "g7", "memory", "cc"); \
+ } \
+} while(0)
+
+/* The following acquire and release the master kernel global lock,
+ * the idea is that the usage of this mechanmism becomes less and less
+ * as time goes on, to the point where they are no longer needed at all
+ * and can thus disappear.
+ */
+
+/* Do not fuck with this without consulting arch/sparc64/lib/locks.S first! */
+extern __inline__ void lock_kernel(void)
+{
+ register struct klock_info *klip asm("g1");
+ klip = &klock_info;
+ __asm__ __volatile__("
+ mov %%o7, %%g5
+ call ___lock_kernel
+ ld [%%g6 + %0], %%g2
+" : : "i" (AOFF_task_lock_depth), "r" (klip)
+ : "g2", "g3", "g5", "g7", "memory", "cc");
+}
+
+/* Release kernel global lock. */
+extern __inline__ void unlock_kernel(void)
+{
+ register struct klock_info *klip asm("g1");
+ klip = &klock_info;
+ __asm__ __volatile__("
+ mov %%o7, %%g5
+ call ___unlock_kernel
+ ld [%%g6 + %0], %%g2
+" : : "i" (AOFF_task_lock_depth), "r" (klip)
+ : "g2", "g3", "g5", "memory", "cc");
+}
+
#endif /* (__SMP__) */
#endif /* !(__SPARC64_SMPLOCK_H) */
diff --git a/include/asm-sparc64/softirq.h b/include/asm-sparc64/softirq.h
index 8386e4a15..397d6bf50 100644
--- a/include/asm-sparc64/softirq.h
+++ b/include/asm-sparc64/softirq.h
@@ -68,6 +68,8 @@ extern atomic_t __sparc64_bh_counter;
#include <asm/spinlock.h>
+extern spinlock_t global_bh_lock;
+
#define init_bh(nr, routine) \
do { unsigned long flags; \
int ent = nr; \
@@ -115,13 +117,13 @@ do { unsigned long flags; \
#define softirq_trylock() \
({ \
int ret = 1; \
- if(atomic_add_return(1, &__sparc_bh_counter) != 1) { \
- atomic_dec(&__sparc_bh_counter); \
+ if(atomic_add_return(1, &__sparc64_bh_counter) != 1) { \
+ atomic_dec(&__sparc64_bh_counter); \
ret = 0; \
} \
ret; \
})
-#define softirq_endlock() atomic_dec(&__sparc_bh_counter)
+#define softirq_endlock() atomic_dec(&__sparc64_bh_counter)
#define clear_active_bhs(mask) \
do { unsigned long flags; \
spin_lock_irqsave(&global_bh_lock, flags); \
diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
index cefd43309..cf2e51c71 100644
--- a/include/asm-sparc64/spinlock.h
+++ b/include/asm-sparc64/spinlock.h
@@ -56,6 +56,14 @@ typedef struct { } rwlock_t;
/* All of these locking primitives are expected to work properly
* even in an RMO memory model, which currently is what the kernel
* runs in.
+ *
+ * There is another issue. Because we play games to save cycles
+ * in the non-contention case, we need to be extra careful about
+ * branch targets into the "spinning" code. They live in their
+ * own section, but the newer V9 branches have a shorter range
+ * than the traditional 32-bit sparc branch variants. The rule
+ * is that the branches that go into and out of the spinner sections
+ * must be pre-V9 branches.
*/
typedef unsigned char spinlock_t;
@@ -67,13 +75,15 @@ extern __inline__ void spin_lock(spinlock_t *lock)
{
__asm__ __volatile__("
1: ldstub [%0], %%g2
- brnz,a,pn %%g2, 2f
- ldub [%0], %%g2
- membar #LoadLoad | #LoadStore
+ brz,pt %%g2, 2f
+ membar #LoadLoad | #LoadStore
+ b,a %%xcc, 3f
+2:
.text 2
-2: brnz,a,pt 2b
+3: ldub [%0], %%g2
+4: brnz,a,pt %%g2, 4b
ldub [%0], %%g2
- b,a,pt %%xcc, 1b
+ b,a 1b
.previous
" : /* no outputs */
: "r" (lock)
@@ -104,14 +114,16 @@ extern __inline__ void spin_lock_irq(spinlock_t *lock)
{
__asm__ __volatile__("
wrpr %%g0, 15, %%pil
- ldstub [%0], %%g2
- brnz,a,pn %%g2, 2f
- ldub [%0], %%g2
- membar #LoadLoad | #LoadStore
+1: ldstub [%0], %%g2
+ brz,pt %%g2, 2f
+ membar #LoadLoad | #LoadStore
+ b,a 3f
+2:
.text 2
-2: brnz,a,pt 2b
+3: ldub [%0], %%g2
+4: brnz,a,pt %%g2, 4b
ldub [%0], %%g2
- b,a,pt %%xcc, 1b
+ b,a 1b
.previous
" : /* no outputs */
: "r" (lock)
@@ -133,18 +145,20 @@ extern __inline__ void spin_unlock_irq(spinlock_t *lock)
do { register spinlock_t *lp asm("g1"); \
lp = lock; \
__asm__ __volatile__( \
- " rdpr %%pil, %0\n\t" \
- " wrpr %%g0, 15, %%pil\n\t" \
- "1: ldstub [%1], %%g2\n\t" \
- " brnz,a,pnt %%g2, 2f\n\t" \
- " ldub [%1], %%g2\n\t" \
- " membar #LoadLoad | #LoadStore\n\t" \
- " .text 2\n\t" \
- "2: brnz,a,pt %%g2, 2b\n\t" \
- " ldub [%1], %%g2\n\t" \
- " b,a,pt %%xcc, 1b\n\t" \
+ "\n rdpr %%pil, %0\n" \
+ " wrpr %%g0, 15, %%pil\n" \
+ "1: ldstub [%1], %%g2\n" \
+ " brz,pt %%g2, 2f\n" \
+ " membar #LoadLoad | #LoadStore\n" \
+ " b,a 3f\n" \
+ "2:\n" \
+ " .text 2\n" \
+ "3: ldub [%1], %%g2\n" \
+ "4: brnz,a,pt %%g2, 4b\n" \
+ " ldub [%1], %%g2\n" \
+ " b,a 1b\n" \
" .previous\n" \
- : "=r" (flags) \
+ : "=&r" (flags) \
: "r" (lp) \
: "g2", "memory"); \
} while(0)
@@ -169,19 +183,20 @@ extern __inline__ void read_lock(rwlock_t *rw)
{
__asm__ __volatile__("
ldx [%0], %%g2
-1:
- brlz,pn %%g2, 2f
-4: add %%g2, 1, %%g3
- casx [%0], %%g2, %%g3
+1: brgez,pt %%g2, 4f
+ add %%g2, 1, %%g3
+ b,a 2f
+4: casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
- ldx [%0],%%g2
+ ldx [%0], %%g2
membar #LoadLoad | #LoadStore
.text 2
2: ldx [%0], %%g2
-3: brlz,pt %%g2, 3b
+3: brlz,a,pt %%g2, 3b
ldx [%0], %%g2
- b,a,pt %%xcc, 4b
+ b 4b
+ add %%g2, 1, %%g3
.previous
" : /* no outputs */
: "r" (rw)
@@ -193,8 +208,7 @@ extern __inline__ void read_unlock(rwlock_t *rw)
__asm__ __volatile__("
membar #StoreStore | #LoadStore
ldx [%0], %%g2
-1:
- sub %%g2, 1, %%g3
+1: sub %%g2, 1, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
@@ -208,31 +222,34 @@ extern __inline__ void write_lock(rwlock_t *rw)
{
__asm__ __volatile__("
sethi %%uhi(0x8000000000000000), %%g5
- ldx [%0] %%g2
+ ldx [%0], %%g2
sllx %%g5, 32, %%g5
-1:
- brlz,pn %%g2, 5f
-4: or %%g2, %%g5, %%g3
- casx [%0], %%g2, %%g3
+1: brgez,pt %%g2, 4f
+ or %%g2, %%g5, %%g3
+ b,a 5f
+4: casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
ldx [%0], %%g2
andncc %%g3, %%g5, %%g0
- bne,a,pn %%xcc, 3f
- ldx [%0], %%g2
- membar #LoadLoad | #LoadStore
+ be,pt %%xcc, 2f
+ membar #LoadLoad | #LoadStore
+ b,a 7f
+2:
.text 2
-3:
- andn %%g2, %%g5, %%g3
+7: ldx [%0], %%g2
+3: andn %%g2, %%g5, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 3b
ldx [%0], %%g2
membar #LoadLoad | #LoadStore
5: ldx [%0], %%g2
-6: brlz,pt %%g2, 6b
+6: brlz,a,pt %%g2, 6b
ldx [%0], %%g2
- b,a,pt %%xcc, 4b
+ b 4b
+ or %%g2, %%g5, %%g3
+ .previous
" : /* no outputs */
: "r" (rw)
: "g2", "g3", "g5", "memory", "cc");
@@ -245,8 +262,7 @@ extern __inline__ void write_unlock(rwlock_t *rw)
sethi %%uhi(0x8000000000000000), %%g5
ldx [%0], %%g2
sllx %%g5, 32, %%g5
-1:
- andn %%g2, %%g5, %%g3
+1: andn %%g2, %%g5, %%g3
casx [%0], %%g2, %%g3
cmp %%g2, %%g3
bne,a,pn %%xcc, 1b
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 6e7c42e55..ab05190e9 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.26 1997/06/28 10:04:03 davem Exp $ */
+/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
#ifndef __SPARC64_SYSTEM_H
#define __SPARC64_SYSTEM_H
@@ -74,7 +74,27 @@ extern unsigned long empty_zero_page;
#define restore_flags(x) __restore_flags(x)
#define save_and_cli(x) __save_and_cli(x)
#else
-#error SMP not supported on sparc64
+
+#ifndef __ASSEMBLY__
+extern unsigned char global_irq_holder;
+#endif
+
+#define save_flags(x) \
+do { ((x) = ((global_irq_holder == (unsigned char) smp_processor_id()) ? 1 : \
+ ((getipl() != 0) ? 2 : 0))); } while(0)
+
+#define save_and_cli(flags) do { save_flags(flags); cli(); } while(0)
+
+#ifndef __ASSEMBLY__
+extern void __global_cli(void);
+extern void __global_sti(void);
+extern void __global_restore_flags(unsigned long flags);
+#endif
+
+#define cli() __global_cli()
+#define sti() __global_sti()
+#define restore_flags(flags) __global_restore_flags(flags)
+
#endif
#define mb() __asm__ __volatile__ ("stbar" : : : "memory")
@@ -112,48 +132,48 @@ extern __inline__ void flushw_user(void)
* when modifying this code inspect output of sched.s very
* carefully to make sure things still work. -DaveM
*/
-#define switch_to(prev, next) \
-do { \
- __label__ switch_continue; \
- register unsigned long task_pc asm("o7"); \
- (prev)->tss.kregs->fprs = 0; \
- task_pc = ((unsigned long) &&switch_continue) - 0x8; \
- __asm__ __volatile__( \
- "rdpr %%pstate, %%g2\n\t" \
- "wrpr %%g2, 0x3, %%pstate\n\t" \
- "flushw\n\t" \
-/*XXX*/ "wr %%g0, 0, %%fprs\n\t" \
- "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
- "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
- "rdpr %%wstate, %%o5\n\t" \
- "stx %%o6, [%%g6 + %3]\n\t" \
- "stx %%o5, [%%g6 + %2]\n\t" \
- "rdpr %%cwp, %%o5\n\t" \
- "stx %%o7, [%%g6 + %4]\n\t" \
- "st %%o5, [%%g6 + %5]\n\t" \
- "mov %0, %%g6\n\t" \
- "ld [%0 + %5], %%g1\n\t" \
- "wrpr %%g1, %%cwp\n\t" \
- "ldx [%%g6 + %2], %%o5\n\t" \
- "ldx [%%g6 + %3], %%o6\n\t" \
- "ldx [%%g6 + %4], %%o7\n\t" \
- "mov %%g6, %0\n\t" \
- "wrpr %%o5, 0x0, %%wstate\n\t" \
- "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
- "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
- "wrpr %%g0, 0x96, %%pstate\n\t" \
- "jmpl %%o7 + 0x8, %%g0\n\t" \
- " mov %0, %%g6\n\t" \
- : /* No outputs */ \
- : "r" (next), "r" (task_pc), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \
- "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \
- : "cc", "g1", "g2", "g3", "g5", "g7", \
- "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
- "i0", "i1", "i2", "i3", "i4", "i5", \
- "o0", "o1", "o2", "o3", "o4", "o5"); \
+#define switch_to(prev, next) \
+do { __label__ switch_continue; \
+ register unsigned long task_pc asm("o7"); \
+ (prev)->tss.kregs->fprs = 0; \
+ task_pc = ((unsigned long) &&switch_continue) - 0x8; \
+ (next)->mm->cpu_vm_mask |= (1UL << smp_processor_id()); \
+ __asm__ __volatile__( \
+ "rdpr %%pstate, %%g2\n\t" \
+ "wrpr %%g2, 0x3, %%pstate\n\t" \
+ "flushw\n\t" \
+/*XXX*/ "wr %%g0, 0, %%fprs\n\t" \
+ "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \
+ "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \
+ "rdpr %%wstate, %%o5\n\t" \
+ "stx %%o6, [%%g6 + %3]\n\t" \
+ "stx %%o5, [%%g6 + %2]\n\t" \
+ "rdpr %%cwp, %%o5\n\t" \
+ "stx %%o7, [%%g6 + %4]\n\t" \
+ "st %%o5, [%%g6 + %5]\n\t" \
+ "mov %0, %%g6\n\t" \
+ "ld [%0 + %5], %%g1\n\t" \
+ "wrpr %%g1, %%cwp\n\t" \
+ "ldx [%%g6 + %2], %%o5\n\t" \
+ "ldx [%%g6 + %3], %%o6\n\t" \
+ "ldx [%%g6 + %4], %%o7\n\t" \
+ "mov %%g6, %0\n\t" \
+ "wrpr %%o5, 0x0, %%wstate\n\t" \
+ "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
+ "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
+ "wrpr %%g0, 0x96, %%pstate\n\t" \
+ "jmpl %%o7 + 0x8, %%g0\n\t" \
+ " mov %0, %%g6\n\t" \
+ : /* No outputs */ \
+ : "r" (next), "r" (task_pc), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ksp)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpc)), \
+ "i" ((const unsigned long)(&((struct task_struct *)0)->tss.cwp)) \
+ : "cc", "g1", "g2", "g3", "g5", "g7", \
+ "l1", "l2", "l3", "l4", "l5", "l6", "l7", \
+ "i0", "i1", "i2", "i3", "i4", "i5", \
+ "o0", "o1", "o2", "o3", "o4", "o5"); \
switch_continue: } while(0)
/* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 5a1dc90bf..82390ea64 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -49,9 +49,13 @@ struct dentry {
struct list_head d_alias; /* inode alias list */
struct list_head d_lru; /* d_count = 0 LRU list */
struct qstr d_name;
- struct dentry * (*d_revalidate)(struct dentry *);
+ unsigned long d_time; /* used by d_revalidate */
+ int (*d_revalidate)(struct dentry *);
};
+/* d_flags entries */
+#define DCACHE_AUTOFS_PENDING 0x0001 /* autofs: "under construction" */
+
/*
* d_drop() unhashes the entry from the parent
* dentry hashes, so that it won't be found through
@@ -102,8 +106,8 @@ extern struct dentry * d_lookup(struct dentry * dir, struct qstr * name);
extern int d_validate(struct dentry *dentry, struct dentry *dparent,
unsigned int hash, unsigned int len);
-/* write full pathname into buffer and return length */
-extern int d_path(struct dentry * entry, struct dentry * chroot, char * buf);
+/* write full pathname into buffer and return start of pathname */
+extern char * d_path(struct dentry * entry, char * buf, int buflen);
/* Allocation counts.. */
static inline struct dentry * dget(struct dentry *dentry)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4ccb6d569..665b56c38 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -672,7 +672,7 @@ extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
}
extern int check_disk_change(kdev_t dev);
-extern void invalidate_inodes(kdev_t dev);
+extern int invalidate_inodes(kdev_t dev);
extern void invalidate_inode_pages(struct inode *);
extern void invalidate_buffers(kdev_t dev);
extern int floppy_is_wp(int minor);
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 6ea9d896e..4886d464c 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -11,6 +11,7 @@
#define PC110PAD_MINOR 9
#define RTC_MINOR 135
#define SUN_OPENPROM_MINOR 139
+#define NVRAM_MINOR 144
#define MISC_DYNAMIC_MINOR 255
#define SGI_GRAPHICS_MINOR 146
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 674f69479..cab25f117 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -118,9 +118,8 @@ typedef struct page {
unsigned long offset;
struct page *next_hash;
atomic_t count;
+ unsigned int age;
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
- unsigned dirty:16,
- age:8;
struct wait_queue *wait;
struct page **pprev_hash;
struct buffer_head * buffers;
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index fb17117a0..dba07c796 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -7,7 +7,6 @@
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/fd.h>
-#include <linux/config.h>
#include <asm/byteorder.h>
@@ -72,13 +71,9 @@
#define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
-#ifdef CONFIG_ATARI
-#define EOF_FAT12 0xFFF /* Atari GEMDOS fs uses a different EOF */
-#define EOF_FAT16 0xFFFF
-#else
#define EOF_FAT12 0xFF8 /* standard EOF */
#define EOF_FAT16 0xFFF8
-#endif
+#define EOF_FAT(s) (MSDOS_SB(s)->fat_bits == 16 ? 0xFFF8 : 0xFF8)
/*
* Inode flags
diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
index bf5ea6345..4cc224838 100644
--- a/include/linux/msdos_fs_sb.h
+++ b/include/linux/msdos_fs_sb.h
@@ -18,7 +18,8 @@ struct fat_mount_options {
isvfat:1, /* 0=no vfat long filename support, 1=vfat support */
unicode_xlate:1, /* create escape sequences for unhandled Unicode */
posixfs:1, /* Allow names like makefile and Makefile to coexist */
- numtail:1; /* Does first alias have a numeric '~1' type tail? */
+ numtail:1, /* Does first alias have a numeric '~1' type tail? */
+ atari:1; /* Use Atari GEMDOS variation of MS-DOS fs */
};
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 45c55f5a3..eca37ac03 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -1,4 +1,4 @@
-/* $Id: parport.h,v 1.2.6.3.2.2 1997/04/18 15:03:53 phil Exp $ */
+/* $Id: parport.h,v 1.2 1997/07/29 04:00:12 ralf Exp $ */
#ifndef _PARPORT_H_
#define _PARPORT_H_
@@ -130,8 +130,7 @@ struct parport_device_info {
*
* 2) a wake-up function, called by the resource manager to tell drivers
* that the port is available to be claimed. If a driver wants to use
- * the port, it should call parport_claim() here. The return value from
- * this function is ignored.
+ * the port, it should call parport_claim() here.
*/
/* A parallel port device */
@@ -187,6 +186,9 @@ struct parport {
struct parport *parport_register_port(unsigned long base, int irq, int dma,
struct parport_operations *ops);
+/* Unregister a port. */
+void parport_unregister_port(struct parport *port);
+
/* parport_in_use returns nonzero if there are devices attached to a port. */
#define parport_in_use(x) ((x)->devices != NULL)
@@ -209,7 +211,7 @@ struct parport *parport_enumerate(void);
*/
struct pardevice *parport_register_device(struct parport *port,
const char *name,
- int (*pf)(void *), int (*kf)(void *),
+ int (*pf)(void *), void (*kf)(void *),
void (*irq_func)(int, void *, struct pt_regs *),
int flags, void *handle);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 80cdf71a7..901a8b9ef 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -336,7 +336,7 @@ struct openpromfs_dev {
};
extern struct inode_operations *
proc_openprom_register(int (*readdir)(struct inode *, struct file *, void *, filldir_t),
- int (*lookup)(struct inode *, struct qstr *, struct inode **),
+ int (*lookup)(struct inode *, struct dentry *),
void (*use)(struct inode *, int),
struct openpromfs_dev ***);
extern void proc_openprom_deregister(void);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 1aafb505f..f1fc28b18 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -384,33 +384,36 @@ extern spinlock_t pidhash_lock;
extern __inline__ void hash_pid(struct task_struct *p)
{
struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
+ unsigned long flags;
- spin_lock(&pidhash_lock);
+ spin_lock_irqsave(&pidhash_lock, flags);
if((p->pidhash_next = *htable) != NULL)
(*htable)->pidhash_pprev = &p->pidhash_next;
*htable = p;
p->pidhash_pprev = htable;
- spin_unlock(&pidhash_lock);
+ spin_unlock_irqrestore(&pidhash_lock, flags);
}
extern __inline__ void unhash_pid(struct task_struct *p)
{
- spin_lock(&pidhash_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pidhash_lock, flags);
if(p->pidhash_next)
p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
*p->pidhash_pprev = p->pidhash_next;
- spin_unlock(&pidhash_lock);
+ spin_unlock_irqrestore(&pidhash_lock, flags);
}
extern __inline__ struct task_struct *find_task_by_pid(int pid)
{
- struct task_struct **htable = &pidhash[pid_hashfn(pid)];
- struct task_struct *p;
+ struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
+ unsigned long flags;
- spin_lock(&pidhash_lock);
+ spin_lock_irqsave(&pidhash_lock, flags);
for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
;
- spin_unlock(&pidhash_lock);
+ spin_unlock_irqrestore(&pidhash_lock, flags);
return p;
}
@@ -441,7 +444,7 @@ extern void wake_up(struct wait_queue ** p);
extern void wake_up_interruptible(struct wait_queue ** p);
extern void wake_up_process(struct task_struct * tsk);
-extern void notify_parent(struct task_struct * tsk);
+extern void notify_parent(struct task_struct * tsk, int signal);
extern void release(struct task_struct * p);
extern void force_sig(unsigned long sig,struct task_struct * p);
extern int send_sig(unsigned long sig,struct task_struct * p,int priv);
diff --git a/include/linux/selection.h b/include/linux/selection.h
index cad2a29b0..e41e9ebef 100644
--- a/include/linux/selection.h
+++ b/include/linux/selection.h
@@ -23,11 +23,11 @@ extern unsigned long get_video_size_row(unsigned int console);
#define get_video_num_columns(dummy) video_num_columns
#define get_video_num_lines(dummy) video_num_lines
#define get_video_size_row(dummy) video_size_row
+#endif
+
extern unsigned long video_num_columns;
extern unsigned long video_num_lines;
extern unsigned long video_size_row;
-#endif
-
extern unsigned char video_type;
extern unsigned long video_mem_base;
extern unsigned long video_mem_term;
@@ -73,8 +73,6 @@ extern void putconsxy(int currcons, char *p);
/* how to access screen memory */
-#include <linux/config.h>
-
#if defined(CONFIG_TGA_CONSOLE)
extern int tga_blitc(unsigned int, unsigned long);
@@ -244,17 +242,25 @@ static inline unsigned char scr_readb(unsigned char * addr)
static inline void scr_writew(unsigned short val, unsigned short * addr)
{
+#ifdef __powerpc__
+ st_le16(addr, val);
+#else
if ((long) addr < 0)
*addr = val;
else
writew(val, (unsigned long) addr);
+#endif /* !__powerpc__ */
}
static inline unsigned short scr_readw(unsigned short * addr)
{
+#ifdef __powerpc__
+ return ld_le16(addr);
+#else
if ((long) addr < 0)
return *addr;
return readw((unsigned long) addr);
+#endif /* !__powerpc__ */
}
#endif /* CONFIG_TGA_CONSOLE */
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 8cfd21b0e..c65304671 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
*
- * $Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ * $Id: sysrq.h,v 1.1 1997/06/17 13:30:39 ralf Exp $
*
* Linux Magic System Request Key Hacks
*
@@ -9,12 +9,25 @@
#include <linux/config.h>
+struct pt_regs;
+struct kbd_struct;
+struct tty_struct;
+
+/* Generic SysRq interface -- you may call it from any device driver, supplying
+ * ASCII code of the key, pointer to registers and kbd/tty structs (if they
+ * are available -- else NULL's).
+ */
+
+void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+
+/* Deferred actions */
+
extern int emergency_sync_scheduled;
#define EMERG_SYNC 1
#define EMERG_REMOUNT 2
-extern void do_emergency_sync(void);
+void do_emergency_sync(void);
#ifdef CONFIG_MAGIC_SYSRQ
#define CHECK_EMERGENCY_SYNC \
diff --git a/init/main.c b/init/main.c
index 45211f11b..659f86b2e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -218,7 +218,7 @@ extern void sm_setup(char *str, int *ints);
#ifdef CONFIG_WDT
extern void wdt_setup(char *str, int *ints);
#endif
-#ifdef CONFIG_PNP_PARPORT
+#ifdef CONFIG_PARPORT
extern void parport_setup(char *str, int *ints);
#endif
#ifdef CONFIG_PLIP
@@ -522,7 +522,7 @@ struct {
#ifdef CONFIG_WDT
{ "wdt=", wdt_setup },
#endif
-#ifdef CONFIG_PNP_PARPORT
+#ifdef CONFIG_PARPORT
{ "parport=", parport_setup },
#endif
#ifdef CONFIG_PLIP
diff --git a/kernel/exit.c b/kernel/exit.c
index afa3e5393..23f0da655 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -119,12 +119,12 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv)
return 0;
}
-void notify_parent(struct task_struct * tsk)
+void notify_parent(struct task_struct * tsk, int signal)
{
- if (tsk->p_pptr == task[smp_num_cpus]) /* Init */
- tsk->exit_signal = SIGCHLD;
- send_sig(tsk->exit_signal, tsk->p_pptr, 1);
- wake_up_interruptible(&tsk->p_pptr->wait_chldexit);
+ struct task_struct * parent = tsk->p_pptr;
+
+ send_sig(signal, parent, 1);
+ wake_up_interruptible(&parent->wait_chldexit);
}
void release(struct task_struct * p)
@@ -346,11 +346,10 @@ static inline void forget_original_parent(struct task_struct * father)
read_lock(&tasklist_lock);
for_each_task(p) {
- if (p->p_opptr == father)
- if (task[smp_num_cpus]) /* init */
- p->p_opptr = task[smp_num_cpus];
- else
- p->p_opptr = task[0];
+ if (p->p_opptr == father) {
+ p->exit_signal = SIGCHLD;
+ p->p_opptr = task[smp_num_cpus] ? : task[0]; /* init */
+ }
}
read_unlock(&tasklist_lock);
}
@@ -488,7 +487,7 @@ static void exit_notify(void)
kill_pg(current->pgrp,SIGCONT,1);
}
/* Let father know we died */
- notify_parent(current);
+ notify_parent(current, current->exit_signal);
/*
* This loop does two things:
@@ -502,15 +501,13 @@ static void exit_notify(void)
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
p->flags &= ~(PF_PTRACED|PF_TRACESYS);
- if (task[smp_num_cpus] && task[smp_num_cpus] != current) /* init */
- p->p_pptr = task[smp_num_cpus];
- else
- p->p_pptr = task[0];
+
+ p->p_pptr = p->p_opptr;
p->p_osptr = p->p_pptr->p_cptr;
p->p_osptr->p_ysptr = p;
p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE)
- notify_parent(p);
+ notify_parent(p, p->exit_signal);
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
@@ -651,7 +648,7 @@ repeat:
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
SET_LINKS(p);
- notify_parent(p);
+ notify_parent(p, SIGCHLD);
} else
release(p);
#ifdef DEBUG_PROC_TREE
diff --git a/kernel/ksyms.c b/kernel/ksyms.c
index 8e55af454..e75cfcc5e 100644
--- a/kernel/ksyms.c
+++ b/kernel/ksyms.c
@@ -156,6 +156,7 @@ EXPORT_SYMBOL(d_add);
EXPORT_SYMBOL(d_move);
EXPORT_SYMBOL(d_instantiate);
EXPORT_SYMBOL(__mark_inode_dirty);
+EXPORT_SYMBOL(init_private_file);
EXPORT_SYMBOL(insert_file_free);
EXPORT_SYMBOL(check_disk_change);
EXPORT_SYMBOL(invalidate_buffers);
diff --git a/kernel/sched.c b/kernel/sched.c
index 5d35e45e0..7330129ec 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1379,6 +1379,11 @@ asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param)
asmlinkage int sys_sched_yield(void)
{
+ /*
+ * This is not really right. We'd like to reschedule
+ * just _once_ with this process having a zero count.
+ */
+ current->counter = 0;
spin_lock(&scheduler_lock);
spin_lock_irq(&runqueue_lock);
move_last_runqueue(current);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 8f813c655..b63f5469c 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -131,6 +131,9 @@ static char * number(char * str, long num, int base, int size, int precision
return str;
}
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char * buf, const char *fmt, ...);
+
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
@@ -250,6 +253,41 @@ int vsprintf(char *buf, const char *fmt, va_list args)
}
continue;
+ case 'I': /* IPv4 / IPv6 printout */
+ {
+ __u8 *ip4;
+ char sbuf[6];
+ if (qualifier == 'l') {
+ __u16 *ip6 = va_arg(args, __u16 *);
+ i = 6;
+ for ( ; i > 0; --i, ++ip6)
+ if (*ip6 != 0)
+ break;
+ if (i < 6)
+ *str++ = ':';
+ for ( ; i > 0; --i, ++ip6) {
+ sprintf(sbuf,":%04x",(int)(*ip6));
+ s = sbuf;
+ while (*s)
+ *str++ = *s++;
+ }
+ *str++ = ':';
+ ip4 = (__u8*) ip6;
+ } else {
+ ip4 = va_arg(args, __u8 *);
+ }
+ for (i = 0; i < 4; ++i, ++ip4) {
+ if (i == 3)
+ sprintf(sbuf,"%d", 0xFF & (*ip4));
+ else
+ sprintf(sbuf,"%d.", 0xFF & (*ip4));
+ s = sbuf;
+ while (*s)
+ *str++ = *s++;
+ }
+ }
+ continue;
+
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
diff --git a/mm/filemap.c b/mm/filemap.c
index 7c7740e65..03e82469e 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -64,7 +64,6 @@ void invalidate_inode_pages(struct inode * inode)
inode->i_nrpages--;
if ((*p = page->next) != NULL)
(*p)->prev = page->prev;
- page->dirty = 0;
page->next = NULL;
page->prev = NULL;
remove_page_from_hash_queue(page);
@@ -97,7 +96,6 @@ repeat:
inode->i_nrpages--;
if ((*p = page->next) != NULL)
(*p)->prev = page->prev;
- page->dirty = 0;
page->next = NULL;
page->prev = NULL;
remove_page_from_hash_queue(page);
diff --git a/mm/simp.c b/mm/simp.c
index 7959d6a0e..6ad6bc73c 100644
--- a/mm/simp.c
+++ b/mm/simp.c
@@ -6,6 +6,7 @@
*/
#include <linux/simp.h>
+#include <linux/tasks.h>
#include <linux/smp.h>
#include <linux/mm.h>
#include <asm/spinlock.h>
@@ -207,7 +208,6 @@ static void alloc_header(struct simp * simp)
simp->usable_list = hdr;
}
-
/* current x86 memcpy() is horribly moving around registers for nothing,
* is doing unnecessary work if the size is dividable by a power-of-two,
* and it clobbers way too many registers.
diff --git a/net/Changes b/net/Changes
index 30898803a..b6e1d5ea3 100644
--- a/net/Changes
+++ b/net/Changes
@@ -413,18 +413,20 @@ the frame following the ack. (The assumption being that the acks are
because a single frame in the data stream has been lost). Given a
mathematician with some queue theory you can show this allows you to
lose one frame per window full of data without measurable speed loss.
+[done]
4. RFC1323. These are the extensions for very fast nets.
RFC1323 will be useful for Linux talking to systems over 100Mb/sec
ethernet and over ATM as it allows large windows and protects from some
potential high speed TCP problems.
+[In progress]
6. Delayed ack. This is mostly supported but not actually set up and
used yet. Basically ack frames are held back 1/10th of a second in the hope
that two acks can be merged into one or for interactive use the ack can
piggyback on the next character typed (great improvement on 2400 baud
modems). Johannes Stille did some work on this about 0.99.13 but it never
-got merged in. [Pedro Roque]
+got merged in. [Pedro Roque] [Done, but needs fixing]
7. One on my tempting project list. Add an extra (unofficial - but so
is SLIP6) SLIP mode that does packet data compression [maybe use the code
@@ -439,7 +441,7 @@ driver but that's for an internal project and its general release is still
a maybe (so is finishing it ;))][Jim Freeman is working on Frame Relay as is
Mike McLagan][Fritz Elfert is doing the isdn4linux kit].
-11. IP over SCSI.
+11. IP over SCSI. [worked on]
14. Bidirectional PLIP. Also PLIP for the newer style parallel ports.
diff --git a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
index d26f008dd..3a8594fba 100644
--- a/net/ax25/ax25_ip.c
+++ b/net/ax25/ax25_ip.c
@@ -165,6 +165,8 @@ int ax25_rebuild_header(struct sk_buff *skb)
bp[14] |= AX25_EBIT;
bp[14] |= AX25_SSSID_SPARE;
+ skb_pull(skb, AX25_KISS_HEADER_LEN);
+
if (route->digipeat != NULL) {
if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
kfree_skb(skb, FREE_WRITE);
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index 2c7d082a9..911b54834 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -410,8 +410,6 @@ struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_
unsigned char *bp;
int len;
- skb_pull(skb, 1); /* skip KISS command */
-
len = digi->ndigi * AX25_ADDR_LEN;
if (skb_headroom(skb) < len) {
diff --git a/net/core/dev.c b/net/core/dev.c
index 2b593cbb1..93db2e220 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1082,8 +1082,9 @@ int dev_get_info(char *buffer, char **start, off_t offset, int length, int dummy
struct device *dev;
- size = sprintf(buffer, "Inter-| Receive | Transmit\n"
- " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier\n");
+ size = sprintf(buffer,
+ "Inter-| Receive | Transmit\n"
+ " face |bytes packets errs drop fifo frame|bytes packets errs drop fifo colls carrier\n");
pos+=size;
len+=size;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index e4fe370fd..d499873dd 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -5,7 +5,7 @@
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.23 1997/05/31 12:36:35 freitag Exp $
+ * Version: $Id: ip_fragment.c,v 1.2 1997/06/17 13:31:27 ralf Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
@@ -358,6 +358,9 @@ static struct sk_buff *ip_glue(struct ipq *qp)
fp = fp->next;
}
+ skb->pkt_type = qp->fragments->skb->pkt_type;
+ skb->protocol = qp->fragments->skb->protocol;
+
/* We glued together all fragments, so remove the queue entry. */
ip_free(qp);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 75346d6dc..31e1258e8 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -65,7 +65,8 @@ int ipip_rcv(struct sk_buff *skb, unsigned short len)
/*
* Discard the original IP header
*/
-
+
+ skb->mac.raw = skb->data;
skb_pull(skb, skb->h.raw - skb->nh.raw);
/*
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index e3b41e2ad..1184c9f41 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -77,7 +77,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
* This was very pretty but didn't work when a socket is destroyed
* at the wrong moment (eg a syn recv socket getting a reset), or
* a memory timer destroy. Instead of playing with timers we just
- * concede defeat and cli().
+ * concede defeat and do a start_bh_atomic().
*/
SOCKHASH_LOCK();
sp = pro->sklist_next;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index b43a972cc..0ba7640f6 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
+ * Version: $Id: tcp.c,v 1.2 1997/06/17 13:31:29 ralf Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -201,26 +201,6 @@
* Eric Schenk : Fix fast close down bug with
* shutdown() followed by close().
*
- * To Fix:
- * Fast path the code. Two things here - fix the window calculation
- * so it doesn't iterate over the queue, also spot packets with no funny
- * options arriving in order and process directly.
- *
- * Rewrite output state machine to use a single queue.
- * Speed up input assembly algorithm.
- * RFC1323 - PAWS and window scaling.[Required for IPv6]
- * User settable/learned rtt/max window/mtu
- *
- * Change the fundamental structure to a single send queue maintained
- * by TCP (removing the bogus ip stuff [thus fixing mtu drops on
- * active routes too]). Cut the queue off in tcp_retransmit/
- * tcp_transmit.
- * Change the receive queue to assemble as it goes. This lets us
- * dispose of most of tcp_sequence, half of tcp_ack and chunks of
- * tcp_data/tcp_read as well as the window shrink crud.
- * Separate out duplicated code - tcp_alloc_skb, tcp_build_ack
- * tcp_queue_skb seem obvious routines to extract.
- *
* 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
@@ -267,6 +247,9 @@
* for violations and the like. tcp.c is just too big... If I say something
* "does?" or "doesn't?", it means I'm not sure, and will have to hash it out
* with Alan. -- MS 950903
+ * [Note: Most of the TCP code has been rewriten/redesigned since this
+ * RFC1122 check. It is probably not correct anymore. It should be redone
+ * before 2.2. -AK]
*
* Use of PSH (4.2.2.2)
* MAY aggregate data sent without the PSH flag. (does)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d89624175..dfe60e712 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.1.1.1 1997/06/01 03:16:26 ralf Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.2 1997/07/20 15:01:56 ralf Exp $
*
* IPv4 specific functions
*
@@ -1205,7 +1205,7 @@ static inline struct sock *tcp_v4_check_req(struct sock *sk, struct sk_buff *skb
/* Check for syn retransmission */
flg = *(((u32 *)skb->h.th) + 3);
- flg &= __constant_htonl(0x002f0000);
+ flg &= __constant_htonl(0x001f0000);
if ((flg == __constant_htonl(0x00020000)) &&
(!after(skb->seq, req->rcv_isn))) {
/* retransmited syn
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b8e6ac4a5..1b4235dbd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: route.c,v 1.12 1997/04/29 09:38:50 mj Exp $
+ * $Id: route.c,v 1.1.1.1 1997/06/01 03:16:27 ralf Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1427,8 +1427,8 @@ static void rt6_info_node(struct fib6_node *fn, void *p_arg)
}
arg->len += sprintf(arg->buffer + arg->len,
" %08lx %08x %08x %08lx %8s\n",
- rt->rt6i_metric, rt->rt6i_use,
- rt->rt6i_ref, rt->rt6i_flags,
+ rt->rt6i_metric, atomic_read(&rt->rt6i_use),
+ atomic_read(&rt->rt6i_ref), rt->rt6i_flags,
rt->rt6i_dev ? rt->rt6i_dev->name : "");
}
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 51b9eff4c..9a5e2dfc7 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.2 1997/06/17 13:31:32 ralf Exp $
+ * $Id: tcp_ipv6.c,v 1.35 1997/07/23 15:18:04 freitag Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
@@ -699,7 +699,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb, void *ptr,
{
struct tcp_opt tp;
struct open_request *req;
- __u16 req_mss;
/* If the socket is dead, don't accept the connection. */
if (sk->dead) {
@@ -1048,7 +1047,7 @@ struct sock *tcp_v6_check_req(struct sock *sk, struct sk_buff *skb)
/* Check for syn retransmission */
flg = *(((u32 *)skb->h.th) + 3);
- flg &= __constant_htonl(0x002f0000);
+ flg &= __constant_htonl(0x001f0000);
if ((flg == __constant_htonl(0x00020000)) &&
(!after(skb->seq, req->rcv_isn))) {